commit 3d7202a91586823af74cb235ab60ebd2f33a536c Author: Deukhoofd Date: Mon Apr 12 20:25:02 2021 +0200 initial commit diff --git a/add_on/autowrapper/aswrappedcall.h b/add_on/autowrapper/aswrappedcall.h new file mode 100644 index 0000000..880265e --- /dev/null +++ b/add_on/autowrapper/aswrappedcall.h @@ -0,0 +1,581 @@ +#ifndef AS_GEN_WRAPPER_H +#define AS_GEN_WRAPPER_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include + +namespace gw { + +template class Proxy { + public: + T value; + Proxy(T value) : value(value) {} + static T cast(void * ptr) { + return reinterpret_cast *>(&ptr)->value; + } + private: + Proxy(const Proxy &); + Proxy & operator=(const Proxy &); +}; + +template struct Wrapper {}; +template struct ObjFirst {}; +template struct ObjLast {}; +template struct Constructor {}; + +template +void destroy(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + static_cast(gen->GetObject())->~T(); +} +template <> +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * /*gen*/) { + ((fp)()); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)()); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)()); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)()); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)()); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)()); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + Proxy::cast(gen->GetObject()))); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + Proxy::cast(gen->GetObject()))); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + Proxy::cast(gen->GetObject()))); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + Proxy::cast(gen->GetObject()))); + } +}; +template +struct Constructor { + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetObject()) T(); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value)); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct Constructor { + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetObject()) T( + static_cast *>(gen->GetAddressOfArg(0))->value); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value)); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct Constructor { + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetObject()) T( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value)); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct Constructor { + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetObject()) T( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct Wrapper { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((static_cast(gen->GetObject())->*fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct ObjFirst { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + Proxy::cast(gen->GetObject()), + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value)); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + ((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct ObjLast { + template + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetAddressOfReturnLocation()) Proxy((fp)( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value, + Proxy::cast(gen->GetObject()))); + } +}; +template +struct Constructor { + static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) { + new (gen->GetObject()) T( + static_cast *>(gen->GetAddressOfArg(0))->value, + static_cast *>(gen->GetAddressOfArg(1))->value, + static_cast *>(gen->GetAddressOfArg(2))->value, + static_cast *>(gen->GetAddressOfArg(3))->value); + } +}; +template +struct Id { + template AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&Wrapper::template f); } + template AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&ObjFirst::template f); } + template AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&ObjLast::template f); } +}; + +template +Id id(T /*fn_ptr*/) { return Id(); } + +// On some versions of GNUC it is necessary to use the template keyword as disambiguator, +// on others the template keyword gives an error, hence the need for the following define. +// MSVC on the other hand seems to accept both with or without the template keyword. +#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4)) + // GNUC 4.4.3 doesn't need the template keyword, and + // hopefully upcoming versions won't need it either + #define TMPL template +#else + #define TMPL +#endif + +#define WRAP_FN(name) (::gw::id(name).TMPL f< name >()) +#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).TMPL f< &ClassType::name >()) +#define WRAP_OBJ_FIRST(name) (::gw::id(name).TMPL of< name >()) +#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >()) + +#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< name >)) +#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< &ClassType::name >)) +#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst::TMPL f< name >)) +#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast::TMPL f< name >)) + +#define WRAP_CON(ClassType, Parameters) asFUNCTION((::gw::Constructor::f)) +#define WRAP_DES(ClassType) asFUNCTION((::gw::destroy)) + + +} // end namespace gw + +#endif diff --git a/add_on/autowrapper/generator/generateheader.cpp b/add_on/autowrapper/generator/generateheader.cpp new file mode 100644 index 0000000..277799a --- /dev/null +++ b/add_on/autowrapper/generator/generateheader.cpp @@ -0,0 +1,166 @@ +// +// This generator creates a header file that implements automatic +// wrapper functions for the generic calling convention. +// +// Originally implemented by George Yohng from 4Front Technologies in 2009-03-11 +// Modifications by Pierre Fortin in order to add constructor wrapper generation +// +// A completely new implementation of automatic wrapper functions was +// implemented by SiCrane at GameDev.net in 2011-12-18. The generator was +// adapted from Python to C++ by Andreas. +// +// ref: http://www.gamedev.net/topic/617111-more-angelscript-binding-wrappers/ +// + + +#include +#include + +// Generate templates for up to this number of function parameters +const int max_args = 4; + +using namespace std; + +void PrintTemplate(const char *base, const char *typeNameList, const char *retType, const char *objType, const char *isConst, const char *newExpr, const char *objExpr, const char *argList1, const char *argList2, const char *wrapName); +void PrintConstructor(const char *comma, const char *typeNameList, const char *typeList, const char *argList); + +int main() +{ + printf("#ifndef AS_GEN_WRAPPER_H\n" + "#define AS_GEN_WRAPPER_H\n" + "\n" + "#ifndef ANGELSCRIPT_H\n" + "// Avoid having to inform include path if header is already include before\n" + "#include \n" + "#endif\n" + "#include \n" + "\n" + "namespace gw {\n" + "\n" + "template class Proxy {\n" + " public:\n" + " T value;\n" + " Proxy(T value) : value(value) {}\n" + " static T cast(void * ptr) {\n" + " return reinterpret_cast *>(&ptr)->value;\n" + " }\n" + " private:\n" + " Proxy(const Proxy &);\n" + " Proxy & operator=(const Proxy &);\n" + "};\n" + "\n" + "template struct Wrapper {};\n" + "template struct ObjFirst {};\n" + "template struct ObjLast {};\n" + "template struct Constructor {};\n" + "\n" + "template \n" + "void destroy(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n" + " static_cast(gen->GetObject())->~T();\n" + "}\n"); + + string typename_list = "typename A0"; + string type_list = "A0"; + string arg_list = "\n static_cast *>(gen->GetAddressOfArg(0))->value"; + string new_exp = "new (gen->GetAddressOfReturnLocation()) Proxy"; + string obj_exp = "static_cast(gen->GetObject())->*"; + string obj_arg_exp = "\n Proxy::cast(gen->GetObject())"; + + PrintTemplate("", "", "void", "", "", "", "", "void", "", "Wrapper"); + PrintTemplate("typename R", "", "R", "", "", new_exp.c_str(), "", "void", "", "Wrapper"); + PrintTemplate("typename T", "", "void", "T::", "", "", obj_exp.c_str(), "void", "", "Wrapper"); + PrintTemplate("typename T, typename R", "", "R", "T::", "", new_exp.c_str(), obj_exp.c_str(), "void", "", "Wrapper"); + PrintTemplate("typename T", "", "void", "T::", " const", "", obj_exp.c_str(), "void", "", "Wrapper"); + PrintTemplate("typename T, typename R", "", "R", "T::", " const", new_exp.c_str(), obj_exp.c_str(), "void", "", "Wrapper"); + + PrintTemplate("typename T", "", "void", "", "", "", "", "T", obj_arg_exp.c_str(), "ObjFirst"); + PrintTemplate("typename T, typename R", "", "R", "", "", new_exp.c_str(), "", "T", obj_arg_exp.c_str(), "ObjFirst"); + PrintTemplate("typename T", "", "void", "", "", "", "", "T", obj_arg_exp.c_str(), "ObjLast"); + PrintTemplate("typename T, typename R", "", "R", "", "", new_exp.c_str(), "", "T", obj_arg_exp.c_str(), "ObjLast"); + + PrintConstructor("", "", "", ""); + + for( int i = 0; i < max_args; i++ ) + { + PrintTemplate("", typename_list.c_str(), "void", "", "", "", "", type_list.c_str(), arg_list.c_str(), "Wrapper"); + PrintTemplate("typename R, ", typename_list.c_str(), "R", "", "", new_exp.c_str(), "", type_list.c_str(), arg_list.c_str(), "Wrapper"); + PrintTemplate("typename T, ", typename_list.c_str(), "void", "T::", "", "", obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); + PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "T::", "", new_exp.c_str(), obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); + PrintTemplate("typename T, ", typename_list.c_str(), "void", "T::", " const", "", obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); + PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "T::", " const", new_exp.c_str(), obj_exp.c_str(), type_list.c_str(), arg_list.c_str(), "Wrapper"); + + PrintTemplate("typename T, ", typename_list.c_str(), "void", "", "", "", "", ("T, " + type_list).c_str(), (obj_arg_exp + "," + arg_list).c_str(), "ObjFirst"); + PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "", "", new_exp.c_str(), "", ("T, " + type_list).c_str(), (obj_arg_exp + "," + arg_list).c_str(), "ObjFirst"); + PrintTemplate("typename T, ", typename_list.c_str(), "void", "", "", "", "", (type_list + ", T").c_str(), (arg_list + "," + obj_arg_exp).c_str(), "ObjLast"); + PrintTemplate("typename T, typename R, ", typename_list.c_str(), "R", "", "", new_exp.c_str(), "", (type_list + ", T").c_str(), (arg_list + "," + obj_arg_exp).c_str(), "ObjLast"); + + PrintConstructor(", ", typename_list.c_str(), type_list.c_str(), arg_list.c_str()); + + char buf[5]; + sprintf(buf, "%d", i + 1); + typename_list += ", typename A" + string(buf); + type_list += ", A" + string(buf); + arg_list += ",\n static_cast *>(gen->GetAddressOfArg(" + string(buf) + "))->value"; + } + + printf("template \n" + "struct Id {\n" + " template AS_NAMESPACE_QUALIFIER asSFuncPtr f(void) { return asFUNCTION(&Wrapper::template f); }\n" + " template AS_NAMESPACE_QUALIFIER asSFuncPtr of(void) { return asFUNCTION(&ObjFirst::template f); }\n" + " template AS_NAMESPACE_QUALIFIER asSFuncPtr ol(void) { return asFUNCTION(&ObjLast::template f); }\n" + "};\n" + "\n" + "template \n" + "Id id(T fn_ptr) { return Id(); }\n" + "\n" + "// On some versions of GNUC it is necessary to use the template keyword as disambiguator,\n" + "// on others the template keyword gives an error, hence the need for the following define.\n" + "// MSVC on the other hand seems to accept both with or without the template keyword.\n" + "#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 4))\n" + " // GNUC 4.4.3 doesn't need the template keyword, and\n" + " // hopefully upcoming versions won't need it either\n" + " #define TMPL template\n" + "#else\n" + " #define TMPL\n" + "#endif\n" + "\n" + "#define WRAP_FN(name) (::gw::id(name).TMPL f< name >())\n" + "#define WRAP_MFN(ClassType, name) (::gw::id(&ClassType::name).TMPL f< &ClassType::name >())\n" + "#define WRAP_OBJ_FIRST(name) (::gw::id(name).TMPL of< name >())\n" + "#define WRAP_OBJ_LAST(name) (::gw::id(name).TMPL ol< name >())\n" + "\n" + "#define WRAP_FN_PR(name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< name >))\n" + "#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType) asFUNCTION((::gw::Wrapper::TMPL f< &ClassType::name >))\n" + "#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjFirst::TMPL f< name >))\n" + "#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType) asFUNCTION((::gw::ObjLast::TMPL f< name >))\n" + "\n" + "#define WRAP_CON(ClassType, Parameters) asFUNCTION((::gw::Constructor::f))\n" + "#define WRAP_DES(ClassType) asFUNCTION((::gw::destroy))\n" + "\n" + "} // end namespace gw\n" + "\n" + "#endif\n"); + + return 0; +} + +void PrintTemplate(const char *base, const char *typeNameList, const char *retType, const char *objType, const char *isConst, const char *newExpr, const char *objExpr, const char *argList1, const char *argList2, const char *wrapName) +{ + printf("template <%s%s>\n", base, typeNameList); + printf("struct %s<%s (%s*)(%s)%s> {\n", wrapName, retType, objType, argList1, isConst); + printf(" template <%s (%s*fp)(%s)%s>\n", retType, objType, argList1, isConst); + printf(" static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n"); + printf(" %s((%sfp)(%s));\n", newExpr, objExpr, argList2); + printf(" }\n"); + printf("};\n"); +} + +void PrintConstructor(const char *comma, const char *typeNameList, const char *typeList, const char *argList) +{ + printf("template \n", comma, typeNameList); + printf("struct Constructor {\n", typeList); + printf(" static void f(AS_NAMESPACE_QUALIFIER asIScriptGeneric * gen) {\n"); + printf(" new (gen->GetObject()) T(%s);\n", argList); + printf(" }\n"); + printf("};\n"); +} \ No newline at end of file diff --git a/add_on/autowrapper/generator/generator.sln b/add_on/autowrapper/generator/generator.sln new file mode 100644 index 0000000..b84712a --- /dev/null +++ b/add_on/autowrapper/generator/generator.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "generator", "generator.vcproj", "{086A2F1A-01B1-4EB3-A8FA-0926FF10E953}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Debug|Win32.ActiveCfg = Debug|Win32 + {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Debug|Win32.Build.0 = Debug|Win32 + {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Release|Win32.ActiveCfg = Release|Win32 + {086A2F1A-01B1-4EB3-A8FA-0926FF10E953}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/add_on/autowrapper/generator/generator.vcproj b/add_on/autowrapper/generator/generator.vcproj new file mode 100644 index 0000000..e663fdc --- /dev/null +++ b/add_on/autowrapper/generator/generator.vcproj @@ -0,0 +1,236 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/add_on/contextmgr/contextmgr.cpp b/add_on/contextmgr/contextmgr.cpp new file mode 100644 index 0000000..091f8c5 --- /dev/null +++ b/add_on/contextmgr/contextmgr.cpp @@ -0,0 +1,401 @@ +#include +#include + +#include "contextmgr.h" + +using namespace std; + +// TODO: Should have a pool of free asIScriptContext so that new contexts +// won't be allocated every time. The application must not keep +// its own references, instead it must tell the context manager +// that it is using the context. Otherwise the context manager may +// think it can reuse the context too early. + +// TODO: Need to have a callback for when scripts finishes, so that the +// application can receive return values. + +BEGIN_AS_NAMESPACE + +// The id for the context manager user data. +// The add-ons have reserved the numbers 1000 +// through 1999 for this purpose, so we should be fine. +const asPWORD CONTEXT_MGR = 1002; + +struct SContextInfo +{ + asUINT sleepUntil; + vector coRoutines; + asUINT currentCoRoutine; + asIScriptContext * keepCtxAfterExecution; +}; + +static void ScriptSleep(asUINT milliSeconds) +{ + // Get a pointer to the context that is currently being executed + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + // Get the context manager from the user data + CContextMgr *ctxMgr = reinterpret_cast(ctx->GetUserData(CONTEXT_MGR)); + if( ctxMgr ) + { + // Suspend its execution. The VM will continue until the current + // statement is finished and then return from the Execute() method + ctx->Suspend(); + + // Tell the context manager when the context is to continue execution + ctxMgr->SetSleeping(ctx, milliSeconds); + } + } +} + +static void ScriptYield() +{ + // Get a pointer to the context that is currently being executed + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + // Get the context manager from the user data + CContextMgr *ctxMgr = reinterpret_cast(ctx->GetUserData(CONTEXT_MGR)); + if( ctxMgr ) + { + // Let the context manager know that it should run the next co-routine + ctxMgr->NextCoRoutine(); + + // The current context must be suspended so that VM will return from + // the Execute() method where the context manager will continue. + ctx->Suspend(); + } + } +} + +void ScriptCreateCoRoutine(asIScriptFunction *func, CScriptDictionary *arg) +{ + if( func == 0 ) + return; + + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + // Get the context manager from the user data + CContextMgr *ctxMgr = reinterpret_cast(ctx->GetUserData(CONTEXT_MGR)); + if( ctxMgr ) + { + // Create a new context for the co-routine + asIScriptContext *coctx = ctxMgr->AddContextForCoRoutine(ctx, func); + + // Pass the argument to the context + coctx->SetArgObject(0, arg); + + // The context manager will call Execute() on the context when it is time + } + } +} + +#ifdef AS_MAX_PORTABILITY +void ScriptYield_generic(asIScriptGeneric *) +{ + ScriptYield(); +} + +void ScriptCreateCoRoutine_generic(asIScriptGeneric *gen) +{ + asIScriptFunction *func = reinterpret_cast(gen->GetArgAddress(0)); + CScriptDictionary *dict = reinterpret_cast(gen->GetArgAddress(1)); + ScriptCreateCoRoutine(func, dict); +} +#endif + +CContextMgr::CContextMgr() +{ + m_getTimeFunc = 0; + m_currentThread = 0; + + m_numExecutions = 0; + m_numGCObjectsCreated = 0; + m_numGCObjectsDestroyed = 0; +} + +CContextMgr::~CContextMgr() +{ + asUINT n; + + // Free the memory + for( n = 0; n < m_threads.size(); n++ ) + { + if( m_threads[n] ) + { + for( asUINT c = 0; c < m_threads[n]->coRoutines.size(); c++ ) + { + asIScriptContext *ctx = m_threads[n]->coRoutines[c]; + if( ctx ) + { + // Return the context to the engine (and possible context pool configured in it) + ctx->GetEngine()->ReturnContext(ctx); + } + } + + delete m_threads[n]; + } + } + + for( n = 0; n < m_freeThreads.size(); n++ ) + { + if( m_freeThreads[n] ) + { + assert( m_freeThreads[n]->coRoutines.size() == 0 ); + + delete m_freeThreads[n]; + } + } +} + +int CContextMgr::ExecuteScripts() +{ + // TODO: Should have an optional time out for this function. If not all scripts executed before the + // time out, the next time the function is called the loop should continue + // where it left off. + + // TODO: There should be a time out per thread as well. If a thread executes for too + // long, it should be aborted. A group of co-routines count as a single thread. + + // Check if the system time is higher than the time set for the contexts + asUINT time = m_getTimeFunc ? m_getTimeFunc() : asUINT(-1); + for( m_currentThread = 0; m_currentThread < m_threads.size(); m_currentThread++ ) + { + SContextInfo *thread = m_threads[m_currentThread]; + if( thread->sleepUntil < time ) + { + int currentCoRoutine = thread->currentCoRoutine; + + // Gather some statistics from the GC + asIScriptEngine *engine = thread->coRoutines[currentCoRoutine]->GetEngine(); + asUINT gcSize1, gcSize2, gcSize3; + engine->GetGCStatistics(&gcSize1); + + // Execute the script for this thread and co-routine + int r = thread->coRoutines[currentCoRoutine]->Execute(); + + // Determine how many new objects were created in the GC + engine->GetGCStatistics(&gcSize2); + m_numGCObjectsCreated += gcSize2 - gcSize1; + m_numExecutions++; + + if( r != asEXECUTION_SUSPENDED ) + { + // The context has terminated execution (for one reason or other) + // Unless the application has requested to keep the context we'll return it to the pool now + if( thread->keepCtxAfterExecution != thread->coRoutines[currentCoRoutine] ) + engine->ReturnContext(thread->coRoutines[currentCoRoutine]); + thread->coRoutines[currentCoRoutine] = 0; + + thread->coRoutines.erase(thread->coRoutines.begin() + thread->currentCoRoutine); + if( thread->currentCoRoutine >= thread->coRoutines.size() ) + thread->currentCoRoutine = 0; + + // If this was the last co-routine terminate the thread + if( thread->coRoutines.size() == 0 ) + { + m_freeThreads.push_back(thread); + m_threads.erase(m_threads.begin() + m_currentThread); + m_currentThread--; + } + } + + // Destroy all known garbage if any new objects were created + if( gcSize2 > gcSize1 ) + { + engine->GarbageCollect(asGC_FULL_CYCLE | asGC_DESTROY_GARBAGE); + + // Determine how many objects were destroyed + engine->GetGCStatistics(&gcSize3); + m_numGCObjectsDestroyed += gcSize3 - gcSize2; + } + + // TODO: If more objects are created per execution than destroyed on average + // then it may be necessary to run more iterations of the detection of + // cyclic references. At the startup of an application there is usually + // a lot of objects created that will live on through out the application + // so the average number of objects created per execution will be higher + // than the number of destroyed objects in the beginning, but afterwards + // it usually levels out to be more or less equal. + + // Just run an incremental step for detecting cyclic references + engine->GarbageCollect(asGC_ONE_STEP | asGC_DETECT_GARBAGE); + } + } + + return int(m_threads.size()); +} + +void CContextMgr::DoneWithContext(asIScriptContext *ctx) +{ + ctx->GetEngine()->ReturnContext(ctx); +} + +void CContextMgr::NextCoRoutine() +{ + m_threads[m_currentThread]->currentCoRoutine++; + if( m_threads[m_currentThread]->currentCoRoutine >= m_threads[m_currentThread]->coRoutines.size() ) + m_threads[m_currentThread]->currentCoRoutine = 0; +} + +void CContextMgr::AbortAll() +{ + // Abort all contexts and release them. The script engine will make + // sure that all resources held by the scripts are properly released. + + for( asUINT n = 0; n < m_threads.size(); n++ ) + { + for( asUINT c = 0; c < m_threads[n]->coRoutines.size(); c++ ) + { + asIScriptContext *ctx = m_threads[n]->coRoutines[c]; + if( ctx ) + { + ctx->Abort(); + ctx->GetEngine()->ReturnContext(ctx); + ctx = 0; + } + } + m_threads[n]->coRoutines.resize(0); + + m_freeThreads.push_back(m_threads[n]); + } + + m_threads.resize(0); + + m_currentThread = 0; +} + +asIScriptContext *CContextMgr::AddContext(asIScriptEngine *engine, asIScriptFunction *func, bool keepCtxAfterExec) +{ + // Use RequestContext instead of CreateContext so we can take + // advantage of possible context pooling configured with the engine + asIScriptContext *ctx = engine->RequestContext(); + if( ctx == 0 ) + return 0; + + // Prepare it to execute the function + int r = ctx->Prepare(func); + if( r < 0 ) + { + engine->ReturnContext(ctx); + return 0; + } + + // Set the context manager as user data with the context so it + // can be retrieved by the functions registered with the engine + ctx->SetUserData(this, CONTEXT_MGR); + + // Add the context to the list for execution + SContextInfo *info = 0; + if( m_freeThreads.size() > 0 ) + { + info = *m_freeThreads.rbegin(); + m_freeThreads.pop_back(); + } + else + { + info = new SContextInfo; + } + + info->coRoutines.push_back(ctx); + info->currentCoRoutine = 0; + info->sleepUntil = 0; + info->keepCtxAfterExecution = keepCtxAfterExec ? ctx : 0; + m_threads.push_back(info); + + return ctx; +} + +asIScriptContext *CContextMgr::AddContextForCoRoutine(asIScriptContext *currCtx, asIScriptFunction *func) +{ + asIScriptEngine *engine = currCtx->GetEngine(); + asIScriptContext *coctx = engine->RequestContext(); + if( coctx == 0 ) + { + return 0; + } + + // Prepare the context + int r = coctx->Prepare(func); + if( r < 0 ) + { + // Couldn't prepare the context + engine->ReturnContext(coctx); + return 0; + } + + // Set the context manager as user data with the context so it + // can be retrieved by the functions registered with the engine + coctx->SetUserData(this, CONTEXT_MGR); + + // Find the current context thread info + // TODO: Start with the current thread so that we can find the group faster + for( asUINT n = 0; n < m_threads.size(); n++ ) + { + if( m_threads[n]->coRoutines[m_threads[n]->currentCoRoutine] == currCtx ) + { + // Add the coRoutine to the list + m_threads[n]->coRoutines.push_back(coctx); + } + } + + return coctx; +} + +void CContextMgr::SetSleeping(asIScriptContext *ctx, asUINT milliSeconds) +{ + assert( m_getTimeFunc != 0 ); + + // Find the context and update the timeStamp + // for when the context is to be continued + + // TODO: Start with the current thread + + for( asUINT n = 0; n < m_threads.size(); n++ ) + { + if( m_threads[n]->coRoutines[m_threads[n]->currentCoRoutine] == ctx ) + { + m_threads[n]->sleepUntil = (m_getTimeFunc ? m_getTimeFunc() : 0) + milliSeconds; + } + } +} + +void CContextMgr::RegisterThreadSupport(asIScriptEngine *engine) +{ + int r; + + // Must set the get time callback function for this to work + assert( m_getTimeFunc != 0 ); + + // Register the sleep function + r = engine->RegisterGlobalFunction("void sleep(uint)", asFUNCTION(ScriptSleep), asCALL_CDECL); assert( r >= 0 ); + + // TODO: Add support for spawning new threads, waiting for signals, etc +} + +void CContextMgr::RegisterCoRoutineSupport(asIScriptEngine *engine) +{ + int r; + + // The dictionary add-on must have been registered already + assert( engine->GetTypeInfoByDecl("dictionary") ); + +#ifndef AS_MAX_PORTABILITY + r = engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterFuncdef("void coroutine(dictionary@)"); + r = engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine), asCALL_CDECL); assert( r >= 0 ); +#else + r = engine->RegisterGlobalFunction("void yield()", asFUNCTION(ScriptYield_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterFuncdef("void coroutine(dictionary@)"); + r = engine->RegisterGlobalFunction("void createCoRoutine(coroutine @+, dictionary @+)", asFUNCTION(ScriptCreateCoRoutine_generic), asCALL_GENERIC); assert( r >= 0 ); +#endif +} + +void CContextMgr::SetGetTimeCallback(TIMEFUNC_t func) +{ + m_getTimeFunc = func; +} + +END_AS_NAMESPACE diff --git a/add_on/contextmgr/contextmgr.h b/add_on/contextmgr/contextmgr.h new file mode 100644 index 0000000..f57630c --- /dev/null +++ b/add_on/contextmgr/contextmgr.h @@ -0,0 +1,99 @@ +#ifndef CONTEXTMGR_H +#define CONTEXTMGR_H + +// The context manager simplifies the management of multiple concurrent scripts + +// More than one context manager can be used, if you wish to control different +// groups of scripts separately, e.g. game object scripts, and GUI scripts. + +// OBSERVATION: This class is currently not thread safe. + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include + +BEGIN_AS_NAMESPACE + +class CScriptDictionary; + +// The internal structure for holding contexts +struct SContextInfo; + +// The signature of the get time callback function +typedef asUINT (*TIMEFUNC_t)(); + +class CContextMgr +{ +public: + CContextMgr(); + ~CContextMgr(); + + // Set the function that the manager will use to obtain the time in milliseconds + void SetGetTimeCallback(TIMEFUNC_t func); + + // Registers the following: + // + // void sleep(uint milliseconds) + // + // The application must set the get time callback for this to work + void RegisterThreadSupport(asIScriptEngine *engine); + + // Registers the following: + // + // funcdef void coroutine(dictionary@) + // void createCoRoutine(coroutine @func, dictionary @args) + // void yield() + void RegisterCoRoutineSupport(asIScriptEngine *engine); + + // Create a new context, prepare it with the function id, then return + // it so that the application can pass the argument values. The context + // will be released by the manager after the execution has completed. + // Set keepCtxAfterExecution to true if the application needs to retrieve + // information from the context after it the script has finished. + asIScriptContext *AddContext(asIScriptEngine *engine, asIScriptFunction *func, bool keepCtxAfterExecution = false); + + // If the context was kept after the execution, this method must be + // called when the application is done with the context so it can be + // returned to the pool for reuse. + void DoneWithContext(asIScriptContext *ctx); + + // Create a new context, prepare it with the function id, then return + // it so that the application can pass the argument values. The context + // will be added as a co-routine in the same thread as the currCtx. + asIScriptContext *AddContextForCoRoutine(asIScriptContext *currCtx, asIScriptFunction *func); + + // Execute each script that is not currently sleeping. The function returns after + // each script has been executed once. The application should call this function + // for each iteration of the message pump, or game loop, or whatever. + // Returns the number of scripts still in execution. + int ExecuteScripts(); + + // Put a script to sleep for a while + void SetSleeping(asIScriptContext *ctx, asUINT milliSeconds); + + // Switch the execution to the next co-routine in the group. + // Returns true if the switch was successful. + void NextCoRoutine(); + + // Abort all scripts + void AbortAll(); + +protected: + std::vector m_threads; + std::vector m_freeThreads; + asUINT m_currentThread; + TIMEFUNC_t m_getTimeFunc; + + // Statistics for Garbage Collection + asUINT m_numExecutions; + asUINT m_numGCObjectsCreated; + asUINT m_numGCObjectsDestroyed; +}; + + +END_AS_NAMESPACE + +#endif diff --git a/add_on/datetime/datetime.cpp b/add_on/datetime/datetime.cpp new file mode 100644 index 0000000..3ea75d8 --- /dev/null +++ b/add_on/datetime/datetime.cpp @@ -0,0 +1,270 @@ +#include "datetime.h" +#include "../autowrapper/aswrappedcall.h" +#include +#include +#include + +using namespace std; +using namespace std::chrono; + +BEGIN_AS_NAMESPACE + +// TODO: Allow setting the timezone to use + +static tm time_point_to_tm(const std::chrono::time_point &tp) +{ + time_t t = system_clock::to_time_t(tp); + tm local; + + // Use the universal timezone +#ifdef _MSC_VER + gmtime_s(&local, &t); +#else + local = *gmtime(&t); +#endif + return local; +} + +// Returns true if successful. Doesn't modify tp if not successful +static bool tm_to_time_point(const tm &_tm, std::chrono::time_point &tp) +{ + tm localTm = _tm; + + // Do not rely on timezone, as it is not portable + // ref: https://stackoverflow.com/questions/38298261/why-there-is-no-inverse-function-for-gmtime-in-libc + // ref: https://stackoverflow.com/questions/8558919/mktime-and-tm-isdst + localTm.tm_isdst = -1; // Always use current settings, so mktime doesn't modify the time for daylight savings + time_t t = mktime(&localTm); + if (t == -1) + return false; + + // Adjust the time_t since epoch with the difference of the local timezone to the universal timezone + t += (mktime(localtime(&t)) - mktime(gmtime(&t))); + + // Verify if the members were modified, indicating an out-of-range value in input + if (localTm.tm_year != _tm.tm_year || + localTm.tm_mon != _tm.tm_mon || + localTm.tm_mday != _tm.tm_mday || + localTm.tm_hour != _tm.tm_hour || + localTm.tm_min != _tm.tm_min || + localTm.tm_sec != _tm.tm_sec) + return false; + + tp = system_clock::from_time_t(t); + return true; +} + +CDateTime::CDateTime() : tp(std::chrono::system_clock::now()) +{ +} + +CDateTime::CDateTime(const CDateTime &o) : tp(o.tp) +{ +} + +CDateTime &CDateTime::operator=(const CDateTime &o) +{ + tp = o.tp; + return *this; +} + +asUINT CDateTime::getYear() const +{ + tm local = time_point_to_tm(tp); + return local.tm_year + 1900; +} + +asUINT CDateTime::getMonth() const +{ + tm local = time_point_to_tm(tp); + return local.tm_mon + 1; +} + +asUINT CDateTime::getDay() const +{ + tm local = time_point_to_tm(tp); + return local.tm_mday; +} + +asUINT CDateTime::getHour() const +{ + tm local = time_point_to_tm(tp); + return local.tm_hour; +} + +asUINT CDateTime::getMinute() const +{ + tm local = time_point_to_tm(tp); + return local.tm_min; +} + +asUINT CDateTime::getSecond() const +{ + tm local = time_point_to_tm(tp); + return local.tm_sec; +} + +bool CDateTime::setDate(asUINT year, asUINT month, asUINT day) +{ + tm local = time_point_to_tm(tp); + local.tm_year = int(year) - 1900; + local.tm_mon = month - 1; + local.tm_mday = day; + + return tm_to_time_point(local, tp); +} + +bool CDateTime::setTime(asUINT hour, asUINT minute, asUINT second) +{ + tm local = time_point_to_tm(tp); + local.tm_hour = hour; + local.tm_min = minute; + local.tm_sec = second; + + return tm_to_time_point(local, tp); +} + +CDateTime::CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second) +{ + tp = std::chrono::system_clock::now(); + setDate(year, month, day); + setTime(hour, minute, second); +} + +asINT64 CDateTime::operator-(const CDateTime &dt) const +{ + return (tp - dt.tp).count() / std::chrono::system_clock::period::den * std::chrono::system_clock::period::num; +} + +CDateTime CDateTime::operator+(asINT64 seconds) const +{ + CDateTime dt(*this); + dt.tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num); + return dt; +} + +CDateTime &CDateTime::operator+=(asINT64 seconds) +{ + tp += std::chrono::system_clock::duration(seconds * std::chrono::system_clock::period::den / std::chrono::system_clock::period::num); + return *this; +} + +CDateTime operator+(asINT64 seconds, const CDateTime &other) +{ + return other + seconds; +} + +CDateTime CDateTime::operator-(asINT64 seconds) const +{ + return *this + -seconds; +} + +CDateTime &CDateTime::operator-=(asINT64 seconds) +{ + return *this += -seconds; +} + +CDateTime operator-(asINT64 seconds, const CDateTime &other) +{ + return other + -seconds; +} + +bool CDateTime::operator==(const CDateTime &other) const +{ + return tp == other.tp; +} + +bool CDateTime::operator<(const CDateTime &other) const +{ + return tp < other.tp; +} + +static int opCmp(const CDateTime &a, const CDateTime &b) +{ + if (a < b) return -1; + if (a == b) return 0; + return 1; +} + +static void Construct(CDateTime *mem) +{ + new(mem) CDateTime(); +} + +static void ConstructCopy(CDateTime *mem, const CDateTime &o) +{ + new(mem) CDateTime(o); +} + +static void ConstructSet(CDateTime *mem, asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second) +{ + new(mem) CDateTime(year, month, day, hour, minute, second); +} + +static void ConstructSet_Generic(asIScriptGeneric *gen) +{ + CDateTime *date = (CDateTime*)gen->GetObject(); + asUINT year = *(asUINT*)gen->GetAddressOfArg(0); + asUINT month = *(asUINT*)gen->GetAddressOfArg(1); + asUINT day = *(asUINT*)gen->GetAddressOfArg(2); + asUINT hour = *(asUINT*)gen->GetAddressOfArg(3); + asUINT minute = *(asUINT*)gen->GetAddressOfArg(4); + asUINT second = *(asUINT*)gen->GetAddressOfArg(5); + ConstructSet(date, year, month, day, hour, minute, second); +} + +void RegisterScriptDateTime(asIScriptEngine *engine) +{ + int r = engine->RegisterObjectType("datetime", sizeof(CDateTime), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits()); assert(r >= 0); + + if(strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")==0) + { + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Construct), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", asFUNCTION(ConstructCopy), asCALL_CDECL_OBJFIRST); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet), asCALL_CDECL_OBJFIRST); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", asMETHOD(CDateTime, operator=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", asMETHOD(CDateTime, getYear), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", asMETHOD(CDateTime, getMonth), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", asMETHOD(CDateTime, getDay), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", asMETHOD(CDateTime, getHour), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", asMETHOD(CDateTime, getMinute), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", asMETHOD(CDateTime, getSecond), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", asMETHOD(CDateTime, setDate), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", asMETHOD(CDateTime, setTime), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", asMETHODPR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", asMETHOD(CDateTime, operator+), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", asFUNCTIONPR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", asMETHOD(CDateTime, operator+=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", asMETHODPR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", asFUNCTIONPR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", asMETHOD(CDateTime, operator-=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", asMETHODPR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", asFUNCTION(opCmp), asCALL_CDECL_OBJFIRST); assert(r >= 0); + } + else + { + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f()", WRAP_OBJ_LAST(Construct), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(const datetime &in)", WRAP_OBJ_FIRST(ConstructCopy), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("datetime", asBEHAVE_CONSTRUCT, "void f(uint, uint, uint, uint = 0, uint = 0, uint = 0)", asFUNCTION(ConstructSet_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAssign(const datetime &in)", WRAP_MFN(CDateTime, operator=), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_year() const property", WRAP_MFN(CDateTime, getYear), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_month() const property", WRAP_MFN(CDateTime, getMonth), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_day() const property", WRAP_MFN(CDateTime, getDay), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_hour() const property", WRAP_MFN(CDateTime, getHour), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_minute() const property", WRAP_MFN(CDateTime, getMinute), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "uint get_second() const property", WRAP_MFN(CDateTime, getSecond), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setDate(uint year, uint month, uint day)", WRAP_MFN(CDateTime, setDate), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool setTime(uint hour, uint minute, uint second)", WRAP_MFN(CDateTime, setTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int64 opSub(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator-, (const CDateTime &other) const, asINT64), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd(int64 seconds) const", WRAP_MFN(CDateTime, operator+), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opAdd_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator+, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opAddAssign(int64 seconds)", WRAP_MFN(CDateTime, operator+=), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub(int64 seconds) const", WRAP_MFN_PR(CDateTime, operator-, (asINT64) const, CDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime opSub_r(int64 seconds) const", WRAP_OBJ_LAST_PR(operator-, (asINT64 seconds, const CDateTime &other), CDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "datetime &opSubAssign(int64 seconds)", WRAP_MFN(CDateTime, operator-=), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "bool opEquals(const datetime &in) const", WRAP_MFN_PR(CDateTime, operator==, (const CDateTime &other) const, bool), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("datetime", "int opCmp(const datetime &in) const", WRAP_OBJ_FIRST(opCmp), asCALL_GENERIC); assert(r >= 0); + } +} + +END_AS_NAMESPACE diff --git a/add_on/datetime/datetime.h b/add_on/datetime/datetime.h new file mode 100644 index 0000000..8148da9 --- /dev/null +++ b/add_on/datetime/datetime.h @@ -0,0 +1,61 @@ +#ifndef SCRIPTDATETIME_H +#define SCRIPTDATETIME_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#ifdef AS_CAN_USE_CPP11 +#include +#else +#error Sorry, this requires C++11 which your compiler doesnt appear to support +#endif + +BEGIN_AS_NAMESPACE + +class CDateTime +{ +public: + // Constructors + CDateTime(); + CDateTime(const CDateTime &other); + CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second); + + // Copy the stored value from another any object + CDateTime &operator=(const CDateTime &other); + + // Accessors + asUINT getYear() const; + asUINT getMonth() const; + asUINT getDay() const; + asUINT getHour() const; + asUINT getMinute() const; + asUINT getSecond() const; + + // Setters + // Returns true if valid + bool setDate(asUINT year, asUINT month, asUINT day); + bool setTime(asUINT hour, asUINT minute, asUINT second); + + // Operators + // Return difference in seconds + asINT64 operator-(const CDateTime &other) const; + CDateTime operator+(asINT64 seconds) const; + friend CDateTime operator+(asINT64 seconds, const CDateTime &other); + CDateTime & operator+=(asINT64 seconds); + CDateTime operator-(asINT64 seconds) const; + friend CDateTime operator-(asINT64 seconds, const CDateTime &other); + CDateTime & operator-=(asINT64 seconds); + bool operator==(const CDateTime &other) const; + bool operator<(const CDateTime &other) const; + +protected: + std::chrono::system_clock::time_point tp; +}; + +void RegisterScriptDateTime(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/debugger/debugger.cpp b/add_on/debugger/debugger.cpp new file mode 100644 index 0000000..1554d70 --- /dev/null +++ b/add_on/debugger/debugger.cpp @@ -0,0 +1,852 @@ +#include "debugger.h" +#include // cout +#include // stringstream +#include // atoi +#include // assert + +using namespace std; + +BEGIN_AS_NAMESPACE + +CDebugger::CDebugger() +{ + m_action = CONTINUE; + m_lastFunction = 0; + m_engine = 0; +} + +CDebugger::~CDebugger() +{ + SetEngine(0); +} + +string CDebugger::ToString(void *value, asUINT typeId, int expandMembers, asIScriptEngine *engine) +{ + if( value == 0 ) + return ""; + + // If no engine pointer was provided use the default + if( engine == 0 ) + engine = m_engine; + + stringstream s; + if( typeId == asTYPEID_VOID ) + return ""; + else if( typeId == asTYPEID_BOOL ) + return *(bool*)value ? "true" : "false"; + else if( typeId == asTYPEID_INT8 ) + s << (int)*(signed char*)value; + else if( typeId == asTYPEID_INT16 ) + s << (int)*(signed short*)value; + else if( typeId == asTYPEID_INT32 ) + s << *(signed int*)value; + else if( typeId == asTYPEID_INT64 ) +#if defined(_MSC_VER) && _MSC_VER <= 1200 + s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer +#else + s << *(asINT64*)value; +#endif + else if( typeId == asTYPEID_UINT8 ) + s << (unsigned int)*(unsigned char*)value; + else if( typeId == asTYPEID_UINT16 ) + s << (unsigned int)*(unsigned short*)value; + else if( typeId == asTYPEID_UINT32 ) + s << *(unsigned int*)value; + else if( typeId == asTYPEID_UINT64 ) +#if defined(_MSC_VER) && _MSC_VER <= 1200 + s << "{...}"; // MSVC6 doesn't like the << operator for 64bit integer +#else + s << *(asQWORD*)value; +#endif + else if( typeId == asTYPEID_FLOAT ) + s << *(float*)value; + else if( typeId == asTYPEID_DOUBLE ) + s << *(double*)value; + else if( (typeId & asTYPEID_MASK_OBJECT) == 0 ) + { + // The type is an enum + s << *(asUINT*)value; + + // Check if the value matches one of the defined enums + if( engine ) + { + asITypeInfo *t = engine->GetTypeInfoById(typeId); + for( int n = t->GetEnumValueCount(); n-- > 0; ) + { + int enumVal; + const char *enumName = t->GetEnumValueByIndex(n, &enumVal); + if( enumVal == *(int*)value ) + { + s << ", " << enumName; + break; + } + } + } + } + else if( typeId & asTYPEID_SCRIPTOBJECT ) + { + // Dereference handles, so we can see what it points to + if( typeId & asTYPEID_OBJHANDLE ) + value = *(void**)value; + + asIScriptObject *obj = (asIScriptObject *)value; + + // Print the address of the object + s << "{" << obj << "}"; + + // Print the members + if( obj && expandMembers > 0 ) + { + asITypeInfo *type = obj->GetObjectType(); + for( asUINT n = 0; n < obj->GetPropertyCount(); n++ ) + { + if( n == 0 ) + s << " "; + else + s << ", "; + + s << type->GetPropertyDeclaration(n) << " = " << ToString(obj->GetAddressOfProperty(n), obj->GetPropertyTypeId(n), expandMembers - 1, type->GetEngine()); + } + } + } + else + { + // Dereference handles, so we can see what it points to + if( typeId & asTYPEID_OBJHANDLE ) + value = *(void**)value; + + // Print the address for reference types so it will be + // possible to see when handles point to the same object + if( engine ) + { + asITypeInfo *type = engine->GetTypeInfoById(typeId); + if( type->GetFlags() & asOBJ_REF ) + s << "{" << value << "}"; + + if( value ) + { + // Check if there is a registered to-string callback + map::iterator it = m_toStringCallbacks.find(type); + if( it == m_toStringCallbacks.end() ) + { + // If the type is a template instance, there might be a + // to-string callback for the generic template type + if( type->GetFlags() & asOBJ_TEMPLATE ) + { + asITypeInfo *tmplType = engine->GetTypeInfoByName(type->GetName()); + it = m_toStringCallbacks.find(tmplType); + } + } + + if( it != m_toStringCallbacks.end() ) + { + if( type->GetFlags() & asOBJ_REF ) + s << " "; + + // Invoke the callback to get the string representation of this type + string str = it->second(value, expandMembers, this); + s << str; + } + } + } + else + s << "{no engine}"; + } + + return s.str(); +} + +void CDebugger::RegisterToStringCallback(const asITypeInfo *ot, ToStringCallback callback) +{ + if( m_toStringCallbacks.find(ot) == m_toStringCallbacks.end() ) + m_toStringCallbacks.insert(map::value_type(ot, callback)); +} + +void CDebugger::LineCallback(asIScriptContext *ctx) +{ + assert( ctx ); + + // This should never happen, but it doesn't hurt to validate it + if( ctx == 0 ) + return; + + // By default we ignore callbacks when the context is not active. + // An application might override this to for example disconnect the + // debugger as the execution finished. + if( ctx->GetState() != asEXECUTION_ACTIVE ) + return; + + if( m_action == CONTINUE ) + { + if( !CheckBreakPoint(ctx) ) + return; + } + else if( m_action == STEP_OVER ) + { + if( ctx->GetCallstackSize() > m_lastCommandAtStackLevel ) + { + if( !CheckBreakPoint(ctx) ) + return; + } + } + else if( m_action == STEP_OUT ) + { + if( ctx->GetCallstackSize() >= m_lastCommandAtStackLevel ) + { + if( !CheckBreakPoint(ctx) ) + return; + } + } + else if( m_action == STEP_INTO ) + { + CheckBreakPoint(ctx); + + // Always break, but we call the check break point anyway + // to tell user when break point has been reached + } + + stringstream s; + const char *file = 0; + int lineNbr = ctx->GetLineNumber(0, 0, &file); + s << (file ? file : "{unnamed}") << ":" << lineNbr << "; " << ctx->GetFunction()->GetDeclaration() << endl; + Output(s.str()); + + TakeCommands(ctx); +} + +bool CDebugger::CheckBreakPoint(asIScriptContext *ctx) +{ + if( ctx == 0 ) + return false; + + // TODO: Should cache the break points in a function by checking which possible break points + // can be hit when entering a function. If there are no break points in the current function + // then there is no need to check every line. + + const char *tmp = 0; + int lineNbr = ctx->GetLineNumber(0, 0, &tmp); + + // Consider just filename, not the full path + string file = tmp ? tmp : ""; + size_t r = file.find_last_of("\\/"); + if( r != string::npos ) + file = file.substr(r+1); + + // Did we move into a new function? + asIScriptFunction *func = ctx->GetFunction(); + if( m_lastFunction != func ) + { + // Check if any breakpoints need adjusting + for( size_t n = 0; n < m_breakPoints.size(); n++ ) + { + // We need to check for a breakpoint at entering the function + if( m_breakPoints[n].func ) + { + if( m_breakPoints[n].name == func->GetName() ) + { + stringstream s; + s << "Entering function '" << m_breakPoints[n].name << "'. Transforming it into break point" << endl; + Output(s.str()); + + // Transform the function breakpoint into a file breakpoint + m_breakPoints[n].name = file; + m_breakPoints[n].lineNbr = lineNbr; + m_breakPoints[n].func = false; + m_breakPoints[n].needsAdjusting = false; + } + } + // Check if a given breakpoint fall on a line with code or else adjust it to the next line + else if( m_breakPoints[n].needsAdjusting && + m_breakPoints[n].name == file ) + { + int line = func->FindNextLineWithCode(m_breakPoints[n].lineNbr); + if( line >= 0 ) + { + m_breakPoints[n].needsAdjusting = false; + if( line != m_breakPoints[n].lineNbr ) + { + stringstream s; + s << "Moving break point " << n << " in file '" << file << "' to next line with code at line " << line << endl; + Output(s.str()); + + // Move the breakpoint to the next line + m_breakPoints[n].lineNbr = line; + } + } + } + } + } + m_lastFunction = func; + + // Determine if there is a breakpoint at the current line + for( size_t n = 0; n < m_breakPoints.size(); n++ ) + { + // TODO: do case-less comparison for file name + + // Should we break? + if( !m_breakPoints[n].func && + m_breakPoints[n].lineNbr == lineNbr && + m_breakPoints[n].name == file ) + { + stringstream s; + s << "Reached break point " << n << " in file '" << file << "' at line " << lineNbr << endl; + Output(s.str()); + return true; + } + } + + return false; +} + +void CDebugger::TakeCommands(asIScriptContext *ctx) +{ + for(;;) + { + char buf[512]; + + Output("[dbg]> "); + cin.getline(buf, 512); + + if( InterpretCommand(string(buf), ctx) ) + break; + } +} + +bool CDebugger::InterpretCommand(const string &cmd, asIScriptContext *ctx) +{ + if( cmd.length() == 0 ) return true; + + switch( cmd[0] ) + { + case 'c': + m_action = CONTINUE; + break; + + case 's': + m_action = STEP_INTO; + break; + + case 'n': + m_action = STEP_OVER; + m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 1; + break; + + case 'o': + m_action = STEP_OUT; + m_lastCommandAtStackLevel = ctx ? ctx->GetCallstackSize() : 0; + break; + + case 'b': + { + // Set break point + size_t p = cmd.find_first_not_of(" \t", 1); + size_t div = cmd.find(':'); + if( div != string::npos && div > 2 && p > 1 ) + { + string file = cmd.substr(2, div-2); + string line = cmd.substr(div+1); + + int nbr = atoi(line.c_str()); + + AddFileBreakPoint(file, nbr); + } + else if( div == string::npos && p != string::npos && p > 1 ) + { + string func = cmd.substr(p); + + AddFuncBreakPoint(func); + } + else + { + Output("Incorrect format for setting break point, expected one of:\n" + " b :\n" + " b \n"); + } + } + // take more commands + return false; + + case 'r': + { + // Remove break point + size_t p = cmd.find_first_not_of(" \t", 1); + if( cmd.length() > 2 && p != string::npos && p > 1 ) + { + string br = cmd.substr(2); + if( br == "all" ) + { + m_breakPoints.clear(); + Output("All break points have been removed\n"); + } + else + { + int nbr = atoi(br.c_str()); + if( nbr >= 0 && nbr < (int)m_breakPoints.size() ) + m_breakPoints.erase(m_breakPoints.begin()+nbr); + ListBreakPoints(); + } + } + else + { + Output("Incorrect format for removing break points, expected:\n" + " r \n"); + } + } + // take more commands + return false; + + case 'l': + { + // List something + bool printHelp = false; + size_t p = cmd.find_first_not_of(" \t", 1); + if( p != string::npos && p > 1 ) + { + if( cmd[p] == 'b' ) + { + ListBreakPoints(); + } + else if( cmd[p] == 'v' ) + { + ListLocalVariables(ctx); + } + else if( cmd[p] == 'g' ) + { + ListGlobalVariables(ctx); + } + else if( cmd[p] == 'm' ) + { + ListMemberProperties(ctx); + } + else if( cmd[p] == 's' ) + { + ListStatistics(ctx); + } + else + { + Output("Unknown list option.\n"); + printHelp = true; + } + } + else + { + Output("Incorrect format for list command.\n"); + printHelp = true; + } + + if( printHelp ) + { + Output("Expected format: \n" + " l \n" + "Available options: \n" + " b - breakpoints\n" + " v - local variables\n" + " m - member properties\n" + " g - global variables\n" + " s - statistics\n"); + } + } + // take more commands + return false; + + case 'h': + PrintHelp(); + // take more commands + return false; + + case 'p': + { + // Print a value + size_t p = cmd.find_first_not_of(" \t", 1); + if( p != string::npos && p > 1 ) + { + PrintValue(cmd.substr(p), ctx); + } + else + { + Output("Incorrect format for print, expected:\n" + " p \n"); + } + } + // take more commands + return false; + + case 'w': + // Where am I? + PrintCallstack(ctx); + // take more commands + return false; + + case 'a': + // abort the execution + if( ctx == 0 ) + { + Output("No script is running\n"); + return false; + } + ctx->Abort(); + break; + + default: + Output("Unknown command\n"); + // take more commands + return false; + } + + // Continue execution + return true; +} + +void CDebugger::PrintValue(const std::string &expr, asIScriptContext *ctx) +{ + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + asIScriptEngine *engine = ctx->GetEngine(); + + // Tokenize the input string to get the variable scope and name + asUINT len = 0; + string scope; + string name; + string str = expr; + asETokenClass t = engine->ParseToken(str.c_str(), 0, &len); + while( t == asTC_IDENTIFIER || (t == asTC_KEYWORD && len == 2 && str.compare(0, 2, "::") == 0) ) + { + if( t == asTC_KEYWORD ) + { + if( scope == "" && name == "" ) + scope = "::"; // global scope + else if( scope == "::" || scope == "" ) + scope = name; // namespace + else + scope += "::" + name; // nested namespace + name = ""; + } + else if( t == asTC_IDENTIFIER ) + name.assign(str.c_str(), len); + + // Skip the parsed token and get the next one + str = str.substr(len); + t = engine->ParseToken(str.c_str(), 0, &len); + } + + if( name.size() ) + { + // Find the variable + void *ptr = 0; + int typeId = 0; + + asIScriptFunction *func = ctx->GetFunction(); + if( !func ) return; + + // skip local variables if a scope was informed + if( scope == "" ) + { + // We start from the end, in case the same name is reused in different scopes + for( asUINT n = func->GetVarCount(); n-- > 0; ) + { + if( ctx->IsVarInScope(n) && name == ctx->GetVarName(n) ) + { + ptr = ctx->GetAddressOfVar(n); + typeId = ctx->GetVarTypeId(n); + break; + } + } + + // Look for class members, if we're in a class method + if( !ptr && func->GetObjectType() ) + { + if( name == "this" ) + { + ptr = ctx->GetThisPointer(); + typeId = ctx->GetThisTypeId(); + } + else + { + asITypeInfo *type = engine->GetTypeInfoById(ctx->GetThisTypeId()); + for( asUINT n = 0; n < type->GetPropertyCount(); n++ ) + { + const char *propName = 0; + int offset = 0; + bool isReference = 0; + int compositeOffset = 0; + bool isCompositeIndirect = false; + type->GetProperty(n, &propName, &typeId, 0, 0, &offset, &isReference, 0, &compositeOffset, &isCompositeIndirect); + if( name == propName ) + { + ptr = (void*)(((asBYTE*)ctx->GetThisPointer())+compositeOffset); + if (isCompositeIndirect) ptr = *(void**)ptr; + ptr = (void*)(((asBYTE*)ptr) + offset); + if( isReference ) ptr = *(void**)ptr; + break; + } + } + } + } + } + + // Look for global variables + if( !ptr ) + { + if( scope == "" ) + { + // If no explicit scope was informed then use the namespace of the current function by default + scope = func->GetNamespace(); + } + else if( scope == "::" ) + { + // The global namespace will be empty + scope = ""; + } + + asIScriptModule *mod = func->GetModule(); + if( mod ) + { + for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ ) + { + const char *varName = 0, *nameSpace = 0; + mod->GetGlobalVar(n, &varName, &nameSpace, &typeId); + + // Check if both name and namespace match + if( name == varName && scope == nameSpace ) + { + ptr = mod->GetAddressOfGlobalVar(n); + break; + } + } + } + } + + if( ptr ) + { + // TODO: If there is a . after the identifier, check for members + // TODO: If there is a [ after the identifier try to call the 'opIndex(expr) const' method + if( str != "" ) + { + Output("Invalid expression. Expression doesn't end after symbol\n"); + } + else + { + stringstream s; + // TODO: Allow user to set if members should be expanded + // Expand members by default to 3 recursive levels only + s << ToString(ptr, typeId, 3, engine) << endl; + Output(s.str()); + } + } + else + { + Output("Invalid expression. No matching symbol\n"); + } + } + else + { + Output("Invalid expression. Expected identifier\n"); + } +} + +void CDebugger::ListBreakPoints() +{ + // List all break points + stringstream s; + for( size_t b = 0; b < m_breakPoints.size(); b++ ) + if( m_breakPoints[b].func ) + s << b << " - " << m_breakPoints[b].name << endl; + else + s << b << " - " << m_breakPoints[b].name << ":" << m_breakPoints[b].lineNbr << endl; + Output(s.str()); +} + +void CDebugger::ListMemberProperties(asIScriptContext *ctx) +{ + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + void *ptr = ctx->GetThisPointer(); + if( ptr ) + { + stringstream s; + // TODO: Allow user to define if members should be expanded or not + // Expand members by default to 3 recursive levels only + s << "this = " << ToString(ptr, ctx->GetThisTypeId(), 3, ctx->GetEngine()) << endl; + Output(s.str()); + } +} + +void CDebugger::ListLocalVariables(asIScriptContext *ctx) +{ + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + asIScriptFunction *func = ctx->GetFunction(); + if( !func ) return; + + stringstream s; + for( asUINT n = 0; n < func->GetVarCount(); n++ ) + { + if( ctx->IsVarInScope(n) ) + { + // TODO: Allow user to set if members should be expanded or not + // Expand members by default to 3 recursive levels only + s << func->GetVarDecl(n) << " = " << ToString(ctx->GetAddressOfVar(n), ctx->GetVarTypeId(n), 3, ctx->GetEngine()) << endl; + } + } + Output(s.str()); +} + +void CDebugger::ListGlobalVariables(asIScriptContext *ctx) +{ + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + // Determine the current module from the function + asIScriptFunction *func = ctx->GetFunction(); + if( !func ) return; + + asIScriptModule *mod = func->GetModule(); + if( !mod ) return; + + stringstream s; + for( asUINT n = 0; n < mod->GetGlobalVarCount(); n++ ) + { + int typeId = 0; + mod->GetGlobalVar(n, 0, 0, &typeId); + // TODO: Allow user to set how many recursive expansions should be done + // Expand members by default to 3 recursive levels only + s << mod->GetGlobalVarDeclaration(n) << " = " << ToString(mod->GetAddressOfGlobalVar(n), typeId, 3, ctx->GetEngine()) << endl; + } + Output(s.str()); +} + +void CDebugger::ListStatistics(asIScriptContext *ctx) +{ + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + asIScriptEngine *engine = ctx->GetEngine(); + + asUINT gcCurrSize, gcTotalDestr, gcTotalDet, gcNewObjects, gcTotalNewDestr; + engine->GetGCStatistics(&gcCurrSize, &gcTotalDestr, &gcTotalDet, &gcNewObjects, &gcTotalNewDestr); + + stringstream s; + s << "Garbage collector:" << endl; + s << " current size: " << gcCurrSize << endl; + s << " total destroyed: " << gcTotalDestr << endl; + s << " total detected: " << gcTotalDet << endl; + s << " new objects: " << gcNewObjects << endl; + s << " new objects destroyed: " << gcTotalNewDestr << endl; + + Output(s.str()); +} + +void CDebugger::PrintCallstack(asIScriptContext *ctx) +{ + if( ctx == 0 ) + { + Output("No script is running\n"); + return; + } + + stringstream s; + const char *file = 0; + int lineNbr = 0; + for( asUINT n = 0; n < ctx->GetCallstackSize(); n++ ) + { + lineNbr = ctx->GetLineNumber(n, 0, &file); + s << (file ? file : "{unnamed}") << ":" << lineNbr << "; " << ctx->GetFunction(n)->GetDeclaration() << endl; + } + Output(s.str()); +} + +void CDebugger::AddFuncBreakPoint(const string &func) +{ + // Trim the function name + size_t b = func.find_first_not_of(" \t"); + size_t e = func.find_last_not_of(" \t"); + string actual = func.substr(b, e != string::npos ? e-b+1 : string::npos); + + stringstream s; + s << "Adding deferred break point for function '" << actual << "'" << endl; + Output(s.str()); + + BreakPoint bp(actual, 0, true); + m_breakPoints.push_back(bp); +} + +void CDebugger::AddFileBreakPoint(const string &file, int lineNbr) +{ + // Store just file name, not entire path + size_t r = file.find_last_of("\\/"); + string actual; + if( r != string::npos ) + actual = file.substr(r+1); + else + actual = file; + + // Trim the file name + size_t b = actual.find_first_not_of(" \t"); + size_t e = actual.find_last_not_of(" \t"); + actual = actual.substr(b, e != string::npos ? e-b+1 : string::npos); + + stringstream s; + s << "Setting break point in file '" << actual << "' at line " << lineNbr << endl; + Output(s.str()); + + BreakPoint bp(actual, lineNbr, false); + m_breakPoints.push_back(bp); +} + +void CDebugger::PrintHelp() +{ + Output(" c - Continue\n" + " s - Step into\n" + " n - Next step\n" + " o - Step out\n" + " b - Set break point\n" + " l - List various things\n" + " r - Remove break point\n" + " p - Print value\n" + " w - Where am I?\n" + " a - Abort execution\n" + " h - Print this help text\n"); +} + +void CDebugger::Output(const string &str) +{ + // By default we just output to stdout + cout << str; +} + +void CDebugger::SetEngine(asIScriptEngine *engine) +{ + if( m_engine != engine ) + { + if( m_engine ) + m_engine->Release(); + m_engine = engine; + if( m_engine ) + m_engine->AddRef(); + } +} + +asIScriptEngine *CDebugger::GetEngine() +{ + return m_engine; +} + +END_AS_NAMESPACE diff --git a/add_on/debugger/debugger.h b/add_on/debugger/debugger.h new file mode 100644 index 0000000..3bb560c --- /dev/null +++ b/add_on/debugger/debugger.h @@ -0,0 +1,87 @@ +#ifndef DEBUGGER_H +#define DEBUGGER_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include +#include +#include + +BEGIN_AS_NAMESPACE + +class CDebugger +{ +public: + CDebugger(); + virtual ~CDebugger(); + + // Register callbacks to handle to-string conversions of application types + // The expandMembersLevel is a counter for how many recursive levels the members should be expanded. + // If the object that is being converted to a string has members of its own the callback should call + // the debugger's ToString passing in expandMembersLevel - 1. + typedef std::string (*ToStringCallback)(void *obj, int expandMembersLevel, CDebugger *dbg); + virtual void RegisterToStringCallback(const asITypeInfo *ti, ToStringCallback callback); + + // User interaction + virtual void TakeCommands(asIScriptContext *ctx); + virtual void Output(const std::string &str); + + // Line callback invoked by context + virtual void LineCallback(asIScriptContext *ctx); + + // Commands + virtual void PrintHelp(); + virtual void AddFileBreakPoint(const std::string &file, int lineNbr); + virtual void AddFuncBreakPoint(const std::string &func); + virtual void ListBreakPoints(); + virtual void ListLocalVariables(asIScriptContext *ctx); + virtual void ListGlobalVariables(asIScriptContext *ctx); + virtual void ListMemberProperties(asIScriptContext *ctx); + virtual void ListStatistics(asIScriptContext *ctx); + virtual void PrintCallstack(asIScriptContext *ctx); + virtual void PrintValue(const std::string &expr, asIScriptContext *ctx); + + // Helpers + virtual bool InterpretCommand(const std::string &cmd, asIScriptContext *ctx); + virtual bool CheckBreakPoint(asIScriptContext *ctx); + virtual std::string ToString(void *value, asUINT typeId, int expandMembersLevel, asIScriptEngine *engine); + + // Optionally set the engine pointer in the debugger so it can be retrieved + // by callbacks that need it. This will hold a reference to the engine. + virtual void SetEngine(asIScriptEngine *engine); + virtual asIScriptEngine *GetEngine(); + +protected: + enum DebugAction + { + CONTINUE, // continue until next break point + STEP_INTO, // stop at next instruction + STEP_OVER, // stop at next instruction, skipping called functions + STEP_OUT // run until returning from current function + }; + DebugAction m_action; + asUINT m_lastCommandAtStackLevel; + asIScriptFunction *m_lastFunction; + + struct BreakPoint + { + BreakPoint(std::string f, int n, bool _func) : name(f), lineNbr(n), func(_func), needsAdjusting(true) {} + std::string name; + int lineNbr; + bool func; + bool needsAdjusting; + }; + std::vector m_breakPoints; + + asIScriptEngine *m_engine; + + // Registered callbacks for converting types to strings + std::map m_toStringCallbacks; +}; + +END_AS_NAMESPACE + +#endif \ No newline at end of file diff --git a/add_on/scriptany/scriptany.cpp b/add_on/scriptany/scriptany.cpp new file mode 100644 index 0000000..a7cf312 --- /dev/null +++ b/add_on/scriptany/scriptany.cpp @@ -0,0 +1,490 @@ +#include "scriptany.h" +#include +#include +#include + +BEGIN_AS_NAMESPACE + +// We'll use the generic interface for the factories as we need the engine pointer +static void ScriptAnyFactory_Generic(asIScriptGeneric *gen) +{ + asIScriptEngine *engine = gen->GetEngine(); + + *(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(engine); +} + +static void ScriptAnyFactory2_Generic(asIScriptGeneric *gen) +{ + asIScriptEngine *engine = gen->GetEngine(); + void *ref = (void*)gen->GetArgAddress(0); + int refType = gen->GetArgTypeId(0); + + *(CScriptAny**)gen->GetAddressOfReturnLocation() = new CScriptAny(ref,refType,engine); +} + +static CScriptAny &ScriptAnyAssignment(CScriptAny *other, CScriptAny *self) +{ + return *self = *other; +} + +static void ScriptAnyAssignment_Generic(asIScriptGeneric *gen) +{ + CScriptAny *other = (CScriptAny*)gen->GetArgObject(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + + *self = *other; + + gen->SetReturnObject(self); +} + +static void ScriptAny_Store_Generic(asIScriptGeneric *gen) +{ + void *ref = (void*)gen->GetArgAddress(0); + int refTypeId = gen->GetArgTypeId(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + + self->Store(ref, refTypeId); +} + +static void ScriptAny_StoreInt_Generic(asIScriptGeneric *gen) +{ + asINT64 *ref = (asINT64*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + + self->Store(*ref); +} + +static void ScriptAny_StoreFlt_Generic(asIScriptGeneric *gen) +{ + double *ref = (double*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + + self->Store(*ref); +} + +static void ScriptAny_Retrieve_Generic(asIScriptGeneric *gen) +{ + void *ref = (void*)gen->GetArgAddress(0); + int refTypeId = gen->GetArgTypeId(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + + *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(ref, refTypeId); +} + +static void ScriptAny_RetrieveInt_Generic(asIScriptGeneric *gen) +{ + asINT64 *ref = (asINT64*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + + *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref); +} + +static void ScriptAny_RetrieveFlt_Generic(asIScriptGeneric *gen) +{ + double *ref = (double*)gen->GetArgAddress(0); + CScriptAny *self = (CScriptAny*)gen->GetObject(); + + *(bool*)gen->GetAddressOfReturnLocation() = self->Retrieve(*ref); +} + +static void ScriptAny_AddRef_Generic(asIScriptGeneric *gen) +{ + CScriptAny *self = (CScriptAny*)gen->GetObject(); + self->AddRef(); +} + +static void ScriptAny_Release_Generic(asIScriptGeneric *gen) +{ + CScriptAny *self = (CScriptAny*)gen->GetObject(); + self->Release(); +} + +static void ScriptAny_GetRefCount_Generic(asIScriptGeneric *gen) +{ + CScriptAny *self = (CScriptAny*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); +} + +static void ScriptAny_SetFlag_Generic(asIScriptGeneric *gen) +{ + CScriptAny *self = (CScriptAny*)gen->GetObject(); + self->SetFlag(); +} + +static void ScriptAny_GetFlag_Generic(asIScriptGeneric *gen) +{ + CScriptAny *self = (CScriptAny*)gen->GetObject(); + *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); +} + +static void ScriptAny_EnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptAny *self = (CScriptAny*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); +} + +static void ScriptAny_ReleaseAllHandles_Generic(asIScriptGeneric *gen) +{ + CScriptAny *self = (CScriptAny*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); +} + +void RegisterScriptAny(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptAny_Generic(engine); + else + RegisterScriptAny_Native(engine); +} + +void RegisterScriptAny_Native(asIScriptEngine *engine) +{ + int r; + r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + + // We'll use the generic interface for the constructor as we need the engine pointer + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptAny,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptAny,Release), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(?&in)", asMETHODPR(CScriptAny,Store,(void*,int),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asMETHODPR(CScriptAny,Store,(asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const double&in)", asMETHODPR(CScriptAny,Store,(double&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(?&out)", asMETHODPR(CScriptAny,Retrieve,(void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out)", asMETHODPR(CScriptAny,Retrieve,(asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(double&out)", asMETHODPR(CScriptAny,Retrieve,(double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptAny,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptAny,SetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptAny,GetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptAny,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptAny,ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); +} + +void RegisterScriptAny_Generic(asIScriptEngine *engine) +{ + int r; + r = engine->RegisterObjectType("any", sizeof(CScriptAny), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + + // We'll use the generic interface for the constructor as we need the engine pointer + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f()", asFUNCTION(ScriptAnyFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(?&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const int64&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_FACTORY, "any@ f(const double&in) explicit", asFUNCTION(ScriptAnyFactory2_Generic), asCALL_GENERIC); assert(r >= 0); + + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptAny_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptAny_Release_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "any &opAssign(any&in)", asFUNCTION(ScriptAnyAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(?&in)", asFUNCTION(ScriptAny_Store_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const int64&in)", asFUNCTION(ScriptAny_StoreInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "void store(const double&in)", asFUNCTION(ScriptAny_StoreFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(?&out) const", asFUNCTION(ScriptAny_Retrieve_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(int64&out) const", asFUNCTION(ScriptAny_RetrieveInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("any", "bool retrieve(double&out) const", asFUNCTION(ScriptAny_RetrieveFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptAny_GetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptAny_SetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptAny_GetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptAny_EnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("any", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptAny_ReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); +} + + +CScriptAny &CScriptAny::operator=(const CScriptAny &other) +{ + // Hold on to the object type reference so it isn't destroyed too early + if( (other.value.typeId & asTYPEID_MASK_OBJECT) ) + { + asITypeInfo *ti = engine->GetTypeInfoById(other.value.typeId); + if( ti ) + ti->AddRef(); + } + + FreeObject(); + + value.typeId = other.value.typeId; + if( value.typeId & asTYPEID_OBJHANDLE ) + { + // For handles, copy the pointer and increment the reference count + value.valueObj = other.value.valueObj; + engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId)); + } + else if( value.typeId & asTYPEID_MASK_OBJECT ) + { + // Create a copy of the object + value.valueObj = engine->CreateScriptObjectCopy(other.value.valueObj, engine->GetTypeInfoById(value.typeId)); + } + else + { + // Primitives can be copied directly + value.valueInt = other.value.valueInt; + } + + return *this; +} + +int CScriptAny::CopyFrom(const CScriptAny *other) +{ + if( other == 0 ) return asINVALID_ARG; + + *this = *(CScriptAny*)other; + + return 0; +} + +CScriptAny::CScriptAny(asIScriptEngine *engine) +{ + this->engine = engine; + refCount = 1; + gcFlag = false; + + value.typeId = 0; + value.valueInt = 0; + + // Notify the garbage collector of this object + engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any")); +} + +CScriptAny::CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine) +{ + this->engine = engine; + refCount = 1; + gcFlag = false; + + value.typeId = 0; + value.valueInt = 0; + + // Notify the garbage collector of this object + engine->NotifyGarbageCollectorOfNewObject(this, engine->GetTypeInfoByName("any")); + + Store(ref, refTypeId); +} + +CScriptAny::~CScriptAny() +{ + FreeObject(); +} + +void CScriptAny::Store(void *ref, int refTypeId) +{ + // This method is not expected to be used for primitive types, except for bool, int64, or double + assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_VOID || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE ); + + // Hold on to the object type reference so it isn't destroyed too early + if( (refTypeId & asTYPEID_MASK_OBJECT) ) + { + asITypeInfo *ti = engine->GetTypeInfoById(refTypeId); + if( ti ) + ti->AddRef(); + } + + FreeObject(); + + value.typeId = refTypeId; + if( value.typeId & asTYPEID_OBJHANDLE ) + { + // We're receiving a reference to the handle, so we need to dereference it + value.valueObj = *(void**)ref; + engine->AddRefScriptObject(value.valueObj, engine->GetTypeInfoById(value.typeId)); + } + else if( value.typeId & asTYPEID_MASK_OBJECT ) + { + // Create a copy of the object + value.valueObj = engine->CreateScriptObjectCopy(ref, engine->GetTypeInfoById(value.typeId)); + } + else + { + // Primitives can be copied directly + value.valueInt = 0; + + // Copy the primitive value + // We receive a pointer to the value. + int size = engine->GetSizeOfPrimitiveType(value.typeId); + memcpy(&value.valueInt, ref, size); + } +} + +void CScriptAny::Store(double &ref) +{ + Store(&ref, asTYPEID_DOUBLE); +} + +void CScriptAny::Store(asINT64 &ref) +{ + Store(&ref, asTYPEID_INT64); +} + + +bool CScriptAny::Retrieve(void *ref, int refTypeId) const +{ + // This method is not expected to be used for primitive types, except for bool, int64, or double + assert( refTypeId > asTYPEID_DOUBLE || refTypeId == asTYPEID_BOOL || refTypeId == asTYPEID_INT64 || refTypeId == asTYPEID_DOUBLE ); + + if( refTypeId & asTYPEID_OBJHANDLE ) + { + // Is the handle type compatible with the stored value? + + // A handle can be retrieved if the stored type is a handle of same or compatible type + // or if the stored type is an object that implements the interface that the handle refer to. + if( (value.typeId & asTYPEID_MASK_OBJECT) ) + { + // Don't allow the retrieval if the stored handle is to a const object but not the wanted handle + if( (value.typeId & asTYPEID_HANDLETOCONST) && !(refTypeId & asTYPEID_HANDLETOCONST) ) + return false; + + // RefCastObject will increment the refCount of the returned pointer if successful + engine->RefCastObject(value.valueObj, engine->GetTypeInfoById(value.typeId), engine->GetTypeInfoById(refTypeId), reinterpret_cast(ref)); + if( *(asPWORD*)ref == 0 ) + return false; + return true; + } + } + else if( refTypeId & asTYPEID_MASK_OBJECT ) + { + // Is the object type compatible with the stored value? + + // Copy the object into the given reference + if( value.typeId == refTypeId ) + { + engine->AssignScriptObject(ref, value.valueObj, engine->GetTypeInfoById(value.typeId)); + return true; + } + } + else + { + // Is the primitive type compatible with the stored value? + + if( value.typeId == refTypeId ) + { + int size = engine->GetSizeOfPrimitiveType(refTypeId); + memcpy(ref, &value.valueInt, size); + return true; + } + + // We know all numbers are stored as either int64 or double, since we register overloaded functions for those + if( value.typeId == asTYPEID_INT64 && refTypeId == asTYPEID_DOUBLE ) + { + *(double*)ref = double(value.valueInt); + return true; + } + else if( value.typeId == asTYPEID_DOUBLE && refTypeId == asTYPEID_INT64 ) + { + *(asINT64*)ref = asINT64(value.valueFlt); + return true; + } + } + + return false; +} + +bool CScriptAny::Retrieve(asINT64 &outValue) const +{ + return Retrieve(&outValue, asTYPEID_INT64); +} + +bool CScriptAny::Retrieve(double &outValue) const +{ + return Retrieve(&outValue, asTYPEID_DOUBLE); +} + +int CScriptAny::GetTypeId() const +{ + return value.typeId; +} + +void CScriptAny::FreeObject() +{ + // If it is a handle or a ref counted object, call release + if( value.typeId & asTYPEID_MASK_OBJECT ) + { + // Let the engine release the object + asITypeInfo *ti = engine->GetTypeInfoById(value.typeId); + engine->ReleaseScriptObject(value.valueObj, ti); + + // Release the object type info + if( ti ) + ti->Release(); + + value.valueObj = 0; + value.typeId = 0; + } + + // For primitives, there's nothing to do +} + + +void CScriptAny::EnumReferences(asIScriptEngine *inEngine) +{ + // If we're holding a reference, we'll notify the garbage collector of it + if (value.valueObj && (value.typeId & asTYPEID_MASK_OBJECT)) + { + asITypeInfo *subType = engine->GetTypeInfoById(value.typeId); + if ((subType->GetFlags() & asOBJ_REF)) + { + inEngine->GCEnumCallback(value.valueObj); + } + else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + engine->ForwardGCEnumReferences(value.valueObj, subType); + } + + // The object type itself is also garbage collected + asITypeInfo *ti = inEngine->GetTypeInfoById(value.typeId); + if (ti) + inEngine->GCEnumCallback(ti); + } +} + +void CScriptAny::ReleaseAllHandles(asIScriptEngine * /*engine*/) +{ + FreeObject(); +} + +int CScriptAny::AddRef() const +{ + // Increase counter and clear flag set by GC + gcFlag = false; + return asAtomicInc(refCount); +} + +int CScriptAny::Release() const +{ + // Decrease the ref counter + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + // Delete this object as no more references to it exists + delete this; + return 0; + } + + return refCount; +} + +int CScriptAny::GetRefCount() +{ + return refCount; +} + +void CScriptAny::SetFlag() +{ + gcFlag = true; +} + +bool CScriptAny::GetFlag() +{ + return gcFlag; +} + + +END_AS_NAMESPACE diff --git a/add_on/scriptany/scriptany.h b/add_on/scriptany/scriptany.h new file mode 100644 index 0000000..4b23f57 --- /dev/null +++ b/add_on/scriptany/scriptany.h @@ -0,0 +1,76 @@ +#ifndef SCRIPTANY_H +#define SCRIPTANY_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +class CScriptAny +{ +public: + // Constructors + CScriptAny(asIScriptEngine *engine); + CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine); + + // Memory management + int AddRef() const; + int Release() const; + + // Copy the stored value from another any object + CScriptAny &operator=(const CScriptAny&); + int CopyFrom(const CScriptAny *other); + + // Store the value, either as variable type, integer number, or real number + void Store(void *ref, int refTypeId); + void Store(asINT64 &value); + void Store(double &value); + + // Retrieve the stored value, either as variable type, integer number, or real number + bool Retrieve(void *ref, int refTypeId) const; + bool Retrieve(asINT64 &value) const; + bool Retrieve(double &value) const; + + // Get the type id of the stored value + int GetTypeId() const; + + // GC methods + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); + +protected: + virtual ~CScriptAny(); + void FreeObject(); + + mutable int refCount; + mutable bool gcFlag; + asIScriptEngine *engine; + + // The structure for holding the values + struct valueStruct + { + union + { + asINT64 valueInt; + double valueFlt; + void *valueObj; + }; + int typeId; + }; + + valueStruct value; +}; + +void RegisterScriptAny(asIScriptEngine *engine); +void RegisterScriptAny_Native(asIScriptEngine *engine); +void RegisterScriptAny_Generic(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptarray/scriptarray.cpp b/add_on/scriptarray/scriptarray.cpp new file mode 100644 index 0000000..58512f3 --- /dev/null +++ b/add_on/scriptarray/scriptarray.cpp @@ -0,0 +1,2186 @@ +#include +#include +#include +#include +#include // sprintf +#include +#include // std::sort + +#include "scriptarray.h" + +using namespace std; + +BEGIN_AS_NAMESPACE + +// This macro is used to avoid warnings about unused variables. +// Usually where the variables are only used in debug mode. +#define UNUSED_VAR(x) (void)(x) + +// Set the default memory routines +// Use the angelscript engine's memory routines by default +static asALLOCFUNC_t userAlloc = asAllocMem; +static asFREEFUNC_t userFree = asFreeMem; + +// Allows the application to set which memory routines should be used by the array object +void CScriptArray::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) +{ + userAlloc = allocFunc; + userFree = freeFunc; +} + +static void RegisterScriptArray_Native(asIScriptEngine *engine); +static void RegisterScriptArray_Generic(asIScriptEngine *engine); + +struct SArrayBuffer +{ + asDWORD maxElements; + asDWORD numElements; + asBYTE data[1]; +}; + +struct SArrayCache +{ + asIScriptFunction *cmpFunc; + asIScriptFunction *eqFunc; + int cmpFuncReturnCode; // To allow better error message in case of multiple matches + int eqFuncReturnCode; +}; + +// We just define a number here that we assume nobody else is using for +// object type user data. The add-ons have reserved the numbers 1000 +// through 1999 for this purpose, so we should be fine. +const asPWORD ARRAY_CACHE = 1000; + +static void CleanupTypeInfoArrayCache(asITypeInfo *type) +{ + SArrayCache *cache = reinterpret_cast(type->GetUserData(ARRAY_CACHE)); + if( cache ) + { + cache->~SArrayCache(); + userFree(cache); + } +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(length, ti); + + return a; +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti, void *initList) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(ti, initList); + + return a; +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti, asUINT length, void *defVal) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptArray)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptArray *a = new(mem) CScriptArray(length, defVal, ti); + + return a; +} + +CScriptArray* CScriptArray::Create(asITypeInfo *ti) +{ + return CScriptArray::Create(ti, asUINT(0)); +} + +// This optional callback is called when the template type is first used by the compiler. +// It allows the application to validate if the template can be instantiated for the requested +// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect +// allow the callback to tell the engine if the template instance type shouldn't be garbage collected, +// i.e. no asOBJ_GC flag. +static bool ScriptArrayTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect) +{ + // Make sure the subtype can be instantiated with a default factory/constructor, + // otherwise we won't be able to instantiate the elements. + int typeId = ti->GetSubTypeId(); + if( typeId == asTYPEID_VOID ) + return false; + if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) + { + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) ) + { + // Verify that there is a default constructor + bool found = false; + for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ ) + { + asEBehaviours beh; + asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh); + if( beh != asBEHAVE_CONSTRUCT ) continue; + + if( func->GetParamCount() == 0 ) + { + // Found the default constructor + found = true; + break; + } + } + + if( !found ) + { + // There is no default constructor + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); + return false; + } + } + else if( (flags & asOBJ_REF) ) + { + bool found = false; + + // If value assignment for ref type has been disabled then the array + // can be created if the type has a default factory function + if( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) + { + // Verify that there is a default factory + for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) + { + asIScriptFunction *func = subtype->GetFactoryByIndex(n); + if( func->GetParamCount() == 0 ) + { + // Found the default factory + found = true; + break; + } + } + } + + if( !found ) + { + // No default factory + // TODO: Should format the message to give the name of the subtype for better understanding + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); + return false; + } + } + + // If the object type is not garbage collected then the array also doesn't need to be + if( !(flags & asOBJ_GC) ) + dontGarbageCollect = true; + } + else if( !(typeId & asTYPEID_OBJHANDLE) ) + { + // Arrays with primitives cannot form circular references, + // thus there is no need to garbage collect them + dontGarbageCollect = true; + } + else + { + assert( typeId & asTYPEID_OBJHANDLE ); + + // It is not necessary to set the array as garbage collected for all handle types. + // If it is possible to determine that the handle cannot refer to an object type + // that can potentially form a circular reference with the array then it is not + // necessary to make the array garbage collected. + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( !(flags & asOBJ_GC) ) + { + if( (flags & asOBJ_SCRIPT_OBJECT) ) + { + // Even if a script class is by itself not garbage collected, it is possible + // that classes that derive from it may be, so it is not possible to know + // that no circular reference can occur. + if( (flags & asOBJ_NOINHERIT) ) + { + // A script class declared as final cannot be inherited from, thus + // we can be certain that the object cannot be garbage collected. + dontGarbageCollect = true; + } + } + else + { + // For application registered classes we assume the application knows + // what it is doing and don't mark the array as garbage collected unless + // the type is also garbage collected. + dontGarbageCollect = true; + } + } + } + + // The type is ok + return true; +} + +// Registers the template array type +void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") == 0 ) + RegisterScriptArray_Native(engine); + else + RegisterScriptArray_Generic(engine); + + if( defaultArray ) + { + int r = engine->RegisterDefaultArrayType("array"); assert( r >= 0 ); + UNUSED_VAR(r); + } +} + +static void RegisterScriptArray_Native(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + // Register the object type user data clean up + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); + + // Register the array type as a template + r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + + // Register a callback for validating the subtype before it is used + r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback), asCALL_CDECL); assert( r >= 0 ); + + // Templates receive the object type as the first parameter. To the script writer this is hidden + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, asUINT, void *), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + + // Register the factory that will be used for initialization lists + r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in type, int&in list) {repeat T}", asFUNCTIONPR(CScriptArray::Create, (asITypeInfo*, void*), CScriptArray*), asCALL_CDECL); assert( r >= 0 ); + + // The memory management methods + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptArray,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptArray,Release), asCALL_THISCALL); assert( r >= 0 ); + + // The index operator returns the template subtype + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asMETHODPR(CScriptArray, At, (asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asMETHODPR(CScriptArray, At, (asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); + + // The assignment operator + r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asMETHOD(CScriptArray, operator=), asCALL_THISCALL); assert( r >= 0 ); + + // Other methods + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeLast()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asMETHOD(CScriptArray, RemoveRange), asCALL_THISCALL); assert(r >= 0); + // TODO: Should length() and resize() be deprecated as the property accessors do the same thing? + // TODO: Register as size() for consistency with other types +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("array", "uint length() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asMETHOD(CScriptArray, Reserve), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc()", asMETHODPR(CScriptArray, SortAsc, (), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortAsc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc()", asMETHODPR(CScriptArray, SortDesc, (), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asMETHODPR(CScriptArray, SortDesc, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reverse()", asMETHOD(CScriptArray, Reverse), asCALL_THISCALL); assert( r >= 0 ); + // The token 'if_handle_then_const' tells the engine that if the type T is a handle, then it should refer to a read-only object + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int find(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, Find, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + // TODO: It should be "int findByRef(const T&in value, uint startAt = 0) const" + r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asMETHODPR(CScriptArray, FindByRef, (asUINT, void*) const, int), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asMETHOD(CScriptArray, operator==), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + + // Sort with callback for comparison + r = engine->RegisterFuncdef("bool array::less(const T&in if_handle_then_const a, const T&in if_handle_then_const b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asMETHODPR(CScriptArray, Sort, (asIScriptFunction*, asUINT, asUINT), void), asCALL_THISCALL); assert(r >= 0); + +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + // Register virtual properties + r = engine->RegisterObjectMethod("array", "uint get_length() const property", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asMETHODPR(CScriptArray, Resize, (asUINT), void), asCALL_THISCALL); assert( r >= 0 ); +#endif + + // Register GC behaviours in case the array needs to be garbage collected + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptArray, GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptArray, SetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptArray, GetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptArray, EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptArray, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); + +#if AS_USE_STLNAMES == 1 + // Same as length + r = engine->RegisterObjectMethod("array", "uint size() const", asMETHOD(CScriptArray, GetSize), asCALL_THISCALL); assert( r >= 0 ); + // Same as isEmpty + r = engine->RegisterObjectMethod("array", "bool empty() const", asMETHOD(CScriptArray, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + // Same as insertLast + r = engine->RegisterObjectMethod("array", "void push_back(const T&in)", asMETHOD(CScriptArray, InsertLast), asCALL_THISCALL); assert( r >= 0 ); + // Same as removeLast + r = engine->RegisterObjectMethod("array", "void pop_back()", asMETHOD(CScriptArray, RemoveLast), asCALL_THISCALL); assert( r >= 0 ); + // Same as insertAt + r = engine->RegisterObjectMethod("array", "void insert(uint index, const T&in value)", asMETHODPR(CScriptArray, InsertAt, (asUINT, void *), void), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insert(uint index, const array& arr)", asMETHODPR(CScriptArray, InsertAt, (asUINT, const CScriptArray &), void), asCALL_THISCALL); assert(r >= 0); + // Same as removeAt + r = engine->RegisterObjectMethod("array", "void erase(uint)", asMETHOD(CScriptArray, RemoveAt), asCALL_THISCALL); assert( r >= 0 ); +#endif +} + +CScriptArray &CScriptArray::operator=(const CScriptArray &other) +{ + // Only perform the copy if the array types are the same + if( &other != this && + other.GetArrayObjectType() == GetArrayObjectType() ) + { + // Make sure the arrays are of the same size + Resize(other.buffer->numElements); + + // Copy the value of each element + CopyBuffer(buffer, other.buffer); + } + + return *this; +} + +CScriptArray::CScriptArray(asITypeInfo *ti, void *buf) +{ + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + + Precache(); + + asIScriptEngine *engine = ti->GetEngine(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = engine->GetSizeOfPrimitiveType(subTypeId); + + // Determine the initial size from the buffer + asUINT length = *(asUINT*)buf; + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } + + // Copy the values of the array elements from the buffer + if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) + { + CreateBuffer(&buffer, length); + + // Copy the values of the primitive type into the internal buffer + if( length > 0 ) + memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); + } + else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) + { + CreateBuffer(&buffer, length); + + // Copy the handles into the internal buffer + if( length > 0 ) + memcpy(At(0), (((asUINT*)buf)+1), length * elementSize); + + // With object handles it is safe to clear the memory in the received buffer + // instead of increasing the ref count. It will save time both by avoiding the + // call the increase ref, and also relieve the engine from having to release + // its references too + memset((((asUINT*)buf)+1), 0, length * elementSize); + } + else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) + { + // Only allocate the buffer, but not the objects + subTypeId |= asTYPEID_OBJHANDLE; + CreateBuffer(&buffer, length); + subTypeId &= ~asTYPEID_OBJHANDLE; + + // Copy the handles into the internal buffer + if( length > 0 ) + memcpy(buffer->data, (((asUINT*)buf)+1), length * elementSize); + + // For ref types we can do the same as for handles, as they are + // implicitly stored as handles. + memset((((asUINT*)buf)+1), 0, length * elementSize); + } + else + { + // TODO: Optimize by calling the copy constructor of the object instead of + // constructing with the default constructor and then assigning the value + // TODO: With C++11 ideally we should be calling the move constructor, instead + // of the copy constructor as the engine will just discard the objects in the + // buffer afterwards. + CreateBuffer(&buffer, length); + + // For value types we need to call the opAssign for each individual object + for( asUINT n = 0; n < length; n++ ) + { + void *obj = At(n); + asBYTE *srcObj = (asBYTE*)buf; + srcObj += 4 + n*ti->GetSubType()->GetSize(); + engine->AssignScriptObject(obj, srcObj, ti->GetSubType()); + } + } + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); +} + +CScriptArray::CScriptArray(asUINT length, asITypeInfo *ti) +{ + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + + Precache(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } + + CreateBuffer(&buffer, length); + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); +} + +CScriptArray::CScriptArray(const CScriptArray &other) +{ + refCount = 1; + gcFlag = false; + objType = other.objType; + objType->AddRef(); + buffer = 0; + + Precache(); + + elementSize = other.elementSize; + + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + + CreateBuffer(&buffer, 0); + + // Copy the content + *this = other; +} + +CScriptArray::CScriptArray(asUINT length, void *defVal, asITypeInfo *ti) +{ + // The object type should be the template instance of the array + assert( ti && string(ti->GetName()) == "array" ); + + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + + Precache(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(length) ) + { + // Don't continue with the initialization + return; + } + + CreateBuffer(&buffer, length); + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + + // Initialize the elements with the default value + for( asUINT n = 0; n < GetSize(); n++ ) + SetValue(n, defVal); +} + +void CScriptArray::SetValue(asUINT index, void *value) +{ + // At() will take care of the out-of-bounds checking, though + // if called from the application then nothing will be done + void *ptr = At(index); + if( ptr == 0 ) return; + + if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) ) + objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType()); + else if( subTypeId & asTYPEID_OBJHANDLE ) + { + void *tmp = *(void**)ptr; + *(void**)ptr = *(void**)value; + objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType()); + if( tmp ) + objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType()); + } + else if( subTypeId == asTYPEID_BOOL || + subTypeId == asTYPEID_INT8 || + subTypeId == asTYPEID_UINT8 ) + *(char*)ptr = *(char*)value; + else if( subTypeId == asTYPEID_INT16 || + subTypeId == asTYPEID_UINT16 ) + *(short*)ptr = *(short*)value; + else if( subTypeId == asTYPEID_INT32 || + subTypeId == asTYPEID_UINT32 || + subTypeId == asTYPEID_FLOAT || + subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles + *(int*)ptr = *(int*)value; + else if( subTypeId == asTYPEID_INT64 || + subTypeId == asTYPEID_UINT64 || + subTypeId == asTYPEID_DOUBLE ) + *(double*)ptr = *(double*)value; +} + +CScriptArray::~CScriptArray() +{ + if( buffer ) + { + DeleteBuffer(buffer); + buffer = 0; + } + if( objType ) objType->Release(); +} + +asUINT CScriptArray::GetSize() const +{ + return buffer->numElements; +} + +bool CScriptArray::IsEmpty() const +{ + return buffer->numElements == 0; +} + +void CScriptArray::Reserve(asUINT maxElements) +{ + if( maxElements <= buffer->maxElements ) + return; + + if( !CheckMaxSize(maxElements) ) + return; + + // Allocate memory for the buffer + SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*maxElements)); + if( newBuffer ) + { + newBuffer->numElements = buffer->numElements; + newBuffer->maxElements = maxElements; + } + else + { + // Out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + return; + } + + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. + memcpy(newBuffer->data, buffer->data, buffer->numElements*elementSize); + + // Release the old buffer + userFree(buffer); + + buffer = newBuffer; +} + +void CScriptArray::Resize(asUINT numElements) +{ + if( !CheckMaxSize(numElements) ) + return; + + Resize((int)numElements - (int)buffer->numElements, (asUINT)-1); +} + +void CScriptArray::RemoveRange(asUINT start, asUINT count) +{ + if (count == 0) + return; + + if( buffer == 0 || start > buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } + + // Cap count to the end of the array + if (start + count > buffer->numElements) + count = buffer->numElements - start; + + // Destroy the elements that are being removed + Destruct(buffer, start, start + count); + + // Compact the elements + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + start*elementSize, buffer->data + (start + count)*elementSize, (buffer->numElements - start - count)*elementSize); + buffer->numElements -= count; +} + +// Internal +void CScriptArray::Resize(int delta, asUINT at) +{ + if( delta < 0 ) + { + if( -delta > (int)buffer->numElements ) + delta = -(int)buffer->numElements; + if( at > buffer->numElements + delta ) + at = buffer->numElements + delta; + } + else if( delta > 0 ) + { + // Make sure the array size isn't too large for us to handle + if( delta > 0 && !CheckMaxSize(buffer->numElements + delta) ) + return; + + if( at > buffer->numElements ) + at = buffer->numElements; + } + + if( delta == 0 ) return; + + if( buffer->maxElements < buffer->numElements + delta ) + { + // Allocate memory for the buffer + SArrayBuffer *newBuffer = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1 + elementSize*(buffer->numElements + delta))); + if( newBuffer ) + { + newBuffer->numElements = buffer->numElements + delta; + newBuffer->maxElements = newBuffer->numElements; + } + else + { + // Out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + return; + } + + // As objects in arrays of objects are not stored inline, it is safe to use memcpy here + // since we're just copying the pointers to objects and not the actual objects. + memcpy(newBuffer->data, buffer->data, at*elementSize); + if( at < buffer->numElements ) + memcpy(newBuffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements-at)*elementSize); + + // Initialize the new elements with default values + Construct(newBuffer, at, at+delta); + + // Release the old buffer + userFree(buffer); + + buffer = newBuffer; + } + else if( delta < 0 ) + { + Destruct(buffer, at, at-delta); + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + at*elementSize, buffer->data + (at-delta)*elementSize, (buffer->numElements - (at-delta))*elementSize); + buffer->numElements += delta; + } + else + { + // As objects in arrays of objects are not stored inline, it is safe to use memmove here + // since we're just copying the pointers to objects and not the actual objects. + memmove(buffer->data + (at+delta)*elementSize, buffer->data + at*elementSize, (buffer->numElements - at)*elementSize); + Construct(buffer, at, at+delta); + buffer->numElements += delta; + } +} + +// internal +bool CScriptArray::CheckMaxSize(asUINT numElements) +{ + // This code makes sure the size of the buffer that is allocated + // for the array doesn't overflow and becomes smaller than requested + + asUINT maxSize = 0xFFFFFFFFul - sizeof(SArrayBuffer) + 1; + if( elementSize > 0 ) + maxSize /= elementSize; + + if( numElements > maxSize ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Too large array size"); + + return false; + } + + // OK + return true; +} + +asITypeInfo *CScriptArray::GetArrayObjectType() const +{ + return objType; +} + +int CScriptArray::GetArrayTypeId() const +{ + return objType->GetTypeId(); +} + +int CScriptArray::GetElementTypeId() const +{ + return subTypeId; +} + +void CScriptArray::InsertAt(asUINT index, void *value) +{ + if( index > buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return; + } + + // Make room for the new element + Resize(1, index); + + // Set the value of the new element + SetValue(index, value); +} + +void CScriptArray::InsertAt(asUINT index, const CScriptArray &arr) +{ + if (index > buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Index out of bounds"); + return; + } + + if (objType != arr.objType) + { + // This shouldn't really be possible to happen when + // called from a script, but let's check for it anyway + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Mismatching array types"); + return; + } + + asUINT elements = arr.GetSize(); + Resize(elements, index); + if (&arr != this) + { + for (asUINT n = 0; n < arr.GetSize(); n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + } + else + { + // The array that is being inserted is the same as this one. + // So we should iterate over the elements before the index, + // and then the elements after + for (asUINT n = 0; n < index; n++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + n, value); + } + + for (asUINT n = index + elements, m = 0; n < arr.GetSize(); n++, m++) + { + // This const cast is allowed, since we know the + // value will only be used to make a copy of it + void *value = const_cast(arr.At(n)); + SetValue(index + index + m, value); + } + } +} + +void CScriptArray::InsertLast(void *value) +{ + InsertAt(buffer->numElements, value); +} + +void CScriptArray::RemoveAt(asUINT index) +{ + if( index >= buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return; + } + + // Remove the element + Resize(-1, index); +} + +void CScriptArray::RemoveLast() +{ + RemoveAt(buffer->numElements-1); +} + +// Return a pointer to the array element. Returns 0 if the index is out of bounds +const void *CScriptArray::At(asUINT index) const +{ + if( buffer == 0 || index >= buffer->numElements ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return 0; + } + + if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + return *(void**)(buffer->data + elementSize*index); + else + return buffer->data + elementSize*index; +} +void *CScriptArray::At(asUINT index) +{ + return const_cast(const_cast(this)->At(index)); +} + +void *CScriptArray::GetBuffer() +{ + return buffer->data; +} + + +// internal +void CScriptArray::CreateBuffer(SArrayBuffer **buf, asUINT numElements) +{ + *buf = reinterpret_cast(userAlloc(sizeof(SArrayBuffer)-1+elementSize*numElements)); + + if( *buf ) + { + (*buf)->numElements = numElements; + (*buf)->maxElements = numElements; + Construct(*buf, 0, numElements); + } + else + { + // Oops, out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + } +} + +// internal +void CScriptArray::DeleteBuffer(SArrayBuffer *buf) +{ + Destruct(buf, 0, buf->numElements); + + // Free the buffer + userFree(buf); +} + +// internal +void CScriptArray::Construct(SArrayBuffer *buf, asUINT start, asUINT end) +{ + if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + { + // Create an object using the default constructor/factory for each element + void **max = (void**)(buf->data + end * sizeof(void*)); + void **d = (void**)(buf->data + start * sizeof(void*)); + + asIScriptEngine *engine = objType->GetEngine(); + asITypeInfo *subType = objType->GetSubType(); + + for( ; d < max; d++ ) + { + *d = (void*)engine->CreateScriptObject(subType); + if( *d == 0 ) + { + // Set the remaining entries to null so the destructor + // won't attempt to destroy invalid objects later + memset(d, 0, sizeof(void*)*(max-d)); + + // There is no need to set an exception on the context, + // as CreateScriptObject has already done that + return; + } + } + } + else + { + // Set all elements to zero whether they are handles or primitives + void *d = (void*)(buf->data + start * elementSize); + memset(d, 0, (end-start)*elementSize); + } +} + +// internal +void CScriptArray::Destruct(SArrayBuffer *buf, asUINT start, asUINT end) +{ + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + asIScriptEngine *engine = objType->GetEngine(); + + void **max = (void**)(buf->data + end * sizeof(void*)); + void **d = (void**)(buf->data + start * sizeof(void*)); + + for( ; d < max; d++ ) + { + if( *d ) + engine->ReleaseScriptObject(*d, objType->GetSubType()); + } + } +} + + +// internal +bool CScriptArray::Less(const void *a, const void *b, bool asc) +{ + if( !asc ) + { + // Swap items + const void *TEMP = a; + a = b; + b = TEMP; + } + + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + { + // Simple compare of values + switch( subTypeId ) + { + #define COMPARE(T) *((T*)a) < *((T*)b) + case asTYPEID_BOOL: return COMPARE(bool); + case asTYPEID_INT8: return COMPARE(signed char); + case asTYPEID_UINT8: return COMPARE(unsigned char); + case asTYPEID_INT16: return COMPARE(signed short); + case asTYPEID_UINT16: return COMPARE(unsigned short); + case asTYPEID_INT32: return COMPARE(signed int); + case asTYPEID_UINT32: return COMPARE(unsigned int); + case asTYPEID_FLOAT: return COMPARE(float); + case asTYPEID_DOUBLE: return COMPARE(double); + default: return COMPARE(signed int); // All enums fall in this case + #undef COMPARE + } + } + + return false; +} + +void CScriptArray::Reverse() +{ + asUINT size = GetSize(); + + if( size >= 2 ) + { + asBYTE TEMP[16]; + + for( asUINT i = 0; i < size / 2; i++ ) + { + Copy(TEMP, GetArrayItemPointer(i)); + Copy(GetArrayItemPointer(i), GetArrayItemPointer(size - i - 1)); + Copy(GetArrayItemPointer(size - i - 1), TEMP); + } + } +} + +bool CScriptArray::operator==(const CScriptArray &other) const +{ + if( objType != other.objType ) + return false; + + if( GetSize() != other.GetSize() ) + return false; + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + { + // TODO: Ideally this context would be retrieved from a pool, so we don't have to + // create a new one everytime. We could keep a context with the array object + // but that would consume a lot of resources as each context is quite heavy. + cmpContext = objType->GetEngine()->CreateContext(); + } + } + + // Check if all elements are equal + bool isEqual = true; + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + for( asUINT n = 0; n < GetSize(); n++ ) + if( !Equals(At(n), other.At(n), cmpContext, cache) ) + { + isEqual = false; + break; + } + + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + cmpContext->Release(); + } + + return isEqual; +} + +// internal +bool CScriptArray::Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const +{ + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + { + // Simple compare of values + switch( subTypeId ) + { + #define COMPARE(T) *((T*)a) == *((T*)b) + case asTYPEID_BOOL: return COMPARE(bool); + case asTYPEID_INT8: return COMPARE(signed char); + case asTYPEID_UINT8: return COMPARE(unsigned char); + case asTYPEID_INT16: return COMPARE(signed short); + case asTYPEID_UINT16: return COMPARE(unsigned short); + case asTYPEID_INT32: return COMPARE(signed int); + case asTYPEID_UINT32: return COMPARE(unsigned int); + case asTYPEID_FLOAT: return COMPARE(float); + case asTYPEID_DOUBLE: return COMPARE(double); + default: return COMPARE(signed int); // All enums fall here + #undef COMPARE + } + } + else + { + int r = 0; + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Allow the find to work even if the array contains null handles + if( *(void**)a == *(void**)b ) return true; + } + + // Execute object opEquals if available + if( cache && cache->eqFunc ) + { + // TODO: Add proper error handling + r = ctx->Prepare(cache->eqFunc); assert(r >= 0); + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + r = ctx->SetObject(*((void**)a)); assert(r >= 0); + r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); + } + else + { + r = ctx->SetObject((void*)a); assert(r >= 0); + r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); + } + + r = ctx->Execute(); + + if( r == asEXECUTION_FINISHED ) + return ctx->GetReturnByte() != 0; + + return false; + } + + // Execute object opCmp if available + if( cache && cache->cmpFunc ) + { + // TODO: Add proper error handling + r = ctx->Prepare(cache->cmpFunc); assert(r >= 0); + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + r = ctx->SetObject(*((void**)a)); assert(r >= 0); + r = ctx->SetArgObject(0, *((void**)b)); assert(r >= 0); + } + else + { + r = ctx->SetObject((void*)a); assert(r >= 0); + r = ctx->SetArgObject(0, (void*)b); assert(r >= 0); + } + + r = ctx->Execute(); + + if( r == asEXECUTION_FINISHED ) + return (int)ctx->GetReturnDWord() == 0; + + return false; + } + } + + return false; +} + +int CScriptArray::FindByRef(void *ref) const +{ + return FindByRef(0, ref); +} + +int CScriptArray::FindByRef(asUINT startAt, void *ref) const +{ + // Find the matching element by its reference + asUINT size = GetSize(); + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Dereference the pointer + ref = *(void**)ref; + for( asUINT i = startAt; i < size; i++ ) + { + if( *(void**)At(i) == ref ) + return i; + } + } + else + { + // Compare the reference directly + for( asUINT i = startAt; i < size; i++ ) + { + if( At(i) == ref ) + return i; + } + } + + return -1; +} + +int CScriptArray::Find(void *value) const +{ + return Find(0, value); +} + +int CScriptArray::Find(asUINT startAt, void *value) const +{ + // Check if the subtype really supports find() + // TODO: Can't this be done at compile time too by the template callback + SArrayCache *cache = 0; + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( !cache || (cache->cmpFunc == 0 && cache->eqFunc == 0) ) + { + asIScriptContext *ctx = asGetActiveContext(); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + + // Throw an exception + if( ctx ) + { + char tmp[512]; + + if( cache && cache->eqFuncReturnCode == asMULTIPLE_FUNCTIONS ) +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); +#else + sprintf(tmp, "Type '%s' has multiple matching opEquals or opCmp methods", subType->GetName()); +#endif + else +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); +#else + sprintf(tmp, "Type '%s' does not have a matching opEquals or opCmp method", subType->GetName()); +#endif + ctx->SetException(tmp); + } + + return -1; + } + } + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + { + // TODO: Ideally this context would be retrieved from a pool, so we don't have to + // create a new one everytime. We could keep a context with the array object + // but that would consume a lot of resources as each context is quite heavy. + cmpContext = objType->GetEngine()->CreateContext(); + } + } + + // Find the matching element + int ret = -1; + asUINT size = GetSize(); + + for( asUINT i = startAt; i < size; i++ ) + { + // value passed by reference + if( Equals(At(i), value, cmpContext, cache) ) + { + ret = (int)i; + break; + } + } + + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + cmpContext->Release(); + } + + return ret; +} + + + +// internal +// Copy object handle or primitive value +// Even in arrays of objects the objects are allocated on +// the heap and the array stores the pointers to the objects +void CScriptArray::Copy(void *dst, void *src) +{ + memcpy(dst, src, elementSize); +} + + +// internal +// Return pointer to array item (object handle or primitive value) +void *CScriptArray::GetArrayItemPointer(int index) +{ + return buffer->data + index * elementSize; +} + +// internal +// Return pointer to data in buffer (object or primitive) +void *CScriptArray::GetDataPointer(void *buf) +{ + if ((subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + { + // Real address of object + return reinterpret_cast(*(size_t*)buf); + } + else + { + // Primitive is just a raw data + return buf; + } +} + + +// Sort ascending +void CScriptArray::SortAsc() +{ + Sort(0, GetSize(), true); +} + +// Sort ascending +void CScriptArray::SortAsc(asUINT startAt, asUINT count) +{ + Sort(startAt, count, true); +} + +// Sort descending +void CScriptArray::SortDesc() +{ + Sort(0, GetSize(), false); +} + +// Sort descending +void CScriptArray::SortDesc(asUINT startAt, asUINT count) +{ + Sort(startAt, count, false); +} + + +// internal +void CScriptArray::Sort(asUINT startAt, asUINT count, bool asc) +{ + // Subtype isn't primitive and doesn't have opCmp + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + if( !cache || cache->cmpFunc == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + asITypeInfo* subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + + // Throw an exception + if( ctx ) + { + char tmp[512]; + + if( cache && cache->cmpFuncReturnCode == asMULTIPLE_FUNCTIONS ) +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' has multiple matching opCmp methods", subType->GetName()); +#else + sprintf(tmp, "Type '%s' has multiple matching opCmp methods", subType->GetName()); +#endif + else +#if defined(_MSC_VER) && _MSC_VER >= 1500 && !defined(__S3E__) + sprintf_s(tmp, 512, "Type '%s' does not have a matching opCmp method", subType->GetName()); +#else + sprintf(tmp, "Type '%s' does not have a matching opCmp method", subType->GetName()); +#endif + + ctx->SetException(tmp); + } + + return; + } + } + + // No need to sort + if( count < 2 ) + { + return; + } + + int start = startAt; + int end = startAt + count; + + // Check if we could access invalid item while sorting + if( start >= (int)buffer->numElements || end > (int)buffer->numElements ) + { + asIScriptContext *ctx = asGetActiveContext(); + + // Throw an exception + if( ctx ) + { + ctx->SetException("Index out of bounds"); + } + + return; + } + + if( subTypeId & ~asTYPEID_MASK_SEQNBR ) + { + asIScriptContext *cmpContext = 0; + bool isNested = false; + + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if( cmpContext ) + { + if( cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0 ) + isNested = true; + else + cmpContext = 0; + } + if( cmpContext == 0 ) + cmpContext = objType->GetEngine()->RequestContext(); + + // Do the sorting + struct { + bool asc; + asIScriptContext *cmpContext; + asIScriptFunction *cmpFunc; + bool operator()(void *a, void *b) const + { + if( !asc ) + { + // Swap items + void *TEMP = a; + a = b; + b = TEMP; + } + + int r = 0; + + // Allow sort to work even if the array contains null handles + if( a == 0 ) return true; + if( b == 0 ) return false; + + // Execute object opCmp + if( cmpFunc ) + { + // TODO: Add proper error handling + r = cmpContext->Prepare(cmpFunc); assert(r >= 0); + r = cmpContext->SetObject(a); assert(r >= 0); + r = cmpContext->SetArgObject(0, b); assert(r >= 0); + r = cmpContext->Execute(); + + if( r == asEXECUTION_FINISHED ) + { + return (int)cmpContext->GetReturnDWord() < 0; + } + } + + return false; + } + } customLess = {asc, cmpContext, cache ? cache->cmpFunc : 0}; + std::sort((void**)GetArrayItemPointer(start), (void**)GetArrayItemPointer(end), customLess); + + // Clean up + if( cmpContext ) + { + if( isNested ) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if( state == asEXECUTION_ABORTED ) + cmpContext->Abort(); + } + else + objType->GetEngine()->ReturnContext(cmpContext); + } + } + else + { + // TODO: Use std::sort for primitive types too + + // Insertion sort + asBYTE tmp[16]; + for( int i = start + 1; i < end; i++ ) + { + Copy(tmp, GetArrayItemPointer(i)); + + int j = i - 1; + + while( j >= start && Less(GetDataPointer(tmp), At(j), asc) ) + { + Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); + j--; + } + + Copy(GetArrayItemPointer(j + 1), tmp); + } + } +} + +// Sort with script callback for comparing elements +void CScriptArray::Sort(asIScriptFunction *func, asUINT startAt, asUINT count) +{ + // No need to sort + if (count < 2) + return; + + // Check if we could access invalid item while sorting + asUINT start = startAt; + asUINT end = asQWORD(startAt) + asQWORD(count) >= (asQWORD(1)<<32) ? 0xFFFFFFFF : startAt + count; + if (end > buffer->numElements) + end = buffer->numElements; + + if (start >= buffer->numElements) + { + asIScriptContext *ctx = asGetActiveContext(); + + // Throw an exception + if (ctx) + ctx->SetException("Index out of bounds"); + + return; + } + + asIScriptContext *cmpContext = 0; + bool isNested = false; + + // Try to reuse the active context + cmpContext = asGetActiveContext(); + if (cmpContext) + { + if (cmpContext->GetEngine() == objType->GetEngine() && cmpContext->PushState() >= 0) + isNested = true; + else + cmpContext = 0; + } + if (cmpContext == 0) + cmpContext = objType->GetEngine()->RequestContext(); + + // Insertion sort + asBYTE tmp[16]; + for (asUINT i = start + 1; i < end; i++) + { + Copy(tmp, GetArrayItemPointer(i)); + + asUINT j = i - 1; + + while (j != 0xFFFFFFFF && j >= start ) + { + cmpContext->Prepare(func); + cmpContext->SetArgAddress(0, GetDataPointer(tmp)); + cmpContext->SetArgAddress(1, At(j)); + int r = cmpContext->Execute(); + if (r != asEXECUTION_FINISHED) + break; + if (*(bool*)(cmpContext->GetAddressOfReturnValue())) + { + Copy(GetArrayItemPointer(j + 1), GetArrayItemPointer(j)); + j--; + } + else + break; + } + + Copy(GetArrayItemPointer(j + 1), tmp); + } + + if (cmpContext) + { + if (isNested) + { + asEContextState state = cmpContext->GetState(); + cmpContext->PopState(); + if (state == asEXECUTION_ABORTED) + cmpContext->Abort(); + } + else + objType->GetEngine()->ReturnContext(cmpContext); + } +} + +// internal +void CScriptArray::CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src) +{ + asIScriptEngine *engine = objType->GetEngine(); + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Copy the references and increase the reference counters + if( dst->numElements > 0 && src->numElements > 0 ) + { + int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; + + void **max = (void**)(dst->data + count * sizeof(void*)); + void **d = (void**)dst->data; + void **s = (void**)src->data; + + for( ; d < max; d++, s++ ) + { + void *tmp = *d; + *d = *s; + if( *d ) + engine->AddRefScriptObject(*d, objType->GetSubType()); + // Release the old ref after incrementing the new to avoid problem incase it is the same ref + if( tmp ) + engine->ReleaseScriptObject(tmp, objType->GetSubType()); + } + } + } + else + { + if( dst->numElements > 0 && src->numElements > 0 ) + { + int count = dst->numElements > src->numElements ? src->numElements : dst->numElements; + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + // Call the assignment operator on all of the objects + void **max = (void**)(dst->data + count * sizeof(void*)); + void **d = (void**)dst->data; + void **s = (void**)src->data; + + asITypeInfo *subType = objType->GetSubType(); + for( ; d < max; d++, s++ ) + engine->AssignScriptObject(*d, *s, subType); + } + else + { + // Primitives are copied byte for byte + memcpy(dst->data, src->data, count*elementSize); + } + } + } +} + +// internal +// Precache some info +void CScriptArray::Precache() +{ + subTypeId = objType->GetSubTypeId(); + + // Check if it is an array of objects. Only for these do we need to cache anything + // Type ids for primitives and enums only has the sequence number part + if( !(subTypeId & ~asTYPEID_MASK_SEQNBR) ) + return; + + // The opCmp and opEquals methods are cached because the searching for the + // methods is quite time consuming if a lot of array objects are created. + + // First check if a cache already exists for this array type + SArrayCache *cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( cache ) return; + + // We need to make sure the cache is created only once, even + // if multiple threads reach the same point at the same time + asAcquireExclusiveLock(); + + // Now that we got the lock, we need to check again to make sure the + // cache wasn't created while we were waiting for the lock + cache = reinterpret_cast(objType->GetUserData(ARRAY_CACHE)); + if( cache ) + { + asReleaseExclusiveLock(); + return; + } + + // Create the cache + cache = reinterpret_cast(userAlloc(sizeof(SArrayCache))); + if( !cache ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + asReleaseExclusiveLock(); + return; + } + memset(cache, 0, sizeof(SArrayCache)); + + // If the sub type is a handle to const, then the methods must be const too + bool mustBeConst = (subTypeId & asTYPEID_HANDLETOCONST) ? true : false; + + asITypeInfo *subType = objType->GetEngine()->GetTypeInfoById(subTypeId); + if( subType ) + { + for( asUINT i = 0; i < subType->GetMethodCount(); i++ ) + { + asIScriptFunction *func = subType->GetMethodByIndex(i); + + if( func->GetParamCount() == 1 && (!mustBeConst || func->IsReadOnly()) ) + { + asDWORD flags = 0; + int returnTypeId = func->GetReturnTypeId(&flags); + + // The method must not return a reference + if( flags != asTM_NONE ) + continue; + + // opCmp returns an int and opEquals returns a bool + bool isCmp = false, isEq = false; + if( returnTypeId == asTYPEID_INT32 && strcmp(func->GetName(), "opCmp") == 0 ) + isCmp = true; + if( returnTypeId == asTYPEID_BOOL && strcmp(func->GetName(), "opEquals") == 0 ) + isEq = true; + + if( !isCmp && !isEq ) + continue; + + // The parameter must either be a reference to the subtype or a handle to the subtype + int paramTypeId; + func->GetParam(0, ¶mTypeId, &flags); + + if( (paramTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) != (subTypeId & ~(asTYPEID_OBJHANDLE|asTYPEID_HANDLETOCONST)) ) + continue; + + if( (flags & asTM_INREF) ) + { + if( (paramTypeId & asTYPEID_OBJHANDLE) || (mustBeConst && !(flags & asTM_CONST)) ) + continue; + } + else if( paramTypeId & asTYPEID_OBJHANDLE ) + { + if( mustBeConst && !(paramTypeId & asTYPEID_HANDLETOCONST) ) + continue; + } + else + continue; + + if( isCmp ) + { + if( cache->cmpFunc || cache->cmpFuncReturnCode ) + { + cache->cmpFunc = 0; + cache->cmpFuncReturnCode = asMULTIPLE_FUNCTIONS; + } + else + cache->cmpFunc = func; + } + else if( isEq ) + { + if( cache->eqFunc || cache->eqFuncReturnCode ) + { + cache->eqFunc = 0; + cache->eqFuncReturnCode = asMULTIPLE_FUNCTIONS; + } + else + cache->eqFunc = func; + } + } + } + } + + if( cache->eqFunc == 0 && cache->eqFuncReturnCode == 0 ) + cache->eqFuncReturnCode = asNO_FUNCTION; + if( cache->cmpFunc == 0 && cache->cmpFuncReturnCode == 0 ) + cache->cmpFuncReturnCode = asNO_FUNCTION; + + // Set the user data only at the end so others that retrieve it will know it is complete + objType->SetUserData(cache, ARRAY_CACHE); + + asReleaseExclusiveLock(); +} + +// GC behaviour +void CScriptArray::EnumReferences(asIScriptEngine *engine) +{ + // TODO: If garbage collection can be done from a separate thread, then this method must be + // protected so that it doesn't get lost during the iteration if the array is modified + + // If the array is holding handles, then we need to notify the GC of them + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + void **d = (void**)buffer->data; + + asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); + if ((subType->GetFlags() & asOBJ_REF)) + { + // For reference types we need to notify the GC of each instance + for (asUINT n = 0; n < buffer->numElements; n++) + { + if (d[n]) + engine->GCEnumCallback(d[n]); + } + } + else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + for (asUINT n = 0; n < buffer->numElements; n++) + { + if (d[n]) + engine->ForwardGCEnumReferences(d[n], subType); + } + } + } +} + +// GC behaviour +void CScriptArray::ReleaseAllHandles(asIScriptEngine *) +{ + // Resizing to zero will release everything + Resize(0); +} + +void CScriptArray::AddRef() const +{ + // Clear the GC flag then increase the counter + gcFlag = false; + asAtomicInc(refCount); +} + +void CScriptArray::Release() const +{ + // Clearing the GC flag then descrease the counter + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + // When reaching 0 no more references to this instance + // exists and the object should be destroyed + this->~CScriptArray(); + userFree(const_cast(this)); + } +} + +// GC behaviour +int CScriptArray::GetRefCount() +{ + return refCount; +} + +// GC behaviour +void CScriptArray::SetFlag() +{ + gcFlag = true; +} + +// GC behaviour +bool CScriptArray::GetFlag() +{ + return gcFlag; +} + +//-------------------------------------------- +// Generic calling conventions + +static void ScriptArrayFactory_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti); +} + +static void ScriptArrayFactory2_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + asUINT length = gen->GetArgDWord(1); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length); +} + +static void ScriptArrayListFactory_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + void *buf = gen->GetArgAddress(1); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, buf); +} + +static void ScriptArrayFactoryDefVal_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + asUINT length = gen->GetArgDWord(1); + void *defVal = gen->GetArgAddress(2); + + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = CScriptArray::Create(ti, length, defVal); +} + +static void ScriptArrayTemplateCallback_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *(asITypeInfo**)gen->GetAddressOfArg(0); + bool *dontGarbageCollect = *(bool**)gen->GetAddressOfArg(1); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptArrayTemplateCallback(ti, *dontGarbageCollect); +} + +static void ScriptArrayAssignment_Generic(asIScriptGeneric *gen) +{ + CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *self = *other; + gen->SetReturnObject(self); +} + +static void ScriptArrayEquals_Generic(asIScriptGeneric *gen) +{ + CScriptArray *other = (CScriptArray*)gen->GetArgObject(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnByte(self->operator==(*other)); +} + +static void ScriptArrayFind_Generic(asIScriptGeneric *gen) +{ + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->Find(value)); +} + +static void ScriptArrayFind2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->Find(index, value)); +} + +static void ScriptArrayFindByRef_Generic(asIScriptGeneric *gen) +{ + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->FindByRef(value)); +} + +static void ScriptArrayFindByRef2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + gen->SetReturnDWord(self->FindByRef(index, value)); +} + +static void ScriptArrayAt_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + + gen->SetReturnAddress(self->At(index)); +} + +static void ScriptArrayInsertAt_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + void *value = gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertAt(index, value); +} + +static void ScriptArrayInsertAtArray_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + CScriptArray *array = (CScriptArray*)gen->GetArgAddress(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertAt(index, *array); +} + +static void ScriptArrayRemoveAt_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveAt(index); +} + +static void ScriptArrayRemoveRange_Generic(asIScriptGeneric *gen) +{ + asUINT start = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveRange(start, count); +} + +static void ScriptArrayInsertLast_Generic(asIScriptGeneric *gen) +{ + void *value = gen->GetArgAddress(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->InsertLast(value); +} + +static void ScriptArrayRemoveLast_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->RemoveLast(); +} + +static void ScriptArrayLength_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + + gen->SetReturnDWord(self->GetSize()); +} + +static void ScriptArrayResize_Generic(asIScriptGeneric *gen) +{ + asUINT size = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + + self->Resize(size); +} + +static void ScriptArrayReserve_Generic(asIScriptGeneric *gen) +{ + asUINT size = gen->GetArgDWord(0); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Reserve(size); +} + +static void ScriptArraySortAsc_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortAsc(); +} + +static void ScriptArrayReverse_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Reverse(); +} + +static void ScriptArrayIsEmpty_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->IsEmpty(); +} + +static void ScriptArraySortAsc2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortAsc(index, count); +} + +static void ScriptArraySortDesc_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortDesc(); +} + +static void ScriptArraySortDesc2_Generic(asIScriptGeneric *gen) +{ + asUINT index = gen->GetArgDWord(0); + asUINT count = gen->GetArgDWord(1); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SortDesc(index, count); +} + +static void ScriptArraySortCallback_Generic(asIScriptGeneric *gen) +{ + asIScriptFunction *callback = (asIScriptFunction*)gen->GetArgAddress(0); + asUINT startAt = gen->GetArgDWord(1); + asUINT count = gen->GetArgDWord(2); + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Sort(callback, startAt, count); +} + +static void ScriptArrayAddRef_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->AddRef(); +} + +static void ScriptArrayRelease_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->Release(); +} + +static void ScriptArrayGetRefCount_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetRefCount(); +} + +static void ScriptArraySetFlag_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + self->SetFlag(); +} + +static void ScriptArrayGetFlag_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = self->GetFlag(); +} + +static void ScriptArrayEnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); +} + +static void ScriptArrayReleaseAllHandles_Generic(asIScriptGeneric *gen) +{ + CScriptArray *self = (CScriptArray*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); +} + +static void RegisterScriptArray_Generic(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + engine->SetTypeInfoUserDataCleanupCallback(CleanupTypeInfoArrayCache, ARRAY_CACHE); + + r = engine->RegisterObjectType("array", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptArrayTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in)", asFUNCTION(ScriptArrayFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length) explicit", asFUNCTION(ScriptArrayFactory2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_FACTORY, "array@ f(int&in, uint length, const T &in value)", asFUNCTION(ScriptArrayFactoryDefVal_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_LIST_FACTORY, "array@ f(int&in, int&in) {repeat T}", asFUNCTION(ScriptArrayListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptArrayAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptArrayRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "T &opIndex(uint index)", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "const T &opIndex(uint index) const", asFUNCTION(ScriptArrayAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "array &opAssign(const array&in)", asFUNCTION(ScriptArrayAssignment_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const T&in value)", asFUNCTION(ScriptArrayInsertAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void insertAt(uint index, const array& arr)", asFUNCTION(ScriptArrayInsertAtArray_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void insertLast(const T&in value)", asFUNCTION(ScriptArrayInsertLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("array", "void removeAt(uint index)", asFUNCTION(ScriptArrayRemoveAt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeLast()", asFUNCTION(ScriptArrayRemoveLast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void removeRange(uint start, uint count)", asFUNCTION(ScriptArrayRemoveRange_Generic), asCALL_GENERIC); assert(r >= 0); +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("array", "uint length() const", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("array", "void reserve(uint length)", asFUNCTION(ScriptArrayReserve_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void resize(uint length)", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc()", asFUNCTION(ScriptArraySortAsc_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortAsc(uint startAt, uint count)", asFUNCTION(ScriptArraySortAsc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc()", asFUNCTION(ScriptArraySortDesc_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void sortDesc(uint startAt, uint count)", asFUNCTION(ScriptArraySortDesc2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void reverse()", asFUNCTION(ScriptArrayReverse_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int find(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFind2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "int findByRef(uint startAt, const T&in if_handle_then_const value) const", asFUNCTION(ScriptArrayFindByRef2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool opEquals(const array&in) const", asFUNCTION(ScriptArrayEquals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "bool isEmpty() const", asFUNCTION(ScriptArrayIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterFuncdef("bool array::less(const T&in a, const T&in b)"); + r = engine->RegisterObjectMethod("array", "void sort(const less &in, uint startAt = 0, uint count = uint(-1))", asFUNCTION(ScriptArraySortCallback_Generic), asCALL_GENERIC); assert(r >= 0); +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + r = engine->RegisterObjectMethod("array", "uint get_length() const property", asFUNCTION(ScriptArrayLength_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("array", "void set_length(uint) property", asFUNCTION(ScriptArrayResize_Generic), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptArrayGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptArraySetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptArrayGetFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptArrayEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("array", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptArrayReleaseAllHandles_Generic), asCALL_GENERIC); assert( r >= 0 ); +} + +END_AS_NAMESPACE diff --git a/add_on/scriptarray/scriptarray.h b/add_on/scriptarray/scriptarray.h new file mode 100644 index 0000000..4903a97 --- /dev/null +++ b/add_on/scriptarray/scriptarray.h @@ -0,0 +1,142 @@ +#ifndef SCRIPTARRAY_H +#define SCRIPTARRAY_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +// Sometimes it may be desired to use the same method names as used by C++ STL. +// This may for example reduce time when converting code from script to C++ or +// back. +// +// 0 = off +// 1 = on +#ifndef AS_USE_STLNAMES +#define AS_USE_STLNAMES 0 +#endif + +// Some prefer to use property accessors to get/set the length of the array +// This option registers the accessors instead of the method length() +#ifndef AS_USE_ACCESSORS +#define AS_USE_ACCESSORS 0 +#endif + +BEGIN_AS_NAMESPACE + +struct SArrayBuffer; +struct SArrayCache; + +class CScriptArray +{ +public: + // Set the memory functions that should be used by all CScriptArrays + static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); + + // Factory functions + static CScriptArray *Create(asITypeInfo *ot); + static CScriptArray *Create(asITypeInfo *ot, asUINT length); + static CScriptArray *Create(asITypeInfo *ot, asUINT length, void *defaultValue); + static CScriptArray *Create(asITypeInfo *ot, void *listBuffer); + + // Memory management + void AddRef() const; + void Release() const; + + // Type information + asITypeInfo *GetArrayObjectType() const; + int GetArrayTypeId() const; + int GetElementTypeId() const; + + // Get the current size + asUINT GetSize() const; + + // Returns true if the array is empty + bool IsEmpty() const; + + // Pre-allocates memory for elements + void Reserve(asUINT maxElements); + + // Resize the array + void Resize(asUINT numElements); + + // Get a pointer to an element. Returns 0 if out of bounds + void *At(asUINT index); + const void *At(asUINT index) const; + + // Set value of an element. + // The value arg should be a pointer to the value that will be copied to the element. + // Remember, if the array holds handles the value parameter should be the + // address of the handle. The refCount of the object will also be incremented + void SetValue(asUINT index, void *value); + + // Copy the contents of one array to another (only if the types are the same) + CScriptArray &operator=(const CScriptArray&); + + // Compare two arrays + bool operator==(const CScriptArray &) const; + + // Array manipulation + void InsertAt(asUINT index, void *value); + void InsertAt(asUINT index, const CScriptArray &arr); + void InsertLast(void *value); + void RemoveAt(asUINT index); + void RemoveLast(); + void RemoveRange(asUINT start, asUINT count); + void SortAsc(); + void SortDesc(); + void SortAsc(asUINT startAt, asUINT count); + void SortDesc(asUINT startAt, asUINT count); + void Sort(asUINT startAt, asUINT count, bool asc); + void Sort(asIScriptFunction *less, asUINT startAt, asUINT count); + void Reverse(); + int Find(void *value) const; + int Find(asUINT startAt, void *value) const; + int FindByRef(void *ref) const; + int FindByRef(asUINT startAt, void *ref) const; + + // Return the address of internal buffer for direct manipulation of elements + void *GetBuffer(); + + // GC methods + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); + +protected: + mutable int refCount; + mutable bool gcFlag; + asITypeInfo *objType; + SArrayBuffer *buffer; + int elementSize; + int subTypeId; + + // Constructors + CScriptArray(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list + CScriptArray(asUINT length, asITypeInfo *ot); + CScriptArray(asUINT length, void *defVal, asITypeInfo *ot); + CScriptArray(const CScriptArray &other); + virtual ~CScriptArray(); + + bool Less(const void *a, const void *b, bool asc); + void *GetArrayItemPointer(int index); + void *GetDataPointer(void *buffer); + void Copy(void *dst, void *src); + void Precache(); + bool CheckMaxSize(asUINT numElements); + void Resize(int delta, asUINT at); + void CreateBuffer(SArrayBuffer **buf, asUINT numElements); + void DeleteBuffer(SArrayBuffer *buf); + void CopyBuffer(SArrayBuffer *dst, SArrayBuffer *src); + void Construct(SArrayBuffer *buf, asUINT start, asUINT end); + void Destruct(SArrayBuffer *buf, asUINT start, asUINT end); + bool Equals(const void *a, const void *b, asIScriptContext *ctx, SArrayCache *cache) const; +}; + +void RegisterScriptArray(asIScriptEngine *engine, bool defaultArray); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptbuilder/scriptbuilder.cpp b/add_on/scriptbuilder/scriptbuilder.cpp new file mode 100644 index 0000000..97b2833 --- /dev/null +++ b/add_on/scriptbuilder/scriptbuilder.cpp @@ -0,0 +1,1167 @@ +#include "scriptbuilder.h" +#include +#include +using namespace std; + +#include +#if defined(_MSC_VER) && !defined(_WIN32_WCE) && !defined(__S3E__) +#include +#endif +#ifdef _WIN32_WCE +#include // For GetModuleFileName() +#endif + +#if defined(__S3E__) || defined(__APPLE__) || defined(__GNUC__) +#include // For getcwd() +#endif + +BEGIN_AS_NAMESPACE + +// Helper functions +static string GetCurrentDir(); +static string GetAbsolutePath(const string &path); + + +CScriptBuilder::CScriptBuilder() +{ + engine = 0; + module = 0; + + includeCallback = 0; + includeParam = 0; + + pragmaCallback = 0; + pragmaParam = 0; +} + +void CScriptBuilder::SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam) +{ + includeCallback = callback; + includeParam = userParam; +} + +void CScriptBuilder::SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam) +{ + pragmaCallback = callback; + pragmaParam = userParam; +} + +int CScriptBuilder::StartNewModule(asIScriptEngine *inEngine, const char *moduleName) +{ + if(inEngine == 0 ) return -1; + + engine = inEngine; + module = inEngine->GetModule(moduleName, asGM_ALWAYS_CREATE); + if( module == 0 ) + return -1; + + ClearAll(); + + return 0; +} + +asIScriptEngine *CScriptBuilder::GetEngine() +{ + return engine; +} + +asIScriptModule *CScriptBuilder::GetModule() +{ + return module; +} + +unsigned int CScriptBuilder::GetSectionCount() const +{ + return (unsigned int)(includedScripts.size()); +} + +string CScriptBuilder::GetSectionName(unsigned int idx) const +{ + if( idx >= includedScripts.size() ) return ""; + +#ifdef _WIN32 + set::const_iterator it = includedScripts.begin(); +#else + set::const_iterator it = includedScripts.begin(); +#endif + while( idx-- > 0 ) it++; + return *it; +} + +// Returns 1 if the section was included +// Returns 0 if the section was not included because it had already been included before +// Returns <0 if there was an error +int CScriptBuilder::AddSectionFromFile(const char *filename) +{ + // The file name stored in the set should be the fully resolved name because + // it is possible to name the same file in multiple ways using relative paths. + string fullpath = GetAbsolutePath(filename); + + if( IncludeIfNotAlreadyIncluded(fullpath.c_str()) ) + { + int r = LoadScriptSection(fullpath.c_str()); + if( r < 0 ) + return r; + else + return 1; + } + + return 0; +} + +// Returns 1 if the section was included +// Returns 0 if the section was not included because it had already been included before +// Returns <0 if there was an error +int CScriptBuilder::AddSectionFromMemory(const char *sectionName, const char *scriptCode, unsigned int scriptLength, int lineOffset) +{ + if( IncludeIfNotAlreadyIncluded(sectionName) ) + { + int r = ProcessScriptSection(scriptCode, scriptLength, sectionName, lineOffset); + if( r < 0 ) + return r; + else + return 1; + } + + return 0; +} + +int CScriptBuilder::BuildModule() +{ + return Build(); +} + +void CScriptBuilder::DefineWord(const char *word) +{ + string sword = word; + if( definedWords.find(sword) == definedWords.end() ) + { + definedWords.insert(sword); + } +} + +void CScriptBuilder::ClearAll() +{ + includedScripts.clear(); + +#if AS_PROCESS_METADATA == 1 + currentClass = ""; + currentNamespace = ""; + + foundDeclarations.clear(); + typeMetadataMap.clear(); + funcMetadataMap.clear(); + varMetadataMap.clear(); +#endif +} + +bool CScriptBuilder::IncludeIfNotAlreadyIncluded(const char *filename) +{ + string scriptFile = filename; + if( includedScripts.find(scriptFile) != includedScripts.end() ) + { + // Already included + return false; + } + + // Add the file to the set of included sections + includedScripts.insert(scriptFile); + + return true; +} + +int CScriptBuilder::LoadScriptSection(const char *filename) +{ + // Open the script file + string scriptFile = filename; +#if _MSC_VER >= 1500 && !defined(__S3E__) + FILE *f = 0; + fopen_s(&f, scriptFile.c_str(), "rb"); +#else + FILE *f = fopen(scriptFile.c_str(), "rb"); +#endif + if( f == 0 ) + { + // Write a message to the engine's message callback + string msg = "Failed to open script file '" + GetAbsolutePath(scriptFile) + "'"; + engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); + + // TODO: Write the file where this one was included from + + return -1; + } + + // Determine size of the file + fseek(f, 0, SEEK_END); + int len = ftell(f); + fseek(f, 0, SEEK_SET); + + // On Win32 it is possible to do the following instead + // int len = _filelength(_fileno(f)); + + // Read the entire file + string code; + size_t c = 0; + if( len > 0 ) + { + code.resize(len); + c = fread(&code[0], len, 1, f); + } + + fclose(f); + + if( c == 0 && len > 0 ) + { + // Write a message to the engine's message callback + string msg = "Failed to load script file '" + GetAbsolutePath(scriptFile) + "'"; + engine->WriteMessage(filename, 0, 0, asMSGTYPE_ERROR, msg.c_str()); + return -1; + } + + // Process the script section even if it is zero length so that the name is registered + return ProcessScriptSection(code.c_str(), (unsigned int)(code.length()), filename, 0); +} + +int CScriptBuilder::ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset) +{ + vector includes; + + // Perform a superficial parsing of the script first to store the metadata + if( length ) + modifiedScript.assign(script, length); + else + modifiedScript = script; + + // First perform the checks for #if directives to exclude code that shouldn't be compiled + unsigned int pos = 0; + int nested = 0; + while( pos < modifiedScript.size() ) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_UNKNOWN && modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) + { + int start = pos++; + + // Is this an #if directive? + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + string token; + token.assign(&modifiedScript[pos], len); + + pos += len; + + if( token == "if" ) + { + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_WHITESPACE ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if( t == asTC_IDENTIFIER ) + { + string word; + word.assign(&modifiedScript[pos], len); + + // Overwrite the #if directive with space characters to avoid compiler error + pos += len; + OverwriteCode(start, pos-start); + + // Has this identifier been defined by the application or not? + if( definedWords.find(word) == definedWords.end() ) + { + // Exclude all the code until and including the #endif + pos = ExcludeCode(pos); + } + else + { + nested++; + } + } + } + else if( token == "endif" ) + { + // Only remove the #endif if there was a matching #if + if( nested > 0 ) + { + OverwriteCode(start, pos-start); + nested--; + } + } + } + else + pos += len; + } + +#if AS_PROCESS_METADATA == 1 + // Preallocate memory + string name, declaration; + vector metadata; + declaration.reserve(100); +#endif + + // Then check for meta data and #include directives + pos = 0; + while( pos < modifiedScript.size() ) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_COMMENT || t == asTC_WHITESPACE ) + { + pos += len; + continue; + } + +#if AS_PROCESS_METADATA == 1 + // Check if class + if( currentClass == "" && modifiedScript.substr(pos,len) == "class" ) + { + // Get the identifier after "class" + do + { + pos += len; + if( pos >= modifiedScript.size() ) + { + t = asTC_UNKNOWN; + break; + } + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while(t == asTC_COMMENT || t == asTC_WHITESPACE); + + if( t == asTC_IDENTIFIER ) + { + currentClass = modifiedScript.substr(pos,len); + + // Search until first { or ; is encountered + while( pos < modifiedScript.length() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + // If start of class section encountered stop + if( modifiedScript[pos] == '{' ) + { + pos += len; + break; + } + else if (modifiedScript[pos] == ';') + { + // The class declaration has ended and there are no children + currentClass = ""; + pos += len; + break; + } + + // Check next symbol + pos += len; + } + } + + continue; + } + + // Check if end of class + if( currentClass != "" && modifiedScript[pos] == '}' ) + { + currentClass = ""; + pos += len; + continue; + } + + // Check if namespace + if( modifiedScript.substr(pos,len) == "namespace" ) + { + // Get the identifier after "namespace" + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while(t == asTC_COMMENT || t == asTC_WHITESPACE); + + if( currentNamespace != "" ) + currentNamespace += "::"; + currentNamespace += modifiedScript.substr(pos,len); + + // Search until first { is encountered + while( pos < modifiedScript.length() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + + // If start of namespace section encountered stop + if( modifiedScript[pos] == '{' ) + { + pos += len; + break; + } + + // Check next symbol + pos += len; + } + + continue; + } + + // Check if end of namespace + if( currentNamespace != "" && modifiedScript[pos] == '}' ) + { + size_t found = currentNamespace.rfind( "::" ); + if( found != string::npos ) + { + currentNamespace.erase( found ); + } + else + { + currentNamespace = ""; + } + pos += len; + continue; + } + + // Is this the start of metadata? + if( modifiedScript[pos] == '[' ) + { + // Get the metadata string + pos = ExtractMetadata(pos, metadata); + + // Determine what this metadata is for + int type; + ExtractDeclaration(pos, name, declaration, type); + + // Store away the declaration in a map for lookup after the build has completed + if( type > 0 ) + { + SMetadataDecl decl(metadata, name, declaration, type, currentClass, currentNamespace); + foundDeclarations.push_back(decl); + } + } + else +#endif + // Is this a preprocessor directive? + if( modifiedScript[pos] == '#' && (pos + 1 < modifiedScript.size()) ) + { + int start = pos++; + + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_IDENTIFIER ) + { + string token; + token.assign(&modifiedScript[pos], len); + if( token == "include" ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_WHITESPACE ) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if( t == asTC_VALUE && len > 2 && (modifiedScript[pos] == '"' || modifiedScript[pos] == '\'') ) + { + // Get the include file + string includefile; + includefile.assign(&modifiedScript[pos+1], len-2); + pos += len; + + // Store it for later processing + includes.push_back(includefile); + + // Overwrite the include directive with space characters to avoid compiler error + OverwriteCode(start, pos-start); + } + } + else if (token == "pragma") + { + // Read until the end of the line + pos += len; + for (; pos < modifiedScript.size() && modifiedScript[pos] != '\n'; pos++); + + // Call the pragma callback + string pragmaText(&modifiedScript[start + 7], pos - start - 7); + int r = pragmaCallback ? pragmaCallback(pragmaText, *this, pragmaParam) : -1; + if (r < 0) + { + // TODO: Report the correct line number + engine->WriteMessage(sectionname, 0, 0, asMSGTYPE_ERROR, "Invalid #pragma directive"); + return r; + } + + // Overwrite the pragma directive with space characters to avoid compiler error + OverwriteCode(start, pos - start); + } + } + } + // Don't search for metadata/includes within statement blocks or between tokens in statements + else + { + pos = SkipStatement(pos); + } + } + + // Build the actual script + engine->SetEngineProperty(asEP_COPY_SCRIPT_SECTIONS, true); + module->AddScriptSection(sectionname, modifiedScript.c_str(), modifiedScript.size(), lineOffset); + + if( includes.size() > 0 ) + { + // If the callback has been set, then call it for each included file + if( includeCallback ) + { + for( int n = 0; n < (int)includes.size(); n++ ) + { + int r = includeCallback(includes[n].c_str(), sectionname, this, includeParam); + if( r < 0 ) + return r; + } + } + else + { + // By default we try to load the included file from the relative directory of the current file + + // Determine the path of the current script so that we can resolve relative paths for includes + string path = sectionname; + size_t posOfSlash = path.find_last_of("/\\"); + if( posOfSlash != string::npos ) + path.resize(posOfSlash+1); + else + path = ""; + + // Load the included scripts + for( int n = 0; n < (int)includes.size(); n++ ) + { + // If the include is a relative path, then prepend the path of the originating script + if( includes[n].find_first_of("/\\") != 0 && + includes[n].find_first_of(":") == string::npos ) + { + includes[n] = path + includes[n]; + } + + // Include the script section + int r = AddSectionFromFile(includes[n].c_str()); + if( r < 0 ) + return r; + } + } + } + + return 0; +} + +int CScriptBuilder::Build() +{ + int r = module->Build(); + if( r < 0 ) + return r; + +#if AS_PROCESS_METADATA == 1 + // After the script has been built, the metadata strings should be + // stored for later lookup by function id, type id, and variable index + for( int n = 0; n < (int)foundDeclarations.size(); n++ ) + { + SMetadataDecl *decl = &foundDeclarations[n]; + module->SetDefaultNamespace(decl->nameSpace.c_str()); + if( decl->type == MDT_TYPE ) + { + // Find the type id + int typeId = module->GetTypeIdByDecl(decl->declaration.c_str()); + assert( typeId >= 0 ); + if( typeId >= 0 ) + typeMetadataMap.insert(map >::value_type(typeId, decl->metadata)); + } + else if( decl->type == MDT_FUNC ) + { + if( decl->parentClass == "" ) + { + // Find the function id + asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); + assert( func ); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + else + { + // Find the method id + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); + assert( func ); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else if( decl->type == MDT_VIRTPROP ) + { + if( decl->parentClass == "" ) + { + // Find the global virtual property accessors + asIScriptFunction *func = module->GetFunctionByName(("get_" + decl->declaration).c_str()); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + func = module->GetFunctionByName(("set_" + decl->declaration).c_str()); + if( func ) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + else + { + // Find the method virtual property accessors + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByName(("get_" + decl->declaration).c_str()); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + func = type->GetMethodByName(("set_" + decl->declaration).c_str()); + if( func ) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else if( decl->type == MDT_VAR ) + { + if( decl->parentClass == "" ) + { + // Find the global variable index + int varIdx = module->GetGlobalVarIndexByName(decl->declaration.c_str()); + assert( varIdx >= 0 ); + if( varIdx >= 0 ) + varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); + } + else + { + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert( typeId > 0 ); + + // Add the classes if needed + map::iterator it = classMetadataMap.find(typeId); + if( it == classMetadataMap.end() ) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + // Add the variable to class + asITypeInfo *objectType = engine->GetTypeInfoById(typeId); + int idx = -1; + + // Search through all properties to get proper declaration + for( asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i ) + { + const char *name; + objectType->GetProperty(i, &name); + if( decl->declaration == name ) + { + idx = i; + break; + } + } + + // If found, add it + assert( idx >= 0 ); + if( idx >= 0 ) it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); + } + } + else if (decl->type == MDT_FUNC_OR_VAR) + { + if (decl->parentClass == "") + { + // Find the global variable index + int varIdx = module->GetGlobalVarIndexByName(decl->name.c_str()); + if (varIdx >= 0) + varMetadataMap.insert(map >::value_type(varIdx, decl->metadata)); + else + { + asIScriptFunction *func = module->GetFunctionByDecl(decl->declaration.c_str()); + assert(func); + if (func) + funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + else + { + int typeId = module->GetTypeIdByDecl(decl->parentClass.c_str()); + assert(typeId > 0); + + // Add the classes if needed + map::iterator it = classMetadataMap.find(typeId); + if (it == classMetadataMap.end()) + { + classMetadataMap.insert(map::value_type(typeId, SClassMetadata(decl->parentClass))); + it = classMetadataMap.find(typeId); + } + + // Add the variable to class + asITypeInfo *objectType = engine->GetTypeInfoById(typeId); + int idx = -1; + + // Search through all properties to get proper declaration + for (asUINT i = 0; i < (asUINT)objectType->GetPropertyCount(); ++i) + { + const char *name; + objectType->GetProperty(i, &name); + if (decl->name == name) + { + idx = i; + break; + } + } + + // If found, add it + if (idx >= 0) + it->second.varMetadataMap.insert(map >::value_type(idx, decl->metadata)); + else + { + // Look for the matching method instead + asITypeInfo *type = engine->GetTypeInfoById(typeId); + asIScriptFunction *func = type->GetMethodByDecl(decl->declaration.c_str()); + assert(func); + if (func) + it->second.funcMetadataMap.insert(map >::value_type(func->GetId(), decl->metadata)); + } + } + } + } + module->SetDefaultNamespace(""); +#endif + + return 0; +} + +int CScriptBuilder::SkipStatement(int pos) +{ + asUINT len = 0; + + // Skip until ; or { whichever comes first + while( pos < (int)modifiedScript.length() && modifiedScript[pos] != ';' && modifiedScript[pos] != '{' ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + pos += len; + } + + // Skip entire statement block + if( pos < (int)modifiedScript.length() && modifiedScript[pos] == '{' ) + { + pos += 1; + + // Find the end of the statement block + int level = 1; + while( level > 0 && pos < (int)modifiedScript.size() ) + { + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( t == asTC_KEYWORD ) + { + if( modifiedScript[pos] == '{' ) + level++; + else if( modifiedScript[pos] == '}' ) + level--; + } + + pos += len; + } + } + else + pos += 1; + + return pos; +} + +// Overwrite all code with blanks until the matching #endif +int CScriptBuilder::ExcludeCode(int pos) +{ + asUINT len = 0; + int nested = 0; + while( pos < (int)modifiedScript.size() ) + { + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if( modifiedScript[pos] == '#' ) + { + modifiedScript[pos] = ' '; + pos++; + + // Is it an #if or #endif directive? + engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + string token; + token.assign(&modifiedScript[pos], len); + OverwriteCode(pos, len); + + if( token == "if" ) + { + nested++; + } + else if( token == "endif" ) + { + if( nested-- == 0 ) + { + pos += len; + break; + } + } + } + else if( modifiedScript[pos] != '\n' ) + { + OverwriteCode(pos, len); + } + pos += len; + } + + return pos; +} + +// Overwrite all characters except line breaks with blanks +void CScriptBuilder::OverwriteCode(int start, int len) +{ + char *code = &modifiedScript[start]; + for( int n = 0; n < len; n++ ) + { + if( *code != '\n' ) + *code = ' '; + code++; + } +} + +#if AS_PROCESS_METADATA == 1 +int CScriptBuilder::ExtractMetadata(int pos, vector &metadata) +{ + metadata.clear(); + + // Extract all metadata. They can be separated by whitespace and comments + for (;;) + { + string metadataString = ""; + + // Overwrite the metadata with space characters to allow compilation + modifiedScript[pos] = ' '; + + // Skip opening brackets + pos += 1; + + int level = 1; + asUINT len = 0; + while (level > 0 && pos < (int)modifiedScript.size()) + { + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + if (t == asTC_KEYWORD) + { + if (modifiedScript[pos] == '[') + level++; + else if (modifiedScript[pos] == ']') + level--; + } + + // Copy the metadata to our buffer + if (level > 0) + metadataString.append(&modifiedScript[pos], len); + + // Overwrite the metadata with space characters to allow compilation + if (t != asTC_WHITESPACE) + OverwriteCode(pos, len); + + pos += len; + } + + metadata.push_back(metadataString); + + // Check for more metadata. Possibly separated by comments + asETokenClass t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + while (t == asTC_COMMENT || t == asTC_WHITESPACE) + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } + + if (modifiedScript[pos] != '[') + break; + } + + return pos; +} + +int CScriptBuilder::ExtractDeclaration(int pos, string &name, string &declaration, int &type) +{ + declaration = ""; + type = 0; + + int start = pos; + + std::string token; + asUINT len = 0; + asETokenClass t = asTC_WHITESPACE; + + // Skip white spaces, comments, and leading decorators + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + token.assign(&modifiedScript[pos], len); + } while ( t == asTC_WHITESPACE || t == asTC_COMMENT || + token == "private" || token == "protected" || + token == "shared" || token == "external" || + token == "final" || token == "abstract" ); + + // We're expecting, either a class, interface, function, or variable declaration + if( t == asTC_KEYWORD || t == asTC_IDENTIFIER ) + { + token.assign(&modifiedScript[pos], len); + if( token == "interface" || token == "class" || token == "enum" ) + { + // Skip white spaces and comments + do + { + pos += len; + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + } while ( t == asTC_WHITESPACE || t == asTC_COMMENT ); + + if( t == asTC_IDENTIFIER ) + { + type = MDT_TYPE; + declaration.assign(&modifiedScript[pos], len); + pos += len; + return pos; + } + } + else + { + // For function declarations, store everything up to the start of the + // statement block, except for succeeding decorators (final, override, etc) + + // For variable declaration store just the name as there can only be one + + // We'll only know if the declaration is a variable or function declaration + // when we see the statement block, or absense of a statement block. + bool hasParenthesis = false; + int nestedParenthesis = 0; + declaration.append(&modifiedScript[pos], len); + pos += len; + for(; pos < (int)modifiedScript.size();) + { + t = engine->ParseToken(&modifiedScript[pos], modifiedScript.size() - pos, &len); + token.assign(&modifiedScript[pos], len); + if (t == asTC_KEYWORD) + { + if (token == "{" && nestedParenthesis == 0) + { + if (hasParenthesis) + { + // We've found the end of a function signature + type = MDT_FUNC; + } + else + { + // We've found a virtual property. Just keep the name + declaration = name; + type = MDT_VIRTPROP; + } + return pos; + } + if ((token == "=" && !hasParenthesis) || token == ";") + { + if (hasParenthesis) + { + // The declaration is ambigous. It can be a variable with initialization, or a function prototype + type = MDT_FUNC_OR_VAR; + } + else + { + // Substitute the declaration with just the name + declaration = name; + type = MDT_VAR; + } + return pos; + } + else if (token == "(") + { + nestedParenthesis++; + + // This is the first parenthesis we encounter. If the parenthesis isn't followed + // by a statement block, then this is a variable declaration, in which case we + // should only store the type and name of the variable, not the initialization parameters. + hasParenthesis = true; + } + else if (token == ")") + { + nestedParenthesis--; + } + } + else if( t == asTC_IDENTIFIER ) + { + name = token; + } + + // Skip trailing decorators + if( !hasParenthesis || nestedParenthesis > 0 || t != asTC_IDENTIFIER || (token != "final" && token != "override") ) + declaration += token; + + pos += len; + } + } + } + + return start; +} + +vector CScriptBuilder::GetMetadataForType(int typeId) +{ + map >::iterator it = typeMetadataMap.find(typeId); + if( it != typeMetadataMap.end() ) + return it->second; + + return vector(); +} + +vector CScriptBuilder::GetMetadataForFunc(asIScriptFunction *func) +{ + if( func ) + { + map >::iterator it = funcMetadataMap.find(func->GetId()); + if( it != funcMetadataMap.end() ) + return it->second; + } + + return vector(); +} + +vector CScriptBuilder::GetMetadataForVar(int varIdx) +{ + map >::iterator it = varMetadataMap.find(varIdx); + if( it != varMetadataMap.end() ) + return it->second; + + return vector(); +} + +vector CScriptBuilder::GetMetadataForTypeProperty(int typeId, int varIdx) +{ + map::iterator typeIt = classMetadataMap.find(typeId); + if(typeIt == classMetadataMap.end()) return vector(); + + map >::iterator propIt = typeIt->second.varMetadataMap.find(varIdx); + if(propIt == typeIt->second.varMetadataMap.end()) return vector(); + + return propIt->second; +} + +vector CScriptBuilder::GetMetadataForTypeMethod(int typeId, asIScriptFunction *method) +{ + if( method ) + { + map::iterator typeIt = classMetadataMap.find(typeId); + if (typeIt == classMetadataMap.end()) return vector(); + + map >::iterator methodIt = typeIt->second.funcMetadataMap.find(method->GetId()); + if(methodIt == typeIt->second.funcMetadataMap.end()) return vector(); + + return methodIt->second; + } + + return vector(); +} +#endif + +string GetAbsolutePath(const string &file) +{ + string str = file; + + // If this is a relative path, complement it with the current path + if( !((str.length() > 0 && (str[0] == '/' || str[0] == '\\')) || + str.find(":") != string::npos) ) + { + str = GetCurrentDir() + "/" + str; + } + + // Replace backslashes for forward slashes + size_t pos = 0; + while( (pos = str.find("\\", pos)) != string::npos ) + str[pos] = '/'; + + // Replace /./ with / + pos = 0; + while( (pos = str.find("/./", pos)) != string::npos ) + str.erase(pos+1, 2); + + // For each /../ remove the parent dir and the /../ + pos = 0; + while( (pos = str.find("/../")) != string::npos ) + { + size_t pos2 = str.rfind("/", pos-1); + if( pos2 != string::npos ) + str.erase(pos2, pos+3-pos2); + else + { + // The path is invalid + break; + } + } + + return str; +} + +string GetCurrentDir() +{ + char buffer[1024]; +#if defined(_MSC_VER) || defined(_WIN32) + #ifdef _WIN32_WCE + static TCHAR apppath[MAX_PATH] = TEXT(""); + if (!apppath[0]) + { + GetModuleFileName(NULL, apppath, MAX_PATH); + + int appLen = _tcslen(apppath); + + // Look for the last backslash in the path, which would be the end + // of the path itself and the start of the filename. We only want + // the path part of the exe's full-path filename + // Safety is that we make sure not to walk off the front of the + // array (in case the path is nothing more than a filename) + while (appLen > 1) + { + if (apppath[appLen-1] == TEXT('\\')) + break; + appLen--; + } + + // Terminate the string after the trailing backslash + apppath[appLen] = TEXT('\0'); + } + #ifdef _UNICODE + wcstombs(buffer, apppath, min(1024, wcslen(apppath)*sizeof(wchar_t))); + #else + memcpy(buffer, apppath, min(1024, strlen(apppath))); + #endif + + return buffer; + #elif defined(__S3E__) + // Marmalade uses its own portable C library + return getcwd(buffer, (int)1024); + #elif _XBOX_VER >= 200 + // XBox 360 doesn't support the getcwd function, just use the root folder + return "game:/"; + #elif defined(_M_ARM) + // TODO: How to determine current working dir on Windows Phone? + return ""; + #else + return _getcwd(buffer, (int)1024); + #endif // _MSC_VER +#elif defined(__APPLE__) || defined(__linux__) + return getcwd(buffer, 1024); +#else + return ""; +#endif +} + +END_AS_NAMESPACE + + diff --git a/add_on/scriptbuilder/scriptbuilder.h b/add_on/scriptbuilder/scriptbuilder.h new file mode 100644 index 0000000..c11f1b9 --- /dev/null +++ b/add_on/scriptbuilder/scriptbuilder.h @@ -0,0 +1,216 @@ +#ifndef SCRIPTBUILDER_H +#define SCRIPTBUILDER_H + +//--------------------------- +// Compilation settings +// + +// Set this flag to turn on/off metadata processing +// 0 = off +// 1 = on +#ifndef AS_PROCESS_METADATA +#define AS_PROCESS_METADATA 1 +#endif + +// TODO: Implement flags for turning on/off include directives and conditional programming + + + +//--------------------------- +// Declaration +// + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +#if defined(_MSC_VER) && _MSC_VER <= 1200 +// disable the annoying warnings on MSVC 6 +#pragma warning (disable:4786) +#endif + +#include +#include +#include +#include +#include // _strcmpi + +BEGIN_AS_NAMESPACE + +class CScriptBuilder; + +// This callback will be called for each #include directive encountered by the +// builder. The callback should call the AddSectionFromFile or AddSectionFromMemory +// to add the included section to the script. If the include cannot be resolved +// then the function should return a negative value to abort the compilation. +typedef int (*INCLUDECALLBACK_t)(const char *include, const char *from, CScriptBuilder *builder, void *userParam); + +// This callback will be called for each #pragma directive encountered by the builder. +// The application can interpret the pragmaText and decide what do to based on that. +// If the callback returns a negative value the builder will report an error and abort the compilation. +typedef int(*PRAGMACALLBACK_t)(const std::string &pragmaText, CScriptBuilder &builder, void *userParam); + +// Helper class for loading and pre-processing script files to +// support include directives and metadata declarations +class CScriptBuilder +{ +public: + CScriptBuilder(); + + // Start a new module + int StartNewModule(asIScriptEngine *engine, const char *moduleName); + + // Load a script section from a file on disk + // Returns 1 if the file was included + // 0 if the file had already been included before + // <0 on error + int AddSectionFromFile(const char *filename); + + // Load a script section from memory + // Returns 1 if the section was included + // 0 if a section with the same name had already been included before + // <0 on error + int AddSectionFromMemory(const char *sectionName, + const char *scriptCode, + unsigned int scriptLength = 0, + int lineOffset = 0); + + // Build the added script sections + int BuildModule(); + + // Returns the engine + asIScriptEngine *GetEngine(); + + // Returns the current module + asIScriptModule *GetModule(); + + // Register the callback for resolving include directive + void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam); + + // Register the callback for resolving pragma directive + void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam); + + // Add a pre-processor define for conditional compilation + void DefineWord(const char *word); + + // Enumerate included script sections + unsigned int GetSectionCount() const; + std::string GetSectionName(unsigned int idx) const; + +#if AS_PROCESS_METADATA == 1 + // Get metadata declared for classes, interfaces, and enums + std::vector GetMetadataForType(int typeId); + + // Get metadata declared for functions + std::vector GetMetadataForFunc(asIScriptFunction *func); + + // Get metadata declared for global variables + std::vector GetMetadataForVar(int varIdx); + + // Get metadata declared for class variables + std::vector GetMetadataForTypeProperty(int typeId, int varIdx); + + // Get metadata declared for class methods + std::vector GetMetadataForTypeMethod(int typeId, asIScriptFunction *method); +#endif + +protected: + void ClearAll(); + int Build(); + int ProcessScriptSection(const char *script, unsigned int length, const char *sectionname, int lineOffset); + int LoadScriptSection(const char *filename); + bool IncludeIfNotAlreadyIncluded(const char *filename); + + int SkipStatement(int pos); + + int ExcludeCode(int start); + void OverwriteCode(int start, int len); + + asIScriptEngine *engine; + asIScriptModule *module; + std::string modifiedScript; + + INCLUDECALLBACK_t includeCallback; + void *includeParam; + + PRAGMACALLBACK_t pragmaCallback; + void *pragmaParam; + +#if AS_PROCESS_METADATA == 1 + int ExtractMetadata(int pos, std::vector &outMetadata); + int ExtractDeclaration(int pos, std::string &outName, std::string &outDeclaration, int &outType); + + enum METADATATYPE + { + MDT_TYPE = 1, + MDT_FUNC = 2, + MDT_VAR = 3, + MDT_VIRTPROP = 4, + MDT_FUNC_OR_VAR = 5 + }; + + // Temporary structure for storing metadata and declaration + struct SMetadataDecl + { + SMetadataDecl(std::vector m, std::string n, std::string d, int t, std::string c, std::string ns) : metadata(m), name(n), declaration(d), type(t), parentClass(c), nameSpace(ns) {} + std::vector metadata; + std::string name; + std::string declaration; + int type; + std::string parentClass; + std::string nameSpace; + }; + std::vector foundDeclarations; + std::string currentClass; + std::string currentNamespace; + + // Storage of metadata for global declarations + std::map > typeMetadataMap; + std::map > funcMetadataMap; + std::map > varMetadataMap; + + // Storage of metadata for class member declarations + struct SClassMetadata + { + SClassMetadata(const std::string& aName) : className(aName) {} + std::string className; + std::map > funcMetadataMap; + std::map > varMetadataMap; + }; + std::map classMetadataMap; + +#endif + +#ifdef _WIN32 + // On Windows the filenames are case insensitive so the comparisons to + // avoid duplicate includes must also be case insensitive. True case insensitive + // is not easy as it must be language aware, but a simple implementation such + // as strcmpi should suffice in almost all cases. + // + // ref: http://www.gotw.ca/gotw/029.htm + // ref: https://msdn.microsoft.com/en-us/library/windows/desktop/dd317761(v=vs.85).aspx + // ref: http://site.icu-project.org/ + + // TODO: Strings by default are treated as UTF8 encoded. If the application choses to + // use a different encoding, the comparison algorithm should be adjusted as well + + struct ci_less + { + bool operator()(const std::string &a, const std::string &b) const + { + return _stricmp(a.c_str(), b.c_str()) < 0; + } + }; + std::set includedScripts; +#else + std::set includedScripts; +#endif + + std::set definedWords; +}; + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptdictionary/scriptdictionary.cpp b/add_on/scriptdictionary/scriptdictionary.cpp new file mode 100644 index 0000000..2ae5305 --- /dev/null +++ b/add_on/scriptdictionary/scriptdictionary.cpp @@ -0,0 +1,1299 @@ +#include +#include +#include "scriptdictionary.h" +#include "../scriptarray/scriptarray.h" + +BEGIN_AS_NAMESPACE + +using namespace std; + +//------------------------------------------------------------------------ +// Object types are cached as user data to avoid costly runtime lookups + +// We just define a number here that we assume nobody else is using for +// object type user data. The add-ons have reserved the numbers 1000 +// through 1999 for this purpose, so we should be fine. +const asPWORD DICTIONARY_CACHE = 1003; + +// This cache holds the object type of the dictionary type and array type +// so it isn't necessary to look this up each time the dictionary or array +// is created. +struct SDictionaryCache +{ + asITypeInfo *dictType; + asITypeInfo *arrayType; + asITypeInfo *keyType; + + // This is called from RegisterScriptDictionary + static void Setup(asIScriptEngine *engine) + { + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + if( cache == 0 ) + { + cache = new SDictionaryCache; + engine->SetUserData(cache, DICTIONARY_CACHE); + engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); + + cache->dictType = engine->GetTypeInfoByName("dictionary"); + cache->arrayType = engine->GetTypeInfoByDecl("array"); + cache->keyType = engine->GetTypeInfoByDecl("string"); + } + } + + // This is called from the engine when shutting down + static void Cleanup(asIScriptEngine *engine) + { + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + if( cache ) + delete cache; + } +}; + +//-------------------------------------------------------------------------- +// CScriptDictionary implementation + +CScriptDictionary *CScriptDictionary::Create(asIScriptEngine *engine) +{ + // Use the custom memory routine from AngelScript to allow application to better control how much memory is used + CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); + new(obj) CScriptDictionary(engine); + return obj; +} + +CScriptDictionary *CScriptDictionary::Create(asBYTE *buffer) +{ + // Use the custom memory routine from AngelScript to allow application to better control how much memory is used + CScriptDictionary *obj = (CScriptDictionary*)asAllocMem(sizeof(CScriptDictionary)); + new(obj) CScriptDictionary(buffer); + return obj; +} + +CScriptDictionary::CScriptDictionary(asIScriptEngine *engine) +{ + Init(engine); +} + +void CScriptDictionary::Init(asIScriptEngine *e) +{ + // We start with one reference + refCount = 1; + gcFlag = false; + + // Keep a reference to the engine for as long as we live + // We don't increment the reference counter, because the + // engine will hold a pointer to the object in the GC. + engine = e; + + // The dictionary object type is cached to avoid dynamically parsing it each time + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + + // Notify the garbage collector of this object + engine->NotifyGarbageCollectorOfNewObject(this, cache->dictType); +} + +CScriptDictionary::CScriptDictionary(asBYTE *buffer) +{ + // This constructor will always be called from a script + // so we can get the engine from the active context + asIScriptContext *ctx = asGetActiveContext(); + Init(ctx->GetEngine()); + + // Determine if the dictionary key type is registered as reference type or value type + SDictionaryCache& cache = *reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + bool keyAsRef = cache.keyType->GetFlags() & asOBJ_REF ? true : false; + + // Initialize the dictionary from the buffer + asUINT length = *(asUINT*)buffer; + buffer += 4; + + while( length-- ) + { + // Align the buffer pointer on a 4 byte boundary in + // case previous value was smaller than 4 bytes + if( asPWORD(buffer) & 0x3 ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + // Get the name value pair from the buffer and insert it in the dictionary + dictKey_t name; + if (keyAsRef) + { + name = **(dictKey_t**)buffer; + buffer += sizeof(dictKey_t*); + } + else + { + name = *(dictKey_t*)buffer; + buffer += sizeof(dictKey_t); + } + + // Get the type id of the value + int typeId = *(int*)buffer; + buffer += sizeof(int); + + // Depending on the type id, the value will inline in the buffer or a pointer + void *ref = (void*)buffer; + + if( typeId >= asTYPEID_INT8 && typeId <= asTYPEID_DOUBLE ) + { + // Convert primitive values to either int64 or double, so we can use the overloaded Set methods + asINT64 i64; + double d; + switch( typeId ) + { + case asTYPEID_INT8: i64 = *(char*) ref; break; + case asTYPEID_INT16: i64 = *(short*) ref; break; + case asTYPEID_INT32: i64 = *(int*) ref; break; + case asTYPEID_INT64: i64 = *(asINT64*) ref; break; + case asTYPEID_UINT8: i64 = *(unsigned char*) ref; break; + case asTYPEID_UINT16: i64 = *(unsigned short*)ref; break; + case asTYPEID_UINT32: i64 = *(unsigned int*) ref; break; + case asTYPEID_UINT64: i64 = *(asINT64*) ref; break; + case asTYPEID_FLOAT: d = *(float*) ref; break; + case asTYPEID_DOUBLE: d = *(double*) ref; break; + } + + if( typeId >= asTYPEID_FLOAT ) + Set(name, d); + else + Set(name, i64); + } + else + { + if( (typeId & asTYPEID_MASK_OBJECT) && + !(typeId & asTYPEID_OBJHANDLE) && + (engine->GetTypeInfoById(typeId)->GetFlags() & asOBJ_REF) ) + { + // Dereference the pointer to get the reference to the actual object + ref = *(void**)ref; + } + + Set(name, ref, typeId); + } + + // Advance the buffer pointer with the size of the value + if( typeId & asTYPEID_MASK_OBJECT ) + { + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti->GetFlags() & asOBJ_VALUE ) + buffer += ti->GetSize(); + else + buffer += sizeof(void*); + } + else if( typeId == 0 ) + { + // null pointer + buffer += sizeof(void*); + } + else + { + buffer += engine->GetSizeOfPrimitiveType(typeId); + } + } +} + +CScriptDictionary::~CScriptDictionary() +{ + // Delete all keys and values + DeleteAll(); +} + +void CScriptDictionary::AddRef() const +{ + // We need to clear the GC flag + gcFlag = false; + asAtomicInc(refCount); +} + +void CScriptDictionary::Release() const +{ + // We need to clear the GC flag + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + this->~CScriptDictionary(); + asFreeMem(const_cast(this)); + } +} + +int CScriptDictionary::GetRefCount() +{ + return refCount; +} + +void CScriptDictionary::SetGCFlag() +{ + gcFlag = true; +} + +bool CScriptDictionary::GetGCFlag() +{ + return gcFlag; +} + +void CScriptDictionary::EnumReferences(asIScriptEngine *inEngine) +{ + // TODO: If garbage collection can be done from a separate thread, then this method must be + // protected so that it doesn't get lost during the iteration if the dictionary is modified + + // Call the gc enum callback for each of the objects + dictMap_t::iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + { + if (it->second.m_typeId & asTYPEID_MASK_OBJECT) + { + asITypeInfo *subType = engine->GetTypeInfoById(it->second.m_typeId); + if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + engine->ForwardGCEnumReferences(it->second.m_valueObj, subType); + } + else + { + // For others, simply notify the GC about the reference + inEngine->GCEnumCallback(it->second.m_valueObj); + } + } + } +} + +void CScriptDictionary::ReleaseAllReferences(asIScriptEngine * /*engine*/) +{ + // We're being told to release all references in + // order to break circular references for dead objects + DeleteAll(); +} + +CScriptDictionary &CScriptDictionary::operator =(const CScriptDictionary &other) +{ + // Clear everything we had before + DeleteAll(); + + // Do a shallow copy of the dictionary + dictMap_t::const_iterator it; + for( it = other.dict.begin(); it != other.dict.end(); it++ ) + { + if( it->second.m_typeId & asTYPEID_OBJHANDLE ) + Set(it->first, (void*)&it->second.m_valueObj, it->second.m_typeId); + else if( it->second.m_typeId & asTYPEID_MASK_OBJECT ) + Set(it->first, (void*)it->second.m_valueObj, it->second.m_typeId); + else + Set(it->first, (void*)&it->second.m_valueInt, it->second.m_typeId); + } + + return *this; +} + +CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) +{ + // Return the existing value if it exists, else insert an empty value + return &dict[key]; +} + +const CScriptDictValue *CScriptDictionary::operator[](const dictKey_t &key) const +{ + // Return the existing value if it exists + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return &it->second; + + // Else raise an exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Invalid access to non-existing value"); + + return 0; +} + +void CScriptDictionary::Set(const dictKey_t &key, void *value, int typeId) +{ + dictMap_t::iterator it; + it = dict.find(key); + if( it == dict.end() ) + it = dict.insert(dictMap_t::value_type(key, CScriptDictValue())).first; + + it->second.Set(engine, value, typeId); +} + +// This overloaded method is implemented so that all integer and +// unsigned integers types will be stored in the dictionary as int64 +// through implicit conversions. This simplifies the management of the +// numeric types when the script retrieves the stored value using a +// different type. +void CScriptDictionary::Set(const dictKey_t &key, const asINT64 &value) +{ + Set(key, const_cast(&value), asTYPEID_INT64); +} + +// This overloaded method is implemented so that all floating point types +// will be stored in the dictionary as double through implicit conversions. +// This simplifies the management of the numeric types when the script +// retrieves the stored value using a different type. +void CScriptDictionary::Set(const dictKey_t &key, const double &value) +{ + Set(key, const_cast(&value), asTYPEID_DOUBLE); +} + +// Returns true if the value was successfully retrieved +bool CScriptDictionary::Get(const dictKey_t &key, void *value, int typeId) const +{ + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return it->second.Get(engine, value, typeId); + + // AngelScript has already initialized the value with a default value, + // so we don't have to do anything if we don't find the element, or if + // the element is incompatible with the requested type. + + return false; +} + +// Returns the type id of the stored value +int CScriptDictionary::GetTypeId(const dictKey_t &key) const +{ + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return it->second.m_typeId; + + return -1; +} + +bool CScriptDictionary::Get(const dictKey_t &key, asINT64 &value) const +{ + return Get(key, &value, asTYPEID_INT64); +} + +bool CScriptDictionary::Get(const dictKey_t &key, double &value) const +{ + return Get(key, &value, asTYPEID_DOUBLE); +} + +bool CScriptDictionary::Exists(const dictKey_t &key) const +{ + dictMap_t::const_iterator it; + it = dict.find(key); + if( it != dict.end() ) + return true; + + return false; +} + +bool CScriptDictionary::IsEmpty() const +{ + if( dict.size() == 0 ) + return true; + + return false; +} + +asUINT CScriptDictionary::GetSize() const +{ + return asUINT(dict.size()); +} + +bool CScriptDictionary::Delete(const dictKey_t &key) +{ + dictMap_t::iterator it; + it = dict.find(key); + if( it != dict.end() ) + { + it->second.FreeValue(engine); + dict.erase(it); + return true; + } + + return false; +} + +void CScriptDictionary::DeleteAll() +{ + dictMap_t::iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + it->second.FreeValue(engine); + + dict.clear(); +} + +CScriptArray* CScriptDictionary::GetKeys() const +{ + // Retrieve the object type for the array from the cache + SDictionaryCache *cache = reinterpret_cast(engine->GetUserData(DICTIONARY_CACHE)); + asITypeInfo *ti = cache->arrayType; + + // Create the array object + CScriptArray *array = CScriptArray::Create(ti, asUINT(dict.size())); + long current = -1; + dictMap_t::const_iterator it; + for( it = dict.begin(); it != dict.end(); it++ ) + { + current++; + *(dictKey_t*)array->At(current) = it->first; + } + + return array; +} + +//-------------------------------------------------------------------------- +// Generic wrappers + +void ScriptDictionaryFactory_Generic(asIScriptGeneric *gen) +{ + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(gen->GetEngine()); +} + +void ScriptDictionaryListFactory_Generic(asIScriptGeneric *gen) +{ + asBYTE *buffer = (asBYTE*)gen->GetArgAddress(0); + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = CScriptDictionary::Create(buffer); +} + +void ScriptDictionaryAddRef_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->AddRef(); +} + +void ScriptDictionaryRelease_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->Release(); +} + +void ScriptDictionaryAssign_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + CScriptDictionary *other = *(CScriptDictionary**)gen->GetAddressOfArg(0); + *dict = *other; + *(CScriptDictionary**)gen->GetAddressOfReturnLocation() = dict; +} + +void ScriptDictionarySet_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + int typeId = gen->GetArgTypeId(1); + dict->Set(*key, ref, typeId); +} + +void ScriptDictionarySetInt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + dict->Set(*key, *(asINT64*)ref); +} + +void ScriptDictionarySetFlt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + dict->Set(*key, *(double*)ref); +} + +void ScriptDictionaryGet_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + int typeId = gen->GetArgTypeId(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, ref, typeId); +} + +void ScriptDictionaryGetInt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(asINT64*)ref); +} + +void ScriptDictionaryGetFlt_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + void *ref = *(void**)gen->GetAddressOfArg(1); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Get(*key, *(double*)ref); +} + +void ScriptDictionaryExists_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + bool ret = dict->Exists(*key); + *(bool*)gen->GetAddressOfReturnLocation() = ret; +} + +void ScriptDictionaryIsEmpty_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + bool ret = dict->IsEmpty(); + *(bool*)gen->GetAddressOfReturnLocation() = ret; +} + +void ScriptDictionaryGetSize_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + asUINT ret = dict->GetSize(); + *(asUINT*)gen->GetAddressOfReturnLocation() = ret; +} + +void ScriptDictionaryDelete_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(bool*)gen->GetAddressOfReturnLocation() = dict->Delete(*key); +} + +void ScriptDictionaryDeleteAll_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *dict = (CScriptDictionary*)gen->GetObject(); + dict->DeleteAll(); +} + +static void ScriptDictionaryGetRefCount_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); +} + +static void ScriptDictionarySetGCFlag_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + self->SetGCFlag(); +} + +static void ScriptDictionaryGetGCFlag_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(bool*)gen->GetAddressOfReturnLocation() = self->GetGCFlag(); +} + +static void ScriptDictionaryEnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); +} + +static void ScriptDictionaryReleaseAllReferences_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllReferences(engine); +} + +static void CScriptDictionaryGetKeys_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + *(CScriptArray**)gen->GetAddressOfReturnLocation() = self->GetKeys(); +} + +static void CScriptDictionary_opIndex_Generic(asIScriptGeneric *gen) +{ + CScriptDictionary *self = (CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); +} + +static void CScriptDictionary_opIndex_const_Generic(asIScriptGeneric *gen) +{ + const CScriptDictionary *self = (const CScriptDictionary*)gen->GetObject(); + dictKey_t *key = *(dictKey_t**)gen->GetAddressOfArg(0); + *(const CScriptDictValue**)gen->GetAddressOfReturnLocation() = self->operator[](*key); +} + + +//------------------------------------------------------------------------- +// CScriptDictValue + +CScriptDictValue::CScriptDictValue() +{ + m_valueObj = 0; + m_typeId = 0; +} + +CScriptDictValue::CScriptDictValue(asIScriptEngine *engine, void *value, int typeId) +{ + m_valueObj = 0; + m_typeId = 0; + Set(engine, value, typeId); +} + +CScriptDictValue::~CScriptDictValue() +{ + if (m_valueObj && m_typeId) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + FreeValue(ctx->GetEngine()); + else + { + // Must not hold an object when destroyed, as then the object will never be freed + assert((m_typeId & asTYPEID_MASK_OBJECT) == 0); + } + } +} + +void CScriptDictValue::FreeValue(asIScriptEngine *engine) +{ + // If it is a handle or a ref counted object, call release + if( m_typeId & asTYPEID_MASK_OBJECT ) + { + // Let the engine release the object + engine->ReleaseScriptObject(m_valueObj, engine->GetTypeInfoById(m_typeId)); + m_valueObj = 0; + m_typeId = 0; + } + + // For primitives, there's nothing to do +} + +void CScriptDictValue::EnumReferences(asIScriptEngine *inEngine) +{ + // If we're holding a reference, we'll notify the garbage collector of it + if (m_valueObj) + inEngine->GCEnumCallback(m_valueObj); + + // The object type itself is also garbage collected + if (m_typeId) + inEngine->GCEnumCallback(inEngine->GetTypeInfoById(m_typeId)); +} + +void CScriptDictValue::Set(asIScriptEngine *engine, void *value, int typeId) +{ + FreeValue(engine); + + m_typeId = typeId; + if( typeId & asTYPEID_OBJHANDLE ) + { + // We're receiving a reference to the handle, so we need to dereference it + m_valueObj = *(void**)value; + engine->AddRefScriptObject(m_valueObj, engine->GetTypeInfoById(typeId)); + } + else if( typeId & asTYPEID_MASK_OBJECT ) + { + // Create a copy of the object + m_valueObj = engine->CreateScriptObjectCopy(value, engine->GetTypeInfoById(typeId)); + if( m_valueObj == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Cannot create copy of object"); + } + } + else + { + // Copy the primitive value + // We receive a pointer to the value. + int size = engine->GetSizeOfPrimitiveType(typeId); + memcpy(&m_valueInt, value, size); + } +} + +void CScriptDictValue::Set(asIScriptEngine *engine, CScriptDictValue &value) +{ + if( value.m_typeId & asTYPEID_OBJHANDLE ) + Set(engine, (void*)&value.m_valueObj, value.m_typeId); + else if( value.m_typeId & asTYPEID_MASK_OBJECT ) + Set(engine, (void*)value.m_valueObj, value.m_typeId); + else + Set(engine, (void*)&value.m_valueInt, value.m_typeId); +} + +// This overloaded method is implemented so that all integer and +// unsigned integers types will be stored in the dictionary as int64 +// through implicit conversions. This simplifies the management of the +// numeric types when the script retrieves the stored value using a +// different type. +void CScriptDictValue::Set(asIScriptEngine *engine, const asINT64 &value) +{ + Set(engine, const_cast(&value), asTYPEID_INT64); +} + +// This overloaded method is implemented so that all floating point types +// will be stored in the dictionary as double through implicit conversions. +// This simplifies the management of the numeric types when the script +// retrieves the stored value using a different type. +void CScriptDictValue::Set(asIScriptEngine *engine, const double &value) +{ + Set(engine, const_cast(&value), asTYPEID_DOUBLE); +} + +bool CScriptDictValue::Get(asIScriptEngine *engine, void *value, int typeId) const +{ + // Return the value + if( typeId & asTYPEID_OBJHANDLE ) + { + // A handle can be retrieved if the stored type is a handle of same or compatible type + // or if the stored type is an object that implements the interface that the handle refer to. + if( (m_typeId & asTYPEID_MASK_OBJECT) ) + { + // Don't allow the get if the stored handle is to a const, but the desired handle is not + if( (m_typeId & asTYPEID_HANDLETOCONST) && !(typeId & asTYPEID_HANDLETOCONST) ) + return false; + + // RefCastObject will increment the refcount if successful + engine->RefCastObject(m_valueObj, engine->GetTypeInfoById(m_typeId), engine->GetTypeInfoById(typeId), reinterpret_cast(value)); + + return true; + } + } + else if( typeId & asTYPEID_MASK_OBJECT ) + { + // Verify that the copy can be made + bool isCompatible = false; + + // Allow a handle to be value assigned if the wanted type is not a handle + if( (m_typeId & ~(asTYPEID_OBJHANDLE | asTYPEID_HANDLETOCONST) ) == typeId && m_valueObj != 0 ) + isCompatible = true; + + // Copy the object into the given reference + if( isCompatible ) + { + engine->AssignScriptObject(value, m_valueObj, engine->GetTypeInfoById(typeId)); + + return true; + } + } + else + { + if( m_typeId == typeId ) + { + int size = engine->GetSizeOfPrimitiveType(typeId); + memcpy(value, &m_valueInt, size); + return true; + } + + // We know all numbers are stored as either int64 or double, since we register overloaded functions for those + // Only bool and enums needs to be treated separately + if( typeId == asTYPEID_DOUBLE ) + { + if( m_typeId == asTYPEID_INT64 ) + *(double*)value = double(m_valueInt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(double*)value = localValue ? 1.0 : 0.0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(double*)value = double(localValue); // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(double*)value = 0; + return false; + } + return true; + } + else if( typeId == asTYPEID_INT64 ) + { + if( m_typeId == asTYPEID_DOUBLE ) + *(asINT64*)value = asINT64(m_valueFlt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(asINT64*)value = localValue ? 1 : 0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(asINT64*)value = localValue; // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(asINT64*)value = 0; + return false; + } + return true; + } + else if( typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0 ) + { + // The desired type is an enum. These are always 32bit integers + if( m_typeId == asTYPEID_DOUBLE ) + *(int*)value = int(m_valueFlt); + else if( m_typeId == asTYPEID_INT64 ) + *(int*)value = int(m_valueInt); + else if (m_typeId == asTYPEID_BOOL) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + char localValue; + memcpy(&localValue, &m_valueInt, sizeof(char)); + *(int*)value = localValue ? 1 : 0; + } + else if (m_typeId > asTYPEID_DOUBLE && (m_typeId & asTYPEID_MASK_OBJECT) == 0) + { + // Use memcpy instead of type cast to make sure the code is endianess agnostic + int localValue; + memcpy(&localValue, &m_valueInt, sizeof(int)); + *(int*)value = localValue; // enums are 32bit + } + else + { + // The stored type is an object + // TODO: Check if the object has a conversion operator to a primitive value + *(int*)value = 0; + return false; + } + return true; + } + else if( typeId == asTYPEID_BOOL ) + { + if (m_typeId & asTYPEID_OBJHANDLE) + { + // TODO: Check if the object has a conversion operator to a primitive value + *(bool*)value = m_valueObj ? true : false; + } + else if( m_typeId & asTYPEID_MASK_OBJECT ) + { + // TODO: Check if the object has a conversion operator to a primitive value + *(bool*)value = true; + } + else + { + // Compare only the bytes that were actually set + asQWORD zero = 0; + int size = engine->GetSizeOfPrimitiveType(m_typeId); + *(bool*)value = memcmp(&m_valueInt, &zero, size) == 0 ? false : true; + } + return true; + } + } + + // It was not possible to retrieve the value using the desired typeId + return false; +} + +const void * CScriptDictValue::GetAddressOfValue() const +{ + if( (m_typeId & asTYPEID_MASK_OBJECT) && !(m_typeId & asTYPEID_OBJHANDLE) ) + { + // Return the address to the object directly + return m_valueObj; + } + + // Return the address of the primitive or the pointer to the object + return reinterpret_cast(&m_valueObj); +} + +bool CScriptDictValue::Get(asIScriptEngine *engine, asINT64 &value) const +{ + return Get(engine, &value, asTYPEID_INT64); +} + +bool CScriptDictValue::Get(asIScriptEngine *engine, double &value) const +{ + return Get(engine, &value, asTYPEID_DOUBLE); +} + +int CScriptDictValue::GetTypeId() const +{ + return m_typeId; +} + +static void CScriptDictValue_Construct(void *mem) +{ + new(mem) CScriptDictValue(); +} + +static void CScriptDictValue_Destruct(CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->FreeValue(engine); + } + obj->~CScriptDictValue(); +} + +static CScriptDictValue &CScriptDictValue_opAssign(void *ref, int typeId, CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Set(engine, ref, typeId); + } + return *obj; +} + +static CScriptDictValue &CScriptDictValue_opAssign(const CScriptDictValue &other, CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Set(engine, const_cast(other)); + } + + return *obj; +} + +static CScriptDictValue &CScriptDictValue_opAssign(double val, CScriptDictValue *obj) +{ + return CScriptDictValue_opAssign(&val, asTYPEID_DOUBLE, obj); +} + +static CScriptDictValue &CScriptDictValue_opAssign(asINT64 val, CScriptDictValue *obj) +{ + return CScriptDictValue_opAssign(&val, asTYPEID_INT64, obj); +} + +static void CScriptDictValue_opCast(void *ref, int typeId, CScriptDictValue *obj) +{ + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + { + asIScriptEngine *engine = ctx->GetEngine(); + obj->Get(engine, ref, typeId); + } +} + +static asINT64 CScriptDictValue_opConvInt(CScriptDictValue *obj) +{ + asINT64 value; + CScriptDictValue_opCast(&value, asTYPEID_INT64, obj); + return value; +} + +static double CScriptDictValue_opConvDouble(CScriptDictValue *obj) +{ + double value; + CScriptDictValue_opCast(&value, asTYPEID_DOUBLE, obj); + return value; +} + +//------------------------------------------------------------------- +// generic wrapper for CScriptDictValue + +static void CScriptDictValue_opConvDouble_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + double value; + self->Get(gen->GetEngine(), value); + *(double*)gen->GetAddressOfReturnLocation() = value; +} + +static void CScriptDictValue_opConvInt_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + asINT64 value; + self->Get(gen->GetEngine(), value); + *(asINT64*)gen->GetAddressOfReturnLocation() = value; +} + +static void CScriptDictValue_opCast_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->Get(gen->GetEngine(), gen->GetArgAddress(0), gen->GetArgTypeId(0)); +} + +static void CScriptDictValue_opAssign_int64_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign((asINT64)gen->GetArgQWord(0), self); +} + +static void CScriptDictValue_opAssign_double_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgDouble(0), self); +} + +static void CScriptDictValue_opAssign_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(gen->GetArgAddress(0), gen->GetArgTypeId(0), self); +} + +static void CScriptDictValue_opCopyAssign_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + *(CScriptDictValue**)gen->GetAddressOfReturnLocation() = &CScriptDictValue_opAssign(*reinterpret_cast(gen->GetArgAddress(0)), self); +} + +static void CScriptDictValue_Construct_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + CScriptDictValue_Construct(self); +} + +static void CScriptDictValue_Destruct_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + CScriptDictValue_Destruct(self); +} + +static void CScriptDictValue_EnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->EnumReferences(gen->GetEngine()); +} + +static void CScriptDictValue_FreeValue_Generic(asIScriptGeneric *gen) +{ + CScriptDictValue *self = (CScriptDictValue*)gen->GetObject(); + self->FreeValue(gen->GetEngine()); +} + +//-------------------------------------------------------------------------- +// Register the type + +void RegisterScriptDictionary(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptDictionary_Generic(engine); + else + RegisterScriptDictionary_Native(engine); +} + +void RegisterScriptDictionary_Native(asIScriptEngine *engine) +{ + int r; + + // The array type must be available + assert( engine->GetTypeInfoByDecl("array") ); + +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictValue, EnumReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictValue, FreeValue), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTIONPR(CScriptDictValue_opAssign, (const CScriptDictValue &, CScriptDictValue *), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTIONPR(CScriptDictValue_opAssign, (void *, int, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTIONPR(CScriptDictValue_opAssign, (double, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTIONPR(CScriptDictValue_opAssign, (asINT64, CScriptDictValue*), CScriptDictValue &), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTIONPR(CScriptDictValue_opCast, (void *, int, CScriptDictValue*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTIONPR(CScriptDictValue_opConvInt, (CScriptDictValue*), asINT64), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTIONPR(CScriptDictValue_opConvDouble, (CScriptDictValue*), double), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + // Use the generic interface to construct the object since we need the engine pointer, we could also have retrieved the engine pointer from the active context + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptDictionary,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptDictionary,Release), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asMETHODPR(CScriptDictionary, operator=, (const CScriptDictionary &), CScriptDictionary&), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,void*,int),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,void*,int) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const asINT64&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,asINT64&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asMETHODPR(CScriptDictionary,Set,(const dictKey_t&,const double&),void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asMETHODPR(CScriptDictionary,Get,(const dictKey_t&,double&) const,bool), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asMETHOD(CScriptDictionary,Exists), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asMETHOD(CScriptDictionary,GetKeys), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &), CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asMETHODPR(CScriptDictionary, operator[], (const dictKey_t &) const, const CScriptDictValue*), asCALL_THISCALL); assert( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptDictionary,GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptDictionary,SetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptDictionary,GetGCFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptDictionary,EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptDictionary,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 ); + +#if AS_USE_STLNAMES == 1 + // Same as isEmpty + r = engine->RegisterObjectMethod("dictionary", "bool empty() const", asMETHOD(CScriptDictionary, IsEmpty), asCALL_THISCALL); assert( r >= 0 ); + // Same as getSize + r = engine->RegisterObjectMethod("dictionary", "uint size() const", asMETHOD(CScriptDictionary, GetSize), asCALL_THISCALL); assert( r >= 0 ); + // Same as delete + r = engine->RegisterObjectMethod("dictionary", "void erase(const string &in)", asMETHOD(CScriptDictionary,Delete), asCALL_THISCALL); assert( r >= 0 ); + // Same as deleteAll + r = engine->RegisterObjectMethod("dictionary", "void clear()", asMETHOD(CScriptDictionary,DeleteAll), asCALL_THISCALL); assert( r >= 0 ); +#endif + + // Cache some things the dictionary will need at runtime + SDictionaryCache::Setup(engine); +} + +void RegisterScriptDictionary_Generic(asIScriptEngine *engine) +{ + int r; + + // Register the cleanup callback for the object type cache + engine->SetEngineUserDataCleanupCallback(SDictionaryCache::Cleanup, DICTIONARY_CACHE); + +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags that represents the C++ class + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("dictionaryValue", sizeof(CScriptDictValue), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CD); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptDictValue_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptDictValue_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("dictionaryValue", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptDictValue_FreeValue_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opHndlAssign(const dictionaryValue &in)", asFUNCTION(CScriptDictValue_opCopyAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(const ?&in)", asFUNCTION(CScriptDictValue_opAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(double)", asFUNCTION(CScriptDictValue_opAssign_double_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "dictionaryValue &opAssign(int64)", asFUNCTION(CScriptDictValue_opAssign_int64_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opCast(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "void opConv(?&out)", asFUNCTION(CScriptDictValue_opCast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "int64 opConv()", asFUNCTION(CScriptDictValue_opConvInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionaryValue", "double opConv()", asFUNCTION(CScriptDictValue_opConvDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectType("dictionary", sizeof(CScriptDictionary), asOBJ_REF | asOBJ_GC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_FACTORY, "dictionary@ f()", asFUNCTION(ScriptDictionaryFactory_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_LIST_FACTORY, "dictionary @f(int &in) {repeat {string, ?}}", asFUNCTION(ScriptDictionaryListFactory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptDictionaryAddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptDictionaryRelease_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionary &opAssign(const dictionary &in)", asFUNCTION(ScriptDictionaryAssign_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const ?&in)", asFUNCTION(ScriptDictionarySet_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, ?&out) const", asFUNCTION(ScriptDictionaryGet_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const int64&in)", asFUNCTION(ScriptDictionarySetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, int64&out) const", asFUNCTION(ScriptDictionaryGetInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "void set(const string &in, const double&in)", asFUNCTION(ScriptDictionarySetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool get(const string &in, double&out) const", asFUNCTION(ScriptDictionaryGetFlt_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "bool exists(const string &in) const", asFUNCTION(ScriptDictionaryExists_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool isEmpty() const", asFUNCTION(ScriptDictionaryIsEmpty_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "uint getSize() const", asFUNCTION(ScriptDictionaryGetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "bool delete(const string &in)", asFUNCTION(ScriptDictionaryDelete_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "void deleteAll()", asFUNCTION(ScriptDictionaryDeleteAll_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "array @getKeys() const", asFUNCTION(CScriptDictionaryGetKeys_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("dictionary", "dictionaryValue &opIndex(const string &in)", asFUNCTION(CScriptDictionary_opIndex_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("dictionary", "const dictionaryValue &opIndex(const string &in) const", asFUNCTION(CScriptDictionary_opIndex_const_Generic), asCALL_GENERIC); assert( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptDictionaryGetRefCount_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptDictionarySetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptDictionaryGetGCFlag_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryEnumReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("dictionary", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptDictionaryReleaseAllReferences_Generic), asCALL_GENERIC); assert( r >= 0 ); + + // Cache some things the dictionary will need at runtime + SDictionaryCache::Setup(engine); +} + +//------------------------------------------------------------------ +// Iterator implementation + +CScriptDictionary::CIterator CScriptDictionary::begin() const +{ + return CIterator(*this, dict.begin()); +} + +CScriptDictionary::CIterator CScriptDictionary::end() const +{ + return CIterator(*this, dict.end()); +} + +CScriptDictionary::CIterator CScriptDictionary::find(const dictKey_t &key) const +{ + return CIterator(*this, dict.find(key)); +} + +CScriptDictionary::CIterator::CIterator( + const CScriptDictionary &dict, + dictMap_t::const_iterator it) + : m_it(it), m_dict(dict) +{} + +void CScriptDictionary::CIterator::operator++() +{ + ++m_it; +} + +void CScriptDictionary::CIterator::operator++(int) +{ + ++m_it; + + // Normally the post increment would return a copy of the object with the original state, + // but it is rarely used so we skip this extra copy to avoid unnecessary overhead +} + +CScriptDictionary::CIterator &CScriptDictionary::CIterator::operator*() +{ + return *this; +} + +bool CScriptDictionary::CIterator::operator==(const CIterator &other) const +{ + return m_it == other.m_it; +} + +bool CScriptDictionary::CIterator::operator!=(const CIterator &other) const +{ + return m_it != other.m_it; +} + +const dictKey_t &CScriptDictionary::CIterator::GetKey() const +{ + return m_it->first; +} + +int CScriptDictionary::CIterator::GetTypeId() const +{ + return m_it->second.m_typeId; +} + +bool CScriptDictionary::CIterator::GetValue(asINT64 &value) const +{ + return m_it->second.Get(m_dict.engine, &value, asTYPEID_INT64); +} + +bool CScriptDictionary::CIterator::GetValue(double &value) const +{ + return m_it->second.Get(m_dict.engine, &value, asTYPEID_DOUBLE); +} + +bool CScriptDictionary::CIterator::GetValue(void *value, int typeId) const +{ + return m_it->second.Get(m_dict.engine, value, typeId); +} + +const void *CScriptDictionary::CIterator::GetAddressOfValue() const +{ + return m_it->second.GetAddressOfValue(); +} + +END_AS_NAMESPACE + + diff --git a/add_on/scriptdictionary/scriptdictionary.h b/add_on/scriptdictionary/scriptdictionary.h new file mode 100644 index 0000000..062bb15 --- /dev/null +++ b/add_on/scriptdictionary/scriptdictionary.h @@ -0,0 +1,240 @@ +#ifndef SCRIPTDICTIONARY_H +#define SCRIPTDICTIONARY_H + +// The dictionary class relies on the script string object, thus the script +// string type must be registered with the engine before registering the +// dictionary type + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +// By default the CScriptDictionary use the std::string for the keys. +// If the application uses a custom string type, then this typedef +// can be changed accordingly. +#include +typedef std::string dictKey_t; + +// Forward declare CScriptDictValue so we can typedef the internal map type +BEGIN_AS_NAMESPACE +class CScriptDictValue; +END_AS_NAMESPACE + +// C++11 introduced the std::unordered_map which is a hash map which is +// is generally more performatic for lookups than the std::map which is a +// binary tree. +// TODO: memory: The map allocator should use the asAllocMem and asFreeMem +#if AS_CAN_USE_CPP11 +#include +typedef std::unordered_map dictMap_t; +#else +#include +typedef std::map dictMap_t; +#endif + + +#ifdef _MSC_VER +// Turn off annoying warnings about truncated symbol names +#pragma warning (disable:4786) +#endif + + + + +// Sometimes it may be desired to use the same method names as used by C++ STL. +// This may for example reduce time when converting code from script to C++ or +// back. +// +// 0 = off +// 1 = on + +#ifndef AS_USE_STLNAMES +#define AS_USE_STLNAMES 0 +#endif + + +BEGIN_AS_NAMESPACE + +class CScriptArray; +class CScriptDictionary; + +class CScriptDictValue +{ +public: + // This class must not be declared as local variable in C++, because it needs + // to receive the script engine pointer in all operations. The engine pointer + // is not kept as member in order to keep the size down + CScriptDictValue(); + CScriptDictValue(asIScriptEngine *engine, void *value, int typeId); + + // Destructor must not be called without first calling FreeValue, otherwise a memory leak will occur + ~CScriptDictValue(); + + // Replace the stored value + void Set(asIScriptEngine *engine, void *value, int typeId); + void Set(asIScriptEngine *engine, const asINT64 &value); + void Set(asIScriptEngine *engine, const double &value); + void Set(asIScriptEngine *engine, CScriptDictValue &value); + + // Gets the stored value. Returns false if the value isn't compatible with the informed typeId + bool Get(asIScriptEngine *engine, void *value, int typeId) const; + bool Get(asIScriptEngine *engine, asINT64 &value) const; + bool Get(asIScriptEngine *engine, double &value) const; + + // Returns the address of the stored value for inspection + const void *GetAddressOfValue() const; + + // Returns the type id of the stored value + int GetTypeId() const; + + // Free the stored value + void FreeValue(asIScriptEngine *engine); + + // GC callback + void EnumReferences(asIScriptEngine *engine); + +protected: + friend class CScriptDictionary; + + union + { + asINT64 m_valueInt; + double m_valueFlt; + void *m_valueObj; + }; + int m_typeId; +}; + +class CScriptDictionary +{ +public: + // Factory functions + static CScriptDictionary *Create(asIScriptEngine *engine); + + // Called from the script to instantiate a dictionary from an initialization list + static CScriptDictionary *Create(asBYTE *buffer); + + // Reference counting + void AddRef() const; + void Release() const; + + // Reassign the dictionary + CScriptDictionary &operator =(const CScriptDictionary &other); + + // Sets a key/value pair + void Set(const dictKey_t &key, void *value, int typeId); + void Set(const dictKey_t &key, const asINT64 &value); + void Set(const dictKey_t &key, const double &value); + + // Gets the stored value. Returns false if the value isn't compatible with the informed typeId + bool Get(const dictKey_t &key, void *value, int typeId) const; + bool Get(const dictKey_t &key, asINT64 &value) const; + bool Get(const dictKey_t &key, double &value) const; + + // Index accessors. If the dictionary is not const it inserts the value if it doesn't already exist + // If the dictionary is const then a script exception is set if it doesn't exist and a null pointer is returned + CScriptDictValue *operator[](const dictKey_t &key); + const CScriptDictValue *operator[](const dictKey_t &key) const; + + // Returns the type id of the stored value, or negative if it doesn't exist + int GetTypeId(const dictKey_t &key) const; + + // Returns true if the key is set + bool Exists(const dictKey_t &key) const; + + // Returns true if there are no key/value pairs in the dictionary + bool IsEmpty() const; + + // Returns the number of key/value pairs in the dictionary + asUINT GetSize() const; + + // Deletes the key + bool Delete(const dictKey_t &key); + + // Deletes all keys + void DeleteAll(); + + // Get an array of all keys + CScriptArray *GetKeys() const; + + // STL style iterator + class CIterator + { + public: + void operator++(); // Pre-increment + void operator++(int); // Post-increment + + // This is needed to support C++11 range-for + CIterator &operator*(); + + bool operator==(const CIterator &other) const; + bool operator!=(const CIterator &other) const; + + // Accessors + const dictKey_t &GetKey() const; + int GetTypeId() const; + bool GetValue(asINT64 &value) const; + bool GetValue(double &value) const; + bool GetValue(void *value, int typeId) const; + const void * GetAddressOfValue() const; + + protected: + friend class CScriptDictionary; + + CIterator(); + CIterator(const CScriptDictionary &dict, + dictMap_t::const_iterator it); + + CIterator &operator=(const CIterator &) {return *this;} // Not used + + dictMap_t::const_iterator m_it; + const CScriptDictionary &m_dict; + }; + + CIterator begin() const; + CIterator end() const; + CIterator find(const dictKey_t &key) const; + + // Garbage collections behaviours + int GetRefCount(); + void SetGCFlag(); + bool GetGCFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllReferences(asIScriptEngine *engine); + +protected: + // Since the dictionary uses the asAllocMem and asFreeMem functions to allocate memory + // the constructors are made protected so that the application cannot allocate it + // manually in a different way + CScriptDictionary(asIScriptEngine *engine); + CScriptDictionary(asBYTE *buffer); + + // We don't want anyone to call the destructor directly, it should be called through the Release method + virtual ~CScriptDictionary(); + + // Cache the object types needed + void Init(asIScriptEngine *engine); + + // Our properties + asIScriptEngine *engine; + mutable int refCount; + mutable bool gcFlag; + dictMap_t dict; +}; + +// This function will determine the configuration of the engine +// and use one of the two functions below to register the dictionary object +void RegisterScriptDictionary(asIScriptEngine *engine); + +// Call this function to register the math functions +// using native calling conventions +void RegisterScriptDictionary_Native(asIScriptEngine *engine); + +// Use this one instead if native calling conventions +// are not supported on the target platform +void RegisterScriptDictionary_Generic(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptfile/scriptfile.cpp b/add_on/scriptfile/scriptfile.cpp new file mode 100644 index 0000000..5c4e26c --- /dev/null +++ b/add_on/scriptfile/scriptfile.cpp @@ -0,0 +1,660 @@ +#include "scriptfile.h" +#include +#include +#include +#include +#include + +#ifdef _WIN32_WCE +#include // For GetModuleFileName +#ifdef GetObject +#undef GetObject +#endif +#endif + +using namespace std; + +BEGIN_AS_NAMESPACE + +CScriptFile *ScriptFile_Factory() +{ + return new CScriptFile(); +} + +void ScriptFile_Factory_Generic(asIScriptGeneric *gen) +{ + *(CScriptFile**)gen->GetAddressOfReturnLocation() = ScriptFile_Factory(); +} + +void ScriptFile_AddRef_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + file->AddRef(); +} + +void ScriptFile_Release_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + file->Release(); +} + +void ScriptFile_Open_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + std::string *f = (std::string*)gen->GetArgAddress(0); + std::string *m = (std::string*)gen->GetArgAddress(1); + int r = file->Open(*f, *m); + gen->SetReturnDWord(r); +} + +void ScriptFile_Close_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + int r = file->Close(); + gen->SetReturnDWord(r); +} + +void ScriptFile_GetSize_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + int r = file->GetSize(); + gen->SetReturnDWord(r); +} + +void ScriptFile_ReadString_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + int len = gen->GetArgDWord(0); + string str = file->ReadString(len); + gen->SetReturnObject(&str); +} + +void ScriptFile_ReadLine_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + std::string str = file->ReadLine(); + gen->SetReturnObject(&str); +} + +void ScriptFile_ReadInt_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + asUINT bytes = *(asUINT*)gen->GetAddressOfArg(0); + *(asINT64*)gen->GetAddressOfReturnLocation() = file->ReadInt(bytes); +} + +void ScriptFile_ReadUInt_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + asUINT bytes = *(asUINT*)gen->GetAddressOfArg(0); + *(asQWORD*)gen->GetAddressOfReturnLocation() = file->ReadUInt(bytes); +} + +void ScriptFile_ReadFloat_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + *(float*)gen->GetAddressOfReturnLocation() = file->ReadFloat(); +} + +void ScriptFile_ReadDouble_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + *(double*)gen->GetAddressOfReturnLocation() = file->ReadDouble(); +} + +void ScriptFile_WriteString_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + std::string *str = (std::string*)gen->GetArgAddress(0); + gen->SetReturnDWord(file->WriteString(*str)); +} + +void ScriptFile_WriteInt_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + asINT64 val = *(asINT64*)gen->GetAddressOfArg(0); + asUINT bytes = *(asUINT*)gen->GetAddressOfArg(1); + *(int*)gen->GetAddressOfReturnLocation() = file->WriteInt(val, bytes); +} + +void ScriptFile_WriteUInt_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + asQWORD val = *(asQWORD*)gen->GetAddressOfArg(0); + asUINT bytes = *(asUINT*)gen->GetAddressOfArg(1); + *(int*)gen->GetAddressOfReturnLocation() = file->WriteUInt(val, bytes); +} + +void ScriptFile_WriteFloat_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + float val = *(float*)gen->GetAddressOfArg(0); + *(int*)gen->GetAddressOfReturnLocation() = file->WriteFloat(val); +} + +void ScriptFile_WriteDouble_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + double val = *(double*)gen->GetAddressOfArg(0); + *(int*)gen->GetAddressOfReturnLocation() = file->WriteDouble(val); +} + +void ScriptFile_IsEOF_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + bool r = file->IsEOF(); + gen->SetReturnByte(r); +} + +void ScriptFile_GetPos_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + gen->SetReturnDWord(file->GetPos()); +} + +void ScriptFile_SetPos_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + int pos = (int)gen->GetArgDWord(0); + gen->SetReturnDWord(file->SetPos(pos)); +} + +void ScriptFile_MovePos_Generic(asIScriptGeneric *gen) +{ + CScriptFile *file = (CScriptFile*)gen->GetObject(); + int delta = (int)gen->GetArgDWord(0); + gen->SetReturnDWord(file->MovePos(delta)); +} + +void RegisterScriptFile_Native(asIScriptEngine *engine) +{ + int r; + + r = engine->RegisterObjectType("file", 0, asOBJ_REF); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()", asFUNCTION(ScriptFile_Factory), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptFile,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptFile,Release), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("file", "int open(const string &in, const string &in)", asMETHOD(CScriptFile,Open), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int close()", asMETHOD(CScriptFile,Close), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int getSize() const", asMETHOD(CScriptFile,GetSize), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const", asMETHOD(CScriptFile,IsEOF), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "string readString(uint)", asMETHOD(CScriptFile,ReadString), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "string readLine()", asMETHOD(CScriptFile,ReadLine), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int64 readInt(uint)", asMETHOD(CScriptFile,ReadInt), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)", asMETHOD(CScriptFile,ReadUInt), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "float readFloat()", asMETHOD(CScriptFile,ReadFloat), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "double readDouble()", asMETHOD(CScriptFile,ReadDouble), asCALL_THISCALL); assert( r >= 0 ); +#if AS_WRITE_OPS == 1 + r = engine->RegisterObjectMethod("file", "int writeString(const string &in)", asMETHOD(CScriptFile,WriteString), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeInt(int64, uint)", asMETHOD(CScriptFile,WriteInt), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeUInt(uint64, uint)", asMETHOD(CScriptFile,WriteUInt), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeFloat(float)", asMETHOD(CScriptFile,WriteFloat), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeDouble(double)", asMETHOD(CScriptFile,WriteDouble), asCALL_THISCALL); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("file", "int getPos() const", asMETHOD(CScriptFile,GetPos), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int setPos(int)", asMETHOD(CScriptFile,SetPos), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int movePos(int)", asMETHOD(CScriptFile,MovePos), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectProperty("file", "bool mostSignificantByteFirst", asOFFSET(CScriptFile, mostSignificantByteFirst)); assert( r >= 0 ); +} + +void RegisterScriptFile_Generic(asIScriptEngine *engine) +{ + int r; + + r = engine->RegisterObjectType("file", 0, asOBJ_REF); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("file", asBEHAVE_FACTORY, "file @f()", asFUNCTION(ScriptFile_Factory_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("file", asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFile_AddRef_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("file", asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFile_Release_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("file", "int open(const string &in, const string &in)", asFUNCTION(ScriptFile_Open_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int close()", asFUNCTION(ScriptFile_Close_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int getSize() const", asFUNCTION(ScriptFile_GetSize_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "bool isEndOfFile() const", asFUNCTION(ScriptFile_IsEOF_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "string readString(uint)", asFUNCTION(ScriptFile_ReadString_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "string readLine()", asFUNCTION(ScriptFile_ReadLine_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int64 readInt(uint)", asFUNCTION(ScriptFile_ReadInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "uint64 readUInt(uint)", asFUNCTION(ScriptFile_ReadUInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "float readFloat()", asFUNCTION(ScriptFile_ReadFloat_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "double readDouble()", asFUNCTION(ScriptFile_ReadDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); +#if AS_WRITE_OPS == 1 + r = engine->RegisterObjectMethod("file", "int writeString(const string &in)", asFUNCTION(ScriptFile_WriteString_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeInt(int64, uint)", asFUNCTION(ScriptFile_WriteInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeUInt(uint64, uint)", asFUNCTION(ScriptFile_WriteUInt_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeFloat(float)", asFUNCTION(ScriptFile_WriteFloat_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int writeDouble(double)", asFUNCTION(ScriptFile_WriteDouble_Generic), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("file", "int getPos() const", asFUNCTION(ScriptFile_GetPos_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int setPos(int)", asFUNCTION(ScriptFile_SetPos_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("file", "int movePos(int)", asFUNCTION(ScriptFile_MovePos_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectProperty("file", "bool mostSignificantByteFirst", asOFFSET(CScriptFile, mostSignificantByteFirst)); assert( r >= 0 ); +} + +void RegisterScriptFile(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptFile_Generic(engine); + else + RegisterScriptFile_Native(engine); +} + +CScriptFile::CScriptFile() +{ + refCount = 1; + file = 0; + mostSignificantByteFirst = false; +} + +CScriptFile::~CScriptFile() +{ + Close(); +} + +void CScriptFile::AddRef() const +{ + asAtomicInc(refCount); +} + +void CScriptFile::Release() const +{ + if( asAtomicDec(refCount) == 0 ) + delete this; +} + +int CScriptFile::Open(const std::string &filename, const std::string &mode) +{ + // Close the previously opened file handle + if( file ) + Close(); + + std::string myFilename = filename; + + // Validate the mode + string m; +#if AS_WRITE_OPS == 1 + if( mode != "r" && mode != "w" && mode != "a" ) +#else + if( mode != "r" ) +#endif + return -1; + else + m = mode; + +#ifdef _WIN32_WCE + // no relative pathing on CE + char buf[MAX_PATH]; + static TCHAR apppath[MAX_PATH] = TEXT(""); + if (!apppath[0]) + { + GetModuleFileName(NULL, apppath, MAX_PATH); + + int appLen = _tcslen(apppath); + while (appLen > 1) + { + if (apppath[appLen-1] == TEXT('\\')) + break; + appLen--; + } + + // Terminate the string after the trailing backslash + apppath[appLen] = TEXT('\0'); + } +#ifdef _UNICODE + wcstombs(buf, apppath, wcslen(apppath)+1); +#else + memcpy(buf, apppath, strlen(apppath)); +#endif + myFilename = buf + myFilename; +#endif + + + // By default windows translates "\r\n" to "\n", but we want to read the file as-is. + m += "b"; + + // Open the file +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 introduced new functions + // Marmalade doesn't use these, even though it uses the MSVC compiler + fopen_s(&file, myFilename.c_str(), m.c_str()); +#else + file = fopen(myFilename.c_str(), m.c_str()); +#endif + if( file == 0 ) + return -1; + + return 0; +} + +int CScriptFile::Close() +{ + if( file == 0 ) + return -1; + + fclose(file); + file = 0; + + return 0; +} + +int CScriptFile::GetSize() const +{ + if( file == 0 ) + return -1; + + int pos = ftell(file); + fseek(file, 0, SEEK_END); + int size = ftell(file); + fseek(file, pos, SEEK_SET); + + return size; +} + +int CScriptFile::GetPos() const +{ + if( file == 0 ) + return -1; + + return ftell(file); +} + +int CScriptFile::SetPos(int pos) +{ + if( file == 0 ) + return -1; + + int r = fseek(file, pos, SEEK_SET); + + // Return -1 on error + return r ? -1 : 0; +} + +int CScriptFile::MovePos(int delta) +{ + if( file == 0 ) + return -1; + + int r = fseek(file, delta, SEEK_CUR); + + // Return -1 on error + return r ? -1 : 0; +} + +string CScriptFile::ReadString(unsigned int length) +{ + if( file == 0 ) + return ""; + + // Read the string + string str; + str.resize(length); + int size = (int)fread(&str[0], 1, length, file); + str.resize(size); + + return str; +} + +string CScriptFile::ReadLine() +{ + if( file == 0 ) + return ""; + + // Read until the first new-line character + string str; + char buf[256]; + + do + { + // Get the current position so we can determine how many characters were read + int start = ftell(file); + + // Set the last byte to something different that 0, so that we can check if the buffer was filled up + buf[255] = 1; + + // Read the line (or first 255 characters, which ever comes first) + char *r = fgets(buf, 256, file); + if( r == 0 ) break; + + // Get the position after the read + int end = ftell(file); + + // Add the read characters to the output buffer + str.append(buf, end-start); + } + while( !feof(file) && buf[255] == 0 && buf[254] != '\n' ); + + return str; +} + +asINT64 CScriptFile::ReadInt(asUINT bytes) +{ + if( file == 0 ) + return 0; + + if( bytes > 8 ) bytes = 8; + if( bytes == 0 ) return 0; + + unsigned char buf[8]; + size_t r = fread(buf, bytes, 1, file); + if( r == 0 ) return 0; + + asINT64 val = 0; + if( mostSignificantByteFirst ) + { + unsigned int n = 0; + for( ; n < bytes; n++ ) + val |= asQWORD(buf[n]) << ((bytes-n-1)*8); + + // Check the most significant byte to determine if the rest + // of the qword must be filled to give a negative value + if( buf[0] & 0x80 ) + for( ; n < 8; n++ ) + val |= asQWORD(0xFF) << (n*8); + } + else + { + unsigned int n = 0; + for( ; n < bytes; n++ ) + val |= asQWORD(buf[n]) << (n*8); + + // Check the most significant byte to determine if the rest + // of the qword must be filled to give a negative value + if( buf[bytes-1] & 0x80 ) + for( ; n < 8; n++ ) + val |= asQWORD(0xFF) << (n*8); + } + + return val; +} + +asQWORD CScriptFile::ReadUInt(asUINT bytes) +{ + if( file == 0 ) + return 0; + + if( bytes > 8 ) bytes = 8; + if( bytes == 0 ) return 0; + + unsigned char buf[8]; + size_t r = fread(buf, bytes, 1, file); + if( r == 0 ) return 0; + + asQWORD val = 0; + if( mostSignificantByteFirst ) + { + unsigned int n = 0; + for( ; n < bytes; n++ ) + val |= asQWORD(buf[n]) << ((bytes-n-1)*8); + } + else + { + unsigned int n = 0; + for( ; n < bytes; n++ ) + val |= asQWORD(buf[n]) << (n*8); + } + + return val; +} + +float CScriptFile::ReadFloat() +{ + if( file == 0 ) + return 0; + + unsigned char buf[4]; + size_t r = fread(buf, 4, 1, file); + if( r == 0 ) return 0; + + asUINT val = 0; + if( mostSignificantByteFirst ) + { + unsigned int n = 0; + for( ; n < 4; n++ ) + val |= asUINT(buf[n]) << ((3-n)*8); + } + else + { + unsigned int n = 0; + for( ; n < 4; n++ ) + val |= asUINT(buf[n]) << (n*8); + } + + return *reinterpret_cast(&val); +} + +double CScriptFile::ReadDouble() +{ + if( file == 0 ) + return 0; + + unsigned char buf[8]; + size_t r = fread(buf, 8, 1, file); + if( r == 0 ) return 0; + + asQWORD val = 0; + if( mostSignificantByteFirst ) + { + unsigned int n = 0; + for( ; n < 8; n++ ) + val |= asQWORD(buf[n]) << ((7-n)*8); + } + else + { + unsigned int n = 0; + for( ; n < 8; n++ ) + val |= asQWORD(buf[n]) << (n*8); + } + + return *reinterpret_cast(&val); +} + +bool CScriptFile::IsEOF() const +{ + if( file == 0 ) + return true; + + return feof(file) ? true : false; +} + +#if AS_WRITE_OPS == 1 +int CScriptFile::WriteString(const std::string &str) +{ + if( file == 0 ) + return -1; + + // Write the entire string + size_t r = fwrite(&str[0], 1, str.length(), file); + + return int(r); +} + +int CScriptFile::WriteInt(asINT64 val, asUINT bytes) +{ + if( file == 0 ) + return 0; + + unsigned char buf[8]; + if( mostSignificantByteFirst ) + { + for( unsigned int n = 0; n < bytes; n++ ) + buf[n] = (val >> ((bytes-n-1)*8)) & 0xFF; + } + else + { + for( unsigned int n = 0; n < bytes; n++ ) + buf[n] = (val >> (n*8)) & 0xFF; + } + + size_t r = fwrite(&buf, bytes, 1, file); + return int(r); +} + +int CScriptFile::WriteUInt(asQWORD val, asUINT bytes) +{ + if( file == 0 ) + return 0; + + unsigned char buf[8]; + if( mostSignificantByteFirst ) + { + for( unsigned int n = 0; n < bytes; n++ ) + buf[n] = (val >> ((bytes-n-1)*8)) & 0xFF; + } + else + { + for( unsigned int n = 0; n < bytes; n++ ) + buf[n] = (val >> (n*8)) & 0xFF; + } + + size_t r = fwrite(&buf, bytes, 1, file); + return int(r); +} + +int CScriptFile::WriteFloat(float f) +{ + if( file == 0 ) + return 0; + + unsigned char buf[4]; + asUINT val = *reinterpret_cast(&f); + if( mostSignificantByteFirst ) + { + for( unsigned int n = 0; n < 4; n++ ) + buf[n] = (val >> ((3-n)*4)) & 0xFF; + } + else + { + for( unsigned int n = 0; n < 4; n++ ) + buf[n] = (val >> (n*8)) & 0xFF; + } + + size_t r = fwrite(&buf, 4, 1, file); + return int(r); +} + +int CScriptFile::WriteDouble(double d) +{ + if( file == 0 ) + return 0; + + unsigned char buf[8]; + asQWORD val = *reinterpret_cast(&d); + if( mostSignificantByteFirst ) + { + for( unsigned int n = 0; n < 8; n++ ) + buf[n] = (val >> ((7-n)*8)) & 0xFF; + } + else + { + for( unsigned int n = 0; n < 8; n++ ) + buf[n] = (val >> (n*8)) & 0xFF; + } + + size_t r = fwrite(&buf, 8, 1, file); + return int(r); +} +#endif + + +END_AS_NAMESPACE diff --git a/add_on/scriptfile/scriptfile.h b/add_on/scriptfile/scriptfile.h new file mode 100644 index 0000000..748bba7 --- /dev/null +++ b/add_on/scriptfile/scriptfile.h @@ -0,0 +1,101 @@ +// +// CScriptFile +// +// This class encapsulates a FILE pointer in a reference counted class for +// use within AngelScript. +// + +#ifndef SCRIPTFILE_H +#define SCRIPTFILE_H + +//--------------------------- +// Compilation settings +// + +// Set this flag to turn on/off write support +// 0 = off +// 1 = on + +#ifndef AS_WRITE_OPS +#define AS_WRITE_OPS 1 +#endif + + + + +//--------------------------- +// Declaration +// + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include +#include + +BEGIN_AS_NAMESPACE + +class CScriptFile +{ +public: + CScriptFile(); + + void AddRef() const; + void Release() const; + + // TODO: Implement the "r+", "w+" and "a+" modes + // mode = "r" -> open the file for reading + // "w" -> open the file for writing (overwrites existing file) + // "a" -> open the file for appending + int Open(const std::string &filename, const std::string &mode); + int Close(); + int GetSize() const; + bool IsEOF() const; + + // Reading + std::string ReadString(unsigned int length); + std::string ReadLine(); + asINT64 ReadInt(asUINT bytes); + asQWORD ReadUInt(asUINT bytes); + float ReadFloat(); + double ReadDouble(); + + // Writing + int WriteString(const std::string &str); + int WriteInt(asINT64 v, asUINT bytes); + int WriteUInt(asQWORD v, asUINT bytes); + int WriteFloat(float v); + int WriteDouble(double v); + + // Cursor + int GetPos() const; + int SetPos(int pos); + int MovePos(int delta); + + // Big-endian = most significant byte first + bool mostSignificantByteFirst; + +protected: + ~CScriptFile(); + + mutable int refCount; + FILE *file; +}; + +// This function will determine the configuration of the engine +// and use one of the two functions below to register the file type +void RegisterScriptFile(asIScriptEngine *engine); + +// Call this function to register the file type +// using native calling conventions +void RegisterScriptFile_Native(asIScriptEngine *engine); + +// Use this one instead if native calling conventions +// are not supported on the target platform +void RegisterScriptFile_Generic(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptfile/scriptfilesystem.cpp b/add_on/scriptfile/scriptfilesystem.cpp new file mode 100644 index 0000000..99c6277 --- /dev/null +++ b/add_on/scriptfile/scriptfilesystem.cpp @@ -0,0 +1,629 @@ +#include "scriptfilesystem.h" +#include "../autowrapper/aswrappedcall.h" + +#if defined(_WIN32) +#include // _getcwd +#include // FindFirstFile, GetFileAttributes + +#undef DeleteFile +#undef CopyFile + +#else +#include // getcwd +#include // opendir, readdir, closedir +#include // stat +#endif +#include // assert + +using namespace std; + +BEGIN_AS_NAMESPACE + +// TODO: The file system should have a way to allow the application to define in +// which sub directories it is allowed to make changes and/or read + +CScriptFileSystem *ScriptFileSystem_Factory() +{ + return new CScriptFileSystem(); +} + +void RegisterScriptFileSystem_Native(asIScriptEngine *engine) +{ + int r; + + assert( engine->GetTypeInfoByName("string") ); + assert( engine->GetTypeInfoByDecl("array") ); + assert( engine->GetTypeInfoByName("datetime") ); + + r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", asFUNCTION(ScriptFileSystem_Factory), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptFileSystem,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptFileSystem,Release), asCALL_THISCALL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", asMETHOD(CScriptFileSystem, ChangeCurrentPath), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", asMETHOD(CScriptFileSystem, GetCurrentPath), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getDirs() const", asMETHOD(CScriptFileSystem, GetDirs), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getFiles() const", asMETHOD(CScriptFileSystem, GetFiles), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", asMETHOD(CScriptFileSystem, IsDir), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", asMETHOD(CScriptFileSystem, IsLink), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", asMETHOD(CScriptFileSystem, GetSize), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", asMETHOD(CScriptFileSystem, MakeDir), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", asMETHOD(CScriptFileSystem, RemoveDir), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", asMETHOD(CScriptFileSystem, DeleteFile), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", asMETHOD(CScriptFileSystem, CopyFile), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", asMETHOD(CScriptFileSystem, Move), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetCreateDateTime), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", asMETHOD(CScriptFileSystem, GetModifyDateTime), asCALL_THISCALL); assert(r >= 0); +} + +void RegisterScriptFileSystem_Generic(asIScriptEngine *engine) +{ + int r; + + assert( engine->GetTypeInfoByName("string") ); + assert( engine->GetTypeInfoByDecl("array") ); + assert( engine->GetTypeInfoByName("datetime") ); + + r = engine->RegisterObjectType("filesystem", 0, asOBJ_REF); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_FACTORY, "filesystem @f()", WRAP_FN(ScriptFileSystem_Factory), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_ADDREF, "void f()", WRAP_MFN(CScriptFileSystem,AddRef), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("filesystem", asBEHAVE_RELEASE, "void f()", WRAP_MFN(CScriptFileSystem,Release), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("filesystem", "bool changeCurrentPath(const string &in)", WRAP_MFN(CScriptFileSystem, ChangeCurrentPath), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "string getCurrentPath() const", WRAP_MFN(CScriptFileSystem, GetCurrentPath), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getDirs() const", WRAP_MFN(CScriptFileSystem, GetDirs), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "array @getFiles() const", WRAP_MFN(CScriptFileSystem, GetFiles), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isDir(const string &in) const", WRAP_MFN(CScriptFileSystem, IsDir), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("filesystem", "bool isLink(const string &in) const", WRAP_MFN(CScriptFileSystem, IsLink), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int64 getSize(const string &in) const", WRAP_MFN(CScriptFileSystem, GetSize), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int makeDir(const string &in)", WRAP_MFN(CScriptFileSystem, MakeDir), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int removeDir(const string &in)", WRAP_MFN(CScriptFileSystem, RemoveDir), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int deleteFile(const string &in)", WRAP_MFN(CScriptFileSystem, DeleteFile), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int copyFile(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, CopyFile), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "int move(const string &in, const string &in)", WRAP_MFN(CScriptFileSystem, Move), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getCreateDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetCreateDateTime), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("filesystem", "datetime getModifyDateTime(const string &in) const", WRAP_MFN(CScriptFileSystem, GetModifyDateTime), asCALL_GENERIC); assert(r >= 0); +} + +void RegisterScriptFileSystem(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptFileSystem_Generic(engine); + else + RegisterScriptFileSystem_Native(engine); +} + +CScriptFileSystem::CScriptFileSystem() +{ + refCount = 1; + + // Gets the application's current working directory as the starting point + // TODO: Replace backslash with slash to keep a unified naming convention + char buffer[1000]; +#if defined(_WIN32) + currentPath = _getcwd(buffer, 1000); +#else + currentPath = getcwd(buffer, 1000); +#endif +} + +CScriptFileSystem::~CScriptFileSystem() +{ +} + +void CScriptFileSystem::AddRef() const +{ + asAtomicInc(refCount); +} + +void CScriptFileSystem::Release() const +{ + if( asAtomicDec(refCount) == 0 ) + delete this; +} + +CScriptArray *CScriptFileSystem::GetFiles() const +{ + // Obtain a pointer to the engine + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + + // TODO: This should only be done once + // TODO: This assumes that CScriptArray was already registered + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); + + // Create the array object + CScriptArray *array = CScriptArray::Create(arrayType); + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + string searchPattern = currentPath + "/*"; + MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000); + + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW(bufUTF16, &ffd); + if( INVALID_HANDLE_VALUE == hFind ) + return array; + + do + { + // Skip directories + if( (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) + continue; + + // Convert the file name back to UTF8 + char bufUTF8[10000]; + WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0); + + // Add the file to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8); + } + while( FindNextFileW(hFind, &ffd) != 0 ); + + FindClose(hFind); +#else + dirent *ent = 0; + DIR *dir = opendir(currentPath.c_str()); + while( (ent = readdir(dir)) != NULL ) + { + const string filename = ent->d_name; + + // Skip . and .. + if( filename[0] == '.' ) + continue; + + // Skip sub directories + const string fullname = currentPath + "/" + filename; + struct stat st; + if( stat(fullname.c_str(), &st) == -1 ) + continue; + if( (st.st_mode & S_IFDIR) != 0 ) + continue; + + // Add the file to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(filename); + } + closedir(dir); +#endif + + return array; +} + +CScriptArray *CScriptFileSystem::GetDirs() const +{ + // Obtain a pointer to the engine + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + + // TODO: This should only be done once + // TODO: This assumes that CScriptArray was already registered + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); + + // Create the array object + CScriptArray *array = CScriptArray::Create(arrayType); + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + string searchPattern = currentPath + "/*"; + MultiByteToWideChar(CP_UTF8, 0, searchPattern.c_str(), -1, bufUTF16, 10000); + + WIN32_FIND_DATAW ffd; + HANDLE hFind = FindFirstFileW(bufUTF16, &ffd); + if( INVALID_HANDLE_VALUE == hFind ) + return array; + + do + { + // Skip files + if( !(ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) ) + continue; + + // Convert the file name back to UTF8 + char bufUTF8[10000]; + WideCharToMultiByte(CP_UTF8, 0, ffd.cFileName, -1, bufUTF8, 10000, 0, 0); + + if( strcmp(bufUTF8, ".") == 0 || strcmp(bufUTF8, "..") == 0 ) + continue; + + // Add the dir to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(bufUTF8); + } + while( FindNextFileW(hFind, &ffd) != 0 ); + + FindClose(hFind); +#else + dirent *ent = 0; + DIR *dir = opendir(currentPath.c_str()); + while( (ent = readdir(dir)) != NULL ) + { + const string filename = ent->d_name; + + // Skip . and .. + if( filename[0] == '.' ) + continue; + + // Skip files + const string fullname = currentPath + "/" + filename; + struct stat st; + if( stat(fullname.c_str(), &st) == -1 ) + continue; + if( (st.st_mode & S_IFDIR) == 0 ) + continue; + + // Add the dir to the array + array->Resize(array->GetSize()+1); + ((string*)(array->At(array->GetSize()-1)))->assign(filename); + } + closedir(dir); +#endif + + return array; +} + +// Doesn't change anything if the new path is not valid +bool CScriptFileSystem::ChangeCurrentPath(const string &path) +{ + string newPath; + if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 ) + newPath = path; + else + newPath = currentPath + "/" + path; + + // TODO: Resolve internal /./ and /../ + // TODO: Replace backslash with slash to keep a unified naming convention + + // Remove trailing slashes from the path + while(newPath.length() && (newPath[newPath.length()-1] == '/' || newPath[newPath.length()-1] == '\\') ) + newPath.resize(newPath.length()-1); + + if (!IsDir(newPath)) + return false; + + currentPath = newPath; + return true; +} + +bool CScriptFileSystem::IsDir(const string &path) const +{ + string search; + if( path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0 ) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Check if the path exists and is a directory + DWORD attrib = GetFileAttributesW(bufUTF16); + if( attrib == INVALID_FILE_ATTRIBUTES || + !(attrib & FILE_ATTRIBUTE_DIRECTORY) ) + return false; +#else + // Check if the path exists and is a directory + struct stat st; + if( stat(search.c_str(), &st) == -1 ) + return false; + if( (st.st_mode & S_IFDIR) == 0 ) + return false; +#endif + + return true; +} + +bool CScriptFileSystem::IsLink(const string &path) const +{ + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Check if the path exists and is a link + DWORD attrib = GetFileAttributesW(bufUTF16); + if (attrib == INVALID_FILE_ATTRIBUTES || + !(attrib & FILE_ATTRIBUTE_REPARSE_POINT)) + return false; +#else + // Check if the path exists and is a link + struct stat st; + if (stat(search.c_str(), &st) == -1) + return false; + if ((st.st_mode & S_IFLNK) == 0) + return false; +#endif + + return true; +} + +asINT64 CScriptFileSystem::GetSize(const string &path) const +{ + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Get the size of the file + LARGE_INTEGER largeInt; + HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + BOOL success = GetFileSizeEx(file, &largeInt); + CloseHandle(file); + if( !success ) + return -1; + return asINT64(largeInt.QuadPart); +#else + // Get the size of the file + struct stat st; + if (stat(search.c_str(), &st) == -1) + return -1; + return asINT64(st.st_size); +#endif +} + +// TODO: Should be able to return different codes for +// - directory exists +// - path not found +// - access denied +// TODO: Should be able to define the permissions for the directory +int CScriptFileSystem::MakeDir(const string &path) +{ + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Create the directory + BOOL success = CreateDirectoryW(bufUTF16, 0); + return success ? 0 : -1; +#else + // Create the directory + int failure = mkdir(search.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); + return !failure ? 0 : -1; +#endif +} + +// TODO: Should be able to return different codes for +// - directory doesn't exist +// - directory is not empty +// - access denied +// TODO: Should have an option to remove the directory and all content recursively +int CScriptFileSystem::RemoveDir(const string &path) +{ + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Remove the directory + BOOL success = RemoveDirectoryW(bufUTF16); + return success ? 0 : -1; +#else + // Remove the directory + int failure = rmdir(search.c_str()); + return !failure ? 0 : -1; +#endif +} + +int CScriptFileSystem::DeleteFile(const string &path) +{ + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Remove the file + BOOL success = DeleteFileW(bufUTF16); + return success ? 0 : -1; +#else + // Remove the file + int failure = unlink(search.c_str()); + return !failure ? 0 : -1; +#endif +} + +int CScriptFileSystem::CopyFile(const string &source, const string &target) +{ + string search1; + if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0) + search1 = source; + else + search1 = currentPath + "/" + source; + + string search2; + if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0) + search2 = target; + else + search2 = currentPath + "/" + target; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16_1[10000]; + MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000); + + wchar_t bufUTF16_2[10000]; + MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000); + + // Copy the file + BOOL success = CopyFileW(bufUTF16_1, bufUTF16_2, TRUE); + return success ? 0 : -1; +#else + // Copy the file manually as there is no posix function for this + bool failure = false; + FILE *src = 0, *tgt = 0; + src = fopen(search1.c_str(), "r"); + if (src == 0) failure = true; + if( !failure ) tgt = fopen(search2.c_str(), "w"); + if (tgt == 0) failure = true; + char buf[1024]; + size_t n; + while (!failure && (n = fread(buf, sizeof(char), sizeof(buf), src)) > 0) + { + if (fwrite(buf, sizeof(char), n, tgt) != n) + failure = true; + } + if (src) fclose(src); + if (tgt) fclose(tgt); + return !failure ? 0 : -1; +#endif +} + +int CScriptFileSystem::Move(const string &source, const string &target) +{ + string search1; + if (source.find(":") != string::npos || source.find("/") == 0 || source.find("\\") == 0) + search1 = source; + else + search1 = currentPath + "/" + source; + + string search2; + if (target.find(":") != string::npos || target.find("/") == 0 || target.find("\\") == 0) + search2 = target; + else + search2 = currentPath + "/" + target; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16_1[10000]; + MultiByteToWideChar(CP_UTF8, 0, search1.c_str(), -1, bufUTF16_1, 10000); + + wchar_t bufUTF16_2[10000]; + MultiByteToWideChar(CP_UTF8, 0, search2.c_str(), -1, bufUTF16_2, 10000); + + // Move the file or directory + BOOL success = MoveFileW(bufUTF16_1, bufUTF16_2); + return success ? 0 : -1; +#else + // Move the file or directory + int failure = rename(search1.c_str(), search2.c_str()); + return !failure ? 0 : -1; +#endif +} + +string CScriptFileSystem::GetCurrentPath() const +{ + return currentPath; +} + +CDateTime CScriptFileSystem::GetCreateDateTime(const string &path) const +{ + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Get the create date/time of the file + FILETIME createTm; + HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + BOOL success = GetFileTime(file, &createTm, 0, 0); + CloseHandle(file); + if( !success ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file creation date/time"); + return CDateTime(); + } + SYSTEMTIME tm; + FileTimeToSystemTime(&createTm, &tm); + return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); +#else + // Get the create date/time of the file + struct stat st; + if (stat(search.c_str(), &st) == -1) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file creation date/time"); + return CDateTime(); + } + tm *t = localtime(&st.st_ctime); + return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); +#endif +} + +CDateTime CScriptFileSystem::GetModifyDateTime(const string &path) const +{ + string search; + if (path.find(":") != string::npos || path.find("/") == 0 || path.find("\\") == 0) + search = path; + else + search = currentPath + "/" + path; + +#if defined(_WIN32) + // Windows uses UTF16 so it is necessary to convert the string + wchar_t bufUTF16[10000]; + MultiByteToWideChar(CP_UTF8, 0, search.c_str(), -1, bufUTF16, 10000); + + // Get the last modify date/time of the file + FILETIME modifyTm; + HANDLE file = CreateFileW(bufUTF16, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); + BOOL success = GetFileTime(file, 0, 0, &modifyTm); + CloseHandle(file); + if( !success ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file modify date/time"); + return CDateTime(); + } + SYSTEMTIME tm; + FileTimeToSystemTime(&modifyTm, &tm); + return CDateTime(tm.wYear, tm.wMonth, tm.wDay, tm.wHour, tm.wMinute, tm.wSecond); +#else + // Get the last modify date/time of the file + struct stat st; + if (stat(search.c_str(), &st) == -1) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Failed to get file modify date/time"); + return CDateTime(); + } + tm *t = localtime(&st.st_mtime); + return CDateTime(t->tm_year + 1900, t->tm_mon + 1, t->tm_mday, t->tm_hour, t->tm_min, t->tm_sec); +#endif +} + +END_AS_NAMESPACE diff --git a/add_on/scriptfile/scriptfilesystem.h b/add_on/scriptfile/scriptfilesystem.h new file mode 100644 index 0000000..5712d7c --- /dev/null +++ b/add_on/scriptfile/scriptfilesystem.h @@ -0,0 +1,78 @@ +#ifndef AS_SCRIPTFILESYSTEM_H +#define AS_SCRIPTFILESYSTEM_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include +#include + +#include "../scriptarray/scriptarray.h" +#include "../datetime/datetime.h" + +BEGIN_AS_NAMESPACE + +class CScriptFileSystem +{ +public: + CScriptFileSystem(); + + void AddRef() const; + void Release() const; + + // Sets the current path that should be used in other calls when using relative paths + // It can use relative paths too, so moving up a directory is used by passing in ".." + bool ChangeCurrentPath(const std::string &path); + std::string GetCurrentPath() const; + + // Returns true if the path is a directory. Input can be either a full path or a relative path. + // This method does not return the dirs '.' and '..' + bool IsDir(const std::string &path) const; + + // Returns true if the path is a link. Input can be either a full path or a relative path + bool IsLink(const std::string &path) const; + + // Returns the size of file. Input can be either a full path or a relative path + asINT64 GetSize(const std::string &path) const; + + // Returns a list of the files in the current path + CScriptArray *GetFiles() const; + + // Returns a list of the directories in the current path + CScriptArray *GetDirs() const; + + // Creates a new directory. Returns 0 on success + int MakeDir(const std::string &path); + + // Removes a directory. Will only remove the directory if it is empty. Returns 0 on success + int RemoveDir(const std::string &path); + + // Deletes a file. Returns 0 on success + int DeleteFile(const std::string &path); + + // Copies a file. Returns 0 on success + int CopyFile(const std::string &source, const std::string &target); + + // Moves or renames a file or directory. Returns 0 on success + int Move(const std::string &source, const std::string &target); + + // Gets the date and time of the file/dir creation + CDateTime GetCreateDateTime(const std::string &path) const; + + // Gets the date and time of the file/dir modification + CDateTime GetModifyDateTime(const std::string &path) const; + +protected: + ~CScriptFileSystem(); + + mutable int refCount; + std::string currentPath; +}; + +void RegisterScriptFileSystem(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptgrid/scriptgrid.cpp b/add_on/scriptgrid/scriptgrid.cpp new file mode 100644 index 0000000..f636267 --- /dev/null +++ b/add_on/scriptgrid/scriptgrid.cpp @@ -0,0 +1,807 @@ +#include +#include +#include +#include +#include // sprintf + +#include "scriptgrid.h" + +using namespace std; + +BEGIN_AS_NAMESPACE + +// Set the default memory routines +// Use the angelscript engine's memory routines by default +static asALLOCFUNC_t userAlloc = asAllocMem; +static asFREEFUNC_t userFree = asFreeMem; + +// Allows the application to set which memory routines should be used by the array object +void CScriptGrid::SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) +{ + userAlloc = allocFunc; + userFree = freeFunc; +} + +static void RegisterScriptGrid_Native(asIScriptEngine *engine); + +struct SGridBuffer +{ + asDWORD width; + asDWORD height; + asBYTE data[1]; +}; + +CScriptGrid *CScriptGrid::Create(asITypeInfo *ti) +{ + return CScriptGrid::Create(ti, 0, 0); +} + +CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptGrid)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptGrid *a = new(mem) CScriptGrid(w, h, ti); + + return a; +} + +CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, void *initList) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptGrid)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptGrid *a = new(mem) CScriptGrid(ti, initList); + + return a; +} + +CScriptGrid *CScriptGrid::Create(asITypeInfo *ti, asUINT w, asUINT h, void *defVal) +{ + // Allocate the memory + void *mem = userAlloc(sizeof(CScriptGrid)); + if( mem == 0 ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + + return 0; + } + + // Initialize the object + CScriptGrid *a = new(mem) CScriptGrid(w, h, defVal, ti); + + return a; +} + +// This optional callback is called when the template type is first used by the compiler. +// It allows the application to validate if the template can be instantiated for the requested +// subtype at compile time, instead of at runtime. The output argument dontGarbageCollect +// allow the callback to tell the engine if the template instance type shouldn't be garbage collected, +// i.e. no asOBJ_GC flag. +static bool ScriptGridTemplateCallback(asITypeInfo *ti, bool &dontGarbageCollect) +{ + // Make sure the subtype can be instantiated with a default factory/constructor, + // otherwise we won't be able to instantiate the elements. + int typeId = ti->GetSubTypeId(); + if( typeId == asTYPEID_VOID ) + return false; + if( (typeId & asTYPEID_MASK_OBJECT) && !(typeId & asTYPEID_OBJHANDLE) ) + { + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( (flags & asOBJ_VALUE) && !(flags & asOBJ_POD) ) + { + // Verify that there is a default constructor + bool found = false; + for( asUINT n = 0; n < subtype->GetBehaviourCount(); n++ ) + { + asEBehaviours beh; + asIScriptFunction *func = subtype->GetBehaviourByIndex(n, &beh); + if( beh != asBEHAVE_CONSTRUCT ) continue; + + if( func->GetParamCount() == 0 ) + { + // Found the default constructor + found = true; + break; + } + } + + if( !found ) + { + // There is no default constructor + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default constructor"); + return false; + } + } + else if( (flags & asOBJ_REF) ) + { + bool found = false; + + // If value assignment for ref type has been disabled then the array + // can be created if the type has a default factory function + if( !ti->GetEngine()->GetEngineProperty(asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE) ) + { + // Verify that there is a default factory + for( asUINT n = 0; n < subtype->GetFactoryCount(); n++ ) + { + asIScriptFunction *func = subtype->GetFactoryByIndex(n); + if( func->GetParamCount() == 0 ) + { + // Found the default factory + found = true; + break; + } + } + } + + if( !found ) + { + // No default factory + ti->GetEngine()->WriteMessage("array", 0, 0, asMSGTYPE_ERROR, "The subtype has no default factory"); + return false; + } + } + + // If the object type is not garbage collected then the array also doesn't need to be + if( !(flags & asOBJ_GC) ) + dontGarbageCollect = true; + } + else if( !(typeId & asTYPEID_OBJHANDLE) ) + { + // Arrays with primitives cannot form circular references, + // thus there is no need to garbage collect them + dontGarbageCollect = true; + } + else + { + assert( typeId & asTYPEID_OBJHANDLE ); + + // It is not necessary to set the array as garbage collected for all handle types. + // If it is possible to determine that the handle cannot refer to an object type + // that can potentially form a circular reference with the array then it is not + // necessary to make the array garbage collected. + asITypeInfo *subtype = ti->GetEngine()->GetTypeInfoById(typeId); + asDWORD flags = subtype->GetFlags(); + if( !(flags & asOBJ_GC) ) + { + if( (flags & asOBJ_SCRIPT_OBJECT) ) + { + // Even if a script class is by itself not garbage collected, it is possible + // that classes that derive from it may be, so it is not possible to know + // that no circular reference can occur. + if( (flags & asOBJ_NOINHERIT) ) + { + // A script class declared as final cannot be inherited from, thus + // we can be certain that the object cannot be garbage collected. + dontGarbageCollect = true; + } + } + else + { + // For application registered classes we assume the application knows + // what it is doing and don't mark the array as garbage collected unless + // the type is also garbage collected. + dontGarbageCollect = true; + } + } + } + + // The type is ok + return true; +} + +// Registers the template array type +void RegisterScriptGrid(asIScriptEngine *engine) +{ + // TODO: Implement the generic calling convention + RegisterScriptGrid_Native(engine); +} + +static void RegisterScriptGrid_Native(asIScriptEngine *engine) +{ + int r; + + // Register the grid type as a template + r = engine->RegisterObjectType("grid", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 ); + + // Register a callback for validating the subtype before it is used + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptGridTemplateCallback), asCALL_CDECL); assert( r >= 0 ); + + // Templates receive the object type as the first parameter. To the script writer this is hidden + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in, uint, uint)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, asUINT, asUINT), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_FACTORY, "grid@ f(int&in, uint, uint, const T &in)", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, asUINT, asUINT, void *), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); + + // Register the factory that will be used for initialization lists + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_LIST_FACTORY, "grid@ f(int&in type, int&in list) {repeat {repeat_same T}}", asFUNCTIONPR(CScriptGrid::Create, (asITypeInfo*, void*), CScriptGrid*), asCALL_CDECL); assert( r >= 0 ); + + // The memory management methods + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_ADDREF, "void f()", asMETHOD(CScriptGrid,AddRef), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_RELEASE, "void f()", asMETHOD(CScriptGrid,Release), asCALL_THISCALL); assert( r >= 0 ); + + // The index operator returns the template subtype + r = engine->RegisterObjectMethod("grid", "T &opIndex(uint, uint)", asMETHODPR(CScriptGrid, At, (asUINT, asUINT), void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("grid", "const T &opIndex(uint, uint) const", asMETHODPR(CScriptGrid, At, (asUINT, asUINT) const, const void*), asCALL_THISCALL); assert( r >= 0 ); + + // Other methods + r = engine->RegisterObjectMethod("grid", "void resize(uint width, uint height)", asMETHODPR(CScriptGrid, Resize, (asUINT, asUINT), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("grid", "uint width() const", asMETHOD(CScriptGrid, GetWidth), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("grid", "uint height() const", asMETHOD(CScriptGrid, GetHeight), asCALL_THISCALL); assert( r >= 0 ); + + // Register GC behaviours in case the array needs to be garbage collected + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CScriptGrid, GetRefCount), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CScriptGrid, SetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CScriptGrid, GetFlag), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptGrid, EnumReferences), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("grid", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptGrid, ReleaseAllHandles), asCALL_THISCALL); assert( r >= 0 ); +} + +CScriptGrid::CScriptGrid(asITypeInfo *ti, void *buf) +{ + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + subTypeId = objType->GetSubTypeId(); + + asIScriptEngine *engine = ti->GetEngine(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = engine->GetSizeOfPrimitiveType(subTypeId); + + // Determine the initial size from the buffer + asUINT height = *(asUINT*)buf; + asUINT width = height ? *(asUINT*)((char*)(buf)+4) : 0; + + // Make sure the grid size isn't too large for us to handle + if( !CheckMaxSize(width, height) ) + { + // Don't continue with the initialization + return; + } + + // Skip the height value at the start of the buffer + buf = (asUINT*)(buf)+1; + + // Copy the values of the grid elements from the buffer + if( (ti->GetSubTypeId() & asTYPEID_MASK_OBJECT) == 0 ) + { + CreateBuffer(&buffer, width, height); + + // Copy the values of the primitive type into the internal buffer + for( asUINT y = 0; y < height; y++ ) + { + // Skip the length value at the start of each row + buf = (asUINT*)(buf)+1; + + // Copy the line + if( width > 0 ) + memcpy(At(0,y), buf, width*elementSize); + + // Move to next line + buf = (char*)(buf) + width*elementSize; + + // Align to 4 byte boundary + if( asPWORD(buf) & 0x3 ) + buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); + } + } + else if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) + { + CreateBuffer(&buffer, width, height); + + // Copy the handles into the internal buffer + for( asUINT y = 0; y < height; y++ ) + { + // Skip the length value at the start of each row + buf = (asUINT*)(buf)+1; + + // Copy the line + if( width > 0 ) + memcpy(At(0,y), buf, width*elementSize); + + // With object handles it is safe to clear the memory in the received buffer + // instead of increasing the ref count. It will save time both by avoiding the + // call the increase ref, and also relieve the engine from having to release + // its references too + memset(buf, 0, width*elementSize); + + // Move to next line + buf = (char*)(buf) + width*elementSize; + + // Align to 4 byte boundary + if( asPWORD(buf) & 0x3 ) + buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); + } + } + else if( ti->GetSubType()->GetFlags() & asOBJ_REF ) + { + // Only allocate the buffer, but not the objects + subTypeId |= asTYPEID_OBJHANDLE; + CreateBuffer(&buffer, width, height); + subTypeId &= ~asTYPEID_OBJHANDLE; + + // Copy the handles into the internal buffer + for( asUINT y = 0; y < height; y++ ) + { + // Skip the length value at the start of each row + buf = (asUINT*)(buf)+1; + + // Copy the line + if( width > 0 ) + memcpy(At(0,y), buf, width*elementSize); + + // With object handles it is safe to clear the memory in the received buffer + // instead of increasing the ref count. It will save time both by avoiding the + // call the increase ref, and also relieve the engine from having to release + // its references too + memset(buf, 0, width*elementSize); + + // Move to next line + buf = (char*)(buf) + width*elementSize; + + // Align to 4 byte boundary + if( asPWORD(buf) & 0x3 ) + buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); + } + } + else + { + // TODO: Optimize by calling the copy constructor of the object instead of + // constructing with the default constructor and then assigning the value + // TODO: With C++11 ideally we should be calling the move constructor, instead + // of the copy constructor as the engine will just discard the objects in the + // buffer afterwards. + CreateBuffer(&buffer, width, height); + + // For value types we need to call the opAssign for each individual object + asITypeInfo *subType = ti->GetSubType(); + asUINT subTypeSize = subType->GetSize(); + for( asUINT y = 0;y < height; y++ ) + { + // Skip the length value at the start of each row + buf = (asUINT*)(buf)+1; + + // Call opAssign for each of the objects on the row + for( asUINT x = 0; x < width; x++ ) + { + void *obj = At(x,y); + asBYTE *srcObj = (asBYTE*)(buf) + x*subTypeSize; + engine->AssignScriptObject(obj, srcObj, subType); + } + + // Move to next line + buf = (char*)(buf) + width*subTypeSize; + + // Align to 4 byte boundary + if( asPWORD(buf) & 0x3 ) + buf = (char*)(buf) + 4 - (asPWORD(buf) & 0x3); + } + } + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); +} + +CScriptGrid::CScriptGrid(asUINT width, asUINT height, asITypeInfo *ti) +{ + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + subTypeId = objType->GetSubTypeId(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(width, height) ) + { + // Don't continue with the initialization + return; + } + + CreateBuffer(&buffer, width, height); + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); +} + +void CScriptGrid::Resize(asUINT width, asUINT height) +{ + // Make sure the size isn't too large for us to handle + if( !CheckMaxSize(width, height) ) + return; + + // Create a new buffer + SGridBuffer *tmpBuffer = 0; + CreateBuffer(&tmpBuffer, width, height); + if( tmpBuffer == 0 ) + return; + + if( buffer ) + { + // Copy the existing values to the new buffer + asUINT w = width > buffer->width ? buffer->width : width; + asUINT h = height > buffer->height ? buffer->height : height; + for( asUINT y = 0; y < h; y++ ) + for( asUINT x = 0; x < w; x++ ) + SetValue(tmpBuffer, x, y, At(buffer, x, y)); + + // Replace the internal buffer + DeleteBuffer(buffer); + } + + buffer = tmpBuffer; +} + +CScriptGrid::CScriptGrid(asUINT width, asUINT height, void *defVal, asITypeInfo *ti) +{ + refCount = 1; + gcFlag = false; + objType = ti; + objType->AddRef(); + buffer = 0; + subTypeId = objType->GetSubTypeId(); + + // Determine element size + if( subTypeId & asTYPEID_MASK_OBJECT ) + elementSize = sizeof(asPWORD); + else + elementSize = objType->GetEngine()->GetSizeOfPrimitiveType(subTypeId); + + // Make sure the array size isn't too large for us to handle + if( !CheckMaxSize(width, height) ) + { + // Don't continue with the initialization + return; + } + + CreateBuffer(&buffer, width, height); + + // Notify the GC of the successful creation + if( objType->GetFlags() & asOBJ_GC ) + objType->GetEngine()->NotifyGarbageCollectorOfNewObject(this, objType); + + // Initialize the elements with the default value + for( asUINT y = 0; y < GetHeight(); y++ ) + for( asUINT x = 0; x < GetWidth(); x++ ) + SetValue(x, y, defVal); +} + +void CScriptGrid::SetValue(asUINT x, asUINT y, void *value) +{ + SetValue(buffer, x, y, value); +} + +void CScriptGrid::SetValue(SGridBuffer *buf, asUINT x, asUINT y, void *value) +{ + // At() will take care of the out-of-bounds checking, though + // if called from the application then nothing will be done + void *ptr = At(buf, x, y); + if( ptr == 0 ) return; + + if( (subTypeId & ~asTYPEID_MASK_SEQNBR) && !(subTypeId & asTYPEID_OBJHANDLE) ) + objType->GetEngine()->AssignScriptObject(ptr, value, objType->GetSubType()); + else if( subTypeId & asTYPEID_OBJHANDLE ) + { + void *tmp = *(void**)ptr; + *(void**)ptr = *(void**)value; + objType->GetEngine()->AddRefScriptObject(*(void**)value, objType->GetSubType()); + if( tmp ) + objType->GetEngine()->ReleaseScriptObject(tmp, objType->GetSubType()); + } + else if( subTypeId == asTYPEID_BOOL || + subTypeId == asTYPEID_INT8 || + subTypeId == asTYPEID_UINT8 ) + *(char*)ptr = *(char*)value; + else if( subTypeId == asTYPEID_INT16 || + subTypeId == asTYPEID_UINT16 ) + *(short*)ptr = *(short*)value; + else if( subTypeId == asTYPEID_INT32 || + subTypeId == asTYPEID_UINT32 || + subTypeId == asTYPEID_FLOAT || + subTypeId > asTYPEID_DOUBLE ) // enums have a type id larger than doubles + *(int*)ptr = *(int*)value; + else if( subTypeId == asTYPEID_INT64 || + subTypeId == asTYPEID_UINT64 || + subTypeId == asTYPEID_DOUBLE ) + *(double*)ptr = *(double*)value; +} + +CScriptGrid::~CScriptGrid() +{ + if( buffer ) + { + DeleteBuffer(buffer); + buffer = 0; + } + if( objType ) objType->Release(); +} + +asUINT CScriptGrid::GetWidth() const +{ + if( buffer ) + return buffer->width; + + return 0; +} + +asUINT CScriptGrid::GetHeight() const +{ + if( buffer ) + return buffer->height; + + return 0; +} + +// internal +bool CScriptGrid::CheckMaxSize(asUINT width, asUINT height) +{ + // This code makes sure the size of the buffer that is allocated + // for the array doesn't overflow and becomes smaller than requested + + asUINT maxSize = 0xFFFFFFFFul - sizeof(SGridBuffer) + 1; + if( elementSize > 0 ) + maxSize /= elementSize; + + asINT64 numElements = width * height; + + if( (numElements >> 32) || numElements > maxSize ) + { + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Too large grid size"); + + return false; + } + + // OK + return true; +} + +asITypeInfo *CScriptGrid::GetGridObjectType() const +{ + return objType; +} + +int CScriptGrid::GetGridTypeId() const +{ + return objType->GetTypeId(); +} + +int CScriptGrid::GetElementTypeId() const +{ + return subTypeId; +} + +void *CScriptGrid::At(asUINT x, asUINT y) +{ + return At(buffer, x, y); +} + +// Return a pointer to the array element. Returns 0 if the index is out of bounds +void *CScriptGrid::At(SGridBuffer *buf, asUINT x, asUINT y) +{ + if( buf == 0 || x >= buf->width || y >= buf->height ) + { + // If this is called from a script we raise a script exception + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Index out of bounds"); + return 0; + } + + asUINT index = x+y*buf->width; + if( (subTypeId & asTYPEID_MASK_OBJECT) && !(subTypeId & asTYPEID_OBJHANDLE) ) + return *(void**)(buf->data + elementSize*index); + else + return buf->data + elementSize*index; +} +const void *CScriptGrid::At(asUINT x, asUINT y) const +{ + return const_cast(this)->At(const_cast(buffer), x, y); +} + + +// internal +void CScriptGrid::CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h) +{ + asUINT numElements = w * h; + + *buf = reinterpret_cast(userAlloc(sizeof(SGridBuffer)-1+elementSize*numElements)); + + if( *buf ) + { + (*buf)->width = w; + (*buf)->height = h; + Construct(*buf); + } + else + { + // Oops, out of memory + asIScriptContext *ctx = asGetActiveContext(); + if( ctx ) + ctx->SetException("Out of memory"); + } +} + +// internal +void CScriptGrid::DeleteBuffer(SGridBuffer *buf) +{ + assert( buf ); + + Destruct(buf); + + // Free the buffer + userFree(buf); +} + +// internal +void CScriptGrid::Construct(SGridBuffer *buf) +{ + assert( buf ); + + if( subTypeId & asTYPEID_OBJHANDLE ) + { + // Set all object handles to null + void *d = (void*)(buf->data); + memset(d, 0, (buf->width*buf->height)*sizeof(void*)); + } + else if( subTypeId & asTYPEID_MASK_OBJECT ) + { + void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*)); + void **d = (void**)(buf->data); + + asIScriptEngine *engine = objType->GetEngine(); + asITypeInfo *subType = objType->GetSubType(); + + for( ; d < max; d++ ) + { + *d = (void*)engine->CreateScriptObject(subType); + if( *d == 0 ) + { + // Set the remaining entries to null so the destructor + // won't attempt to destroy invalid objects later + memset(d, 0, sizeof(void*)*(max-d)); + + // There is no need to set an exception on the context, + // as CreateScriptObject has already done that + return; + } + } + } +} + +// internal +void CScriptGrid::Destruct(SGridBuffer *buf) +{ + assert( buf ); + + if( subTypeId & asTYPEID_MASK_OBJECT ) + { + asIScriptEngine *engine = objType->GetEngine(); + + void **max = (void**)(buf->data + (buf->width*buf->height) * sizeof(void*)); + void **d = (void**)(buf->data); + + for( ; d < max; d++ ) + { + if( *d ) + engine->ReleaseScriptObject(*d, objType->GetSubType()); + } + } +} + +// GC behaviour +void CScriptGrid::EnumReferences(asIScriptEngine *engine) +{ + if( buffer == 0 ) return; + + // If the grid is holding handles, then we need to notify the GC of them + if (subTypeId & asTYPEID_MASK_OBJECT) + { + asUINT numElements = buffer->width * buffer->height; + void **d = (void**)buffer->data; + asITypeInfo *subType = engine->GetTypeInfoById(subTypeId); + if ((subType->GetFlags() & asOBJ_REF)) + { + // For reference types we need to notify the GC of each instance + for (asUINT n = 0; n < numElements; n++) + { + if (d[n]) + engine->GCEnumCallback(d[n]); + } + } + else if ((subType->GetFlags() & asOBJ_VALUE) && (subType->GetFlags() & asOBJ_GC)) + { + // For value types we need to forward the enum callback + // to the object so it can decide what to do + for (asUINT n = 0; n < numElements; n++) + { + if (d[n]) + engine->ForwardGCEnumReferences(d[n], subType); + } + } + } +} + +// GC behaviour +void CScriptGrid::ReleaseAllHandles(asIScriptEngine*) +{ + if( buffer == 0 ) return; + + DeleteBuffer(buffer); + buffer = 0; +} + +void CScriptGrid::AddRef() const +{ + // Clear the GC flag then increase the counter + gcFlag = false; + asAtomicInc(refCount); +} + +void CScriptGrid::Release() const +{ + // Clearing the GC flag then descrease the counter + gcFlag = false; + if( asAtomicDec(refCount) == 0 ) + { + // When reaching 0 no more references to this instance + // exists and the object should be destroyed + this->~CScriptGrid(); + userFree(const_cast(this)); + } +} + +// GC behaviour +int CScriptGrid::GetRefCount() +{ + return refCount; +} + +// GC behaviour +void CScriptGrid::SetFlag() +{ + gcFlag = true; +} + +// GC behaviour +bool CScriptGrid::GetFlag() +{ + return gcFlag; +} + +END_AS_NAMESPACE diff --git a/add_on/scriptgrid/scriptgrid.h b/add_on/scriptgrid/scriptgrid.h new file mode 100644 index 0000000..feeb167 --- /dev/null +++ b/add_on/scriptgrid/scriptgrid.h @@ -0,0 +1,82 @@ +#ifndef SCRIPTGRID_H +#define SCRIPTGRID_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +BEGIN_AS_NAMESPACE + +struct SGridBuffer; + +class CScriptGrid +{ +public: + // Set the memory functions that should be used by all CScriptGrids + static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); + + // Factory functions + static CScriptGrid *Create(asITypeInfo *ot); + static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height); + static CScriptGrid *Create(asITypeInfo *ot, asUINT width, asUINT height, void *defaultValue); + static CScriptGrid *Create(asITypeInfo *ot, void *listBuffer); + + // Memory management + void AddRef() const; + void Release() const; + + // Type information + asITypeInfo *GetGridObjectType() const; + int GetGridTypeId() const; + int GetElementTypeId() const; + + // Size + asUINT GetWidth() const; + asUINT GetHeight() const; + void Resize(asUINT width, asUINT height); + + // Get a pointer to an element. Returns 0 if out of bounds + void *At(asUINT x, asUINT y); + const void *At(asUINT x, asUINT y) const; + + // Set value of an element + // Remember, if the grid holds handles the value parameter should be the + // address of the handle. The refCount of the object will also be incremented + void SetValue(asUINT x, asUINT y, void *value); + + // GC methods + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); + +protected: + mutable int refCount; + mutable bool gcFlag; + asITypeInfo *objType; + SGridBuffer *buffer; + int elementSize; + int subTypeId; + + // Constructors + CScriptGrid(asITypeInfo *ot, void *initBuf); // Called from script when initialized with list + CScriptGrid(asUINT w, asUINT h, asITypeInfo *ot); + CScriptGrid(asUINT w, asUINT h, void *defVal, asITypeInfo *ot); + virtual ~CScriptGrid(); + + bool CheckMaxSize(asUINT x, asUINT y); + void CreateBuffer(SGridBuffer **buf, asUINT w, asUINT h); + void DeleteBuffer(SGridBuffer *buf); + void Construct(SGridBuffer *buf); + void Destruct(SGridBuffer *buf); + void SetValue(SGridBuffer *buf, asUINT x, asUINT y, void *value); + void *At(SGridBuffer *buf, asUINT x, asUINT y); +}; + +void RegisterScriptGrid(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scripthandle/scripthandle.cpp b/add_on/scripthandle/scripthandle.cpp new file mode 100644 index 0000000..df6cbbe --- /dev/null +++ b/add_on/scripthandle/scripthandle.cpp @@ -0,0 +1,360 @@ +#include "scripthandle.h" +#include +#include +#include + +BEGIN_AS_NAMESPACE + +static void Construct(CScriptHandle *self) { new(self) CScriptHandle(); } +static void Construct(CScriptHandle *self, const CScriptHandle &o) { new(self) CScriptHandle(o); } +// This one is not static because it needs to be friend with the CScriptHandle class +void Construct(CScriptHandle *self, void *ref, int typeId) { new(self) CScriptHandle(ref, typeId); } +static void Destruct(CScriptHandle *self) { self->~CScriptHandle(); } + +CScriptHandle::CScriptHandle() +{ + m_ref = 0; + m_type = 0; +} + +CScriptHandle::CScriptHandle(const CScriptHandle &other) +{ + m_ref = other.m_ref; + m_type = other.m_type; + + AddRefHandle(); +} + +CScriptHandle::CScriptHandle(void *ref, asITypeInfo *type) +{ + m_ref = ref; + m_type = type; + + AddRefHandle(); +} + +// This constructor shouldn't be called from the application +// directly as it requires an active script context +CScriptHandle::CScriptHandle(void *ref, int typeId) +{ + m_ref = 0; + m_type = 0; + + Assign(ref, typeId); +} + +CScriptHandle::~CScriptHandle() +{ + ReleaseHandle(); +} + +void CScriptHandle::ReleaseHandle() +{ + if( m_ref && m_type ) + { + asIScriptEngine *engine = m_type->GetEngine(); + engine->ReleaseScriptObject(m_ref, m_type); + + engine->Release(); + + m_ref = 0; + m_type = 0; + } +} + +void CScriptHandle::AddRefHandle() +{ + if( m_ref && m_type ) + { + asIScriptEngine *engine = m_type->GetEngine(); + engine->AddRefScriptObject(m_ref, m_type); + + // Hold on to the engine so it isn't destroyed while + // a reference to a script object is still held + engine->AddRef(); + } +} + +CScriptHandle &CScriptHandle::operator =(const CScriptHandle &other) +{ + Set(other.m_ref, other.m_type); + + return *this; +} + +void CScriptHandle::Set(void *ref, asITypeInfo *type) +{ + if( m_ref == ref ) return; + + ReleaseHandle(); + + m_ref = ref; + m_type = type; + + AddRefHandle(); +} + +void *CScriptHandle::GetRef() +{ + return m_ref; +} + +asITypeInfo *CScriptHandle::GetType() const +{ + return m_type; +} + +int CScriptHandle::GetTypeId() const +{ + if( m_type == 0 ) return 0; + + return m_type->GetTypeId() | asTYPEID_OBJHANDLE; +} + +// This method shouldn't be called from the application +// directly as it requires an active script context +CScriptHandle &CScriptHandle::Assign(void *ref, int typeId) +{ + // When receiving a null handle we just clear our memory + if( typeId == 0 ) + { + Set(0, 0); + return *this; + } + + // Dereference received handles to get the object + if( typeId & asTYPEID_OBJHANDLE ) + { + // Store the actual reference + ref = *(void**)ref; + typeId &= ~asTYPEID_OBJHANDLE; + } + + // Get the object type + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + asITypeInfo *type = engine->GetTypeInfoById(typeId); + + // If the argument is another CScriptHandle, we should copy the content instead + if( type && strcmp(type->GetName(), "ref") == 0 ) + { + CScriptHandle *r = (CScriptHandle*)ref; + ref = r->m_ref; + type = r->m_type; + } + + Set(ref, type); + + return *this; +} + +bool CScriptHandle::operator==(const CScriptHandle &o) const +{ + if( m_ref == o.m_ref && + m_type == o.m_type ) + return true; + + // TODO: If type is not the same, we should attempt to do a dynamic cast, + // which may change the pointer for application registered classes + + return false; +} + +bool CScriptHandle::operator!=(const CScriptHandle &o) const +{ + return !(*this == o); +} + +bool CScriptHandle::Equals(void *ref, int typeId) const +{ + // Null handles are received as reference to a null handle + if( typeId == 0 ) + ref = 0; + + // Dereference handles to get the object + if( typeId & asTYPEID_OBJHANDLE ) + { + // Compare the actual reference + ref = *(void**)ref; + typeId &= ~asTYPEID_OBJHANDLE; + } + + // TODO: If typeId is not the same, we should attempt to do a dynamic cast, + // which may change the pointer for application registered classes + + if( ref == m_ref ) return true; + + return false; +} + +// AngelScript: used as '@obj = cast(ref);' +void CScriptHandle::Cast(void **outRef, int typeId) +{ + // If we hold a null handle, then just return null + if( m_type == 0 ) + { + *outRef = 0; + return; + } + + // It is expected that the outRef is always a handle + assert( typeId & asTYPEID_OBJHANDLE ); + + // Compare the type id of the actual object + typeId &= ~asTYPEID_OBJHANDLE; + asIScriptEngine *engine = m_type->GetEngine(); + asITypeInfo *type = engine->GetTypeInfoById(typeId); + + *outRef = 0; + + // RefCastObject will increment the refCount of the returned object if successful + engine->RefCastObject(m_ref, m_type, type, outRef); +} + +void CScriptHandle::EnumReferences(asIScriptEngine *inEngine) +{ + // If we're holding a reference, we'll notify the garbage collector of it + if (m_ref) + inEngine->GCEnumCallback(m_ref); + + // The object type itself is also garbage collected + if( m_type) + inEngine->GCEnumCallback(m_type); +} + +void CScriptHandle::ReleaseReferences(asIScriptEngine *inEngine) +{ + // Simply clear the content to release the references + Set(0, 0); +} + +void RegisterScriptHandle_Native(asIScriptEngine *engine) +{ + int r; + +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the flags that represent the C++ class + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); +#endif + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTIONPR(Construct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTIONPR(Construct, (CScriptHandle *, const CScriptHandle &), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTIONPR(Construct, (CScriptHandle *, void *, int), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTIONPR(Destruct, (CScriptHandle *), void), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CScriptHandle,EnumReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CScriptHandle, ReleaseReferences), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asMETHODPR(CScriptHandle, Cast, (void **, int), void), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asMETHOD(CScriptHandle, operator=), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asMETHOD(CScriptHandle, Assign), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asMETHODPR(CScriptHandle, operator==, (const CScriptHandle &) const, bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asMETHODPR(CScriptHandle, Equals, (void*, int) const, bool), asCALL_THISCALL); assert( r >= 0 ); +} + +void CScriptHandle_Construct_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + new(self) CScriptHandle(); +} + +void CScriptHandle_ConstructCopy_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + new(self) CScriptHandle(*other); +} + +void CScriptHandle_ConstructVar_Generic(asIScriptGeneric *gen) +{ + void *ref = gen->GetArgAddress(0); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + Construct(self, ref, typeId); +} + +void CScriptHandle_Destruct_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->~CScriptHandle(); +} + +void CScriptHandle_Cast_Generic(asIScriptGeneric *gen) +{ + void **ref = reinterpret_cast(gen->GetArgAddress(0)); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->Cast(ref, typeId); +} + +void CScriptHandle_Assign_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + *self = *other; + gen->SetReturnAddress(self); +} + +void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen) +{ + void *ref = gen->GetArgAddress(0); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->Assign(ref, typeId); + gen->SetReturnAddress(self); +} + +void CScriptHandle_Equals_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnByte(*self == *other); +} + +void CScriptHandle_EqualsVar_Generic(asIScriptGeneric *gen) +{ + void *ref = gen->GetArgAddress(0); + int typeId = gen->GetArgTypeId(0); + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnByte(self->Equals(ref, typeId)); +} + +void CScriptHandle_EnumReferences_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->EnumReferences(gen->GetEngine()); +} + +void CScriptHandle_ReleaseReferences_Generic(asIScriptGeneric *gen) +{ + CScriptHandle *self = reinterpret_cast(gen->GetObject()); + self->ReleaseReferences(gen->GetEngine()); +} + +void RegisterScriptHandle_Generic(asIScriptEngine *engine) +{ + int r; + + r = engine->RegisterObjectType("ref", sizeof(CScriptHandle), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_GC | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(CScriptHandle_Construct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ref &in)", asFUNCTION(CScriptHandle_ConstructCopy_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_CONSTRUCT, "void f(const ?&in)", asFUNCTION(CScriptHandle_ConstructVar_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(CScriptHandle_Destruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(CScriptHandle_EnumReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(CScriptHandle_ReleaseReferences_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("ref", "void opCast(?&out)", asFUNCTION(CScriptHandle_Cast_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ref &in)", asFUNCTION(CScriptHandle_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "ref &opHndlAssign(const ?&in)", asFUNCTION(CScriptHandle_AssignVar_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ref &in) const", asFUNCTION(CScriptHandle_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("ref", "bool opEquals(const ?&in) const", asFUNCTION(CScriptHandle_EqualsVar_Generic), asCALL_GENERIC); assert( r >= 0 ); +} + +void RegisterScriptHandle(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptHandle_Generic(engine); + else + RegisterScriptHandle_Native(engine); +} + + +END_AS_NAMESPACE diff --git a/add_on/scripthandle/scripthandle.h b/add_on/scripthandle/scripthandle.h new file mode 100644 index 0000000..7adf1b7 --- /dev/null +++ b/add_on/scripthandle/scripthandle.h @@ -0,0 +1,69 @@ +#ifndef SCRIPTHANDLE_H +#define SCRIPTHANDLE_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +class CScriptHandle +{ +public: + // Constructors + CScriptHandle(); + CScriptHandle(const CScriptHandle &other); + CScriptHandle(void *ref, asITypeInfo *type); + ~CScriptHandle(); + + // Copy the stored value from another any object + CScriptHandle &operator=(const CScriptHandle &other); + + // Set the reference + void Set(void *ref, asITypeInfo *type); + + // Compare equalness + bool operator==(const CScriptHandle &o) const; + bool operator!=(const CScriptHandle &o) const; + bool Equals(void *ref, int typeId) const; + + // Dynamic cast to desired handle type + void Cast(void **outRef, int typeId); + + // Returns the type of the reference held + asITypeInfo *GetType() const; + int GetTypeId() const; + + // Get the reference + void *GetRef(); + + // GC callback + void EnumReferences(asIScriptEngine *engine); + void ReleaseReferences(asIScriptEngine *engine); + +protected: + // These functions need to have access to protected + // members in order to call them from the script engine + friend void Construct(CScriptHandle *self, void *ref, int typeId); + friend void RegisterScriptHandle_Native(asIScriptEngine *engine); + friend void CScriptHandle_AssignVar_Generic(asIScriptGeneric *gen); + + void ReleaseHandle(); + void AddRefHandle(); + + // These shouldn't be called directly by the + // application as they requires an active context + CScriptHandle(void *ref, int typeId); + CScriptHandle &Assign(void *ref, int typeId); + + void *m_ref; + asITypeInfo *m_type; +}; + +void RegisterScriptHandle(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scripthelper/scripthelper.cpp b/add_on/scripthelper/scripthelper.cpp new file mode 100644 index 0000000..4af4fde --- /dev/null +++ b/add_on/scripthelper/scripthelper.cpp @@ -0,0 +1,987 @@ +#include +#include "scripthelper.h" +#include +#include +#include +#include +#include + +using namespace std; + +BEGIN_AS_NAMESPACE + +int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result) +{ + // TODO: If a lot of script objects are going to be compared, e.g. when sorting an array, + // then the method id and context should be cached between calls. + + int retval = -1; + asIScriptFunction *func = 0; + + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti ) + { + // Check if the object type has a compatible opCmp method + for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) + { + asIScriptFunction *f = ti->GetMethodByIndex(n); + asDWORD flags; + if( strcmp(f->GetName(), "opCmp") == 0 && + f->GetReturnTypeId(&flags) == asTYPEID_INT32 && + flags == asTM_NONE && + f->GetParamCount() == 1 ) + { + int paramTypeId; + f->GetParam(0, ¶mTypeId, &flags); + + // The parameter must be an input reference of the same type + // If the reference is a inout reference, then it must also be read-only + if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) + break; + + // Found the method + func = f; + break; + } + } + } + + if( func ) + { + // Call the method + asIScriptContext *ctx = engine->CreateContext(); + ctx->Prepare(func); + ctx->SetObject(lobj); + ctx->SetArgAddress(0, robj); + int r = ctx->Execute(); + if( r == asEXECUTION_FINISHED ) + { + result = (int)ctx->GetReturnDWord(); + + // The comparison was successful + retval = 0; + } + ctx->Release(); + } + + return retval; +} + +int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result) +{ + // TODO: If a lot of script objects are going to be compared, e.g. when searching for an + // entry in a set, then the method and context should be cached between calls. + + int retval = -1; + asIScriptFunction *func = 0; + + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if( ti ) + { + // Check if the object type has a compatible opEquals method + for( asUINT n = 0; n < ti->GetMethodCount(); n++ ) + { + asIScriptFunction *f = ti->GetMethodByIndex(n); + asDWORD flags; + if( strcmp(f->GetName(), "opEquals") == 0 && + f->GetReturnTypeId(&flags) == asTYPEID_BOOL && + flags == asTM_NONE && + f->GetParamCount() == 1 ) + { + int paramTypeId; + f->GetParam(0, ¶mTypeId, &flags); + + // The parameter must be an input reference of the same type + // If the reference is a inout reference, then it must also be read-only + if( !(flags & asTM_INREF) || typeId != paramTypeId || ((flags & asTM_OUTREF) && !(flags & asTM_CONST)) ) + break; + + // Found the method + func = f; + break; + } + } + } + + if( func ) + { + // Call the method + asIScriptContext *ctx = engine->CreateContext(); + ctx->Prepare(func); + ctx->SetObject(lobj); + ctx->SetArgAddress(0, robj); + int r = ctx->Execute(); + if( r == asEXECUTION_FINISHED ) + { + result = ctx->GetReturnByte() ? true : false; + + // The comparison was successful + retval = 0; + } + ctx->Release(); + } + else + { + // If the opEquals method doesn't exist, then we try with opCmp instead + int relation; + retval = CompareRelation(engine, lobj, robj, typeId, relation); + if( retval >= 0 ) + result = relation == 0 ? true : false; + } + + return retval; +} + +int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod, asIScriptContext *ctx) +{ + return ExecuteString(engine, code, 0, asTYPEID_VOID, mod, ctx); +} + +int ExecuteString(asIScriptEngine *engine, const char *code, void *ref, int refTypeId, asIScriptModule *mod, asIScriptContext *ctx) +{ + // Wrap the code in a function so that it can be compiled and executed + string funcCode = " ExecuteString() {\n"; + funcCode += code; + funcCode += "\n;}"; + + // Determine the return type based on the type of the ref arg + funcCode = engine->GetTypeDeclaration(refTypeId, true) + funcCode; + + // GetModule will free unused types, so to be on the safe side we'll hold on to a reference to the type + asITypeInfo *type = 0; + if( refTypeId & asTYPEID_MASK_OBJECT ) + { + type = engine->GetTypeInfoById(refTypeId); + if( type ) + type->AddRef(); + } + + // If no module was provided, get a dummy from the engine + asIScriptModule *execMod = mod ? mod : engine->GetModule("ExecuteString", asGM_ALWAYS_CREATE); + + // Now it's ok to release the type + if( type ) + type->Release(); + + // Compile the function that can be executed + asIScriptFunction *func = 0; + int r = execMod->CompileFunction("ExecuteString", funcCode.c_str(), -1, 0, &func); + if( r < 0 ) + return r; + + // If no context was provided, request a new one from the engine + asIScriptContext *execCtx = ctx ? ctx : engine->RequestContext(); + r = execCtx->Prepare(func); + if (r >= 0) + { + // Execute the function + r = execCtx->Execute(); + + // Unless the provided type was void retrieve it's value + if (ref != 0 && refTypeId != asTYPEID_VOID) + { + if (refTypeId & asTYPEID_OBJHANDLE) + { + // Expect the pointer to be null to start with + assert(*reinterpret_cast(ref) == 0); + *reinterpret_cast(ref) = *reinterpret_cast(execCtx->GetAddressOfReturnValue()); + engine->AddRefScriptObject(*reinterpret_cast(ref), engine->GetTypeInfoById(refTypeId)); + } + else if (refTypeId & asTYPEID_MASK_OBJECT) + { + // Use the registered assignment operator to do a value assign. + // This assumes that the ref is pointing to a valid object instance. + engine->AssignScriptObject(ref, execCtx->GetAddressOfReturnValue(), engine->GetTypeInfoById(refTypeId)); + } + else + { + // Copy the primitive value + memcpy(ref, execCtx->GetAddressOfReturnValue(), engine->GetSizeOfPrimitiveType(refTypeId)); + } + } + } + + // Clean up + func->Release(); + if( !ctx ) engine->ReturnContext(execCtx); + + return r; +} + +int WriteConfigToFile(asIScriptEngine *engine, const char *filename) +{ + ofstream strm; + strm.open(filename); + + return WriteConfigToStream(engine, strm); +} + +int WriteConfigToStream(asIScriptEngine *engine, ostream &strm) +{ + // A helper function for escaping quotes in default arguments + struct Escape + { + static string Quotes(const char *decl) + { + string str = decl; + size_t pos = 0; + for(;;) + { + // Find " characters + pos = str.find("\"",pos); + if( pos == string::npos ) + break; + + // Add a \ to escape them + str.insert(pos, "\\"); + pos += 2; + } + + return str; + } + }; + + int c, n; + + asDWORD currAccessMask = 0; + string currNamespace = ""; + engine->SetDefaultNamespace(""); + + // Export the engine version, just for info + strm << "// AngelScript " << asGetLibraryVersion() << "\n"; + strm << "// Lib options " << asGetLibraryOptions() << "\n"; + + // Export the relevant engine properties + strm << "// Engine properties\n"; + for( n = 0; n < asEP_LAST_PROPERTY; n++ ) + strm << "ep " << n << " " << engine->GetEngineProperty(asEEngineProp(n)) << "\n"; + + // Make sure the default array type is expanded to the template form + bool expandDefArrayToTempl = engine->GetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL) ? true : false; + engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, true); + + // Write enum types and their values + strm << "\n// Enums\n"; + c = engine->GetEnumCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *ti = engine->GetEnumByIndex(n); + asDWORD accessMask = ti->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + const char *nameSpace = ti->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + const char *enumName = ti->GetName(); + strm << "enum " << enumName << "\n"; + for( asUINT m = 0; m < ti->GetEnumValueCount(); m++ ) + { + const char *valName; + int val; + valName = ti->GetEnumValueByIndex(m, &val); + strm << "enumval " << enumName << " " << valName << " " << val << "\n"; + } + } + + // Enumerate all types + strm << "\n// Types\n"; + + // Keep a list of the template types, as the methods for these need to be exported first + set templateTypes; + + c = engine->GetObjectTypeCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *type = engine->GetObjectTypeByIndex(n); + asDWORD accessMask = type->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + const char *nameSpace = type->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) + { + // This should only be interfaces + assert( type->GetSize() == 0 ); + + strm << "intf " << type->GetName() << "\n"; + } + else + { + // Only the type flags are necessary. The application flags are application + // specific and doesn't matter to the offline compiler. The object size is also + // unnecessary for the offline compiler + strm << "objtype \"" << engine->GetTypeDeclaration(type->GetTypeId()) << "\" " << (unsigned int)(type->GetFlags() & asOBJ_MASK_VALID_FLAGS) << "\n"; + + // Store the template types (but not template instances) + if( (type->GetFlags() & asOBJ_TEMPLATE) && type->GetSubType() && (type->GetSubType()->GetFlags() & asOBJ_TEMPLATE_SUBTYPE) ) + templateTypes.insert(type); + } + } + + c = engine->GetTypedefCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *ti = engine->GetTypedefByIndex(n); + const char *nameSpace = ti->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + asDWORD accessMask = ti->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "typedef " << ti->GetName() << " \"" << engine->GetTypeDeclaration(ti->GetTypedefTypeId()) << "\"\n"; + } + + c = engine->GetFuncdefCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *funcDef = engine->GetFuncdefByIndex(n); + asDWORD accessMask = funcDef->GetAccessMask(); + const char *nameSpace = funcDef->GetNamespace(); + // Child funcdefs do not have any namespace, as they belong to the parent object + if( nameSpace && nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "funcdef \"" << funcDef->GetFuncdefSignature()->GetDeclaration() << "\"\n"; + } + + // A helper for writing object type members + struct TypeWriter + { + static void Write(asIScriptEngine *engine, ostream &strm, asITypeInfo *type, string &currNamespace, asDWORD &currAccessMask) + { + const char *nameSpace = type->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + string typeDecl = engine->GetTypeDeclaration(type->GetTypeId()); + if( type->GetFlags() & asOBJ_SCRIPT_OBJECT ) + { + for( asUINT m = 0; m < type->GetMethodCount(); m++ ) + { + asIScriptFunction *func = type->GetMethodByIndex(m); + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "intfmthd " << typeDecl.c_str() << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; + } + } + else + { + asUINT m; + for( m = 0; m < type->GetFactoryCount(); m++ ) + { + asIScriptFunction *func = type->GetFactoryByIndex(m); + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "objbeh \"" << typeDecl.c_str() << "\" " << asBEHAVE_FACTORY << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; + } + for( m = 0; m < type->GetBehaviourCount(); m++ ) + { + asEBehaviours beh; + asIScriptFunction *func = type->GetBehaviourByIndex(m, &beh); + + if( beh == asBEHAVE_CONSTRUCT ) + // Prefix 'void' + strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; + else if( beh == asBEHAVE_DESTRUCT ) + // Prefix 'void' and remove ~ + strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"void " << Escape::Quotes(func->GetDeclaration(false)).c_str()+1 << "\"\n"; + else + strm << "objbeh \"" << typeDecl.c_str() << "\" " << beh << " \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << "\"\n"; + } + for( m = 0; m < type->GetMethodCount(); m++ ) + { + asIScriptFunction *func = type->GetMethodByIndex(m); + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "objmthd \"" << typeDecl.c_str() << "\" \"" << Escape::Quotes(func->GetDeclaration(false)).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; + } + for( m = 0; m < type->GetPropertyCount(); m++ ) + { + asDWORD accessMask; + type->GetProperty(m, 0, 0, 0, 0, 0, 0, &accessMask); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "objprop \"" << typeDecl.c_str() << "\" \"" << type->GetPropertyDeclaration(m) << "\""; + + // Save information about composite properties + int compositeOffset; + bool isCompositeIndirect; + type->GetProperty(m, 0, 0, 0, 0, 0, 0, 0, &compositeOffset, &isCompositeIndirect); + strm << " " << compositeOffset << " " << (isCompositeIndirect ? "1" : "0") << "\n"; + } + } + } + }; + + // Write the members of the template types, so they can be fully registered before any other type uses them + // TODO: Order the template types based on dependency to avoid failure if one type uses instances of another + strm << "\n// Template type members\n"; + for( set::iterator it = templateTypes.begin(); it != templateTypes.end(); ++it ) + { + asITypeInfo *type = *it; + TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); + } + + // Write the object types members + strm << "\n// Type members\n"; + + c = engine->GetObjectTypeCount(); + for( n = 0; n < c; n++ ) + { + asITypeInfo *type = engine->GetObjectTypeByIndex(n); + if( templateTypes.find(type) == templateTypes.end() ) + TypeWriter::Write(engine, strm, type, currNamespace, currAccessMask); + } + + // Write functions + strm << "\n// Functions\n"; + + c = engine->GetGlobalFunctionCount(); + for( n = 0; n < c; n++ ) + { + asIScriptFunction *func = engine->GetGlobalFunctionByIndex(n); + const char *nameSpace = func->GetNamespace(); + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + asDWORD accessMask = func->GetAccessMask(); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + strm << "func \"" << Escape::Quotes(func->GetDeclaration()).c_str() << (func->IsProperty() ? " property" : "") << "\"\n"; + } + + // Write global properties + strm << "\n// Properties\n"; + + c = engine->GetGlobalPropertyCount(); + for( n = 0; n < c; n++ ) + { + const char *name; + int typeId; + bool isConst; + asDWORD accessMask; + const char *nameSpace; + engine->GetGlobalPropertyByIndex(n, &name, &nameSpace, &typeId, &isConst, 0, 0, &accessMask); + if( accessMask != currAccessMask ) + { + strm << "access " << hex << (unsigned int)(accessMask) << dec << "\n"; + currAccessMask = accessMask; + } + if( nameSpace != currNamespace ) + { + strm << "namespace \"" << nameSpace << "\"\n"; + currNamespace = nameSpace; + engine->SetDefaultNamespace(currNamespace.c_str()); + } + strm << "prop \"" << (isConst ? "const " : "") << engine->GetTypeDeclaration(typeId) << " " << name << "\"\n"; + } + + // Write string factory + strm << "\n// String factory\n"; + + // Reset the namespace for the string factory and default array type + if ("" != currNamespace) + { + strm << "namespace \"\"\n"; + currNamespace = ""; + engine->SetDefaultNamespace(""); + } + + asDWORD flags = 0; + int typeId = engine->GetStringFactoryReturnTypeId(&flags); + if( typeId > 0 ) + strm << "strfactory \"" << ((flags & asTM_CONST) ? "const " : "") << engine->GetTypeDeclaration(typeId) << ((flags & asTM_INOUTREF) ? "&" : "") << "\"\n"; + + // Write default array type + strm << "\n// Default array type\n"; + typeId = engine->GetDefaultArrayTypeId(); + if( typeId > 0 ) + strm << "defarray \"" << engine->GetTypeDeclaration(typeId) << "\"\n"; + + // Restore original settings + engine->SetEngineProperty(asEP_EXPAND_DEF_ARRAY_TO_TMPL, expandDefArrayToTempl); + + return 0; +} + +int ConfigEngineFromStream(asIScriptEngine *engine, istream &strm, const char *configFile, asIStringFactory *stringFactory) +{ + int r; + + // Some helper functions for parsing the configuration + struct in + { + static asETokenClass GetToken(asIScriptEngine *engine, string &token, const string &text, asUINT &pos) + { + asUINT len = 0; + asETokenClass t = engine->ParseToken(&text[pos], text.length() - pos, &len); + while( (t == asTC_WHITESPACE || t == asTC_COMMENT) && pos < text.length() ) + { + pos += len; + t = engine->ParseToken(&text[pos], text.length() - pos, &len); + } + + token.assign(&text[pos], len); + + pos += len; + + return t; + } + + static void ReplaceSlashQuote(string &str) + { + size_t pos = 0; + for(;;) + { + // Search for \" in the string + pos = str.find("\\\"", pos); + if( pos == string::npos ) + break; + + // Remove the \ character + str.erase(pos, 1); + } + } + + static asUINT GetLineNumber(const string &text, asUINT pos) + { + asUINT count = 1; + for( asUINT n = 0; n < pos; n++ ) + if( text[n] == '\n' ) + count++; + + return count; + } + }; + + // Since we are only going to compile the script and never actually execute it, + // we turn off the initialization of global variables, so that the compiler can + // just register dummy types and functions for the application interface. + r = engine->SetEngineProperty(asEP_INIT_GLOBAL_VARS_AFTER_BUILD, false); assert( r >= 0 ); + + // Read the entire file + char buffer[1000]; + string config; + do { + strm.getline(buffer, 1000); + config += buffer; + config += "\n"; + } while( !strm.eof() && strm.good() ); + + // Process the configuration file and register each entity + asUINT pos = 0; + while( pos < config.length() ) + { + string token; + // TODO: The position where the initial token is found should be stored for error messages + in::GetToken(engine, token, config, pos); + if( token == "ep" ) + { + string tmp; + in::GetToken(engine, tmp, config, pos); + + asEEngineProp ep = asEEngineProp(atol(tmp.c_str())); + + // Only set properties that affect the compiler + if( ep != asEP_COPY_SCRIPT_SECTIONS && + ep != asEP_MAX_STACK_SIZE && + ep != asEP_INIT_GLOBAL_VARS_AFTER_BUILD && + ep != asEP_EXPAND_DEF_ARRAY_TO_TMPL && + ep != asEP_AUTO_GARBAGE_COLLECT ) + { + // Get the value for the property + in::GetToken(engine, tmp, config, pos); + stringstream s(tmp); + asPWORD value; + + s >> value; + + engine->SetEngineProperty(ep, value); + } + } + else if( token == "namespace" ) + { + string ns; + in::GetToken(engine, ns, config, pos); + ns = ns.substr(1, ns.length() - 2); + + r = engine->SetDefaultNamespace(ns.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to set namespace"); + return -1; + } + } + else if( token == "access" ) + { + string maskStr; + in::GetToken(engine, maskStr, config, pos); + asDWORD mask = strtoul(maskStr.c_str(), 0, 16); + engine->SetDefaultAccessMask(mask); + } + else if( token == "objtype" ) + { + string name, flags; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, flags, config, pos); + + // The size of the value type doesn't matter, because the + // engine must adjust it anyway for different platforms + r = engine->RegisterObjectType(name.c_str(), (atol(flags.c_str()) & asOBJ_VALUE) ? 1 : 0, atol(flags.c_str())); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object type"); + return -1; + } + } + else if( token == "objbeh" ) + { + string name, behaviour, decl; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, behaviour, config, pos); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + // Remove the $ that the engine prefixes the behaviours with + size_t n = decl.find("$"); + if( n != string::npos ) + decl[n] = ' '; + + asEBehaviours behave = static_cast(atol(behaviour.c_str())); + if( behave == asBEHAVE_TEMPLATE_CALLBACK ) + { + // TODO: How can we let the compiler register this? Maybe through a plug-in system? Or maybe by implementing the callback as a script itself + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register template callback without the actual implementation"); + } + else + { + r = engine->RegisterObjectBehaviour(name.c_str(), behave, decl.c_str(), asFUNCTION(0), asCALL_GENERIC); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register behaviour"); + return -1; + } + } + } + else if( token == "objmthd" ) + { + string name, decl; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + r = engine->RegisterObjectMethod(name.c_str(), decl.c_str(), asFUNCTION(0), asCALL_GENERIC); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object method"); + return -1; + } + } + else if( token == "objprop" ) + { + string name, decl, compositeOffset, isCompositeIndirect; + in::GetToken(engine, name, config, pos); + name = name.substr(1, name.length() - 2); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::GetToken(engine, compositeOffset, config, pos); + in::GetToken(engine, isCompositeIndirect, config, pos); + + asITypeInfo *type = engine->GetTypeInfoById(engine->GetTypeIdByDecl(name.c_str())); + if( type == 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Type doesn't exist for property registration"); + return -1; + } + + // All properties must have different offsets in order to make them + // distinct, so we simply register them with an incremental offset + r = engine->RegisterObjectProperty(name.c_str(), decl.c_str(), type->GetPropertyCount(), compositeOffset != "0" ? type->GetPropertyCount() : 0, isCompositeIndirect != "0"); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register object property"); + return -1; + } + } + else if( token == "intf" ) + { + string name, size, flags; + in::GetToken(engine, name, config, pos); + + r = engine->RegisterInterface(name.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface"); + return -1; + } + } + else if( token == "intfmthd" ) + { + string name, decl; + in::GetToken(engine, name, config, pos); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + r = engine->RegisterInterfaceMethod(name.c_str(), decl.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register interface method"); + return -1; + } + } + else if( token == "func" ) + { + string decl; + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + in::ReplaceSlashQuote(decl); + + r = engine->RegisterGlobalFunction(decl.c_str(), asFUNCTION(0), asCALL_GENERIC); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global function"); + return -1; + } + } + else if( token == "prop" ) + { + string decl; + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + + // All properties must have different offsets in order to make them + // distinct, so we simply register them with an incremental offset. + // The pointer must also be non-null so we add 1 to have a value. + r = engine->RegisterGlobalProperty(decl.c_str(), reinterpret_cast(asPWORD(engine->GetGlobalPropertyCount()+1))); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register global property"); + return -1; + } + } + else if( token == "strfactory" ) + { + string type; + in::GetToken(engine, type, config, pos); + type = type.substr(1, type.length() - 2); + + if (stringFactory == 0) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_WARNING, "Cannot register string factory without the actual implementation"); + return -1; + } + else + { + r = engine->RegisterStringFactory(type.c_str(), stringFactory); + if (r < 0) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register string factory"); + return -1; + } + } + } + else if( token == "defarray" ) + { + string type; + in::GetToken(engine, type, config, pos); + type = type.substr(1, type.length() - 2); + + r = engine->RegisterDefaultArrayType(type.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register the default array type"); + return -1; + } + } + else if( token == "enum" ) + { + string type; + in::GetToken(engine, type, config, pos); + + r = engine->RegisterEnum(type.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum type"); + return -1; + } + } + else if( token == "enumval" ) + { + string type, name, value; + in::GetToken(engine, type, config, pos); + in::GetToken(engine, name, config, pos); + in::GetToken(engine, value, config, pos); + + r = engine->RegisterEnumValue(type.c_str(), name.c_str(), atol(value.c_str())); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register enum value"); + return -1; + } + } + else if( token == "typedef" ) + { + string type, decl; + in::GetToken(engine, type, config, pos); + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + + r = engine->RegisterTypedef(type.c_str(), decl.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register typedef"); + return -1; + } + } + else if( token == "funcdef" ) + { + string decl; + in::GetToken(engine, decl, config, pos); + decl = decl.substr(1, decl.length() - 2); + + r = engine->RegisterFuncdef(decl.c_str()); + if( r < 0 ) + { + engine->WriteMessage(configFile, in::GetLineNumber(config, pos), 0, asMSGTYPE_ERROR, "Failed to register funcdef"); + return -1; + } + } + } + + return 0; +} + +string GetExceptionInfo(asIScriptContext *ctx, bool showStack) +{ + if( ctx->GetState() != asEXECUTION_EXCEPTION ) return ""; + + stringstream text; + + const asIScriptFunction *function = ctx->GetExceptionFunction(); + text << "func: " << function->GetDeclaration() << "\n"; + text << "modl: " << (function->GetModuleName() ? function->GetModuleName() : "") << "\n"; + text << "sect: " << (function->GetScriptSectionName() ? function->GetScriptSectionName() : "") << "\n"; + text << "line: " << ctx->GetExceptionLineNumber() << "\n"; + text << "desc: " << ctx->GetExceptionString() << "\n"; + + if( showStack ) + { + text << "--- call stack ---\n"; + for( asUINT n = 1; n < ctx->GetCallstackSize(); n++ ) + { + function = ctx->GetFunction(n); + if( function ) + { + if( function->GetFuncType() == asFUNC_SCRIPT ) + { + text << (function->GetScriptSectionName() ? function->GetScriptSectionName() : "") << " (" << ctx->GetLineNumber(n) << "): " << function->GetDeclaration() << "\n"; + } + else + { + // The context is being reused by the application for a nested call + text << "{...application...}: " << function->GetDeclaration() << "\n"; + } + } + else + { + // The context is being reused by the script engine for a nested call + text << "{...script engine...}\n"; + } + } + } + + return text.str(); +} + +void ScriptThrow(const string &msg) +{ + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException(msg.c_str()); +} + +string ScriptGetExceptionInfo() +{ + asIScriptContext *ctx = asGetActiveContext(); + if (!ctx) + return ""; + + const char *msg = ctx->GetExceptionString(); + if (msg == 0) + return ""; + + return string(msg); +} + +void RegisterExceptionRoutines(asIScriptEngine *engine) +{ + int r; + + // The string type must be available + assert(engine->GetTypeInfoByDecl("string")); + + r = engine->RegisterGlobalFunction("void throw(const string &in)", asFUNCTION(ScriptThrow), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string getExceptionInfo()", asFUNCTION(ScriptGetExceptionInfo), asCALL_CDECL); assert(r >= 0); +} + +END_AS_NAMESPACE diff --git a/add_on/scripthelper/scripthelper.h b/add_on/scripthelper/scripthelper.h new file mode 100644 index 0000000..dc3e0b8 --- /dev/null +++ b/add_on/scripthelper/scripthelper.h @@ -0,0 +1,53 @@ +#ifndef SCRIPTHELPER_H +#define SCRIPTHELPER_H + +#include +#include + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +// Compare relation between two objects of the same type +int CompareRelation(asIScriptEngine *engine, void *lobj, void *robj, int typeId, int &result); + +// Compare equality between two objects of the same type +int CompareEquality(asIScriptEngine *engine, void *lobj, void *robj, int typeId, bool &result); + +// Compile and execute simple statements +// The module is optional. If given the statements can access the entities compiled in the module. +// The caller can optionally provide its own context, for example if a context should be reused. +int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); + +// Compile and execute simple statements with option of return value +// The module is optional. If given the statements can access the entitites compiled in the module. +// The caller can optionally provide its own context, for example if a context should be reused. +int ExecuteString(asIScriptEngine *engine, const char *code, void *ret, int retTypeId, asIScriptModule *mod = 0, asIScriptContext *ctx = 0); + +// Write the registered application interface to a file for an offline compiler. +// The format is compatible with the offline compiler in /sdk/samples/asbuild/. +int WriteConfigToFile(asIScriptEngine *engine, const char *filename); + +// Write the registered application interface to a text stream. +int WriteConfigToStream(asIScriptEngine *engine, std::ostream &strm); + +// Loads an interface from a text stream and configures the engine with it. This will not +// set the correct function pointers, so it is not possible to use this engine to execute +// scripts, but it can be used to compile scripts and save the byte code. +int ConfigEngineFromStream(asIScriptEngine *engine, std::istream &strm, const char *nameOfStream = "config", asIStringFactory *stringFactory = 0); + +// Format the details of the script exception into a human readable text +std::string GetExceptionInfo(asIScriptContext *ctx, bool showStack = false); + +// Register the exception routines +// 'void throw(const string &msg)' +// 'string getExceptionInfo()' +void RegisterExceptionRoutines(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptmath/scriptmath.cpp b/add_on/scriptmath/scriptmath.cpp new file mode 100644 index 0000000..c5b86c3 --- /dev/null +++ b/add_on/scriptmath/scriptmath.cpp @@ -0,0 +1,347 @@ +#include +#include +#include +#include +#include "scriptmath.h" + +#ifdef __BORLANDC__ +#include + +// The C++Builder RTL doesn't pull the *f functions into the global namespace per default. +using namespace std; + +#if __BORLANDC__ < 0x580 +// C++Builder 6 and earlier don't come with any *f variants of the math functions at all. +inline float cosf (float arg) { return std::cos (arg); } +inline float sinf (float arg) { return std::sin (arg); } +inline float tanf (float arg) { return std::tan (arg); } +inline float atan2f (float y, float x) { return std::atan2 (y, x); } +inline float logf (float arg) { return std::log (arg); } +inline float powf (float x, float y) { return std::pow (x, y); } +inline float sqrtf (float arg) { return std::sqrt (arg); } +#endif + +// C++Builder doesn't define most of the non-standard float-specific math functions with +// "*f" suffix; instead it provides overloads for the standard math functions which take +// "float" arguments. +inline float acosf (float arg) { return std::acos (arg); } +inline float asinf (float arg) { return std::asin (arg); } +inline float atanf (float arg) { return std::atan (arg); } +inline float coshf (float arg) { return std::cosh (arg); } +inline float sinhf (float arg) { return std::sinh (arg); } +inline float tanhf (float arg) { return std::tanh (arg); } +inline float log10f (float arg) { return std::log10 (arg); } +inline float ceilf (float arg) { return std::ceil (arg); } +inline float fabsf (float arg) { return std::fabs (arg); } +inline float floorf (float arg) { return std::floor (arg); } + +// C++Builder doesn't define a non-standard "modff" function but rather an overload of "modf" +// for float arguments. However, BCC's float overload of fmod() is broken (QC #74816; fixed +// in C++Builder 2010). +inline float modff (float x, float *y) +{ + double d; + float f = (float) modf((double) x, &d); + *y = (float) d; + return f; +} +#endif + +BEGIN_AS_NAMESPACE + +// Determine whether the float version should be registered, or the double version +#ifndef AS_USE_FLOAT +#if !defined(_WIN32_WCE) // WinCE doesn't have the float versions of the math functions +#define AS_USE_FLOAT 1 +#endif +#endif + +// The modf function doesn't seem very intuitive, so I'm writing this +// function that simply returns the fractional part of the float value +#if AS_USE_FLOAT +float fractionf(float v) +{ + float intPart; + return modff(v, &intPart); +} +#else +double fraction(double v) +{ + double intPart; + return modf(v, &intPart); +} +#endif + +// As AngelScript doesn't allow bitwise manipulation of float types we'll provide a couple of +// functions for converting float values to IEEE 754 formatted values etc. This also allow us to +// provide a platform agnostic representation to the script so the scripts don't have to worry +// about whether the CPU uses IEEE 754 floats or some other representation +float fpFromIEEE(asUINT raw) +{ + // TODO: Identify CPU family to provide proper conversion + // if the CPU doesn't natively use IEEE style floats + return *reinterpret_cast(&raw); +} +asUINT fpToIEEE(float fp) +{ + return *reinterpret_cast(&fp); +} +double fpFromIEEE(asQWORD raw) +{ + return *reinterpret_cast(&raw); +} +asQWORD fpToIEEE(double fp) +{ + return *reinterpret_cast(&fp); +} + +// closeTo() is used to determine if the binary representation of two numbers are +// relatively close to each other. Numerical errors due to rounding errors build +// up over many operations, so it is almost impossible to get exact numbers and +// this is where closeTo() comes in. +// +// It shouldn't be used to determine if two numbers are mathematically close to +// each other. +// +// ref: http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm +// ref: http://www.gamedev.net/topic/653449-scriptmath-and-closeto/ +bool closeTo(float a, float b, float epsilon) +{ + // Equal numbers and infinity will return immediately + if( a == b ) return true; + + // When very close to 0, we can use the absolute comparison + float diff = fabsf(a - b); + if( (a == 0 || b == 0) && (diff < epsilon) ) + return true; + + // Otherwise we need to use relative comparison to account for precision + return diff / (fabs(a) + fabs(b)) < epsilon; +} + +bool closeTo(double a, double b, double epsilon) +{ + if( a == b ) return true; + + double diff = fabs(a - b); + if( (a == 0 || b == 0) && (diff < epsilon) ) + return true; + + return diff / (fabs(a) + fabs(b)) < epsilon; +} + +void RegisterScriptMath_Native(asIScriptEngine *engine) +{ + int r; + + // Conversion between floating point and IEEE bits representations + r = engine->RegisterGlobalFunction("float fpFromIEEE(uint)", asFUNCTIONPR(fpFromIEEE, (asUINT), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("uint fpToIEEE(float)", asFUNCTIONPR(fpToIEEE, (float), asUINT), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double fpFromIEEE(uint64)", asFUNCTIONPR(fpFromIEEE, (asQWORD), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("uint64 fpToIEEE(double)", asFUNCTIONPR(fpToIEEE, (double), asQWORD), asCALL_CDECL); assert( r >= 0 ); + + // Close to comparison with epsilon + r = engine->RegisterGlobalFunction("bool closeTo(float, float, float = 0.00001f)", asFUNCTIONPR(closeTo, (float, float, float), bool), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("bool closeTo(double, double, double = 0.0000000001)", asFUNCTIONPR(closeTo, (double, double, double), bool), asCALL_CDECL); assert( r >= 0 ); + +#if AS_USE_FLOAT + // Trigonometric functions + r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTIONPR(cosf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTIONPR(sinf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTIONPR(tanf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTIONPR(acosf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTIONPR(asinf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTIONPR(atanf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTIONPR(atan2f, (float, float), float), asCALL_CDECL); assert( r >= 0 ); + + // Hyberbolic functions + r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTIONPR(coshf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTIONPR(sinhf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTIONPR(tanhf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Exponential and logarithmic functions + r = engine->RegisterGlobalFunction("float log(float)", asFUNCTIONPR(logf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTIONPR(log10f, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Power functions + r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTIONPR(powf, (float, float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTIONPR(sqrtf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Nearest integer, absolute value, and remainder functions + r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTIONPR(ceilf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTIONPR(fabsf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTIONPR(floorf, (float), float), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTIONPR(fractionf, (float), float), asCALL_CDECL); assert( r >= 0 ); + + // Don't register modf because AngelScript already supports the % operator +#else + // double versions of the same + r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTIONPR(cos, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTIONPR(sin, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTIONPR(tan, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTIONPR(acos, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTIONPR(asin, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTIONPR(atan, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTIONPR(atan2, (double, double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTIONPR(cosh, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTIONPR(sinh, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTIONPR(tanh, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double log(double)", asFUNCTIONPR(log, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTIONPR(log10, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTIONPR(pow, (double, double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTIONPR(sqrt, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTIONPR(ceil, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTIONPR(fabs, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTIONPR(floor, (double), double), asCALL_CDECL); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTIONPR(fraction, (double), double), asCALL_CDECL); assert( r >= 0 ); +#endif +} + +#if AS_USE_FLOAT +// This macro creates simple generic wrappers for functions of type 'float func(float)' +#define GENERICff(x) \ +void x##_generic(asIScriptGeneric *gen) \ +{ \ + float f = *(float*)gen->GetAddressOfArg(0); \ + *(float*)gen->GetAddressOfReturnLocation() = x(f); \ +} + +GENERICff(cosf) +GENERICff(sinf) +GENERICff(tanf) +GENERICff(acosf) +GENERICff(asinf) +GENERICff(atanf) +GENERICff(coshf) +GENERICff(sinhf) +GENERICff(tanhf) +GENERICff(logf) +GENERICff(log10f) +GENERICff(sqrtf) +GENERICff(ceilf) +GENERICff(fabsf) +GENERICff(floorf) +GENERICff(fractionf) + +void powf_generic(asIScriptGeneric *gen) +{ + float f1 = *(float*)gen->GetAddressOfArg(0); + float f2 = *(float*)gen->GetAddressOfArg(1); + *(float*)gen->GetAddressOfReturnLocation() = powf(f1, f2); +} +void atan2f_generic(asIScriptGeneric *gen) +{ + float f1 = *(float*)gen->GetAddressOfArg(0); + float f2 = *(float*)gen->GetAddressOfArg(1); + *(float*)gen->GetAddressOfReturnLocation() = atan2f(f1, f2); +} + +#else +// This macro creates simple generic wrappers for functions of type 'double func(double)' +#define GENERICdd(x) \ +void x##_generic(asIScriptGeneric *gen) \ +{ \ + double f = *(double*)gen->GetAddressOfArg(0); \ + *(double*)gen->GetAddressOfReturnLocation() = x(f); \ +} + +GENERICdd(cos) +GENERICdd(sin) +GENERICdd(tan) +GENERICdd(acos) +GENERICdd(asin) +GENERICdd(atan) +GENERICdd(cosh) +GENERICdd(sinh) +GENERICdd(tanh) +GENERICdd(log) +GENERICdd(log10) +GENERICdd(sqrt) +GENERICdd(ceil) +GENERICdd(fabs) +GENERICdd(floor) +GENERICdd(fraction) + +void pow_generic(asIScriptGeneric *gen) +{ + double f1 = *(double*)gen->GetAddressOfArg(0); + double f2 = *(double*)gen->GetAddressOfArg(1); + *(double*)gen->GetAddressOfReturnLocation() = pow(f1, f2); +} +void atan2_generic(asIScriptGeneric *gen) +{ + double f1 = *(double*)gen->GetAddressOfArg(0); + double f2 = *(double*)gen->GetAddressOfArg(1); + *(double*)gen->GetAddressOfReturnLocation() = atan2(f1, f2); +} +#endif +void RegisterScriptMath_Generic(asIScriptEngine *engine) +{ + int r; + +#if AS_USE_FLOAT + // Trigonometric functions + r = engine->RegisterGlobalFunction("float cos(float)", asFUNCTION(cosf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float sin(float)", asFUNCTION(sinf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float tan(float)", asFUNCTION(tanf_generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterGlobalFunction("float acos(float)", asFUNCTION(acosf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float asin(float)", asFUNCTION(asinf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float atan(float)", asFUNCTION(atanf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float atan2(float,float)", asFUNCTION(atan2f_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Hyberbolic functions + r = engine->RegisterGlobalFunction("float cosh(float)", asFUNCTION(coshf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float sinh(float)", asFUNCTION(sinhf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float tanh(float)", asFUNCTION(tanhf_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Exponential and logarithmic functions + r = engine->RegisterGlobalFunction("float log(float)", asFUNCTION(logf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float log10(float)", asFUNCTION(log10f_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Power functions + r = engine->RegisterGlobalFunction("float pow(float, float)", asFUNCTION(powf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float sqrt(float)", asFUNCTION(sqrtf_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Nearest integer, absolute value, and remainder functions + r = engine->RegisterGlobalFunction("float ceil(float)", asFUNCTION(ceilf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float abs(float)", asFUNCTION(fabsf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float floor(float)", asFUNCTION(floorf_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("float fraction(float)", asFUNCTION(fractionf_generic), asCALL_GENERIC); assert( r >= 0 ); + + // Don't register modf because AngelScript already supports the % operator +#else + // double versions of the same + r = engine->RegisterGlobalFunction("double cos(double)", asFUNCTION(cos_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double sin(double)", asFUNCTION(sin_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double tan(double)", asFUNCTION(tan_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double acos(double)", asFUNCTION(acos_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double asin(double)", asFUNCTION(asin_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double atan(double)", asFUNCTION(atan_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double atan2(double,double)", asFUNCTION(atan2_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double cosh(double)", asFUNCTION(cosh_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double sinh(double)", asFUNCTION(sinh_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double tanh(double)", asFUNCTION(tanh_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double log(double)", asFUNCTION(log_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double log10(double)", asFUNCTION(log10_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double pow(double, double)", asFUNCTION(pow_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double sqrt(double)", asFUNCTION(sqrt_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double ceil(double)", asFUNCTION(ceil_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double abs(double)", asFUNCTION(fabs_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double floor(double)", asFUNCTION(floor_generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterGlobalFunction("double fraction(double)", asFUNCTION(fraction_generic), asCALL_GENERIC); assert( r >= 0 ); +#endif +} + +void RegisterScriptMath(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptMath_Generic(engine); + else + RegisterScriptMath_Native(engine); +} + +END_AS_NAMESPACE + + diff --git a/add_on/scriptmath/scriptmath.h b/add_on/scriptmath/scriptmath.h new file mode 100644 index 0000000..a239e38 --- /dev/null +++ b/add_on/scriptmath/scriptmath.h @@ -0,0 +1,26 @@ +#ifndef SCRIPTMATH_H +#define SCRIPTMATH_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +// This function will determine the configuration of the engine +// and use one of the two functions below to register the math functions +void RegisterScriptMath(asIScriptEngine *engine); + +// Call this function to register the math functions +// using native calling conventions +void RegisterScriptMath_Native(asIScriptEngine *engine); + +// Use this one instead if native calling conventions +// are not supported on the target platform +void RegisterScriptMath_Generic(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptmath/scriptmathcomplex.cpp b/add_on/scriptmath/scriptmathcomplex.cpp new file mode 100644 index 0000000..0695b7c --- /dev/null +++ b/add_on/scriptmath/scriptmathcomplex.cpp @@ -0,0 +1,222 @@ +#include +#include // strstr +#include // new() +#include +#include "scriptmathcomplex.h" + +#ifdef __BORLANDC__ +// C++Builder doesn't define a non-standard "sqrtf" function but rather an overload of "sqrt" +// for float arguments. +inline float sqrtf (float x) { return sqrt (x); } +#endif + +BEGIN_AS_NAMESPACE + +Complex::Complex() +{ + r = 0; + i = 0; +} + +Complex::Complex(const Complex &other) +{ + r = other.r; + i = other.i; +} + +Complex::Complex(float _r, float _i) +{ + r = _r; + i = _i; +} + +bool Complex::operator==(const Complex &o) const +{ + return (r == o.r) && (i == o.i); +} + +bool Complex::operator!=(const Complex &o) const +{ + return !(*this == o); +} + +Complex &Complex::operator=(const Complex &other) +{ + r = other.r; + i = other.i; + return *this; +} + +Complex &Complex::operator+=(const Complex &other) +{ + r += other.r; + i += other.i; + return *this; +} + +Complex &Complex::operator-=(const Complex &other) +{ + r -= other.r; + i -= other.i; + return *this; +} + +Complex &Complex::operator*=(const Complex &other) +{ + *this = *this * other; + return *this; +} + +Complex &Complex::operator/=(const Complex &other) +{ + *this = *this / other; + return *this; +} + +float Complex::squaredLength() const +{ + return r*r + i*i; +} + +float Complex::length() const +{ + return sqrtf(squaredLength()); +} + +Complex Complex::operator+(const Complex &other) const +{ + return Complex(r + other.r, i + other.i); +} + +Complex Complex::operator-(const Complex &other) const +{ + return Complex(r - other.r, i + other.i); +} + +Complex Complex::operator*(const Complex &other) const +{ + return Complex(r*other.r - i*other.i, r*other.i + i*other.r); +} + +Complex Complex::operator/(const Complex &other) const +{ + float squaredLen = other.squaredLength(); + if( squaredLen == 0 ) return Complex(0,0); + + return Complex((r*other.r + i*other.i)/squaredLen, (i*other.r - r*other.i)/squaredLen); +} + +//----------------------- +// Swizzle operators +//----------------------- + +Complex Complex::get_ri() const +{ + return *this; +} +Complex Complex::get_ir() const +{ + return Complex(r,i); +} +void Complex::set_ri(const Complex &o) +{ + *this = o; +} +void Complex::set_ir(const Complex &o) +{ + r = o.i; + i = o.r; +} + +//----------------------- +// AngelScript functions +//----------------------- + +static void ComplexDefaultConstructor(Complex *self) +{ + new(self) Complex(); +} + +static void ComplexCopyConstructor(const Complex &other, Complex *self) +{ + new(self) Complex(other); +} + +static void ComplexConvConstructor(float r, Complex *self) +{ + new(self) Complex(r); +} + +static void ComplexInitConstructor(float r, float i, Complex *self) +{ + new(self) Complex(r,i); +} + +static void ComplexListConstructor(float *list, Complex *self) +{ + new(self) Complex(list[0], list[1]); +} + +//-------------------------------- +// Registration +//------------------------------------- + +static void RegisterScriptMathComplex_Native(asIScriptEngine *engine) +{ + int r; + + // Register the type +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to determine the correct flags to represent the C++ class, except for the asOBJ_APP_CLASS_ALLFLOATS + r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asGetTypeTraits() | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("complex", sizeof(Complex), asOBJ_VALUE | asOBJ_POD | asOBJ_APP_CLASS_CAK | asOBJ_APP_CLASS_ALLFLOATS); assert( r >= 0 ); +#endif + + // Register the object properties + r = engine->RegisterObjectProperty("complex", "float r", asOFFSET(Complex, r)); assert( r >= 0 ); + r = engine->RegisterObjectProperty("complex", "float i", asOFFSET(Complex, i)); assert( r >= 0 ); + + // Register the constructors + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ComplexDefaultConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(const complex &in)", asFUNCTION(ComplexCopyConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float)", asFUNCTION(ComplexConvConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_CONSTRUCT, "void f(float, float)", asFUNCTION(ComplexInitConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("complex", asBEHAVE_LIST_CONSTRUCT, "void f(const int &in) {float, float}", asFUNCTION(ComplexListConstructor), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Register the operator overloads + r = engine->RegisterObjectMethod("complex", "complex &opAddAssign(const complex &in)", asMETHODPR(Complex, operator+=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex &opSubAssign(const complex &in)", asMETHODPR(Complex, operator-=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex &opMulAssign(const complex &in)", asMETHODPR(Complex, operator*=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex &opDivAssign(const complex &in)", asMETHODPR(Complex, operator/=, (const Complex &), Complex&), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "bool opEquals(const complex &in) const", asMETHODPR(Complex, operator==, (const Complex &) const, bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opAdd(const complex &in) const", asMETHODPR(Complex, operator+, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opSub(const complex &in) const", asMETHODPR(Complex, operator-, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opMul(const complex &in) const", asMETHODPR(Complex, operator*, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex opDiv(const complex &in) const", asMETHODPR(Complex, operator/, (const Complex &) const, Complex), asCALL_THISCALL); assert( r >= 0 ); + + // Register the object methods + r = engine->RegisterObjectMethod("complex", "float abs() const", asMETHOD(Complex,length), asCALL_THISCALL); assert( r >= 0 ); + + // Register the swizzle operators + r = engine->RegisterObjectMethod("complex", "complex get_ri() const property", asMETHOD(Complex, get_ri), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "complex get_ir() const property", asMETHOD(Complex, get_ir), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "void set_ri(const complex &in) property", asMETHOD(Complex, set_ri), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("complex", "void set_ir(const complex &in) property", asMETHOD(Complex, set_ir), asCALL_THISCALL); assert( r >= 0 ); +} + +void RegisterScriptMathComplex(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + { + assert( false ); + // TODO: implement support for generic calling convention + // RegisterScriptMathComplex_Generic(engine); + } + else + RegisterScriptMathComplex_Native(engine); +} + +END_AS_NAMESPACE + + diff --git a/add_on/scriptmath/scriptmathcomplex.h b/add_on/scriptmath/scriptmathcomplex.h new file mode 100644 index 0000000..8d33915 --- /dev/null +++ b/add_on/scriptmath/scriptmathcomplex.h @@ -0,0 +1,61 @@ +#ifndef SCRIPTMATHCOMPLEX_H +#define SCRIPTMATHCOMPLEX_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +// This class implements complex numbers and the common +// operations that can be done with it. +// +// Ref: http://mathworld.wolfram.com/ComplexNumber.html + +struct Complex +{ + Complex(); + Complex(const Complex &other); + Complex(float r, float i = 0); + + // Assignment operator + Complex &operator=(const Complex &other); + + // Compound assigment operators + Complex &operator+=(const Complex &other); + Complex &operator-=(const Complex &other); + Complex &operator*=(const Complex &other); + Complex &operator/=(const Complex &other); + + float length() const; + float squaredLength() const; + + // Swizzle operators + Complex get_ri() const; + void set_ri(const Complex &in); + Complex get_ir() const; + void set_ir(const Complex &in); + + // Comparison + bool operator==(const Complex &other) const; + bool operator!=(const Complex &other) const; + + // Math operators + Complex operator+(const Complex &other) const; + Complex operator-(const Complex &other) const; + Complex operator*(const Complex &other) const; + Complex operator/(const Complex &other) const; + + float r; + float i; +}; + +// This function will determine the configuration of the engine +// and use one of the two functions below to register the string type +void RegisterScriptMathComplex(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptstdstring/scriptstdstring.cpp b/add_on/scriptstdstring/scriptstdstring.cpp new file mode 100644 index 0000000..2a96ad4 --- /dev/null +++ b/add_on/scriptstdstring/scriptstdstring.cpp @@ -0,0 +1,1365 @@ +#include "scriptstdstring.h" +#include // assert() +#include // std::stringstream +#include // strstr() +#include // sprintf() +#include // strtod() +#ifndef __psp2__ + #include // setlocale() +#endif + +using namespace std; + +// This macro is used to avoid warnings about unused variables. +// Usually where the variables are only used in debug mode. +#define UNUSED_VAR(x) (void)(x) + +#ifdef AS_CAN_USE_CPP11 +// The string factory doesn't need to keep a specific order in the +// cache, so the unordered_map is faster than the ordinary map +#include // std::unordered_map +BEGIN_AS_NAMESPACE +typedef unordered_map map_t; +END_AS_NAMESPACE +#else +#include // std::map +BEGIN_AS_NAMESPACE +typedef map map_t; +END_AS_NAMESPACE +#endif + +BEGIN_AS_NAMESPACE +class CStdStringFactory : public asIStringFactory +{ +public: + CStdStringFactory() {} + ~CStdStringFactory() + { + // The script engine must release each string + // constant that it has requested + assert(stringCache.size() == 0); + } + + const void *GetStringConstant(const char *data, asUINT length) + { + // The string factory might be modified from multiple + // threads, so it is necessary to use a mutex. + asAcquireExclusiveLock(); + + string str(data, length); + map_t::iterator it = stringCache.find(str); + if (it != stringCache.end()) + it->second++; + else + it = stringCache.insert(map_t::value_type(str, 1)).first; + + asReleaseExclusiveLock(); + + return reinterpret_cast(&it->first); + } + + int ReleaseStringConstant(const void *str) + { + if (str == 0) + return asERROR; + + int ret = asSUCCESS; + + // The string factory might be modified from multiple + // threads, so it is necessary to use a mutex. + asAcquireExclusiveLock(); + + map_t::iterator it = stringCache.find(*reinterpret_cast(str)); + if (it == stringCache.end()) + ret = asERROR; + else + { + it->second--; + if (it->second == 0) + stringCache.erase(it); + } + + asReleaseExclusiveLock(); + + return ret; + } + + int GetRawStringData(const void *str, char *data, asUINT *length) const + { + if (str == 0) + return asERROR; + + if (length) + *length = (asUINT)reinterpret_cast(str)->length(); + + if (data) + memcpy(data, reinterpret_cast(str)->c_str(), reinterpret_cast(str)->length()); + + return asSUCCESS; + } + + // THe access to the string cache is protected with the common mutex provided by AngelScript + map_t stringCache; +}; + +static CStdStringFactory *stringFactory = 0; + +// TODO: Make this public so the application can also use the string +// factory and share the string constants if so desired, or to +// monitor the size of the string factory cache. +CStdStringFactory *GetStdStringFactorySingleton() +{ + if( stringFactory == 0 ) + { + // The following instance will be destroyed by the global + // CStdStringFactoryCleaner instance upon application shutdown + stringFactory = new CStdStringFactory(); + } + return stringFactory; +} + +class CStdStringFactoryCleaner +{ +public: + ~CStdStringFactoryCleaner() + { + if (stringFactory) + { + // Only delete the string factory if the stringCache is empty + // If it is not empty, it means that someone might still attempt + // to release string constants, so if we delete the string factory + // the application might crash. Not deleting the cache would + // lead to a memory leak, but since this is only happens when the + // application is shutting down anyway, it is not important. + if (stringFactory->stringCache.empty()) + { + delete stringFactory; + stringFactory = 0; + } + } + } +}; + +static CStdStringFactoryCleaner cleaner; + + +static void ConstructString(string *thisPointer) +{ + new(thisPointer) string(); +} + +static void CopyConstructString(const string &other, string *thisPointer) +{ + new(thisPointer) string(other); +} + +static void DestructString(string *thisPointer) +{ + thisPointer->~string(); +} + +static string &AddAssignStringToString(const string &str, string &dest) +{ + // We don't register the method directly because some compilers + // and standard libraries inline the definition, resulting in the + // linker being unable to find the declaration. + // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 + dest += str; + return dest; +} + +// bool string::isEmpty() +// bool string::empty() // if AS_USE_STLNAMES == 1 +static bool StringIsEmpty(const string &str) +{ + // We don't register the method directly because some compilers + // and standard libraries inline the definition, resulting in the + // linker being unable to find the declaration + // Example: CLang/LLVM with XCode 4.3 on OSX 10.7 + return str.empty(); +} + +static string &AssignUInt64ToString(asQWORD i, string &dest) +{ + ostringstream stream; + stream << i; + dest = stream.str(); + return dest; +} + +static string &AddAssignUInt64ToString(asQWORD i, string &dest) +{ + ostringstream stream; + stream << i; + dest += stream.str(); + return dest; +} + +static string AddStringUInt64(const string &str, asQWORD i) +{ + ostringstream stream; + stream << i; + return str + stream.str(); +} + +static string AddInt64String(asINT64 i, const string &str) +{ + ostringstream stream; + stream << i; + return stream.str() + str; +} + +static string &AssignInt64ToString(asINT64 i, string &dest) +{ + ostringstream stream; + stream << i; + dest = stream.str(); + return dest; +} + +static string &AddAssignInt64ToString(asINT64 i, string &dest) +{ + ostringstream stream; + stream << i; + dest += stream.str(); + return dest; +} + +static string AddStringInt64(const string &str, asINT64 i) +{ + ostringstream stream; + stream << i; + return str + stream.str(); +} + +static string AddUInt64String(asQWORD i, const string &str) +{ + ostringstream stream; + stream << i; + return stream.str() + str; +} + +static string &AssignDoubleToString(double f, string &dest) +{ + ostringstream stream; + stream << f; + dest = stream.str(); + return dest; +} + +static string &AddAssignDoubleToString(double f, string &dest) +{ + ostringstream stream; + stream << f; + dest += stream.str(); + return dest; +} + +static string &AssignFloatToString(float f, string &dest) +{ + ostringstream stream; + stream << f; + dest = stream.str(); + return dest; +} + +static string &AddAssignFloatToString(float f, string &dest) +{ + ostringstream stream; + stream << f; + dest += stream.str(); + return dest; +} + +static string &AssignBoolToString(bool b, string &dest) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + dest = stream.str(); + return dest; +} + +static string &AddAssignBoolToString(bool b, string &dest) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + dest += stream.str(); + return dest; +} + +static string AddStringDouble(const string &str, double f) +{ + ostringstream stream; + stream << f; + return str + stream.str(); +} + +static string AddDoubleString(double f, const string &str) +{ + ostringstream stream; + stream << f; + return stream.str() + str; +} + +static string AddStringFloat(const string &str, float f) +{ + ostringstream stream; + stream << f; + return str + stream.str(); +} + +static string AddFloatString(float f, const string &str) +{ + ostringstream stream; + stream << f; + return stream.str() + str; +} + +static string AddStringBool(const string &str, bool b) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + return str + stream.str(); +} + +static string AddBoolString(bool b, const string &str) +{ + ostringstream stream; + stream << (b ? "true" : "false"); + return stream.str() + str; +} + +static char *StringCharAt(unsigned int i, string &str) +{ + if( i >= str.size() ) + { + // Set a script exception + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException("Out of range"); + + // Return a null pointer + return 0; + } + + return &str[i]; +} + +// AngelScript signature: +// int string::opCmp(const string &in) const +static int StringCmp(const string &a, const string &b) +{ + int cmp = 0; + if( a < b ) cmp = -1; + else if( a > b ) cmp = 1; + return cmp; +} + +// This function returns the index of the first position where the substring +// exists in the input string. If the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findFirst(const string &in sub, uint start = 0) const +static int StringFindFirst(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the first position where the one of the bytes in substring +// exists in the input string. If the characters in the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findFirstOf(const string &in sub, uint start = 0) const +static int StringFindFirstOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where the one of the bytes in substring +// exists in the input string. If the characters in the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findLastOf(const string &in sub, uint start = -1) const +static int StringFindLastOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the first position where a byte other than those in substring +// exists in the input string. If none is found -1 is returned. +// +// AngelScript signature: +// int string::findFirstNotOf(const string &in sub, uint start = 0) const +static int StringFindFirstNotOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_first_not_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where a byte other than those in substring +// exists in the input string. If none is found -1 is returned. +// +// AngelScript signature: +// int string::findLastNotOf(const string &in sub, uint start = -1) const +static int StringFindLastNotOf(const string &sub, asUINT start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.find_last_not_of(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// This function returns the index of the last position where the substring +// exists in the input string. If the substring doesn't exist in the input +// string -1 is returned. +// +// AngelScript signature: +// int string::findLast(const string &in sub, int start = -1) const +static int StringFindLast(const string &sub, int start, const string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + return (int)str.rfind(sub, (size_t)(start < 0 ? string::npos : start)); +} + +// AngelScript signature: +// void string::insert(uint pos, const string &in other) +static void StringInsert(unsigned int pos, const string &other, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.insert(pos, other); +} + +// AngelScript signature: +// void string::erase(uint pos, int count = -1) +static void StringErase(unsigned int pos, int count, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.erase(pos, (size_t)(count < 0 ? string::npos : count)); +} + + +// AngelScript signature: +// uint string::length() const +static asUINT StringLength(const string &str) +{ + // We don't register the method directly because the return type changes between 32bit and 64bit platforms + return (asUINT)str.length(); +} + + +// AngelScript signature: +// void string::resize(uint l) +static void StringResize(asUINT l, string &str) +{ + // We don't register the method directly because the argument types change between 32bit and 64bit platforms + str.resize(l); +} + +// AngelScript signature: +// string formatInt(int64 val, const string &in options, uint width) +static string formatInt(asINT64 value, const string &options, asUINT width) +{ + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool hexSmall = options.find("h") != string::npos; + bool hexLarge = options.find("H") != string::npos; + + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; + +#ifdef _WIN32 + fmt += "*I64"; +#else +#ifdef _LP64 + fmt += "*l"; +#else + fmt += "*ll"; +#endif +#endif + + if( hexSmall ) fmt += "x"; + else if( hexLarge ) fmt += "X"; + else fmt += "d"; + + string buf; + buf.resize(width+30); +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); +#else + sprintf(&buf[0], fmt.c_str(), width, value); +#endif + buf.resize(strlen(&buf[0])); + + return buf; +} + +// AngelScript signature: +// string formatUInt(uint64 val, const string &in options, uint width) +static string formatUInt(asQWORD value, const string &options, asUINT width) +{ + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool hexSmall = options.find("h") != string::npos; + bool hexLarge = options.find("H") != string::npos; + + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; + +#ifdef _WIN32 + fmt += "*I64"; +#else +#ifdef _LP64 + fmt += "*l"; +#else + fmt += "*ll"; +#endif +#endif + + if( hexSmall ) fmt += "x"; + else if( hexLarge ) fmt += "X"; + else fmt += "u"; + + string buf; + buf.resize(width+30); +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, value); +#else + sprintf(&buf[0], fmt.c_str(), width, value); +#endif + buf.resize(strlen(&buf[0])); + + return buf; +} + +// AngelScript signature: +// string formatFloat(double val, const string &in options, uint width, uint precision) +static string formatFloat(double value, const string &options, asUINT width, asUINT precision) +{ + bool leftJustify = options.find("l") != string::npos; + bool padWithZero = options.find("0") != string::npos; + bool alwaysSign = options.find("+") != string::npos; + bool spaceOnSign = options.find(" ") != string::npos; + bool expSmall = options.find("e") != string::npos; + bool expLarge = options.find("E") != string::npos; + + string fmt = "%"; + if( leftJustify ) fmt += "-"; + if( alwaysSign ) fmt += "+"; + if( spaceOnSign ) fmt += " "; + if( padWithZero ) fmt += "0"; + + fmt += "*.*"; + + if( expSmall ) fmt += "e"; + else if( expLarge ) fmt += "E"; + else fmt += "f"; + + string buf; + buf.resize(width+precision+50); +#if _MSC_VER >= 1400 && !defined(__S3E__) + // MSVC 8.0 / 2005 or newer + sprintf_s(&buf[0], buf.size(), fmt.c_str(), width, precision, value); +#else + sprintf(&buf[0], fmt.c_str(), width, precision, value); +#endif + buf.resize(strlen(&buf[0])); + + return buf; +} + +// AngelScript signature: +// int64 parseInt(const string &in val, uint base = 10, uint &out byteCount = 0) +static asINT64 parseInt(const string &val, asUINT base, asUINT *byteCount) +{ + // Only accept base 10 and 16 + if( base != 10 && base != 16 ) + { + if( byteCount ) *byteCount = 0; + return 0; + } + + const char *end = &val[0]; + + // Determine the sign + bool sign = false; + if( *end == '-' ) + { + sign = true; + end++; + } + else if( *end == '+' ) + end++; + + asINT64 res = 0; + if( base == 10 ) + { + while( *end >= '0' && *end <= '9' ) + { + res *= 10; + res += *end++ - '0'; + } + } + else if( base == 16 ) + { + while( (*end >= '0' && *end <= '9') || + (*end >= 'a' && *end <= 'f') || + (*end >= 'A' && *end <= 'F') ) + { + res *= 16; + if( *end >= '0' && *end <= '9' ) + res += *end++ - '0'; + else if( *end >= 'a' && *end <= 'f' ) + res += *end++ - 'a' + 10; + else if( *end >= 'A' && *end <= 'F' ) + res += *end++ - 'A' + 10; + } + } + + if( byteCount ) + *byteCount = asUINT(size_t(end - val.c_str())); + + if( sign ) + res = -res; + + return res; +} + +// AngelScript signature: +// uint64 parseUInt(const string &in val, uint base = 10, uint &out byteCount = 0) +static asQWORD parseUInt(const string &val, asUINT base, asUINT *byteCount) +{ + // Only accept base 10 and 16 + if (base != 10 && base != 16) + { + if (byteCount) *byteCount = 0; + return 0; + } + + const char *end = &val[0]; + + asQWORD res = 0; + if (base == 10) + { + while (*end >= '0' && *end <= '9') + { + res *= 10; + res += *end++ - '0'; + } + } + else if (base == 16) + { + while ((*end >= '0' && *end <= '9') || + (*end >= 'a' && *end <= 'f') || + (*end >= 'A' && *end <= 'F')) + { + res *= 16; + if (*end >= '0' && *end <= '9') + res += *end++ - '0'; + else if (*end >= 'a' && *end <= 'f') + res += *end++ - 'a' + 10; + else if (*end >= 'A' && *end <= 'F') + res += *end++ - 'A' + 10; + } + } + + if (byteCount) + *byteCount = asUINT(size_t(end - val.c_str())); + + return res; +} + +// AngelScript signature: +// double parseFloat(const string &in val, uint &out byteCount = 0) +double parseFloat(const string &val, asUINT *byteCount) +{ + char *end; + + // WinCE doesn't have setlocale. Some quick testing on my current platform + // still manages to parse the numbers such as "3.14" even if the decimal for the + // locale is ",". +#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) + // Set the locale to C so that we are guaranteed to parse the float value correctly + char *tmp = setlocale(LC_NUMERIC, 0); + string orig = tmp ? tmp : "C"; + setlocale(LC_NUMERIC, "C"); +#endif + + double res = strtod(val.c_str(), &end); + +#if !defined(_WIN32_WCE) && !defined(ANDROID) && !defined(__psp2__) + // Restore the locale + setlocale(LC_NUMERIC, orig.c_str()); +#endif + + if( byteCount ) + *byteCount = asUINT(size_t(end - val.c_str())); + + return res; +} + +// This function returns a string containing the substring of the input string +// determined by the starting index and count of characters. +// +// AngelScript signature: +// string string::substr(uint start = 0, int count = -1) const +static string StringSubString(asUINT start, int count, const string &str) +{ + // Check for out-of-bounds + string ret; + if( start < str.length() && count != 0 ) + ret = str.substr(start, (size_t)(count < 0 ? string::npos : count)); + + return ret; +} + +// String equality comparison. +// Returns true iff lhs is equal to rhs. +// +// For some reason gcc 4.7 has difficulties resolving the +// asFUNCTIONPR(operator==, (const string &, const string &) +// makro, so this wrapper was introduced as work around. +static bool StringEquals(const std::string& lhs, const std::string& rhs) +{ + return lhs == rhs; +} + +void RegisterStdString_Native(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + // Register the string type +#if AS_CAN_USE_CPP11 + // With C++11 it is possible to use asGetTypeTraits to automatically determine the correct flags to use + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asGetTypeTraits()); assert( r >= 0 ); +#else + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); +#endif + + r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); + + // Register the object operator overloads + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asMETHODPR(string, operator =, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); + // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails + r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +// r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asMETHODPR(string, operator+=, (const string&), string&), asCALL_THISCALL); assert( r >= 0 ); + + // Need to use a wrapper for operator== otherwise gcc 4.7 fails to compile + r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTIONPR(StringEquals, (const string &, const string &), bool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmp), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTIONPR(operator +, (const string &, const string &), string), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + + // The string length can be accessed through methods or through virtual property + // TODO: Register as size() for consistency with other types +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + // Don't register these if STL names is used, as they conflict with the method size() + r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResize), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#endif + // Need to use a wrapper on Mac OS X 10.7/XCode 4.3 and CLang/LLVM, otherwise the linker fails +// r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asMETHOD(string, empty), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Register the index operator, both as a mutator and as an inspector + // Note that we don't register the operator[] directly, as it doesn't do bounds checking + r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAt), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Automatic conversion from values + r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDoubleToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddStringDouble), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDoubleString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloatToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddStringFloat), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloatString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddStringInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt64ToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddStringUInt64), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt64String), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBoolToString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddStringBool), asCALL_CDECL_OBJFIRST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBoolString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + + // Utilities + r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase), asCALL_CDECL_OBJLAST); assert(r >= 0); + + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt), asCALL_CDECL); assert(r >= 0); + r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat), asCALL_CDECL); assert(r >= 0); + +#if AS_USE_STLNAMES == 1 + // Same as length + r = engine->RegisterObjectMethod("string", "uint size() const", asFUNCTION(StringLength), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as isEmpty + r = engine->RegisterObjectMethod("string", "bool empty() const", asFUNCTION(StringIsEmpty), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as findFirst + r = engine->RegisterObjectMethod("string", "int find(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + // Same as findLast + r = engine->RegisterObjectMethod("string", "int rfind(const string &in, int start = -1) const", asFUNCTION(StringFindLast), asCALL_CDECL_OBJLAST); assert( r >= 0 ); +#endif + + // TODO: Implement the following + // findAndReplace - replaces a text found in the string + // replaceRange - replaces a range of bytes in the string + // multiply/times/opMul/opMul_r - takes the string and multiplies it n times, e.g. "-".multiply(5) returns "-----" +} + +static void ConstructStringGeneric(asIScriptGeneric * gen) +{ + new (gen->GetObject()) string(); +} + +static void CopyConstructStringGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetArgObject(0)); + new (gen->GetObject()) string(*a); +} + +static void DestructStringGeneric(asIScriptGeneric * gen) +{ + string * ptr = static_cast(gen->GetObject()); + ptr->~string(); +} + +static void AssignStringGeneric(asIScriptGeneric *gen) +{ + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self = *a; + gen->SetReturnAddress(self); +} + +static void AddAssignStringGeneric(asIScriptGeneric *gen) +{ + string * a = static_cast(gen->GetArgObject(0)); + string * self = static_cast(gen->GetObject()); + *self += *a; + gen->SetReturnAddress(self); +} + +static void StringEqualsGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + *(bool*)gen->GetAddressOfReturnLocation() = (*a == *b); +} + +static void StringCmpGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + + int cmp = 0; + if( *a < *b ) cmp = -1; + else if( *a > *b ) cmp = 1; + + *(int*)gen->GetAddressOfReturnLocation() = cmp; +} + +static void StringAddGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + string * b = static_cast(gen->GetArgAddress(0)); + string ret_val = *a + *b; + gen->SetReturnObject(&ret_val); +} + +static void StringLengthGeneric(asIScriptGeneric * gen) +{ + string * self = static_cast(gen->GetObject()); + *static_cast(gen->GetAddressOfReturnLocation()) = (asUINT)self->length(); +} + +static void StringIsEmptyGeneric(asIScriptGeneric * gen) +{ + string * self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringIsEmpty(*self); +} + +static void StringResizeGeneric(asIScriptGeneric * gen) +{ + string * self = static_cast(gen->GetObject()); + self->resize(*static_cast(gen->GetAddressOfArg(0))); +} + +static void StringInsert_Generic(asIScriptGeneric *gen) +{ + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + string *other = reinterpret_cast(gen->GetArgAddress(1)); + StringInsert(pos, *other, *self); +} + +static void StringErase_Generic(asIScriptGeneric *gen) +{ + string * self = static_cast(gen->GetObject()); + asUINT pos = gen->GetArgDWord(0); + int count = int(gen->GetArgDWord(1)); + StringErase(pos, count, *self); +} + +static void StringFindFirst_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirst(*find, start, *self); +} + +static void StringFindLast_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLast(*find, start, *self); +} + +static void StringFindFirstOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstOf(*find, start, *self); +} + +static void StringFindLastOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastOf(*find, start, *self); +} + +static void StringFindFirstNotOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindFirstNotOf(*find, start, *self); +} + +static void StringFindLastNotOf_Generic(asIScriptGeneric * gen) +{ + string *find = reinterpret_cast(gen->GetArgAddress(0)); + asUINT start = gen->GetArgDWord(1); + string *self = reinterpret_cast(gen->GetObject()); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = StringFindLastNotOf(*find, start, *self); +} + +static void formatInt_Generic(asIScriptGeneric * gen) +{ + asINT64 val = gen->GetArgQWord(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + new(gen->GetAddressOfReturnLocation()) string(formatInt(val, *options, width)); +} + +static void formatUInt_Generic(asIScriptGeneric * gen) +{ + asQWORD val = gen->GetArgQWord(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + new(gen->GetAddressOfReturnLocation()) string(formatUInt(val, *options, width)); +} + +static void formatFloat_Generic(asIScriptGeneric *gen) +{ + double val = gen->GetArgDouble(0); + string *options = reinterpret_cast(gen->GetArgAddress(1)); + asUINT width = gen->GetArgDWord(2); + asUINT precision = gen->GetArgDWord(3); + new(gen->GetAddressOfReturnLocation()) string(formatFloat(val, *options, width, precision)); +} + +static void parseInt_Generic(asIScriptGeneric *gen) +{ + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT base = gen->GetArgDWord(1); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); + gen->SetReturnQWord(parseInt(*str,base,byteCount)); +} + +static void parseUInt_Generic(asIScriptGeneric *gen) +{ + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT base = gen->GetArgDWord(1); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(2)); + gen->SetReturnQWord(parseUInt(*str, base, byteCount)); +} + +static void parseFloat_Generic(asIScriptGeneric *gen) +{ + string *str = reinterpret_cast(gen->GetArgAddress(0)); + asUINT *byteCount = reinterpret_cast(gen->GetArgAddress(1)); + gen->SetReturnDouble(parseFloat(*str,byteCount)); +} + +static void StringCharAtGeneric(asIScriptGeneric * gen) +{ + unsigned int index = gen->GetArgDWord(0); + string * self = static_cast(gen->GetObject()); + + if (index >= self->size()) + { + // Set a script exception + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException("Out of range"); + + gen->SetReturnAddress(0); + } + else + { + gen->SetReturnAddress(&(self->operator [](index))); + } +} + +static void AssignInt2StringGeneric(asIScriptGeneric *gen) +{ + asINT64 *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignUInt2StringGeneric(asIScriptGeneric *gen) +{ + asQWORD *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignDouble2StringGeneric(asIScriptGeneric *gen) +{ + double *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignFloat2StringGeneric(asIScriptGeneric *gen) +{ + float *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AssignBool2StringGeneric(asIScriptGeneric *gen) +{ + bool *a = static_cast(gen->GetAddressOfArg(0)); + string *self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false"); + *self = sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignDouble2StringGeneric(asIScriptGeneric * gen) +{ + double * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignFloat2StringGeneric(asIScriptGeneric * gen) +{ + float * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignInt2StringGeneric(asIScriptGeneric * gen) +{ + asINT64 * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignUInt2StringGeneric(asIScriptGeneric * gen) +{ + asQWORD * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a; + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddAssignBool2StringGeneric(asIScriptGeneric * gen) +{ + bool * a = static_cast(gen->GetAddressOfArg(0)); + string * self = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false"); + *self += sstr.str(); + gen->SetReturnAddress(self); +} + +static void AddString2DoubleGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + double * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2FloatGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + float * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2IntGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + asINT64 * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2UIntGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + asQWORD * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddString2BoolGeneric(asIScriptGeneric * gen) +{ + string * a = static_cast(gen->GetObject()); + bool * b = static_cast(gen->GetAddressOfArg(0)); + std::stringstream sstr; + sstr << *a << (*b ? "true" : "false"); + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddDouble2StringGeneric(asIScriptGeneric * gen) +{ + double* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddFloat2StringGeneric(asIScriptGeneric * gen) +{ + float* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddInt2StringGeneric(asIScriptGeneric * gen) +{ + asINT64* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddUInt2StringGeneric(asIScriptGeneric * gen) +{ + asQWORD* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << *a << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void AddBool2StringGeneric(asIScriptGeneric * gen) +{ + bool* a = static_cast(gen->GetAddressOfArg(0)); + string * b = static_cast(gen->GetObject()); + std::stringstream sstr; + sstr << (*a ? "true" : "false") << *b; + std::string ret_val = sstr.str(); + gen->SetReturnObject(&ret_val); +} + +static void StringSubString_Generic(asIScriptGeneric *gen) +{ + // Get the arguments + string *str = (string*)gen->GetObject(); + asUINT start = *(int*)gen->GetAddressOfArg(0); + int count = *(int*)gen->GetAddressOfArg(1); + + // Return the substring + new(gen->GetAddressOfReturnLocation()) string(StringSubString(start, count, *str)); +} + +void RegisterStdString_Generic(asIScriptEngine *engine) +{ + int r = 0; + UNUSED_VAR(r); + + // Register the string type + r = engine->RegisterObjectType("string", sizeof(string), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 ); + + r = engine->RegisterStringFactory("string", GetStdStringFactorySingleton()); + + // Register the object operator overloads + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(ConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_CONSTRUCT, "void f(const string &in)", asFUNCTION(CopyConstructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("string", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(DestructStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAssign(const string &in)", asFUNCTION(AssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(const string &in)", asFUNCTION(AddAssignStringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "bool opEquals(const string &in) const", asFUNCTION(StringEqualsGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "int opCmp(const string &in) const", asFUNCTION(StringCmpGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(const string &in) const", asFUNCTION(StringAddGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Register the object methods +#if AS_USE_ACCESSORS != 1 + r = engine->RegisterObjectMethod("string", "uint length() const", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("string", "void resize(uint)", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); +#if AS_USE_STLNAMES != 1 && AS_USE_ACCESSORS == 1 + r = engine->RegisterObjectMethod("string", "uint get_length() const property", asFUNCTION(StringLengthGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "void set_length(uint) property", asFUNCTION(StringResizeGeneric), asCALL_GENERIC); assert( r >= 0 ); +#endif + r = engine->RegisterObjectMethod("string", "bool isEmpty() const", asFUNCTION(StringIsEmptyGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Register the index operator, both as a mutator and as an inspector + r = engine->RegisterObjectMethod("string", "uint8 &opIndex(uint)", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "const uint8 &opIndex(uint) const", asFUNCTION(StringCharAtGeneric), asCALL_GENERIC); assert( r >= 0 ); + + // Automatic conversion from values + r = engine->RegisterObjectMethod("string", "string &opAssign(double)", asFUNCTION(AssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(double)", asFUNCTION(AddAssignDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(double) const", asFUNCTION(AddString2DoubleGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(double) const", asFUNCTION(AddDouble2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(float)", asFUNCTION(AssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(float)", asFUNCTION(AddAssignFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(float) const", asFUNCTION(AddString2FloatGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(float) const", asFUNCTION(AddFloat2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(int64)", asFUNCTION(AssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(int64)", asFUNCTION(AddAssignInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(int64) const", asFUNCTION(AddString2IntGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(int64) const", asFUNCTION(AddInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(uint64)", asFUNCTION(AssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(uint64)", asFUNCTION(AddAssignUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(uint64) const", asFUNCTION(AddString2UIntGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(uint64) const", asFUNCTION(AddUInt2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string &opAssign(bool)", asFUNCTION(AssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string &opAddAssign(bool)", asFUNCTION(AddAssignBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd(bool) const", asFUNCTION(AddString2BoolGeneric), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("string", "string opAdd_r(bool) const", asFUNCTION(AddBool2StringGeneric), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("string", "string substr(uint start = 0, int count = -1) const", asFUNCTION(StringSubString_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirst(const string &in, uint start = 0) const", asFUNCTION(StringFindFirst_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findFirstNotOf(const string &in, uint start = 0) const", asFUNCTION(StringFindFirstNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLast(const string &in, int start = -1) const", asFUNCTION(StringFindLast_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "int findLastNotOf(const string &in, int start = -1) const", asFUNCTION(StringFindLastNotOf_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void insert(uint pos, const string &in other)", asFUNCTION(StringInsert_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("string", "void erase(uint pos, int count = -1)", asFUNCTION(StringErase_Generic), asCALL_GENERIC); assert(r >= 0); + + + r = engine->RegisterGlobalFunction("string formatInt(int64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatUInt(uint64 val, const string &in options = \"\", uint width = 0)", asFUNCTION(formatUInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string formatFloat(double val, const string &in options = \"\", uint width = 0, uint precision = 0)", asFUNCTION(formatFloat_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("int64 parseInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("uint64 parseUInt(const string &in, uint base = 10, uint &out byteCount = 0)", asFUNCTION(parseUInt_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("double parseFloat(const string &in, uint &out byteCount = 0)", asFUNCTION(parseFloat_Generic), asCALL_GENERIC); assert(r >= 0); +} + +void RegisterStdString(asIScriptEngine * engine) +{ + if (strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY")) + RegisterStdString_Generic(engine); + else + RegisterStdString_Native(engine); +} + +END_AS_NAMESPACE + + + + diff --git a/add_on/scriptstdstring/scriptstdstring.h b/add_on/scriptstdstring/scriptstdstring.h new file mode 100644 index 0000000..0960beb --- /dev/null +++ b/add_on/scriptstdstring/scriptstdstring.h @@ -0,0 +1,48 @@ +// +// Script std::string +// +// This function registers the std::string type with AngelScript to be used as the default string type. +// +// The string type is registered as a value type, thus may have performance issues if a lot of +// string operations are performed in the script. However, for relatively few operations, this should +// not cause any problem for most applications. +// + +#ifndef SCRIPTSTDSTRING_H +#define SCRIPTSTDSTRING_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include + +//--------------------------- +// Compilation settings +// + +// Sometimes it may be desired to use the same method names as used by C++ STL. +// This may for example reduce time when converting code from script to C++ or +// back. +// +// 0 = off +// 1 = on +#ifndef AS_USE_STLNAMES +#define AS_USE_STLNAMES 0 +#endif + +// Some prefer to use property accessors to get/set the length of the string +// This option registers the accessors instead of the method length() +#ifndef AS_USE_ACCESSORS +#define AS_USE_ACCESSORS 0 +#endif + +BEGIN_AS_NAMESPACE + +void RegisterStdString(asIScriptEngine *engine); +void RegisterStdStringUtils(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/add_on/scriptstdstring/scriptstdstring_utils.cpp b/add_on/scriptstdstring/scriptstdstring_utils.cpp new file mode 100644 index 0000000..54662aa --- /dev/null +++ b/add_on/scriptstdstring/scriptstdstring_utils.cpp @@ -0,0 +1,129 @@ +#include +#include "scriptstdstring.h" +#include "../scriptarray/scriptarray.h" +#include +#include + +using namespace std; + +BEGIN_AS_NAMESPACE + +// This function takes an input string and splits it into parts by looking +// for a specified delimiter. Example: +// +// string str = "A|B||D"; +// array@ array = str.split("|"); +// +// The resulting array has the following elements: +// +// {"A", "B", "", "D"} +// +// AngelScript signature: +// array@ string::split(const string &in delim) const +static CScriptArray *StringSplit(const string &delim, const string &str) +{ + // Obtain a pointer to the engine + asIScriptContext *ctx = asGetActiveContext(); + asIScriptEngine *engine = ctx->GetEngine(); + + // TODO: This should only be done once + // TODO: This assumes that CScriptArray was already registered + asITypeInfo *arrayType = engine->GetTypeInfoByDecl("array"); + + // Create the array object + CScriptArray *array = CScriptArray::Create(arrayType); + + // Find the existence of the delimiter in the input string + int pos = 0, prev = 0, count = 0; + while( (pos = (int)str.find(delim, prev)) != (int)string::npos ) + { + // Add the part to the array + array->Resize(array->GetSize()+1); + ((string*)array->At(count))->assign(&str[prev], pos-prev); + + // Find the next part + count++; + prev = pos + (int)delim.length(); + } + + // Add the remaining part + array->Resize(array->GetSize()+1); + ((string*)array->At(count))->assign(&str[prev]); + + return array; +} + +static void StringSplit_Generic(asIScriptGeneric *gen) +{ + // Get the arguments + string *str = (string*)gen->GetObject(); + string *delim = *(string**)gen->GetAddressOfArg(0); + + // Return the array by handle + *(CScriptArray**)gen->GetAddressOfReturnLocation() = StringSplit(*delim, *str); +} + + + +// This function takes as input an array of string handles as well as a +// delimiter and concatenates the array elements into one delimited string. +// Example: +// +// array array = {"A", "B", "", "D"}; +// string str = join(array, "|"); +// +// The resulting string is: +// +// "A|B||D" +// +// AngelScript signature: +// string join(const array &in array, const string &in delim) +static string StringJoin(const CScriptArray &array, const string &delim) +{ + // Create the new string + string str = ""; + if( array.GetSize() ) + { + int n; + for( n = 0; n < (int)array.GetSize() - 1; n++ ) + { + str += *(string*)array.At(n); + str += delim; + } + + // Add the last part + str += *(string*)array.At(n); + } + + return str; +} + +static void StringJoin_Generic(asIScriptGeneric *gen) +{ + // Get the arguments + CScriptArray *array = *(CScriptArray**)gen->GetAddressOfArg(0); + string *delim = *(string**)gen->GetAddressOfArg(1); + + // Return the string + new(gen->GetAddressOfReturnLocation()) string(StringJoin(*array, *delim)); +} + +// This is where the utility functions are registered. +// The string type must have been registered first. +void RegisterStdStringUtils(asIScriptEngine *engine) +{ + int r; + + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + { + r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin_Generic), asCALL_GENERIC); assert(r >= 0); + } + else + { + r = engine->RegisterObjectMethod("string", "array@ split(const string &in) const", asFUNCTION(StringSplit), asCALL_CDECL_OBJLAST); assert(r >= 0); + r = engine->RegisterGlobalFunction("string join(const array &in, const string &in)", asFUNCTION(StringJoin), asCALL_CDECL); assert(r >= 0); + } +} + +END_AS_NAMESPACE diff --git a/add_on/serializer/serializer.cpp b/add_on/serializer/serializer.cpp new file mode 100644 index 0000000..a359fcd --- /dev/null +++ b/add_on/serializer/serializer.cpp @@ -0,0 +1,548 @@ +// +// CSerializer +// +// This code was based on the CScriptReloader written by FDsagizi +// http://www.gamedev.net/topic/604890-dynamic-reloading-script/ +// + +#include +#include // strstr +#include // sprintf +#include "serializer.h" + +using namespace std; + +BEGIN_AS_NAMESPACE + +/////////////////////////////////////////////////////////////////////////////////// + +CSerializer::CSerializer() +{ + m_engine = 0; +} + +CSerializer::~CSerializer() +{ + // Extra objects need to be released, since they are not stored in + // the module and we cannot rely on the application releasing them + for( size_t i = 0; i < m_extraObjects.size(); i++ ) + { + SExtraObject &o = m_extraObjects[i]; + for( size_t i2 = 0; i2 < m_root.m_children.size(); i2++ ) + { + if( m_root.m_children[i2]->m_originalPtr == o.originalObject && m_root.m_children[i2]->m_restorePtr ) + reinterpret_cast(m_root.m_children[i2]->m_restorePtr)->Release(); + } + } + + // Clean the serialized values before we remove the user types + m_root.Uninit(); + + // Delete the user types + std::map::iterator it; + for( it = m_userTypes.begin(); it != m_userTypes.end(); it++ ) + delete it->second; + + if( m_engine ) + m_engine->Release(); +} + +void CSerializer::AddUserType(CUserType *ref, const std::string &name) +{ + m_userTypes[name] = ref; +} + +int CSerializer::Store(asIScriptModule *mod) +{ + m_mod = mod; + + // The engine must not be destroyed before we're completed, so we'll hold on to a reference + mod->GetEngine()->AddRef(); + if( m_engine ) m_engine->Release(); + m_engine = mod->GetEngine(); + + m_root.m_serializer = this; + + // First store global variables + asUINT i; + for( i = 0; i < mod->GetGlobalVarCount(); i++ ) + { + const char *name, *nameSpace; + int typeId; + mod->GetGlobalVar(i, &name, &nameSpace, &typeId); + m_root.m_children.push_back(new CSerializedValue(&m_root, name, nameSpace, mod->GetAddressOfGlobalVar(i), typeId)); + } + + // Second store extra objects + for( i = 0; i < m_extraObjects.size(); i++ ) + m_root.m_children.push_back(new CSerializedValue(&m_root, "", "", m_extraObjects[i].originalObject, m_extraObjects[i].originalTypeId)); + + // For the handles that were stored, we need to substitute the stored pointer + // that is still pointing to the original object to an internal reference so + // it can be restored later on. + m_root.ReplaceHandles(); + + return 0; +} + +// Retrieve all global variables after reload script. +int CSerializer::Restore(asIScriptModule *mod) +{ + m_mod = mod; + + // The engine must not be destroyed before we're completed, so we'll hold on to a reference + mod->GetEngine()->AddRef(); + if( m_engine ) m_engine->Release(); + m_engine = mod->GetEngine(); + + // First restore extra objects, i.e. the ones that are not directly seen from the module's global variables + asUINT i; + for( i = 0; i < m_extraObjects.size(); i++ ) + { + SExtraObject &o = m_extraObjects[i]; + asITypeInfo *type = m_mod->GetTypeInfoByName( o.originalClassName.c_str() ); + if( type ) + { + for( size_t i2 = 0; i2 < m_root.m_children.size(); i2++ ) + { + if( m_root.m_children[i2]->m_originalPtr == o.originalObject ) + { + // Create a new script object, but don't call its constructor as we will initialize the members. + // Calling the constructor may have unwanted side effects if for example the constructor changes + // any outside entities, such as setting global variables to point to new objects, etc. + void *newPtr = m_engine->CreateUninitializedScriptObject( type ); + m_root.m_children[i2]->Restore( newPtr, type->GetTypeId() ); + } + } + } + } + + // Second restore the global variables + asUINT varCount = mod->GetGlobalVarCount(); + for( i = 0; i < varCount; i++ ) + { + const char *name, *nameSpace; + int typeId; + mod->GetGlobalVar(i, &name, &nameSpace, &typeId); + + CSerializedValue *v = m_root.FindByName(name, nameSpace); + if( v ) + v->Restore(mod->GetAddressOfGlobalVar(i), typeId); + } + + // The handles that were restored needs to be + // updated to point to their final objects. + m_root.RestoreHandles(); + + return 0; +} + +void *CSerializer::GetPointerToRestoredObject(void *ptr) +{ + return m_root.GetPointerToRestoredObject( ptr ); +} + +void CSerializer::AddExtraObjectToStore( asIScriptObject *object ) +{ + if( !object ) + return; + + // Check if the object hasn't been included already + for( size_t i=0; i < m_extraObjects.size(); i++ ) + if( m_extraObjects[i].originalObject == object ) + return; + + SExtraObject o; + o.originalObject = object; + o.originalClassName = object->GetObjectType()->GetName(); + o.originalTypeId = object->GetTypeId(); + + m_extraObjects.push_back( o ); +} + + +/////////////////////////////////////////////////////////////////////////////////// + +CSerializedValue::CSerializedValue() +{ + Init(); +} + +CSerializedValue::CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId) +{ + Init(); + + m_name = name; + m_nameSpace = nameSpace; + m_serializer = parent->m_serializer; + Store(ref, typeId); +} + +void CSerializedValue::Init() +{ + m_handlePtr = 0; + m_restorePtr = 0; + m_typeId = 0; + m_isInit = false; + m_serializer = 0; + m_userData = 0; + m_originalPtr = 0; +} + +void CSerializedValue::Uninit() +{ + m_isInit = false; + + ClearChildren(); + + if( m_userData ) + { + CUserType *type = m_serializer->m_userTypes[m_typeName]; + if( type ) + type->CleanupUserData(this); + m_userData = 0; + } +} + +void CSerializedValue::ClearChildren() +{ + // If this value is for an object handle that created an object during the restore + // then it is necessary to release the handle here, so we won't get a memory leak + if( (m_typeId & asTYPEID_OBJHANDLE) && m_children.size() == 1 && m_children[0]->m_restorePtr ) + { + m_serializer->m_engine->ReleaseScriptObject(m_children[0]->m_restorePtr, m_serializer->m_engine->GetTypeInfoById(m_children[0]->m_typeId)); + } + + for( size_t n = 0; n < m_children.size(); n++ ) + delete m_children[n]; + m_children.clear(); +} + +CSerializedValue::~CSerializedValue() +{ + Uninit(); +} + +CSerializedValue *CSerializedValue::FindByName(const std::string &name, const std::string &nameSpace) +{ + for( size_t i = 0; i < m_children.size(); i++ ) + if( m_children[i]->m_name == name && + m_children[i]->m_nameSpace == nameSpace ) + return m_children[i]; + + return 0; +} + +void CSerializedValue::GetAllPointersOfChildren(std::vector *ptrs) +{ + ptrs->push_back(m_originalPtr); + + for( size_t i = 0; i < m_children.size(); ++i ) + m_children[i]->GetAllPointersOfChildren(ptrs); +} + +CSerializedValue *CSerializedValue::FindByPtr(void *ptr) +{ + if( m_originalPtr == ptr ) + return this; + + for( size_t i = 0; i < m_children.size(); i++ ) + { + CSerializedValue *find = m_children[i]->FindByPtr(ptr); + if( find ) + return find; + } + + return 0; +} + +void *CSerializedValue::GetPointerToRestoredObject(void *ptr) +{ + if( m_originalPtr == ptr ) + return m_restorePtr; + + for( size_t i = 0; i < m_children.size(); ++i ) + { + void *ret = m_children[i]->GetPointerToRestoredObject(ptr); + if( ret ) + return ret; + } + + return 0; +} + +// find variable by ptr but looking only at those in the references, which will create a new object +CSerializedValue *CSerializedValue::FindByPtrInHandles(void *ptr) +{ + // if this handle created object + if( (m_typeId & asTYPEID_OBJHANDLE) && m_children.size() == 1 ) + { + if( m_children[0]->m_originalPtr == ptr ) + return this; + } + + if( !(m_typeId & asTYPEID_OBJHANDLE) ) + { + for( size_t i = 0; i < m_children.size(); i++ ) + { + CSerializedValue *find = m_children[i]->FindByPtrInHandles(ptr); + if( find ) + return find; + } + } + + return 0; +} + +void CSerializedValue::Store(void *ref, int typeId) +{ + m_isInit = true; + SetType(typeId); + m_originalPtr = ref; + + if( m_typeId & asTYPEID_OBJHANDLE ) + { + m_handlePtr = *(void**)ref; + } + else if( m_typeId & asTYPEID_SCRIPTOBJECT ) + { + asIScriptObject *obj = (asIScriptObject *)ref; + asITypeInfo *type = obj->GetObjectType(); + SetType(type->GetTypeId()); + + // Store children + for( asUINT i = 0; i < type->GetPropertyCount(); i++ ) + { + int childId; + const char *childName; + type->GetProperty(i, &childName, &childId); + + m_children.push_back(new CSerializedValue(this, childName, "", obj->GetAddressOfProperty(i), childId)); + } + } + else + { + int size = m_serializer->m_engine->GetSizeOfPrimitiveType(m_typeId); + + if( size == 0 ) + { + // if it is user type( string, array, etc ... ) + if( m_serializer->m_userTypes[m_typeName] ) + m_serializer->m_userTypes[m_typeName]->Store(this, m_originalPtr); + else + { + // POD-types can be stored without need for user type + asITypeInfo *type = GetType(); + if( type && (type->GetFlags() & asOBJ_POD) ) + size = GetType()->GetSize(); + + // It is not necessary to report an error here if it is not a POD-type as that will be done when restoring + } + } + + if( size ) + { + m_mem.resize(size); + memcpy(&m_mem[0], ref, size); + } + } +} + +void CSerializedValue::Restore(void *ref, int typeId) +{ + if( !this || !m_isInit || !ref ) + return; + + // Verify that the stored type matched the new type of the value being restored + if( typeId <= asTYPEID_DOUBLE && typeId != m_typeId ) return; // TODO: We may try to do a type conversion for primitives + if( (typeId & ~asTYPEID_MASK_SEQNBR) ^ (m_typeId & ~asTYPEID_MASK_SEQNBR) ) return; + asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(typeId); + if( type && m_typeName != type->GetName() ) return; + + // Set the new pointer and type + m_restorePtr = ref; + SetType(typeId); + + // Restore the value + if( m_typeId & asTYPEID_OBJHANDLE ) + { + // if need create objects + if( m_children.size() == 1 ) + { + asITypeInfo *ctype = m_children[0]->GetType(); + + if( ctype->GetFactoryCount() == 0 ) + { + // There are no factories, so assume the same pointer is going to be used + m_children[0]->m_restorePtr = m_handlePtr; + + // Increase the refCount for the object as it will be released upon clean-up + m_serializer->m_engine->AddRefScriptObject(m_handlePtr, ctype); + } + else + { + // Create a new script object, but don't call its constructor as we will initialize the members. + // Calling the constructor may have unwanted side effects if for example the constructor changes + // any outside entities, such as setting global variables to point to new objects, etc. + void *newObject = m_serializer->m_engine->CreateUninitializedScriptObject(ctype); + m_children[0]->Restore(newObject, ctype->GetTypeId()); + } + } + } + else if( m_typeId & asTYPEID_SCRIPTOBJECT ) + { + asIScriptObject *obj = (asIScriptObject *)ref; + + // Retrieve children + for( asUINT i = 0; i < type->GetPropertyCount() ; i++ ) + { + const char *nameProperty; + int ptypeId; + type->GetProperty(i, &nameProperty, &ptypeId); + + CSerializedValue *var = FindByName(nameProperty, ""); + if( var ) + var->Restore(obj->GetAddressOfProperty(i), ptypeId); + } + } + else + { + if( m_mem.size() ) + { + // POD values can be restored with direct copy + memcpy(ref, &m_mem[0], m_mem.size()); + } + else if( m_serializer->m_userTypes[m_typeName] ) + { + // user type restore + m_serializer->m_userTypes[m_typeName]->Restore(this, m_restorePtr); + } + else + { + std::string str = "Cannot restore type '"; + str += type->GetName(); + str += "'"; + m_serializer->m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.c_str()); + } + } +} + +void CSerializedValue::CancelDuplicates(CSerializedValue *from) +{ + std::vector ptrs; + from->GetAllPointersOfChildren(&ptrs); + + for( size_t i = 0; i < ptrs.size(); ++i ) + { + CSerializedValue *find = m_serializer->m_root.FindByPtrInHandles(ptrs[i]); + + while( find ) + { + // cancel create object + find->ClearChildren(); + + // Find next link to this ptr + find = m_serializer->m_root.FindByPtrInHandles(ptrs[i]); + } + } +} + +void CSerializedValue::ReplaceHandles() +{ + if( m_handlePtr ) + { + // Find the object that the handle is referring to + CSerializedValue *handle_to = m_serializer->m_root.FindByPtr(m_handlePtr); + + // If the object hasn't been stored yet... + if( handle_to == 0 ) + { + // Store the object now + asITypeInfo *type = GetType(); + CSerializedValue *need_create = new CSerializedValue(this, m_name, m_nameSpace, m_handlePtr, type->GetTypeId()); + + // Make sure all other handles that point to the same object + // are updated, so we don't end up creating duplicates + CancelDuplicates(need_create); + + m_children.push_back(need_create); + } + } + + // Replace the handles in the children too + for( size_t i = 0; i < m_children.size(); ++i ) + m_children[i]->ReplaceHandles(); +} + +void CSerializedValue::RestoreHandles() +{ + if( m_typeId & asTYPEID_OBJHANDLE ) + { + if( m_handlePtr ) + { + // Find the object the handle is supposed to point to + CSerializedValue *handleTo = m_serializer->m_root.FindByPtr(m_handlePtr); + + if( m_restorePtr && handleTo && handleTo->m_restorePtr ) + { + asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(m_typeId); + + // If the handle is already pointing to something it must be released first + if( *(void**)m_restorePtr ) + m_serializer->m_engine->ReleaseScriptObject(*(void**)m_restorePtr, type); + + // Update the internal pointer + *(void**)m_restorePtr = handleTo->m_restorePtr; + + // Increase the reference + m_serializer->m_engine->AddRefScriptObject(handleTo->m_restorePtr, type); + } + } + else + { + // If the handle is pointing to something, we must release it to restore the null pointer + if( m_restorePtr && *(void**)m_restorePtr ) + { + m_serializer->m_engine->ReleaseScriptObject(*(void**)m_restorePtr, m_serializer->m_engine->GetTypeInfoById(m_typeId)); + *(void**)m_restorePtr = 0; + } + } + } + + // Do the same for the children + for( size_t i = 0; i < m_children.size(); ++i ) + m_children[i]->RestoreHandles(); +} + +void CSerializedValue::SetType(int typeId) +{ + m_typeId = typeId; + + asITypeInfo *type = m_serializer->m_engine->GetTypeInfoById(typeId); + + if( type ) + m_typeName = type->GetName(); +} + +asITypeInfo *CSerializedValue::GetType() +{ + if( !m_typeName.empty() ) + { + int newTypeId = m_serializer->m_mod->GetTypeIdByDecl(m_typeName.c_str()); + return m_serializer->m_engine->GetTypeInfoById(newTypeId); + } + + return 0; +} + +void CSerializedValue::SetUserData(void *data) +{ + m_userData = data; +} + +void *CSerializedValue::GetUserData() +{ + return m_userData; +} + +END_AS_NAMESPACE diff --git a/add_on/serializer/serializer.h b/add_on/serializer/serializer.h new file mode 100644 index 0000000..2d91cbe --- /dev/null +++ b/add_on/serializer/serializer.h @@ -0,0 +1,193 @@ +// +// CSerializer +// +// This code was based on the CScriptReloader written by FDsagizi +// http://www.gamedev.net/topic/604890-dynamic-reloading-script/ +// + +#ifndef SERIALIZER_H +#define SERIALIZER_H + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + +#include +#include +#include + +BEGIN_AS_NAMESPACE + +class CSerializer; +class CSerializedValue; + +// Need for register user types objects +// string, any, array... for all object +// user ref type. +struct CUserType +{ + virtual ~CUserType() {}; + virtual void Store(CSerializedValue *val, void *ptr) = 0; + virtual void Restore(CSerializedValue *val, void *ptr) = 0; + virtual void CleanupUserData(CSerializedValue * /*val*/) {} +}; + + +class CSerializedValue +{ +public: + CSerializedValue(); + CSerializedValue(CSerializedValue *parent, const std::string &name, const std::string &nameSpace, void *ref, int typeId); + ~CSerializedValue(); + + // Save the object and its children + void Store(void *ref, int refTypeId); + + // Restore the object and its children + void Restore(void *ref, int refTypeId); + + // Set type of this var + void SetType(int typeId); + + // Returns the object type for non-primitives + asITypeInfo *GetType(); + + // Get child by name variable + CSerializedValue *FindByName(const std::string &name, const std::string &nameSpace); + + // Find variable by ptr + CSerializedValue *FindByPtr(void *ptr); + + // User data + void *GetUserData(); + void SetUserData(void *data); + + // Children, e.g. properties of a script class, or elements + // of an array, or object pointed to by a handle unless it + // is already a variable) + std::vector m_children; + +protected: + friend class CSerializer; + + void Init(); + void Uninit(); + + // you first need to save all the objects before you can save references to objects + void ReplaceHandles(); + + // After the objects has been restored, the handles needs to + // be updated to point to the right objects + void RestoreHandles(); + + // Recursively get all ptrs of the children + void GetAllPointersOfChildren(std::vector *ptrs); + + // may be that the two references refer to the same variable. + // But this variable is not available in the global list. + // According to this reference will be restores it. + // And so two links are not created 2 variables, + // it is necessary to cancel the creation of one of them. + void CancelDuplicates(CSerializedValue *from); + + // Find variable by ptr but looking only at those in the references, which will create a new object + CSerializedValue *FindByPtrInHandles(void *ptr); + + // ptr - is a handle to class + void *GetPointerToRestoredObject(void *ptr); + + // Cleanup children + void ClearChildren(); + + // The serializer object + CSerializer *m_serializer; + + // The user data can be used by CUserType to store extra information + void *m_userData; + + // The type id of the stored value + int m_typeId; + + // For non-primitives the typeId may change if the module is reloaded so + // it is necessary to store the type name to determine the new type id + std::string m_typeName; + + // Name of variable or property + std::string m_name; + std::string m_nameSpace; + + // Is initialized + bool m_isInit; + + // 'this' pointer to variable. + // While storing, this points to the actual variable that was stored. + // While restoring, it is just a unique identifier. + void *m_originalPtr; + + // where handle references + // While storing, this points to the actual object. + // While restoring, it is just a unique identifier. + void *m_handlePtr; + + // new address object, ie address the restoration + // While storing this isn't used. + // While restoring it will point to the actual variable/object that is restored. + void *m_restorePtr; + + // Serialized data for primitives + std::vector m_mem; +}; + + +// This class keeps a list of variables, then restores them after the script is rebuilt. +// But you have to be careful with the change of signature in classes, or +// changing the types of objects. You can remove or add variables, functions, +// methods, but you can not (yet) change the type of variables. +// +// You also need to understand that after a rebuild you should get +// new functions and typeids from the module. +class CSerializer +{ +public: + CSerializer(); + ~CSerializer(); + + // Add implementation for serializing user types + void AddUserType(CUserType *ref, const std::string &name); + + // Store all global variables in the module + int Store(asIScriptModule *mod); + + // Restore all global variables after reloading script + int Restore(asIScriptModule *mod); + + // Store extra objects that are not seen from the module's global variables + void AddExtraObjectToStore(asIScriptObject *object); + + // Return new pointer to restored object + void *GetPointerToRestoredObject(void *originalObject); + +protected: + friend class CSerializedValue; + + CSerializedValue m_root; + asIScriptEngine *m_engine; + asIScriptModule *m_mod; + + std::map m_userTypes; + + struct SExtraObject + { + asIScriptObject *originalObject; + std::string originalClassName; + int originalTypeId; + }; + + std::vector m_extraObjects; +}; + + +END_AS_NAMESPACE + +#endif diff --git a/add_on/weakref/weakref.cpp b/add_on/weakref/weakref.cpp new file mode 100644 index 0000000..385ff71 --- /dev/null +++ b/add_on/weakref/weakref.cpp @@ -0,0 +1,377 @@ + +// The CScriptWeakRef class was originally implemented by vroad in March 2013 + +#include "weakref.h" +#include +#include +#include // strstr() + +BEGIN_AS_NAMESPACE + +static void ScriptWeakRefConstruct(asITypeInfo *type, void *mem) +{ + new(mem) CScriptWeakRef(type); +} + +static void ScriptWeakRefConstruct2(asITypeInfo *type, void *ref, void *mem) +{ + new(mem) CScriptWeakRef(ref, type); + + // It's possible the constructor raised a script exception, in which case we + // need to call the destructor in order to cleanup the memory before returning + asIScriptContext *ctx = asGetActiveContext(); + if( ctx && ctx->GetState() == asEXECUTION_EXCEPTION ) + reinterpret_cast(mem)->~CScriptWeakRef(); +} + +static void ScriptWeakRefDestruct(CScriptWeakRef *obj) +{ + obj->~CScriptWeakRef(); +} + +static bool ScriptWeakRefTemplateCallback(asITypeInfo *ti, bool &/*dontGarbageCollect*/) +{ + asITypeInfo *subType = ti->GetSubType(); + + // Weak references only work for reference types + if( subType == 0 ) return false; + if( !(subType->GetFlags() & asOBJ_REF) ) return false; + + // The subtype shouldn't be a handle + if( ti->GetSubTypeId() & asTYPEID_OBJHANDLE ) + return false; + + // Make sure the type really supports weak references + asUINT cnt = subType->GetBehaviourCount(); + for( asUINT n = 0; n < cnt; n++ ) + { + asEBehaviours beh; + subType->GetBehaviourByIndex(n, &beh); + if( beh == asBEHAVE_GET_WEAKREF_FLAG ) + return true; + } + + ti->GetEngine()->WriteMessage("weakref", 0, 0, asMSGTYPE_ERROR, "The subtype doesn't support weak references"); + return false; +} + +CScriptWeakRef::CScriptWeakRef(asITypeInfo *type) +{ + m_ref = 0; + m_type = type; + m_type->AddRef(); + m_weakRefFlag = 0; +} + +CScriptWeakRef::CScriptWeakRef(const CScriptWeakRef &other) +{ + m_ref = other.m_ref; + m_type = other.m_type; + m_type->AddRef(); + m_weakRefFlag = other.m_weakRefFlag; + if( m_weakRefFlag ) + m_weakRefFlag->AddRef(); +} + +CScriptWeakRef::CScriptWeakRef(void *ref, asITypeInfo *type) +{ + m_ref = ref; + m_type = type; + m_type->AddRef(); + + // The given type should be the weakref template instance + assert( strcmp(type->GetName(), "weakref") == 0 || + strcmp(type->GetName(), "const_weakref") == 0 ); + + // Get the shared flag that will tell us when the object has been destroyed + // This is threadsafe as we hold a strong reference to the object + m_weakRefFlag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(m_ref, m_type->GetSubType()); + if( m_weakRefFlag ) + m_weakRefFlag->AddRef(); +} + +CScriptWeakRef::~CScriptWeakRef() +{ + if( m_type ) + m_type->Release(); + if( m_weakRefFlag ) + m_weakRefFlag->Release(); +} + +CScriptWeakRef &CScriptWeakRef::operator =(const CScriptWeakRef &other) +{ + // Don't do anything if it is the same reference + // It is not enough to verify only the reference to the object, as the + // address may be reused by another instance after the first has been freed. + // By checking also the weakRefFlag we can be certain that it is the same + // instance. + if( m_ref == other.m_ref && + m_weakRefFlag == other.m_weakRefFlag ) + return *this; + + // Must not allow changing the type + if( m_type != other.m_type ) + { + // We can allow a weakref to be assigned to a const_weakref + if( !(strcmp(m_type->GetName(), "const_weakref") == 0 && + strcmp(other.m_type->GetName(), "weakref") == 0 && + m_type->GetSubType() == other.m_type->GetSubType()) ) + { + assert( false ); + return *this; + } + } + + m_ref = other.m_ref; + + if( m_weakRefFlag ) + m_weakRefFlag->Release(); + m_weakRefFlag = other.m_weakRefFlag; + if( m_weakRefFlag ) + m_weakRefFlag->AddRef(); + + return *this; +} + +CScriptWeakRef &CScriptWeakRef::Set(void *newRef) +{ + // Release the previous weak ref + if( m_weakRefFlag ) + m_weakRefFlag->Release(); + + // Retrieve the new weak ref + m_ref = newRef; + if( newRef ) + { + m_weakRefFlag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(newRef, m_type->GetSubType()); + m_weakRefFlag->AddRef(); + } + else + m_weakRefFlag = 0; + + // Release the newRef since we're only supposed to hold a weakref + m_type->GetEngine()->ReleaseScriptObject(newRef, m_type->GetSubType()); + + return *this; +} + +asITypeInfo *CScriptWeakRef::GetRefType() const +{ + return m_type->GetSubType(); +} + +bool CScriptWeakRef::operator==(const CScriptWeakRef &o) const +{ + // It is not enough to compare just the address of the object, as it may + // be reused by another instance after the first has been freed. By verifying + // also the weakRefFlag we can guarantee that it is indeed the same instance. + if( m_ref == o.m_ref && + m_weakRefFlag == o.m_weakRefFlag && + m_type == o.m_type ) + return true; + + // TODO: If type is not the same, we should attempt to do a dynamic cast, + // which may change the pointer for application registered classes + + return false; +} + +bool CScriptWeakRef::operator!=(const CScriptWeakRef &o) const +{ + return !(*this == o); +} + +// AngelScript: used as '@obj = ref.get();' +void *CScriptWeakRef::Get() const +{ + // If we hold a null handle, then just return null + if( m_ref == 0 || m_weakRefFlag == 0 ) + return 0; + + // Lock on the shared bool, so we can be certain it won't be changed to true + // between the inspection of the flag and the increase of the ref count in the + // owning object. + m_weakRefFlag->Lock(); + if( !m_weakRefFlag->Get() ) + { + m_type->GetEngine()->AddRefScriptObject(m_ref, m_type->GetSubType()); + m_weakRefFlag->Unlock(); + return m_ref; + } + m_weakRefFlag->Unlock(); + + return 0; +} + +bool CScriptWeakRef::Equals(void *ref) const +{ + if( m_ref != ref ) + return false; + + // It is not enough to compare just the address, as another instance may + // get the same address after the first instance has been freed. Verify the + // weakref flag too to make sure it is the same instance + asILockableSharedBool *flag = m_type->GetEngine()->GetWeakRefFlagOfScriptObject(ref, m_type->GetSubType()); + if (m_weakRefFlag != flag) + return false; + + return true; +} + +void RegisterScriptWeakRef_Native(asIScriptEngine *engine) +{ + int r; + + // Register a type for non-const handles + r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("weakref", "T@ opImplCast()", asMETHOD(CScriptWeakRef, Get), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("weakref", "T@ get() const", asMETHODPR(CScriptWeakRef, Get, () const, void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(const weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opAssign(const weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("weakref", "bool opEquals(const weakref &in) const", asMETHODPR(CScriptWeakRef, operator==, (const CScriptWeakRef &) const, bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(T@)", asMETHOD(CScriptWeakRef, Set), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "bool opEquals(const T@+) const", asMETHOD(CScriptWeakRef, Equals), asCALL_THISCALL); assert(r >= 0); + + // Register another type for const handles + r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2), asCALL_CDECL_OBJLAST); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct), asCALL_CDECL_OBJLAST); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback), asCALL_CDECL); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("const_weakref", "const T@ opImplCast() const", asMETHOD(CScriptWeakRef, Get), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("const_weakref", "const T@ get() const", asMETHODPR(CScriptWeakRef, Get, () const, void*), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const const_weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opAssign(const const_weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert(r >= 0); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const const_weakref &in) const", asMETHODPR(CScriptWeakRef, operator==, (const CScriptWeakRef &) const, bool), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const T@)", asMETHOD(CScriptWeakRef, Set), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const T@+) const", asMETHOD(CScriptWeakRef, Equals), asCALL_THISCALL); assert(r >= 0); + + // Allow non-const weak references to be converted to const weak references + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const weakref &in)", asMETHOD(CScriptWeakRef, operator=), asCALL_THISCALL); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const weakref &in) const", asMETHODPR(CScriptWeakRef, operator==, (const CScriptWeakRef &) const, bool), asCALL_THISCALL); assert( r >= 0 ); +} + +static void ScriptWeakRefConstruct_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); + + ScriptWeakRefConstruct(ti, gen->GetObject()); +} + +static void ScriptWeakRefConstruct2_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); + void *ref = gen->GetArgAddress(1); + + ScriptWeakRefConstruct2(ti, ref, gen->GetObject()); +} + +static void ScriptWeakRefDestruct_Generic(asIScriptGeneric *gen) +{ + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + self->~CScriptWeakRef(); +} + +void CScriptWeakRef_Get_Generic(asIScriptGeneric *gen) +{ + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnAddress(self->Get()); +} + +void CScriptWeakRef_Assign_Generic(asIScriptGeneric *gen) +{ + CScriptWeakRef *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + *self = *other; + gen->SetReturnAddress(self); +} + +void CScriptWeakRef_Assign2_Generic(asIScriptGeneric *gen) +{ + void *other = gen->GetArgAddress(0); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + self->Set(other); + gen->SetReturnAddress(self); +} + +void CScriptWeakRef_Equals_Generic(asIScriptGeneric *gen) +{ + CScriptWeakRef *other = reinterpret_cast(gen->GetArgAddress(0)); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + gen->SetReturnByte(*self == *other); +} + +void CScriptWeakRef_Equals2_Generic(asIScriptGeneric *gen) +{ + void *other = gen->GetArgAddress(0); + CScriptWeakRef *self = reinterpret_cast(gen->GetObject()); + + gen->SetReturnByte(self->Equals(other)); +} + +static void ScriptWeakRefTemplateCallback_Generic(asIScriptGeneric *gen) +{ + asITypeInfo *ti = *reinterpret_cast(gen->GetAddressOfArg(0)); + bool *dontGarbageCollect = *reinterpret_cast(gen->GetAddressOfArg(1)); + *reinterpret_cast(gen->GetAddressOfReturnLocation()) = ScriptWeakRefTemplateCallback(ti, *dontGarbageCollect); +} + +void RegisterScriptWeakRef_Generic(asIScriptEngine *engine) +{ + int r; + + // Register a type for non-const handles + r = engine->RegisterObjectType("weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_CONSTRUCT, "void f(int&in, T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("weakref", "T@ opImplCast()", asFUNCTION(CScriptWeakRef_Get_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("weakref", "T@ get() const", asFUNCTION(CScriptWeakRef_Get_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(const weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opAssign(const weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("weakref", "bool opEquals(const weakref &in) const", asFUNCTION(CScriptWeakRef_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "weakref &opHndlAssign(T@)", asFUNCTION(CScriptWeakRef_Assign2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("weakref", "bool opEquals(const T@+) const", asFUNCTION(CScriptWeakRef_Equals2_Generic), asCALL_GENERIC); assert(r >= 0); + + // Register another type for const handles + r = engine->RegisterObjectType("const_weakref", sizeof(CScriptWeakRef), asOBJ_VALUE | asOBJ_ASHANDLE | asOBJ_TEMPLATE | asOBJ_APP_CLASS_DAK); assert( r >= 0 ); + + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptWeakRefConstruct_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_CONSTRUCT, "void f(int&in, const T@+)", asFUNCTION(ScriptWeakRefConstruct2_Generic), asCALL_GENERIC); assert( r>= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int&in, bool&out)", asFUNCTION(ScriptWeakRefTemplateCallback_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectBehaviour("const_weakref", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(ScriptWeakRefDestruct_Generic), asCALL_GENERIC); assert( r >= 0 ); + + r = engine->RegisterObjectMethod("const_weakref", "const T@ opImplCast() const", asFUNCTION(CScriptWeakRef_Get_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("const_weakref", "const T@ get() const", asFUNCTION(CScriptWeakRef_Get_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const const_weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opAssign(const const_weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert(r >= 0); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const const_weakref &in) const", asFUNCTION(CScriptWeakRef_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const T@)", asFUNCTION(CScriptWeakRef_Assign2_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const T@+) const", asFUNCTION(CScriptWeakRef_Equals2_Generic), asCALL_GENERIC); assert(r >= 0); + + // Allow non-const weak references to be converted to const weak references + r = engine->RegisterObjectMethod("const_weakref", "const_weakref &opHndlAssign(const weakref &in)", asFUNCTION(CScriptWeakRef_Assign_Generic), asCALL_GENERIC); assert( r >= 0 ); + r = engine->RegisterObjectMethod("const_weakref", "bool opEquals(const weakref &in) const", asFUNCTION(CScriptWeakRef_Equals_Generic), asCALL_GENERIC); assert( r >= 0 ); +} + +void RegisterScriptWeakRef(asIScriptEngine *engine) +{ + if( strstr(asGetLibraryOptions(), "AS_MAX_PORTABILITY") ) + RegisterScriptWeakRef_Generic(engine); + else + RegisterScriptWeakRef_Native(engine); +} + + +END_AS_NAMESPACE diff --git a/add_on/weakref/weakref.h b/add_on/weakref/weakref.h new file mode 100644 index 0000000..ac24ea9 --- /dev/null +++ b/add_on/weakref/weakref.h @@ -0,0 +1,58 @@ +#ifndef SCRIPTWEAKREF_H +#define SCRIPTWEAKREF_H + +// The CScriptWeakRef class was originally implemented by vroad in March 2013 + +#ifndef ANGELSCRIPT_H +// Avoid having to inform include path if header is already include before +#include +#endif + + +BEGIN_AS_NAMESPACE + +class CScriptWeakRef +{ +public: + // Constructors + CScriptWeakRef(asITypeInfo *type); + CScriptWeakRef(const CScriptWeakRef &other); + CScriptWeakRef(void *ref, asITypeInfo *type); + + ~CScriptWeakRef(); + + // Copy the stored value from another weakref object + CScriptWeakRef &operator=(const CScriptWeakRef &other); + + // Compare equalness + bool operator==(const CScriptWeakRef &o) const; + bool operator!=(const CScriptWeakRef &o) const; + + // Sets a new reference + CScriptWeakRef &Set(void *newRef); + + // Returns the object if it is still alive + // This will increment the refCount of the returned object + void *Get() const; + + // Returns true if the contained reference is the same + bool Equals(void *ref) const; + + // Returns the type of the reference held + asITypeInfo *GetRefType() const; + +protected: + // These functions need to have access to protected + // members in order to call them from the script engine + friend void RegisterScriptWeakRef_Native(asIScriptEngine *engine); + + void *m_ref; + asITypeInfo *m_type; + asILockableSharedBool *m_weakRefFlag; +}; + +void RegisterScriptWeakRef(asIScriptEngine *engine); + +END_AS_NAMESPACE + +#endif \ No newline at end of file diff --git a/angelscript/include/angelscript.h b/angelscript/include/angelscript.h new file mode 100644 index 0000000..32c191b --- /dev/null +++ b/angelscript/include/angelscript.h @@ -0,0 +1,1958 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// angelscript.h +// +// The script engine interface +// + + +#ifndef ANGELSCRIPT_H +#define ANGELSCRIPT_H + +#include +#ifndef _MSC_VER +#include +#endif + +#ifdef AS_USE_NAMESPACE + #define BEGIN_AS_NAMESPACE namespace AngelScript { + #define END_AS_NAMESPACE } + #define AS_NAMESPACE_QUALIFIER AngelScript:: +#else + #define BEGIN_AS_NAMESPACE + #define END_AS_NAMESPACE + #define AS_NAMESPACE_QUALIFIER :: +#endif + +BEGIN_AS_NAMESPACE + +// AngelScript version + +#define ANGELSCRIPT_VERSION 23500 +#define ANGELSCRIPT_VERSION_STRING "2.35.0" + +// Data types + +class asIScriptEngine; +class asIScriptModule; +class asIScriptContext; +class asIScriptGeneric; +class asIScriptObject; +class asITypeInfo; +class asIScriptFunction; +class asIBinaryStream; +class asIJITCompiler; +class asIThreadManager; +class asILockableSharedBool; +class asIStringFactory; + +// Enumerations and constants + +// Return codes +enum asERetCodes +{ + asSUCCESS = 0, + asERROR = -1, + asCONTEXT_ACTIVE = -2, + asCONTEXT_NOT_FINISHED = -3, + asCONTEXT_NOT_PREPARED = -4, + asINVALID_ARG = -5, + asNO_FUNCTION = -6, + asNOT_SUPPORTED = -7, + asINVALID_NAME = -8, + asNAME_TAKEN = -9, + asINVALID_DECLARATION = -10, + asINVALID_OBJECT = -11, + asINVALID_TYPE = -12, + asALREADY_REGISTERED = -13, + asMULTIPLE_FUNCTIONS = -14, + asNO_MODULE = -15, + asNO_GLOBAL_VAR = -16, + asINVALID_CONFIGURATION = -17, + asINVALID_INTERFACE = -18, + asCANT_BIND_ALL_FUNCTIONS = -19, + asLOWER_ARRAY_DIMENSION_NOT_REGISTERED = -20, + asWRONG_CONFIG_GROUP = -21, + asCONFIG_GROUP_IS_IN_USE = -22, + asILLEGAL_BEHAVIOUR_FOR_TYPE = -23, + asWRONG_CALLING_CONV = -24, + asBUILD_IN_PROGRESS = -25, + asINIT_GLOBAL_VARS_FAILED = -26, + asOUT_OF_MEMORY = -27, + asMODULE_IS_IN_USE = -28 +}; + +// Engine properties +enum asEEngineProp +{ + asEP_ALLOW_UNSAFE_REFERENCES = 1, + asEP_OPTIMIZE_BYTECODE = 2, + asEP_COPY_SCRIPT_SECTIONS = 3, + asEP_MAX_STACK_SIZE = 4, + asEP_USE_CHARACTER_LITERALS = 5, + asEP_ALLOW_MULTILINE_STRINGS = 6, + asEP_ALLOW_IMPLICIT_HANDLE_TYPES = 7, + asEP_BUILD_WITHOUT_LINE_CUES = 8, + asEP_INIT_GLOBAL_VARS_AFTER_BUILD = 9, + asEP_REQUIRE_ENUM_SCOPE = 10, + asEP_SCRIPT_SCANNER = 11, + asEP_INCLUDE_JIT_INSTRUCTIONS = 12, + asEP_STRING_ENCODING = 13, + asEP_PROPERTY_ACCESSOR_MODE = 14, + asEP_EXPAND_DEF_ARRAY_TO_TMPL = 15, + asEP_AUTO_GARBAGE_COLLECT = 16, + asEP_DISALLOW_GLOBAL_VARS = 17, + asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT = 18, + asEP_COMPILER_WARNINGS = 19, + asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE = 20, + asEP_ALTER_SYNTAX_NAMED_ARGS = 21, + asEP_DISABLE_INTEGER_DIVISION = 22, + asEP_DISALLOW_EMPTY_LIST_ELEMENTS = 23, + asEP_PRIVATE_PROP_AS_PROTECTED = 24, + asEP_ALLOW_UNICODE_IDENTIFIERS = 25, + asEP_HEREDOC_TRIM_MODE = 26, + asEP_MAX_NESTED_CALLS = 27, + asEP_GENERIC_CALL_MODE = 28, + asEP_INIT_STACK_SIZE = 29, + asEP_INIT_CALL_STACK_SIZE = 30, + asEP_MAX_CALL_STACK_SIZE = 31, + + asEP_LAST_PROPERTY +}; + +// Calling conventions +enum asECallConvTypes +{ + asCALL_CDECL = 0, + asCALL_STDCALL = 1, + asCALL_THISCALL_ASGLOBAL = 2, + asCALL_THISCALL = 3, + asCALL_CDECL_OBJLAST = 4, + asCALL_CDECL_OBJFIRST = 5, + asCALL_GENERIC = 6, + asCALL_THISCALL_OBJLAST = 7, + asCALL_THISCALL_OBJFIRST = 8 +}; + +// Object type flags +enum asEObjTypeFlags +{ + asOBJ_REF = (1<<0), + asOBJ_VALUE = (1<<1), + asOBJ_GC = (1<<2), + asOBJ_POD = (1<<3), + asOBJ_NOHANDLE = (1<<4), + asOBJ_SCOPED = (1<<5), + asOBJ_TEMPLATE = (1<<6), + asOBJ_ASHANDLE = (1<<7), + asOBJ_APP_CLASS = (1<<8), + asOBJ_APP_CLASS_CONSTRUCTOR = (1<<9), + asOBJ_APP_CLASS_DESTRUCTOR = (1<<10), + asOBJ_APP_CLASS_ASSIGNMENT = (1<<11), + asOBJ_APP_CLASS_COPY_CONSTRUCTOR = (1<<12), + asOBJ_APP_CLASS_C = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR), + asOBJ_APP_CLASS_CD = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR), + asOBJ_APP_CLASS_CA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), + asOBJ_APP_CLASS_CK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_CDA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), + asOBJ_APP_CLASS_CDK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_CAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_CDAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_D = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR), + asOBJ_APP_CLASS_DA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), + asOBJ_APP_CLASS_DK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_DAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_A = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_ASSIGNMENT), + asOBJ_APP_CLASS_AK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_K = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), + asOBJ_APP_CLASS_MORE_CONSTRUCTORS = (1<<31), + asOBJ_APP_PRIMITIVE = (1<<13), + asOBJ_APP_FLOAT = (1<<14), + asOBJ_APP_ARRAY = (1<<15), + asOBJ_APP_CLASS_ALLINTS = (1<<16), + asOBJ_APP_CLASS_ALLFLOATS = (1<<17), + asOBJ_NOCOUNT = (1<<18), + asOBJ_APP_CLASS_ALIGN8 = (1<<19), + asOBJ_IMPLICIT_HANDLE = (1<<20), + asOBJ_MASK_VALID_FLAGS = 0x801FFFFF, + // Internal flags + asOBJ_SCRIPT_OBJECT = (1<<21), + asOBJ_SHARED = (1<<22), + asOBJ_NOINHERIT = (1<<23), + asOBJ_FUNCDEF = (1<<24), + asOBJ_LIST_PATTERN = (1<<25), + asOBJ_ENUM = (1<<26), + asOBJ_TEMPLATE_SUBTYPE = (1<<27), + asOBJ_TYPEDEF = (1<<28), + asOBJ_ABSTRACT = (1<<29), + asOBJ_APP_ALIGN16 = (1<<30) +}; + +// Behaviours +enum asEBehaviours +{ + // Value object memory management + asBEHAVE_CONSTRUCT, + asBEHAVE_LIST_CONSTRUCT, + asBEHAVE_DESTRUCT, + + // Reference object memory management + asBEHAVE_FACTORY, + asBEHAVE_LIST_FACTORY, + asBEHAVE_ADDREF, + asBEHAVE_RELEASE, + asBEHAVE_GET_WEAKREF_FLAG, + + // Object operators + asBEHAVE_TEMPLATE_CALLBACK, + + // Garbage collection behaviours + asBEHAVE_FIRST_GC, + asBEHAVE_GETREFCOUNT = asBEHAVE_FIRST_GC, + asBEHAVE_SETGCFLAG, + asBEHAVE_GETGCFLAG, + asBEHAVE_ENUMREFS, + asBEHAVE_RELEASEREFS, + asBEHAVE_LAST_GC = asBEHAVE_RELEASEREFS, + + asBEHAVE_MAX +}; + +// Context states +enum asEContextState +{ + asEXECUTION_FINISHED = 0, + asEXECUTION_SUSPENDED = 1, + asEXECUTION_ABORTED = 2, + asEXECUTION_EXCEPTION = 3, + asEXECUTION_PREPARED = 4, + asEXECUTION_UNINITIALIZED = 5, + asEXECUTION_ACTIVE = 6, + asEXECUTION_ERROR = 7 +}; + +// Message types +enum asEMsgType +{ + asMSGTYPE_ERROR = 0, + asMSGTYPE_WARNING = 1, + asMSGTYPE_INFORMATION = 2 +}; + +// Garbage collector flags +enum asEGCFlags +{ + asGC_FULL_CYCLE = 1, + asGC_ONE_STEP = 2, + asGC_DESTROY_GARBAGE = 4, + asGC_DETECT_GARBAGE = 8 +}; + +// Token classes +enum asETokenClass +{ + asTC_UNKNOWN = 0, + asTC_KEYWORD = 1, + asTC_VALUE = 2, + asTC_IDENTIFIER = 3, + asTC_COMMENT = 4, + asTC_WHITESPACE = 5 +}; + +// Type id flags +enum asETypeIdFlags +{ + asTYPEID_VOID = 0, + asTYPEID_BOOL = 1, + asTYPEID_INT8 = 2, + asTYPEID_INT16 = 3, + asTYPEID_INT32 = 4, + asTYPEID_INT64 = 5, + asTYPEID_UINT8 = 6, + asTYPEID_UINT16 = 7, + asTYPEID_UINT32 = 8, + asTYPEID_UINT64 = 9, + asTYPEID_FLOAT = 10, + asTYPEID_DOUBLE = 11, + asTYPEID_OBJHANDLE = 0x40000000, + asTYPEID_HANDLETOCONST = 0x20000000, + asTYPEID_MASK_OBJECT = 0x1C000000, + asTYPEID_APPOBJECT = 0x04000000, + asTYPEID_SCRIPTOBJECT = 0x08000000, + asTYPEID_TEMPLATE = 0x10000000, + asTYPEID_MASK_SEQNBR = 0x03FFFFFF +}; + +// Type modifiers +enum asETypeModifiers +{ + asTM_NONE = 0, + asTM_INREF = 1, + asTM_OUTREF = 2, + asTM_INOUTREF = 3, + asTM_CONST = 4 +}; + +// GetModule flags +enum asEGMFlags +{ + asGM_ONLY_IF_EXISTS = 0, + asGM_CREATE_IF_NOT_EXISTS = 1, + asGM_ALWAYS_CREATE = 2 +}; + +// Compile flags +enum asECompileFlags +{ + asCOMP_ADD_TO_MODULE = 1 +}; + +// Function types +enum asEFuncType +{ + asFUNC_DUMMY =-1, + asFUNC_SYSTEM = 0, + asFUNC_SCRIPT = 1, + asFUNC_INTERFACE = 2, + asFUNC_VIRTUAL = 3, + asFUNC_FUNCDEF = 4, + asFUNC_IMPORTED = 5, + asFUNC_DELEGATE = 6 +}; + +// +// asBYTE = 8 bits +// asWORD = 16 bits +// asDWORD = 32 bits +// asQWORD = 64 bits +// asPWORD = size of pointer +// +typedef signed char asINT8; +typedef signed short asINT16; +typedef unsigned char asBYTE; +typedef unsigned short asWORD; +typedef unsigned int asUINT; +#if (defined(_MSC_VER) && _MSC_VER <= 1200) || defined(__S3E__) || (defined(_MSC_VER) && defined(__clang__)) + // size_t is not really correct, since it only guaranteed to be large enough to hold the segment size. + // For example, on 16bit systems the size_t may be 16bits only even if pointers are 32bit. But nobody + // is likely to use MSVC6 to compile for 16bit systems anymore, so this should be ok. + typedef size_t asPWORD; +#else + typedef uintptr_t asPWORD; +#endif +#ifdef __LP64__ + typedef unsigned int asDWORD; + typedef unsigned long asQWORD; + typedef long asINT64; +#else + typedef unsigned long asDWORD; + #if !defined(_MSC_VER) && (defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_CC) || defined(__psp2__)) + typedef uint64_t asQWORD; + typedef int64_t asINT64; + #else + typedef unsigned __int64 asQWORD; + typedef __int64 asINT64; + #endif +#endif + +// Is the target a 64bit system? +#if defined(__LP64__) || defined(__amd64__) || defined(__x86_64__) || defined(_M_X64) || defined(__aarch64__) || defined(_M_ARM64) + #ifndef AS_64BIT_PTR + #define AS_64BIT_PTR + #endif +#endif + +typedef void (*asFUNCTION_t)(); +typedef void (*asGENFUNC_t)(asIScriptGeneric *); +typedef void *(*asALLOCFUNC_t)(size_t); +typedef void (*asFREEFUNC_t)(void *); +typedef void (*asCLEANENGINEFUNC_t)(asIScriptEngine *); +typedef void (*asCLEANMODULEFUNC_t)(asIScriptModule *); +typedef void (*asCLEANCONTEXTFUNC_t)(asIScriptContext *); +typedef void (*asCLEANFUNCTIONFUNC_t)(asIScriptFunction *); +typedef void (*asCLEANTYPEINFOFUNC_t)(asITypeInfo *); +typedef void (*asCLEANSCRIPTOBJECTFUNC_t)(asIScriptObject *); +typedef asIScriptContext *(*asREQUESTCONTEXTFUNC_t)(asIScriptEngine *, void *); +typedef void (*asRETURNCONTEXTFUNC_t)(asIScriptEngine *, asIScriptContext *, void *); +typedef void (*asCIRCULARREFFUNC_t)(asITypeInfo *, const void *, void *); + +// Check if the compiler can use C++11 features +#if !defined(_MSC_VER) || _MSC_VER >= 1700 // MSVC 2012 + #if !defined(__GNUC__) || defined(__clang__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) // gnuc 4.7 or clang + #if !(defined(__GNUC__) && defined(__cplusplus) && __cplusplus < 201103L) // gnuc and clang require compiler flag -std=c++11 + #if !defined(__SUNPRO_CC) // Oracle Solaris Studio + #define AS_CAN_USE_CPP11 1 + #endif + #endif + #endif +#endif + +// This macro does basically the same thing as offsetof defined in stddef.h, but +// GNUC should not complain about the usage as I'm not using 0 as the base pointer. +#define asOFFSET(s,m) ((int)(size_t)(&reinterpret_cast(100000)->m)-100000) + +#define asFUNCTION(f) asFunctionPtr(f) +#if (defined(_MSC_VER) && _MSC_VER <= 1200) || (defined(__BORLANDC__) && __BORLANDC__ < 0x590) +// MSVC 6 has a bug that prevents it from properly compiling using the correct asFUNCTIONPR with operator > +// so we need to use ordinary C style cast instead of static_cast. The drawback is that the compiler can't +// check that the cast is really valid. +// BCC v5.8 (C++Builder 2006) and earlier have a similar bug which forces us to fall back to a C-style cast. +#define asFUNCTIONPR(f,p,r) asFunctionPtr((void (*)())((r (*)p)(f))) +#else +#define asFUNCTIONPR(f,p,r) asFunctionPtr(reinterpret_cast(static_cast(f))) +#endif + +#ifndef AS_NO_CLASS_METHODS + +class asCUnknownClass; +typedef void (asCUnknownClass::*asMETHOD_t)(); + +struct asSFuncPtr +{ + asSFuncPtr(asBYTE f = 0) + { + for( size_t n = 0; n < sizeof(ptr.dummy); n++ ) + ptr.dummy[n] = 0; + flag = f; + } + + void CopyMethodPtr(const void *mthdPtr, size_t size) + { + for( size_t n = 0; n < size; n++ ) + ptr.dummy[n] = reinterpret_cast(mthdPtr)[n]; + } + + union + { + // The largest known method point is 20 bytes (MSVC 64bit), + // but with 8byte alignment this becomes 24 bytes. So we need + // to be able to store at least that much. + char dummy[25]; + struct {asMETHOD_t mthd; char dummy[25-sizeof(asMETHOD_t)];} m; + struct {asFUNCTION_t func; char dummy[25-sizeof(asFUNCTION_t)];} f; + } ptr; + asBYTE flag; // 1 = generic, 2 = global func, 3 = method +}; + +#if defined(__BORLANDC__) +// A bug in BCC (QC #85374) makes it impossible to distinguish const/non-const method overloads +// with static_cast<>. The workaround is to use an _implicit_cast instead. + + #if __BORLANDC__ < 0x590 + // BCC v5.8 (C++Builder 2006) and earlier have an even more annoying bug which causes + // the "pretty" workaround below (with _implicit_cast<>) to fail. For these compilers + // we need to use a traditional C-style cast. + #define AS_METHOD_AMBIGUITY_CAST(t) (t) + #else +template + T _implicit_cast (T val) +{ return val; } + #define AS_METHOD_AMBIGUITY_CAST(t) AS_NAMESPACE_QUALIFIER _implicit_cast + #endif +#else + #define AS_METHOD_AMBIGUITY_CAST(t) static_cast +#endif + +#define asMETHOD(c,m) asSMethodPtr::Convert((void (c::*)())(&c::m)) +#define asMETHODPR(c,m,p,r) asSMethodPtr::Convert(AS_METHOD_AMBIGUITY_CAST(r (c::*)p)(&c::m)) + +#else // Class methods are disabled + +struct asSFuncPtr +{ + asSFuncPtr(asBYTE f) + { + for( int n = 0; n < sizeof(ptr.dummy); n++ ) + ptr.dummy[n] = 0; + flag = f; + } + + union + { + char dummy[25]; // largest known class method pointer + struct {asFUNCTION_t func; char dummy[25-sizeof(asFUNCTION_t)];} f; + } ptr; + asBYTE flag; // 1 = generic, 2 = global func +}; + +#endif + +struct asSMessageInfo +{ + const char *section; + int row; + int col; + asEMsgType type; + const char *message; +}; + + +// API functions + +// ANGELSCRIPT_EXPORT is defined when compiling the dll or lib +// ANGELSCRIPT_DLL_LIBRARY_IMPORT is defined when dynamically linking to the +// dll through the link lib automatically generated by MSVC++ +// ANGELSCRIPT_DLL_MANUAL_IMPORT is defined when manually loading the dll +// Don't define anything when linking statically to the lib + +#if defined(WIN32) || defined(_WIN32) || defined(__CYGWIN__) + #if defined(ANGELSCRIPT_EXPORT) + #define AS_API __declspec(dllexport) + #elif defined(ANGELSCRIPT_DLL_LIBRARY_IMPORT) + #define AS_API __declspec(dllimport) + #else // statically linked library + #define AS_API + #endif +#elif defined(__GNUC__) + #if defined(ANGELSCRIPT_EXPORT) + #define AS_API __attribute__((visibility ("default"))) + #else + #define AS_API + #endif +#else + #define AS_API +#endif + +#ifndef ANGELSCRIPT_DLL_MANUAL_IMPORT +extern "C" +{ + // Engine + AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version = ANGELSCRIPT_VERSION); + AS_API const char *asGetLibraryVersion(); + AS_API const char *asGetLibraryOptions(); + + // Context + AS_API asIScriptContext *asGetActiveContext(); + + // Thread support + AS_API int asPrepareMultithread(asIThreadManager *externalMgr = 0); + AS_API void asUnprepareMultithread(); + AS_API asIThreadManager *asGetThreadManager(); + AS_API void asAcquireExclusiveLock(); + AS_API void asReleaseExclusiveLock(); + AS_API void asAcquireSharedLock(); + AS_API void asReleaseSharedLock(); + AS_API int asAtomicInc(int &value); + AS_API int asAtomicDec(int &value); + AS_API int asThreadCleanup(); + + // Memory management + AS_API int asSetGlobalMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc); + AS_API int asResetGlobalMemoryFunctions(); + AS_API void *asAllocMem(size_t size); + AS_API void asFreeMem(void *mem); + + // Auxiliary + AS_API asILockableSharedBool *asCreateLockableSharedBool(); +} +#endif // ANGELSCRIPT_DLL_MANUAL_IMPORT + +// Determine traits of a type for registration of value types +// Relies on C++11 features so it can not be used with non-compliant compilers +#ifdef AS_CAN_USE_CPP11 + +END_AS_NAMESPACE +#include +BEGIN_AS_NAMESPACE + +template +asUINT asGetTypeTraits() +{ +#if defined(_MSC_VER) || defined(_LIBCPP_TYPE_TRAITS) || (__GNUC__ >= 5) || defined(__clang__) + // MSVC, XCode/Clang, and gnuc 5+ + // C++11 compliant code + bool hasConstructor = std::is_default_constructible::value && !std::is_trivially_default_constructible::value; + bool hasDestructor = std::is_destructible::value && !std::is_trivially_destructible::value; + bool hasAssignmentOperator = std::is_copy_assignable::value && !std::is_trivially_copy_assignable::value; + bool hasCopyConstructor = std::is_copy_constructible::value && !std::is_trivially_copy_constructible::value; +#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + // gnuc 4.8 is using a mix of C++11 standard and pre-standard templates + bool hasConstructor = std::is_default_constructible::value && !std::has_trivial_default_constructor::value; + bool hasDestructor = std::is_destructible::value && !std::is_trivially_destructible::value; + bool hasAssignmentOperator = std::is_copy_assignable::value && !std::has_trivial_copy_assign::value; + bool hasCopyConstructor = std::is_copy_constructible::value && !std::has_trivial_copy_constructor::value; +#else + // All other compilers and versions are assumed to use non C++11 compliant code until proven otherwise + // Not fully C++11 compliant. The has_trivial checks were used while the standard was still + // being elaborated, but were then removed in favor of the above is_trivially checks + // http://stackoverflow.com/questions/12702103/writing-code-that-works-when-has-trivial-destructor-is-defined-instead-of-is + // https://github.com/mozart/mozart2/issues/51 + bool hasConstructor = std::is_default_constructible::value && !std::has_trivial_default_constructor::value; + bool hasDestructor = std::is_destructible::value && !std::has_trivial_destructor::value; + bool hasAssignmentOperator = std::is_copy_assignable::value && !std::has_trivial_copy_assign::value; + bool hasCopyConstructor = std::is_copy_constructible::value && !std::has_trivial_copy_constructor::value; +#endif + bool isFloat = std::is_floating_point::value; + bool isPrimitive = std::is_integral::value || std::is_pointer::value || std::is_enum::value; + bool isClass = std::is_class::value; + bool isArray = std::is_array::value; + + if( isFloat ) + return asOBJ_APP_FLOAT; + if( isPrimitive ) + return asOBJ_APP_PRIMITIVE; + + if( isClass ) + { + asDWORD flags = asOBJ_APP_CLASS; + if( hasConstructor ) + flags |= asOBJ_APP_CLASS_CONSTRUCTOR; + if( hasDestructor ) + flags |= asOBJ_APP_CLASS_DESTRUCTOR; + if( hasAssignmentOperator ) + flags |= asOBJ_APP_CLASS_ASSIGNMENT; + if( hasCopyConstructor ) + flags |= asOBJ_APP_CLASS_COPY_CONSTRUCTOR; + return flags; + } + + if( isArray ) + return asOBJ_APP_ARRAY; + + // Unknown type traits + return 0; +} + +#endif // c++11 + +// Interface declarations + +class asIScriptEngine +{ +public: + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + virtual int ShutDownAndRelease() = 0; + + // Engine properties + virtual int SetEngineProperty(asEEngineProp property, asPWORD value) = 0; + virtual asPWORD GetEngineProperty(asEEngineProp property) const = 0; + + // Compiler messages + virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv) = 0; + virtual int ClearMessageCallback() = 0; + virtual int WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message) = 0; + + // JIT Compiler + virtual int SetJITCompiler(asIJITCompiler *compiler) = 0; + virtual asIJITCompiler *GetJITCompiler() const = 0; + + // Global functions + virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0) = 0; + virtual asUINT GetGlobalFunctionCount() const = 0; + virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const = 0; + virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const = 0; + + // Global properties + virtual int RegisterGlobalProperty(const char *declaration, void *pointer) = 0; + virtual asUINT GetGlobalPropertyCount() const = 0; + virtual int GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace = 0, int *typeId = 0, bool *isConst = 0, const char **configGroup = 0, void **pointer = 0, asDWORD *accessMask = 0) const = 0; + virtual int GetGlobalPropertyIndexByName(const char *name) const = 0; + virtual int GetGlobalPropertyIndexByDecl(const char *decl) const = 0; + + // Object types + virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags) = 0; + virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false) = 0; + virtual int RegisterInterface(const char *name) = 0; + virtual int RegisterInterfaceMethod(const char *intf, const char *declaration) = 0; + virtual asUINT GetObjectTypeCount() const = 0; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; + + // String factory + virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory) = 0; + virtual int GetStringFactoryReturnTypeId(asDWORD *flags = 0) const = 0; + + // Default array type + virtual int RegisterDefaultArrayType(const char *type) = 0; + virtual int GetDefaultArrayTypeId() const = 0; + + // Enums + virtual int RegisterEnum(const char *type) = 0; + virtual int RegisterEnumValue(const char *type, const char *name, int value) = 0; + virtual asUINT GetEnumCount() const = 0; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0; + + // Funcdefs + virtual int RegisterFuncdef(const char *decl) = 0; + virtual asUINT GetFuncdefCount() const = 0; + virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const = 0; + + // Typedefs + virtual int RegisterTypedef(const char *type, const char *decl) = 0; + virtual asUINT GetTypedefCount() const = 0; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const = 0; + + // Configuration groups + virtual int BeginConfigGroup(const char *groupName) = 0; + virtual int EndConfigGroup() = 0; + virtual int RemoveConfigGroup(const char *groupName) = 0; + virtual asDWORD SetDefaultAccessMask(asDWORD defaultMask) = 0; + virtual int SetDefaultNamespace(const char *nameSpace) = 0; + virtual const char *GetDefaultNamespace() const = 0; + + // Script modules + virtual asIScriptModule *GetModule(const char *module, asEGMFlags flag = asGM_ONLY_IF_EXISTS) = 0; + virtual int DiscardModule(const char *module) = 0; + virtual asUINT GetModuleCount() const = 0; + virtual asIScriptModule *GetModuleByIndex(asUINT index) const = 0; + + // Script functions + virtual asIScriptFunction *GetFunctionById(int funcId) const = 0; + + // Type identification + virtual int GetTypeIdByDecl(const char *decl) const = 0; + virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const = 0; + virtual int GetSizeOfPrimitiveType(int typeId) const = 0; + virtual asITypeInfo *GetTypeInfoById(int typeId) const = 0; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; + + // Script execution + virtual asIScriptContext *CreateContext() = 0; + virtual void *CreateScriptObject(const asITypeInfo *type) = 0; + virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type) = 0; + virtual void *CreateUninitializedScriptObject(const asITypeInfo *type) = 0; + virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj) = 0; + virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) = 0; + virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type) = 0; + virtual void AddRefScriptObject(void *obj, const asITypeInfo *type) = 0; + virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false) = 0; + virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const = 0; + + // Context pooling + virtual asIScriptContext *RequestContext() = 0; + virtual void ReturnContext(asIScriptContext *ctx) = 0; + virtual int SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param = 0) = 0; + + // String interpretation + virtual asETokenClass ParseToken(const char *string, size_t stringLength = 0, asUINT *tokenLength = 0) const = 0; + + // Garbage collection + virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE, asUINT numIterations = 1) = 0; + virtual void GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed = 0, asUINT *totalDetected = 0, asUINT *newObjects = 0, asUINT *totalNewDestroyed = 0) const = 0; + virtual int NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type) = 0; + virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr = 0, void **obj = 0, asITypeInfo **type = 0) = 0; + virtual void GCEnumCallback(void *reference) = 0; + virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type) = 0; + virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type) = 0; + virtual void SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param = 0) = 0; + + // User data + virtual void *SetUserData(void *data, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; + virtual void SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type = 0) = 0; + virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type = 0) = 0; + virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type = 0) = 0; + virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type = 0) = 0; + virtual void SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type = 0) = 0; + virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type = 0) = 0; + + // Exception handling + virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv) = 0; + +protected: + virtual ~asIScriptEngine() {} +}; + +class asIStringFactory +{ +public: + virtual const void *GetStringConstant(const char *data, asUINT length) = 0; + virtual int ReleaseStringConstant(const void *str) = 0; + virtual int GetRawStringData(const void *str, char *data, asUINT *length) const = 0; + +protected: + virtual ~asIStringFactory() {} +}; + +class asIThreadManager +{ +protected: + virtual ~asIThreadManager() {} +}; + +class asIScriptModule +{ +public: + virtual asIScriptEngine *GetEngine() const = 0; + virtual void SetName(const char *name) = 0; + virtual const char *GetName() const = 0; + virtual void Discard() = 0; + + // Compilation + virtual int AddScriptSection(const char *name, const char *code, size_t codeLength = 0, int lineOffset = 0) = 0; + virtual int Build() = 0; + virtual int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc) = 0; + virtual int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset) = 0; + virtual asDWORD SetAccessMask(asDWORD accessMask) = 0; + virtual int SetDefaultNamespace(const char *nameSpace) = 0; + virtual const char *GetDefaultNamespace() const = 0; + + // Functions + virtual asUINT GetFunctionCount() const = 0; + virtual asIScriptFunction *GetFunctionByIndex(asUINT index) const = 0; + virtual asIScriptFunction *GetFunctionByDecl(const char *decl) const = 0; + virtual asIScriptFunction *GetFunctionByName(const char *name) const = 0; + virtual int RemoveFunction(asIScriptFunction *func) = 0; + + // Global variables + virtual int ResetGlobalVars(asIScriptContext *ctx = 0) = 0; + virtual asUINT GetGlobalVarCount() const = 0; + virtual int GetGlobalVarIndexByName(const char *name) const = 0; + virtual int GetGlobalVarIndexByDecl(const char *decl) const = 0; + virtual const char *GetGlobalVarDeclaration(asUINT index, bool includeNamespace = false) const = 0; + virtual int GetGlobalVar(asUINT index, const char **name, const char **nameSpace = 0, int *typeId = 0, bool *isConst = 0) const = 0; + virtual void *GetAddressOfGlobalVar(asUINT index) = 0; + virtual int RemoveGlobalVar(asUINT index) = 0; + + // Type identification + virtual asUINT GetObjectTypeCount() const = 0; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const = 0; + virtual int GetTypeIdByDecl(const char *decl) const = 0; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const = 0; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const = 0; + + // Enums + virtual asUINT GetEnumCount() const = 0; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const = 0; + + // Typedefs + virtual asUINT GetTypedefCount() const = 0; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const = 0; + + // Dynamic binding between modules + virtual asUINT GetImportedFunctionCount() const = 0; + virtual int GetImportedFunctionIndexByDecl(const char *decl) const = 0; + virtual const char *GetImportedFunctionDeclaration(asUINT importIndex) const = 0; + virtual const char *GetImportedFunctionSourceModule(asUINT importIndex) const = 0; + virtual int BindImportedFunction(asUINT importIndex, asIScriptFunction *func) = 0; + virtual int UnbindImportedFunction(asUINT importIndex) = 0; + virtual int BindAllImportedFunctions() = 0; + virtual int UnbindAllImportedFunctions() = 0; + + // Byte code saving and loading + virtual int SaveByteCode(asIBinaryStream *out, bool stripDebugInfo = false) const = 0; + virtual int LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped = 0) = 0; + + // User data + virtual void *SetUserData(void *data, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; + +protected: + virtual ~asIScriptModule() {} +}; + +class asIScriptContext +{ +public: + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + + // Miscellaneous + virtual asIScriptEngine *GetEngine() const = 0; + + // Execution + virtual int Prepare(asIScriptFunction *func) = 0; + virtual int Unprepare() = 0; + virtual int Execute() = 0; + virtual int Abort() = 0; + virtual int Suspend() = 0; + virtual asEContextState GetState() const = 0; + virtual int PushState() = 0; + virtual int PopState() = 0; + virtual bool IsNested(asUINT *nestCount = 0) const = 0; + + // Object pointer for calling class methods + virtual int SetObject(void *obj) = 0; + + // Arguments + virtual int SetArgByte(asUINT arg, asBYTE value) = 0; + virtual int SetArgWord(asUINT arg, asWORD value) = 0; + virtual int SetArgDWord(asUINT arg, asDWORD value) = 0; + virtual int SetArgQWord(asUINT arg, asQWORD value) = 0; + virtual int SetArgFloat(asUINT arg, float value) = 0; + virtual int SetArgDouble(asUINT arg, double value) = 0; + virtual int SetArgAddress(asUINT arg, void *addr) = 0; + virtual int SetArgObject(asUINT arg, void *obj) = 0; + virtual int SetArgVarType(asUINT arg, void *ptr, int typeId) = 0; + virtual void *GetAddressOfArg(asUINT arg) = 0; + + // Return value + virtual asBYTE GetReturnByte() = 0; + virtual asWORD GetReturnWord() = 0; + virtual asDWORD GetReturnDWord() = 0; + virtual asQWORD GetReturnQWord() = 0; + virtual float GetReturnFloat() = 0; + virtual double GetReturnDouble() = 0; + virtual void *GetReturnAddress() = 0; + virtual void *GetReturnObject() = 0; + virtual void *GetAddressOfReturnValue() = 0; + + // Exception handling + virtual int SetException(const char *info, bool allowCatch = true) = 0; + virtual int GetExceptionLineNumber(int *column = 0, const char **sectionName = 0) = 0; + virtual asIScriptFunction *GetExceptionFunction() = 0; + virtual const char * GetExceptionString() = 0; + virtual bool WillExceptionBeCaught() = 0; + virtual int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv) = 0; + virtual void ClearExceptionCallback() = 0; + + // Debugging + virtual int SetLineCallback(asSFuncPtr callback, void *obj, int callConv) = 0; + virtual void ClearLineCallback() = 0; + virtual asUINT GetCallstackSize() const = 0; + virtual asIScriptFunction *GetFunction(asUINT stackLevel = 0) = 0; + virtual int GetLineNumber(asUINT stackLevel = 0, int *column = 0, const char **sectionName = 0) = 0; + virtual int GetVarCount(asUINT stackLevel = 0) = 0; + virtual const char *GetVarName(asUINT varIndex, asUINT stackLevel = 0) = 0; + virtual const char *GetVarDeclaration(asUINT varIndex, asUINT stackLevel = 0, bool includeNamespace = false) = 0; + virtual int GetVarTypeId(asUINT varIndex, asUINT stackLevel = 0) = 0; + virtual void *GetAddressOfVar(asUINT varIndex, asUINT stackLevel = 0) = 0; + virtual bool IsVarInScope(asUINT varIndex, asUINT stackLevel = 0) = 0; + virtual int GetThisTypeId(asUINT stackLevel = 0) = 0; + virtual void *GetThisPointer(asUINT stackLevel = 0) = 0; + virtual asIScriptFunction *GetSystemFunction() = 0; + + // User data + virtual void *SetUserData(void *data, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; + +protected: + virtual ~asIScriptContext() {} +}; + +class asIScriptGeneric +{ +public: + // Miscellaneous + virtual asIScriptEngine *GetEngine() const = 0; + virtual asIScriptFunction *GetFunction() const = 0; + virtual void *GetAuxiliary() const = 0; + + // Object + virtual void *GetObject() = 0; + virtual int GetObjectTypeId() const = 0; + + // Arguments + virtual int GetArgCount() const = 0; + virtual int GetArgTypeId(asUINT arg, asDWORD *flags = 0) const = 0; + virtual asBYTE GetArgByte(asUINT arg) = 0; + virtual asWORD GetArgWord(asUINT arg) = 0; + virtual asDWORD GetArgDWord(asUINT arg) = 0; + virtual asQWORD GetArgQWord(asUINT arg) = 0; + virtual float GetArgFloat(asUINT arg) = 0; + virtual double GetArgDouble(asUINT arg) = 0; + virtual void *GetArgAddress(asUINT arg) = 0; + virtual void *GetArgObject(asUINT arg) = 0; + virtual void *GetAddressOfArg(asUINT arg) = 0; + + // Return value + virtual int GetReturnTypeId(asDWORD *flags = 0) const = 0; + virtual int SetReturnByte(asBYTE val) = 0; + virtual int SetReturnWord(asWORD val) = 0; + virtual int SetReturnDWord(asDWORD val) = 0; + virtual int SetReturnQWord(asQWORD val) = 0; + virtual int SetReturnFloat(float val) = 0; + virtual int SetReturnDouble(double val) = 0; + virtual int SetReturnAddress(void *addr) = 0; + virtual int SetReturnObject(void *obj) = 0; + virtual void *GetAddressOfReturnLocation() = 0; + +protected: + virtual ~asIScriptGeneric() {} +}; + +class asIScriptObject +{ +public: + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + virtual asILockableSharedBool *GetWeakRefFlag() const = 0; + + // Type info + virtual int GetTypeId() const = 0; + virtual asITypeInfo *GetObjectType() const = 0; + + // Class properties + virtual asUINT GetPropertyCount() const = 0; + virtual int GetPropertyTypeId(asUINT prop) const = 0; + virtual const char *GetPropertyName(asUINT prop) const = 0; + virtual void *GetAddressOfProperty(asUINT prop) = 0; + + // Miscellaneous + virtual asIScriptEngine *GetEngine() const = 0; + virtual int CopyFrom(const asIScriptObject *other) = 0; + + // User data + virtual void *SetUserData(void *data, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; + +protected: + virtual ~asIScriptObject() {} +}; + +class asITypeInfo +{ +public: + // Miscellaneous + virtual asIScriptEngine *GetEngine() const = 0; + virtual const char *GetConfigGroup() const = 0; + virtual asDWORD GetAccessMask() const = 0; + virtual asIScriptModule *GetModule() const = 0; + + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + + // Type info + virtual const char *GetName() const = 0; + virtual const char *GetNamespace() const = 0; + virtual asITypeInfo *GetBaseType() const = 0; + virtual bool DerivesFrom(const asITypeInfo *objType) const = 0; + virtual asDWORD GetFlags() const = 0; + virtual asUINT GetSize() const = 0; + virtual int GetTypeId() const = 0; + virtual int GetSubTypeId(asUINT subTypeIndex = 0) const = 0; + virtual asITypeInfo *GetSubType(asUINT subTypeIndex = 0) const = 0; + virtual asUINT GetSubTypeCount() const = 0; + + // Interfaces + virtual asUINT GetInterfaceCount() const = 0; + virtual asITypeInfo *GetInterface(asUINT index) const = 0; + virtual bool Implements(const asITypeInfo *objType) const = 0; + + // Factories + virtual asUINT GetFactoryCount() const = 0; + virtual asIScriptFunction *GetFactoryByIndex(asUINT index) const = 0; + virtual asIScriptFunction *GetFactoryByDecl(const char *decl) const = 0; + + // Methods + virtual asUINT GetMethodCount() const = 0; + virtual asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual = true) const = 0; + virtual asIScriptFunction *GetMethodByName(const char *name, bool getVirtual = true) const = 0; + virtual asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual = true) const = 0; + + // Properties + virtual asUINT GetPropertyCount() const = 0; + virtual int GetProperty(asUINT index, const char **name, int *typeId = 0, bool *isPrivate = 0, bool *isProtected = 0, int *offset = 0, bool *isReference = 0, asDWORD *accessMask = 0, int *compositeOffset = 0, bool *isCompositeIndirect = 0) const = 0; + virtual const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const = 0; + + // Behaviours + virtual asUINT GetBehaviourCount() const = 0; + virtual asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const = 0; + + // Child types + virtual asUINT GetChildFuncdefCount() const = 0; + virtual asITypeInfo *GetChildFuncdef(asUINT index) const = 0; + virtual asITypeInfo *GetParentType() const = 0; + + // Enums + virtual asUINT GetEnumValueCount() const = 0; + virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const = 0; + + // Typedef + virtual int GetTypedefTypeId() const = 0; + + // Funcdef + virtual asIScriptFunction *GetFuncdefSignature() const = 0; + + // User data + virtual void *SetUserData(void *data, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; + +protected: + virtual ~asITypeInfo() {} +}; + +class asIScriptFunction +{ +public: + virtual asIScriptEngine *GetEngine() const = 0; + + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + + // Miscellaneous + virtual int GetId() const = 0; + virtual asEFuncType GetFuncType() const = 0; + virtual const char *GetModuleName() const = 0; + virtual asIScriptModule *GetModule() const = 0; + virtual const char *GetScriptSectionName() const = 0; + virtual const char *GetConfigGroup() const = 0; + virtual asDWORD GetAccessMask() const = 0; + virtual void *GetAuxiliary() const = 0; + + // Function signature + virtual asITypeInfo *GetObjectType() const = 0; + virtual const char *GetObjectName() const = 0; + virtual const char *GetName() const = 0; + virtual const char *GetNamespace() const = 0; + virtual const char *GetDeclaration(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const = 0; + virtual bool IsReadOnly() const = 0; + virtual bool IsPrivate() const = 0; + virtual bool IsProtected() const = 0; + virtual bool IsFinal() const = 0; + virtual bool IsOverride() const = 0; + virtual bool IsShared() const = 0; + virtual bool IsExplicit() const = 0; + virtual bool IsProperty() const = 0; + virtual asUINT GetParamCount() const = 0; + virtual int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const = 0; + virtual int GetReturnTypeId(asDWORD *flags = 0) const = 0; + + // Type id for function pointers + virtual int GetTypeId() const = 0; + virtual bool IsCompatibleWithTypeId(int typeId) const = 0; + + // Delegates + virtual void *GetDelegateObject() const = 0; + virtual asITypeInfo *GetDelegateObjectType() const = 0; + virtual asIScriptFunction *GetDelegateFunction() const = 0; + + // Debug information + virtual asUINT GetVarCount() const = 0; + virtual int GetVar(asUINT index, const char **name, int *typeId = 0) const = 0; + virtual const char *GetVarDecl(asUINT index, bool includeNamespace = false) const = 0; + virtual int FindNextLineWithCode(int line) const = 0; + + // For JIT compilation + virtual asDWORD *GetByteCode(asUINT *length = 0) = 0; + + // User data + virtual void *SetUserData(void *userData, asPWORD type = 0) = 0; + virtual void *GetUserData(asPWORD type = 0) const = 0; + +protected: + virtual ~asIScriptFunction() {}; +}; + +class asIBinaryStream +{ +public: + virtual int Read(void *ptr, asUINT size) = 0; + virtual int Write(const void *ptr, asUINT size) = 0; + +public: + virtual ~asIBinaryStream() {} +}; + +class asILockableSharedBool +{ +public: + // Memory management + virtual int AddRef() const = 0; + virtual int Release() const = 0; + + // Value + virtual bool Get() const = 0; + virtual void Set(bool val) = 0; + + // Thread management + virtual void Lock() const = 0; + virtual void Unlock() const = 0; + +protected: + virtual ~asILockableSharedBool() {} +}; + +//----------------------------------------------------------------- +// Function pointers + +// Template function to capture all global functions, +// except the ones using the generic calling convention +template +inline asSFuncPtr asFunctionPtr(T func) +{ + // Mark this as a global function + asSFuncPtr p(2); + +#ifdef AS_64BIT_PTR + // The size_t cast is to avoid a compiler warning with asFUNCTION(0) + // on 64bit, as 0 is interpreted as a 32bit int value + p.ptr.f.func = reinterpret_cast(size_t(func)); +#else + // MSVC6 doesn't like the size_t cast above so I + // solved this with a separate code for 32bit. + p.ptr.f.func = reinterpret_cast(func); +#endif + + return p; +} + +// Specialization for functions using the generic calling convention +template<> +inline asSFuncPtr asFunctionPtr(asGENFUNC_t func) +{ + // Mark this as a generic function + asSFuncPtr p(1); + p.ptr.f.func = reinterpret_cast(func); + return p; +} + +#ifndef AS_NO_CLASS_METHODS + +// Method pointers + +// Declare a dummy class so that we can determine the size of a simple method pointer +class asCSimpleDummy {}; +typedef void (asCSimpleDummy::*asSIMPLEMETHOD_t)(); +const int SINGLE_PTR_SIZE = sizeof(asSIMPLEMETHOD_t); + +// Define template +template +struct asSMethodPtr +{ + template + static asSFuncPtr Convert([[maybe_unused]] M Mthd) + { + // This version of the function should never be executed, nor compiled, + // as it would mean that the size of the method pointer cannot be determined. + + int ERROR_UnsupportedMethodPtr[N-100]; + + asSFuncPtr p(0); + return p; + } +}; + +// Template specialization +template <> +struct asSMethodPtr +{ + template + static asSFuncPtr Convert(M Mthd) + { + // Mark this as a class method + asSFuncPtr p(3); + p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE); + return p; + } +}; + +#if defined(_MSC_VER) && !defined(__MWERKS__) + +// MSVC and Intel uses different sizes for different class method pointers +template <> +struct asSMethodPtr +{ + template + static asSFuncPtr Convert(M Mthd) + { + // Mark this as a class method + asSFuncPtr p(3); + p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+sizeof(int)); + return p; + } +}; + +template <> +struct asSMethodPtr +{ + template + static asSFuncPtr Convert(M Mthd) + { + // On 32bit platforms with is where a class with virtual inheritance falls. + // On 64bit platforms we can also fall here if 8byte data alignments is used. + + // Mark this as a class method + asSFuncPtr p(3); + p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+2*sizeof(int)); + + // Microsoft has a terrible optimization on class methods with virtual inheritance. + // They are hardcoding an important offset, which is not coming in the method pointer. + +#if defined(_MSC_VER) && !defined(AS_64BIT_PTR) + // Method pointers for virtual inheritance is not supported, + // as it requires the location of the vbase table, which is + // only available to the C++ compiler, but not in the method + // pointer. + + // You can get around this by forward declaring the class and + // storing the sizeof its method pointer in a constant. Example: + + // class ClassWithVirtualInheritance; + // const int ClassWithVirtualInheritance_workaround = sizeof(void ClassWithVirtualInheritance::*()); + + // This will force the compiler to use the unknown type + // for the class, which falls under the next case + + + // Copy the virtual table index to the 4th dword so that AngelScript + // can properly detect and deny the use of methods with virtual inheritance. + *(reinterpret_cast(&p)+3) = *(reinterpret_cast(&p)+2); +#endif + + return p; + } +}; + +template <> +struct asSMethodPtr +{ + template + static asSFuncPtr Convert(M Mthd) + { + // Mark this as a class method + asSFuncPtr p(3); + p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+3*sizeof(int)); + return p; + } +}; + +template <> +struct asSMethodPtr +{ + template + static asSFuncPtr Convert(M Mthd) + { + // On 64bit platforms with 8byte data alignment + // the unknown class method pointers will come here. + + // Mark this as a class method + asSFuncPtr p(3); + p.CopyMethodPtr(&Mthd, SINGLE_PTR_SIZE+4*sizeof(int)); + return p; + } +}; + +#endif + +#endif // AS_NO_CLASS_METHODS + +//---------------------------------------------------------------- +// JIT compiler + +struct asSVMRegisters +{ + asDWORD *programPointer; // points to current bytecode instruction + asDWORD *stackFramePointer; // function stack frame + asDWORD *stackPointer; // top of stack (grows downward) + asQWORD valueRegister; // temp register for primitives + void *objectRegister; // temp register for objects and handles + asITypeInfo *objectType; // type of object held in object register + bool doProcessSuspend; // whether or not the JIT should break out when it encounters a suspend instruction + asIScriptContext *ctx; // the active context +}; + +typedef void (*asJITFunction)(asSVMRegisters *registers, asPWORD jitArg); + +class asIJITCompiler +{ +public: + virtual int CompileFunction(asIScriptFunction *function, asJITFunction *output) = 0; + virtual void ReleaseJITFunction(asJITFunction func) = 0; +public: + virtual ~asIJITCompiler() {} +}; + +// Byte code instructions +enum asEBCInstr +{ + asBC_PopPtr = 0, + asBC_PshGPtr = 1, + asBC_PshC4 = 2, + asBC_PshV4 = 3, + asBC_PSF = 4, + asBC_SwapPtr = 5, + asBC_NOT = 6, + asBC_PshG4 = 7, + asBC_LdGRdR4 = 8, + asBC_CALL = 9, + asBC_RET = 10, + asBC_JMP = 11, + asBC_JZ = 12, + asBC_JNZ = 13, + asBC_JS = 14, + asBC_JNS = 15, + asBC_JP = 16, + asBC_JNP = 17, + asBC_TZ = 18, + asBC_TNZ = 19, + asBC_TS = 20, + asBC_TNS = 21, + asBC_TP = 22, + asBC_TNP = 23, + asBC_NEGi = 24, + asBC_NEGf = 25, + asBC_NEGd = 26, + asBC_INCi16 = 27, + asBC_INCi8 = 28, + asBC_DECi16 = 29, + asBC_DECi8 = 30, + asBC_INCi = 31, + asBC_DECi = 32, + asBC_INCf = 33, + asBC_DECf = 34, + asBC_INCd = 35, + asBC_DECd = 36, + asBC_IncVi = 37, + asBC_DecVi = 38, + asBC_BNOT = 39, + asBC_BAND = 40, + asBC_BOR = 41, + asBC_BXOR = 42, + asBC_BSLL = 43, + asBC_BSRL = 44, + asBC_BSRA = 45, + asBC_COPY = 46, + asBC_PshC8 = 47, + asBC_PshVPtr = 48, + asBC_RDSPtr = 49, + asBC_CMPd = 50, + asBC_CMPu = 51, + asBC_CMPf = 52, + asBC_CMPi = 53, + asBC_CMPIi = 54, + asBC_CMPIf = 55, + asBC_CMPIu = 56, + asBC_JMPP = 57, + asBC_PopRPtr = 58, + asBC_PshRPtr = 59, + asBC_STR = 60, + asBC_CALLSYS = 61, + asBC_CALLBND = 62, + asBC_SUSPEND = 63, + asBC_ALLOC = 64, + asBC_FREE = 65, + asBC_LOADOBJ = 66, + asBC_STOREOBJ = 67, + asBC_GETOBJ = 68, + asBC_REFCPY = 69, + asBC_CHKREF = 70, + asBC_GETOBJREF = 71, + asBC_GETREF = 72, + asBC_PshNull = 73, + asBC_ClrVPtr = 74, + asBC_OBJTYPE = 75, + asBC_TYPEID = 76, + asBC_SetV4 = 77, + asBC_SetV8 = 78, + asBC_ADDSi = 79, + asBC_CpyVtoV4 = 80, + asBC_CpyVtoV8 = 81, + asBC_CpyVtoR4 = 82, + asBC_CpyVtoR8 = 83, + asBC_CpyVtoG4 = 84, + asBC_CpyRtoV4 = 85, + asBC_CpyRtoV8 = 86, + asBC_CpyGtoV4 = 87, + asBC_WRTV1 = 88, + asBC_WRTV2 = 89, + asBC_WRTV4 = 90, + asBC_WRTV8 = 91, + asBC_RDR1 = 92, + asBC_RDR2 = 93, + asBC_RDR4 = 94, + asBC_RDR8 = 95, + asBC_LDG = 96, + asBC_LDV = 97, + asBC_PGA = 98, + asBC_CmpPtr = 99, + asBC_VAR = 100, + asBC_iTOf = 101, + asBC_fTOi = 102, + asBC_uTOf = 103, + asBC_fTOu = 104, + asBC_sbTOi = 105, + asBC_swTOi = 106, + asBC_ubTOi = 107, + asBC_uwTOi = 108, + asBC_dTOi = 109, + asBC_dTOu = 110, + asBC_dTOf = 111, + asBC_iTOd = 112, + asBC_uTOd = 113, + asBC_fTOd = 114, + asBC_ADDi = 115, + asBC_SUBi = 116, + asBC_MULi = 117, + asBC_DIVi = 118, + asBC_MODi = 119, + asBC_ADDf = 120, + asBC_SUBf = 121, + asBC_MULf = 122, + asBC_DIVf = 123, + asBC_MODf = 124, + asBC_ADDd = 125, + asBC_SUBd = 126, + asBC_MULd = 127, + asBC_DIVd = 128, + asBC_MODd = 129, + asBC_ADDIi = 130, + asBC_SUBIi = 131, + asBC_MULIi = 132, + asBC_ADDIf = 133, + asBC_SUBIf = 134, + asBC_MULIf = 135, + asBC_SetG4 = 136, + asBC_ChkRefS = 137, + asBC_ChkNullV = 138, + asBC_CALLINTF = 139, + asBC_iTOb = 140, + asBC_iTOw = 141, + asBC_SetV1 = 142, + asBC_SetV2 = 143, + asBC_Cast = 144, + asBC_i64TOi = 145, + asBC_uTOi64 = 146, + asBC_iTOi64 = 147, + asBC_fTOi64 = 148, + asBC_dTOi64 = 149, + asBC_fTOu64 = 150, + asBC_dTOu64 = 151, + asBC_i64TOf = 152, + asBC_u64TOf = 153, + asBC_i64TOd = 154, + asBC_u64TOd = 155, + asBC_NEGi64 = 156, + asBC_INCi64 = 157, + asBC_DECi64 = 158, + asBC_BNOT64 = 159, + asBC_ADDi64 = 160, + asBC_SUBi64 = 161, + asBC_MULi64 = 162, + asBC_DIVi64 = 163, + asBC_MODi64 = 164, + asBC_BAND64 = 165, + asBC_BOR64 = 166, + asBC_BXOR64 = 167, + asBC_BSLL64 = 168, + asBC_BSRL64 = 169, + asBC_BSRA64 = 170, + asBC_CMPi64 = 171, + asBC_CMPu64 = 172, + asBC_ChkNullS = 173, + asBC_ClrHi = 174, + asBC_JitEntry = 175, + asBC_CallPtr = 176, + asBC_FuncPtr = 177, + asBC_LoadThisR = 178, + asBC_PshV8 = 179, + asBC_DIVu = 180, + asBC_MODu = 181, + asBC_DIVu64 = 182, + asBC_MODu64 = 183, + asBC_LoadRObjR = 184, + asBC_LoadVObjR = 185, + asBC_RefCpyV = 186, + asBC_JLowZ = 187, + asBC_JLowNZ = 188, + asBC_AllocMem = 189, + asBC_SetListSize = 190, + asBC_PshListElmnt = 191, + asBC_SetListType = 192, + asBC_POWi = 193, + asBC_POWu = 194, + asBC_POWf = 195, + asBC_POWd = 196, + asBC_POWdi = 197, + asBC_POWi64 = 198, + asBC_POWu64 = 199, + asBC_Thiscall1 = 200, + asBC_MAXBYTECODE = 201, + + // Temporary tokens. Can't be output to the final program + asBC_TryBlock = 250, + asBC_VarDecl = 251, + asBC_Block = 252, + asBC_ObjInfo = 253, + asBC_LINE = 254, + asBC_LABEL = 255 +}; + +// Instruction types +enum asEBCType +{ + asBCTYPE_INFO = 0, + asBCTYPE_NO_ARG = 1, + asBCTYPE_W_ARG = 2, + asBCTYPE_wW_ARG = 3, + asBCTYPE_DW_ARG = 4, + asBCTYPE_rW_DW_ARG = 5, + asBCTYPE_QW_ARG = 6, + asBCTYPE_DW_DW_ARG = 7, + asBCTYPE_wW_rW_rW_ARG = 8, + asBCTYPE_wW_QW_ARG = 9, + asBCTYPE_wW_rW_ARG = 10, + asBCTYPE_rW_ARG = 11, + asBCTYPE_wW_DW_ARG = 12, + asBCTYPE_wW_rW_DW_ARG = 13, + asBCTYPE_rW_rW_ARG = 14, + asBCTYPE_wW_W_ARG = 15, + asBCTYPE_QW_DW_ARG = 16, + asBCTYPE_rW_QW_ARG = 17, + asBCTYPE_W_DW_ARG = 18, + asBCTYPE_rW_W_DW_ARG = 19, + asBCTYPE_rW_DW_DW_ARG = 20 +}; + +// Instruction type sizes +const int asBCTypeSize[21] = +{ + 0, // asBCTYPE_INFO + 1, // asBCTYPE_NO_ARG + 1, // asBCTYPE_W_ARG + 1, // asBCTYPE_wW_ARG + 2, // asBCTYPE_DW_ARG + 2, // asBCTYPE_rW_DW_ARG + 3, // asBCTYPE_QW_ARG + 3, // asBCTYPE_DW_DW_ARG + 2, // asBCTYPE_wW_rW_rW_ARG + 3, // asBCTYPE_wW_QW_ARG + 2, // asBCTYPE_wW_rW_ARG + 1, // asBCTYPE_rW_ARG + 2, // asBCTYPE_wW_DW_ARG + 3, // asBCTYPE_wW_rW_DW_ARG + 2, // asBCTYPE_rW_rW_ARG + 2, // asBCTYPE_wW_W_ARG + 4, // asBCTYPE_QW_DW_ARG + 3, // asBCTYPE_rW_QW_ARG + 2, // asBCTYPE_W_DW_ARG + 3, // asBCTYPE_rW_W_DW_ARG + 3 // asBCTYPE_rW_DW_DW_ARG +}; + +// Instruction info +struct asSBCInfo +{ + asEBCInstr bc; + asEBCType type; + int stackInc; + const char *name; +}; + +#ifndef AS_64BIT_PTR + #define asBCTYPE_PTR_ARG asBCTYPE_DW_ARG + #define asBCTYPE_PTR_DW_ARG asBCTYPE_DW_DW_ARG + #define asBCTYPE_wW_PTR_ARG asBCTYPE_wW_DW_ARG + #define asBCTYPE_rW_PTR_ARG asBCTYPE_rW_DW_ARG + #ifndef AS_PTR_SIZE + #define AS_PTR_SIZE 1 + #endif +#else + #define asBCTYPE_PTR_ARG asBCTYPE_QW_ARG + #define asBCTYPE_PTR_DW_ARG asBCTYPE_QW_DW_ARG + #define asBCTYPE_wW_PTR_ARG asBCTYPE_wW_QW_ARG + #define asBCTYPE_rW_PTR_ARG asBCTYPE_rW_QW_ARG + #ifndef AS_PTR_SIZE + #define AS_PTR_SIZE 2 + #endif +#endif + +#define asBCINFO(b,t,s) {asBC_##b, asBCTYPE_##t, s, #b} +#define asBCINFO_DUMMY(b) {asBC_MAXBYTECODE, asBCTYPE_INFO, 0, "BC_" #b} + +const asSBCInfo asBCInfo[256] = +{ + asBCINFO(PopPtr, NO_ARG, -AS_PTR_SIZE), + asBCINFO(PshGPtr, PTR_ARG, AS_PTR_SIZE), + asBCINFO(PshC4, DW_ARG, 1), + asBCINFO(PshV4, rW_ARG, 1), + asBCINFO(PSF, rW_ARG, AS_PTR_SIZE), + asBCINFO(SwapPtr, NO_ARG, 0), + asBCINFO(NOT, rW_ARG, 0), + asBCINFO(PshG4, PTR_ARG, 1), + asBCINFO(LdGRdR4, wW_PTR_ARG, 0), + asBCINFO(CALL, DW_ARG, 0xFFFF), + asBCINFO(RET, W_ARG, 0xFFFF), + asBCINFO(JMP, DW_ARG, 0), + asBCINFO(JZ, DW_ARG, 0), + asBCINFO(JNZ, DW_ARG, 0), + asBCINFO(JS, DW_ARG, 0), + asBCINFO(JNS, DW_ARG, 0), + asBCINFO(JP, DW_ARG, 0), + asBCINFO(JNP, DW_ARG, 0), + asBCINFO(TZ, NO_ARG, 0), + asBCINFO(TNZ, NO_ARG, 0), + asBCINFO(TS, NO_ARG, 0), + asBCINFO(TNS, NO_ARG, 0), + asBCINFO(TP, NO_ARG, 0), + asBCINFO(TNP, NO_ARG, 0), + asBCINFO(NEGi, rW_ARG, 0), + asBCINFO(NEGf, rW_ARG, 0), + asBCINFO(NEGd, rW_ARG, 0), + asBCINFO(INCi16, NO_ARG, 0), + asBCINFO(INCi8, NO_ARG, 0), + asBCINFO(DECi16, NO_ARG, 0), + asBCINFO(DECi8, NO_ARG, 0), + asBCINFO(INCi, NO_ARG, 0), + asBCINFO(DECi, NO_ARG, 0), + asBCINFO(INCf, NO_ARG, 0), + asBCINFO(DECf, NO_ARG, 0), + asBCINFO(INCd, NO_ARG, 0), + asBCINFO(DECd, NO_ARG, 0), + asBCINFO(IncVi, rW_ARG, 0), + asBCINFO(DecVi, rW_ARG, 0), + asBCINFO(BNOT, rW_ARG, 0), + asBCINFO(BAND, wW_rW_rW_ARG, 0), + asBCINFO(BOR, wW_rW_rW_ARG, 0), + asBCINFO(BXOR, wW_rW_rW_ARG, 0), + asBCINFO(BSLL, wW_rW_rW_ARG, 0), + asBCINFO(BSRL, wW_rW_rW_ARG, 0), + asBCINFO(BSRA, wW_rW_rW_ARG, 0), + asBCINFO(COPY, W_DW_ARG, -AS_PTR_SIZE), + asBCINFO(PshC8, QW_ARG, 2), + asBCINFO(PshVPtr, rW_ARG, AS_PTR_SIZE), + asBCINFO(RDSPtr, NO_ARG, 0), + asBCINFO(CMPd, rW_rW_ARG, 0), + asBCINFO(CMPu, rW_rW_ARG, 0), + asBCINFO(CMPf, rW_rW_ARG, 0), + asBCINFO(CMPi, rW_rW_ARG, 0), + asBCINFO(CMPIi, rW_DW_ARG, 0), + asBCINFO(CMPIf, rW_DW_ARG, 0), + asBCINFO(CMPIu, rW_DW_ARG, 0), + asBCINFO(JMPP, rW_ARG, 0), + asBCINFO(PopRPtr, NO_ARG, -AS_PTR_SIZE), + asBCINFO(PshRPtr, NO_ARG, AS_PTR_SIZE), + asBCINFO(STR, W_ARG, 1+AS_PTR_SIZE), + asBCINFO(CALLSYS, DW_ARG, 0xFFFF), + asBCINFO(CALLBND, DW_ARG, 0xFFFF), + asBCINFO(SUSPEND, NO_ARG, 0), + asBCINFO(ALLOC, PTR_DW_ARG, 0xFFFF), + asBCINFO(FREE, wW_PTR_ARG, 0), + asBCINFO(LOADOBJ, rW_ARG, 0), + asBCINFO(STOREOBJ, wW_ARG, 0), + asBCINFO(GETOBJ, W_ARG, 0), + asBCINFO(REFCPY, PTR_ARG, -AS_PTR_SIZE), + asBCINFO(CHKREF, NO_ARG, 0), + asBCINFO(GETOBJREF, W_ARG, 0), + asBCINFO(GETREF, W_ARG, 0), + asBCINFO(PshNull, NO_ARG, AS_PTR_SIZE), + asBCINFO(ClrVPtr, wW_ARG, 0), + asBCINFO(OBJTYPE, PTR_ARG, AS_PTR_SIZE), + asBCINFO(TYPEID, DW_ARG, 1), + asBCINFO(SetV4, wW_DW_ARG, 0), + asBCINFO(SetV8, wW_QW_ARG, 0), + asBCINFO(ADDSi, W_DW_ARG, 0), + asBCINFO(CpyVtoV4, wW_rW_ARG, 0), + asBCINFO(CpyVtoV8, wW_rW_ARG, 0), + asBCINFO(CpyVtoR4, rW_ARG, 0), + asBCINFO(CpyVtoR8, rW_ARG, 0), + asBCINFO(CpyVtoG4, rW_PTR_ARG, 0), + asBCINFO(CpyRtoV4, wW_ARG, 0), + asBCINFO(CpyRtoV8, wW_ARG, 0), + asBCINFO(CpyGtoV4, wW_PTR_ARG, 0), + asBCINFO(WRTV1, rW_ARG, 0), + asBCINFO(WRTV2, rW_ARG, 0), + asBCINFO(WRTV4, rW_ARG, 0), + asBCINFO(WRTV8, rW_ARG, 0), + asBCINFO(RDR1, wW_ARG, 0), + asBCINFO(RDR2, wW_ARG, 0), + asBCINFO(RDR4, wW_ARG, 0), + asBCINFO(RDR8, wW_ARG, 0), + asBCINFO(LDG, PTR_ARG, 0), + asBCINFO(LDV, rW_ARG, 0), + asBCINFO(PGA, PTR_ARG, AS_PTR_SIZE), + asBCINFO(CmpPtr, rW_rW_ARG, 0), + asBCINFO(VAR, rW_ARG, AS_PTR_SIZE), + asBCINFO(iTOf, rW_ARG, 0), + asBCINFO(fTOi, rW_ARG, 0), + asBCINFO(uTOf, rW_ARG, 0), + asBCINFO(fTOu, rW_ARG, 0), + asBCINFO(sbTOi, rW_ARG, 0), + asBCINFO(swTOi, rW_ARG, 0), + asBCINFO(ubTOi, rW_ARG, 0), + asBCINFO(uwTOi, rW_ARG, 0), + asBCINFO(dTOi, wW_rW_ARG, 0), + asBCINFO(dTOu, wW_rW_ARG, 0), + asBCINFO(dTOf, wW_rW_ARG, 0), + asBCINFO(iTOd, wW_rW_ARG, 0), + asBCINFO(uTOd, wW_rW_ARG, 0), + asBCINFO(fTOd, wW_rW_ARG, 0), + asBCINFO(ADDi, wW_rW_rW_ARG, 0), + asBCINFO(SUBi, wW_rW_rW_ARG, 0), + asBCINFO(MULi, wW_rW_rW_ARG, 0), + asBCINFO(DIVi, wW_rW_rW_ARG, 0), + asBCINFO(MODi, wW_rW_rW_ARG, 0), + asBCINFO(ADDf, wW_rW_rW_ARG, 0), + asBCINFO(SUBf, wW_rW_rW_ARG, 0), + asBCINFO(MULf, wW_rW_rW_ARG, 0), + asBCINFO(DIVf, wW_rW_rW_ARG, 0), + asBCINFO(MODf, wW_rW_rW_ARG, 0), + asBCINFO(ADDd, wW_rW_rW_ARG, 0), + asBCINFO(SUBd, wW_rW_rW_ARG, 0), + asBCINFO(MULd, wW_rW_rW_ARG, 0), + asBCINFO(DIVd, wW_rW_rW_ARG, 0), + asBCINFO(MODd, wW_rW_rW_ARG, 0), + asBCINFO(ADDIi, wW_rW_DW_ARG, 0), + asBCINFO(SUBIi, wW_rW_DW_ARG, 0), + asBCINFO(MULIi, wW_rW_DW_ARG, 0), + asBCINFO(ADDIf, wW_rW_DW_ARG, 0), + asBCINFO(SUBIf, wW_rW_DW_ARG, 0), + asBCINFO(MULIf, wW_rW_DW_ARG, 0), + asBCINFO(SetG4, PTR_DW_ARG, 0), + asBCINFO(ChkRefS, NO_ARG, 0), + asBCINFO(ChkNullV, rW_ARG, 0), + asBCINFO(CALLINTF, DW_ARG, 0xFFFF), + asBCINFO(iTOb, rW_ARG, 0), + asBCINFO(iTOw, rW_ARG, 0), + asBCINFO(SetV1, wW_DW_ARG, 0), + asBCINFO(SetV2, wW_DW_ARG, 0), + asBCINFO(Cast, DW_ARG, -AS_PTR_SIZE), + asBCINFO(i64TOi, wW_rW_ARG, 0), + asBCINFO(uTOi64, wW_rW_ARG, 0), + asBCINFO(iTOi64, wW_rW_ARG, 0), + asBCINFO(fTOi64, wW_rW_ARG, 0), + asBCINFO(dTOi64, rW_ARG, 0), + asBCINFO(fTOu64, wW_rW_ARG, 0), + asBCINFO(dTOu64, rW_ARG, 0), + asBCINFO(i64TOf, wW_rW_ARG, 0), + asBCINFO(u64TOf, wW_rW_ARG, 0), + asBCINFO(i64TOd, rW_ARG, 0), + asBCINFO(u64TOd, rW_ARG, 0), + asBCINFO(NEGi64, rW_ARG, 0), + asBCINFO(INCi64, NO_ARG, 0), + asBCINFO(DECi64, NO_ARG, 0), + asBCINFO(BNOT64, rW_ARG, 0), + asBCINFO(ADDi64, wW_rW_rW_ARG, 0), + asBCINFO(SUBi64, wW_rW_rW_ARG, 0), + asBCINFO(MULi64, wW_rW_rW_ARG, 0), + asBCINFO(DIVi64, wW_rW_rW_ARG, 0), + asBCINFO(MODi64, wW_rW_rW_ARG, 0), + asBCINFO(BAND64, wW_rW_rW_ARG, 0), + asBCINFO(BOR64, wW_rW_rW_ARG, 0), + asBCINFO(BXOR64, wW_rW_rW_ARG, 0), + asBCINFO(BSLL64, wW_rW_rW_ARG, 0), + asBCINFO(BSRL64, wW_rW_rW_ARG, 0), + asBCINFO(BSRA64, wW_rW_rW_ARG, 0), + asBCINFO(CMPi64, rW_rW_ARG, 0), + asBCINFO(CMPu64, rW_rW_ARG, 0), + asBCINFO(ChkNullS, W_ARG, 0), + asBCINFO(ClrHi, NO_ARG, 0), + asBCINFO(JitEntry, PTR_ARG, 0), + asBCINFO(CallPtr, rW_ARG, 0xFFFF), + asBCINFO(FuncPtr, PTR_ARG, AS_PTR_SIZE), + asBCINFO(LoadThisR, W_DW_ARG, 0), + asBCINFO(PshV8, rW_ARG, 2), + asBCINFO(DIVu, wW_rW_rW_ARG, 0), + asBCINFO(MODu, wW_rW_rW_ARG, 0), + asBCINFO(DIVu64, wW_rW_rW_ARG, 0), + asBCINFO(MODu64, wW_rW_rW_ARG, 0), + asBCINFO(LoadRObjR, rW_W_DW_ARG, 0), + asBCINFO(LoadVObjR, rW_W_DW_ARG, 0), + asBCINFO(RefCpyV, wW_PTR_ARG, 0), + asBCINFO(JLowZ, DW_ARG, 0), + asBCINFO(JLowNZ, DW_ARG, 0), + asBCINFO(AllocMem, wW_DW_ARG, 0), + asBCINFO(SetListSize, rW_DW_DW_ARG, 0), + asBCINFO(PshListElmnt, rW_DW_ARG, AS_PTR_SIZE), + asBCINFO(SetListType, rW_DW_DW_ARG, 0), + asBCINFO(POWi, wW_rW_rW_ARG, 0), + asBCINFO(POWu, wW_rW_rW_ARG, 0), + asBCINFO(POWf, wW_rW_rW_ARG, 0), + asBCINFO(POWd, wW_rW_rW_ARG, 0), + asBCINFO(POWdi, wW_rW_rW_ARG, 0), + asBCINFO(POWi64, wW_rW_rW_ARG, 0), + asBCINFO(POWu64, wW_rW_rW_ARG, 0), + asBCINFO(Thiscall1, DW_ARG, -AS_PTR_SIZE-1), + + asBCINFO_DUMMY(201), + asBCINFO_DUMMY(202), + asBCINFO_DUMMY(203), + asBCINFO_DUMMY(204), + asBCINFO_DUMMY(205), + asBCINFO_DUMMY(206), + asBCINFO_DUMMY(207), + asBCINFO_DUMMY(208), + asBCINFO_DUMMY(209), + asBCINFO_DUMMY(210), + asBCINFO_DUMMY(211), + asBCINFO_DUMMY(212), + asBCINFO_DUMMY(213), + asBCINFO_DUMMY(214), + asBCINFO_DUMMY(215), + asBCINFO_DUMMY(216), + asBCINFO_DUMMY(217), + asBCINFO_DUMMY(218), + asBCINFO_DUMMY(219), + asBCINFO_DUMMY(220), + asBCINFO_DUMMY(221), + asBCINFO_DUMMY(222), + asBCINFO_DUMMY(223), + asBCINFO_DUMMY(224), + asBCINFO_DUMMY(225), + asBCINFO_DUMMY(226), + asBCINFO_DUMMY(227), + asBCINFO_DUMMY(228), + asBCINFO_DUMMY(229), + asBCINFO_DUMMY(230), + asBCINFO_DUMMY(231), + asBCINFO_DUMMY(232), + asBCINFO_DUMMY(233), + asBCINFO_DUMMY(234), + asBCINFO_DUMMY(235), + asBCINFO_DUMMY(236), + asBCINFO_DUMMY(237), + asBCINFO_DUMMY(238), + asBCINFO_DUMMY(239), + asBCINFO_DUMMY(240), + asBCINFO_DUMMY(241), + asBCINFO_DUMMY(242), + asBCINFO_DUMMY(243), + asBCINFO_DUMMY(244), + asBCINFO_DUMMY(245), + asBCINFO_DUMMY(246), + asBCINFO_DUMMY(247), + asBCINFO_DUMMY(248), + asBCINFO_DUMMY(249), + + asBCINFO(TryBlock, DW_ARG, 0), + asBCINFO(VarDecl, W_ARG, 0), + asBCINFO(Block, INFO, 0), + asBCINFO(ObjInfo, rW_DW_ARG, 0), + asBCINFO(LINE, INFO, 0), + asBCINFO(LABEL, INFO, 0) +}; + +// Macros to access bytecode instruction arguments +#define asBC_DWORDARG(x) (*(((asDWORD*)x)+1)) +#define asBC_INTARG(x) (*(int*)(((asDWORD*)x)+1)) +#define asBC_QWORDARG(x) (*(asQWORD*)(((asDWORD*)x)+1)) +#define asBC_FLOATARG(x) (*(float*)(((asDWORD*)x)+1)) +#define asBC_PTRARG(x) (*(asPWORD*)(((asDWORD*)x)+1)) +#define asBC_WORDARG0(x) (*(((asWORD*)x)+1)) +#define asBC_WORDARG1(x) (*(((asWORD*)x)+2)) +#define asBC_SWORDARG0(x) (*(((short*)x)+1)) +#define asBC_SWORDARG1(x) (*(((short*)x)+2)) +#define asBC_SWORDARG2(x) (*(((short*)x)+3)) + + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/lib/delete.me b/angelscript/lib/delete.me new file mode 100644 index 0000000..0848a35 --- /dev/null +++ b/angelscript/lib/delete.me @@ -0,0 +1 @@ +This file is only here to guarantee that unpackers don't skip creating the /lib directory. \ No newline at end of file diff --git a/angelscript/projects/android/jni/Android.mk b/angelscript/projects/android/jni/Android.mk new file mode 100644 index 0000000..ddf4d2f --- /dev/null +++ b/angelscript/projects/android/jni/Android.mk @@ -0,0 +1,43 @@ +# This makefile assumes the ndk-build tool is executed from the sdk/angelscript/projects/android directory +# Change the next line to full path if there are any errors to link or find files +SDK_BASE_PATH := $(call my-dir)/../../../.. + +ANGELSCRIPT_INCLUDE := $(SDK_BASE_PATH)/angelscript/include/ + +# ----------------------------------------------------- +# Build the AngelScript library +# ----------------------------------------------------- +include $(CLEAR_VARS) +LOCAL_MODULE := libangelscript + +# Android API: Checks if can use pthreads. Version 2.3 fully supports threads and atomic instructions +# ifeq ($(TARGET_PLATFORM),android-3) +# LOCAL_CFLAGS := -DAS_NO_THREADS +# else +# ifeq ($(TARGET_PLATFORM),android-4) +# LOCAL_CFLAGS := -DAS_NO_THREADS +# else +# ifeq ($(TARGET_PLATFORM),android-5) +# LOCAL_CFLAGS := -DAS_NO_THREADS +# else +# ifeq ($(TARGET_PLATFORM),android-6) +# LOCAL_CFLAGS := -DAS_NO_THREADS +# else +# ifeq ($(TARGET_PLATFORM),android-7) +# LOCAL_CFLAGS := -DAS_NO_THREADS +# else +# ifeq ($(TARGET_PLATFORM),android-8) +# LOCAL_CFLAGS := -DAS_NO_THREADS +# endif +# endif +# endif +# endif +# endif +# endif + +LOCAL_CPP_FEATURES += rtti exceptions +LOCAL_SRC_FILES := $(wildcard $(SDK_BASE_PATH)/angelscript/source/*.S) +LOCAL_SRC_FILES += $(wildcard $(SDK_BASE_PATH)/angelscript/source/*.cpp) +LOCAL_PATH := . +LOCAL_ARM_MODE := arm +include $(BUILD_STATIC_LIBRARY) diff --git a/angelscript/projects/android/jni/Application.mk b/angelscript/projects/android/jni/Application.mk new file mode 100644 index 0000000..d502975 --- /dev/null +++ b/angelscript/projects/android/jni/Application.mk @@ -0,0 +1,3 @@ +APP_ABI := mips armeabi armeabi-v7a x86 +APP_PLATFORM := android-19 +APP_STL := gnustl_static diff --git a/angelscript/projects/cmake/Angelscript/AngelscriptConfig.cmake b/angelscript/projects/cmake/Angelscript/AngelscriptConfig.cmake new file mode 100644 index 0000000..4d1ef0f --- /dev/null +++ b/angelscript/projects/cmake/Angelscript/AngelscriptConfig.cmake @@ -0,0 +1,2 @@ +include("${CMAKE_CURRENT_LIST_DIR}/AngelscriptTargets.cmake") + diff --git a/angelscript/projects/cmake/Angelscript/AngelscriptConfigVersion.cmake b/angelscript/projects/cmake/Angelscript/AngelscriptConfigVersion.cmake new file mode 100644 index 0000000..cbf1f96 --- /dev/null +++ b/angelscript/projects/cmake/Angelscript/AngelscriptConfigVersion.cmake @@ -0,0 +1,37 @@ +# This is a basic version file for the Config-mode of find_package(). +# It is used by write_basic_package_version_file() as input file for configure_file() +# to create a version-file which can be installed along a config.cmake file. +# +# The created file sets PACKAGE_VERSION_EXACT if the current version string and +# the requested version string are exactly the same and it sets +# PACKAGE_VERSION_COMPATIBLE if the current version is >= requested version. +# The variable CVF_VERSION must be set before calling configure_file(). + +set(PACKAGE_VERSION "2.34.0") + +if(PACKAGE_VERSION VERSION_LESS PACKAGE_FIND_VERSION) + set(PACKAGE_VERSION_COMPATIBLE FALSE) +else() + set(PACKAGE_VERSION_COMPATIBLE TRUE) + if(PACKAGE_FIND_VERSION STREQUAL PACKAGE_VERSION) + set(PACKAGE_VERSION_EXACT TRUE) + endif() +endif() + + +# if the installed project requested no architecture check, don't perform the check +if("FALSE") + return() +endif() + +# if the installed or the using project don't have CMAKE_SIZEOF_VOID_P set, ignore it: +if("${CMAKE_SIZEOF_VOID_P}" STREQUAL "" OR "8" STREQUAL "") + return() +endif() + +# check that the installed version has the same 32/64bit-ness as the one which is currently searching: +if(NOT CMAKE_SIZEOF_VOID_P STREQUAL "8") + math(EXPR installedBits "8 * 8") + set(PACKAGE_VERSION "${PACKAGE_VERSION} (${installedBits}bit)") + set(PACKAGE_VERSION_UNSUITABLE TRUE) +endif() diff --git a/angelscript/projects/cmake/Angelscript/AngelscriptTargets.cmake b/angelscript/projects/cmake/Angelscript/AngelscriptTargets.cmake new file mode 100644 index 0000000..0bed495 --- /dev/null +++ b/angelscript/projects/cmake/Angelscript/AngelscriptTargets.cmake @@ -0,0 +1,63 @@ +# Generated by CMake + +if("${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION}" LESS 2.5) + message(FATAL_ERROR "CMake >= 2.6.0 required") +endif() +cmake_policy(PUSH) +cmake_policy(VERSION 2.6) +#---------------------------------------------------------------- +# Generated CMake target import file. +#---------------------------------------------------------------- + +# Commands may need to know the format version. +set(CMAKE_IMPORT_FILE_VERSION 1) + +# Protect against multiple inclusion, which would fail when already imported targets are added once more. +set(_targetsDefined) +set(_targetsNotDefined) +set(_expectedTargets) +foreach(_expectedTarget Angelscript::angelscript) + list(APPEND _expectedTargets ${_expectedTarget}) + if(NOT TARGET ${_expectedTarget}) + list(APPEND _targetsNotDefined ${_expectedTarget}) + endif() + if(TARGET ${_expectedTarget}) + list(APPEND _targetsDefined ${_expectedTarget}) + endif() +endforeach() +if("${_targetsDefined}" STREQUAL "${_expectedTargets}") + unset(_targetsDefined) + unset(_targetsNotDefined) + unset(_expectedTargets) + set(CMAKE_IMPORT_FILE_VERSION) + cmake_policy(POP) + return() +endif() +if(NOT "${_targetsDefined}" STREQUAL "") + message(FATAL_ERROR "Some (but not all) targets in this export set were already defined.\nTargets Defined: ${_targetsDefined}\nTargets not yet defined: ${_targetsNotDefined}\n") +endif() +unset(_targetsDefined) +unset(_targetsNotDefined) +unset(_expectedTargets) + + +# Create imported target Angelscript::angelscript +add_library(Angelscript::angelscript STATIC IMPORTED) + +set_target_properties(Angelscript::angelscript PROPERTIES + INTERFACE_LINK_LIBRARIES "Threads::Threads" +) + +# Import target "Angelscript::angelscript" for configuration "Debug" +set_property(TARGET Angelscript::angelscript APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG) +set_target_properties(Angelscript::angelscript PROPERTIES + IMPORTED_LINK_INTERFACE_LANGUAGES_DEBUG "CXX" + IMPORTED_LOCATION_DEBUG "/home/nathan/Projects/Angelscript/angelscript/projects/cmake/libangelscript.a" + ) + +# This file does not depend on other imported targets which have +# been exported from the same project but in a separate export set. + +# Commands beyond this point should not need to know the version. +set(CMAKE_IMPORT_FILE_VERSION) +cmake_policy(POP) diff --git a/angelscript/projects/cmake/CMakeLists.txt b/angelscript/projects/cmake/CMakeLists.txt new file mode 100644 index 0000000..a35fad6 --- /dev/null +++ b/angelscript/projects/cmake/CMakeLists.txt @@ -0,0 +1,239 @@ +cmake_minimum_required(VERSION 3.16) +include(CheckIPOSupported) + +project(angelscript) +set(CMAKE_CXX_STANDARD 20) +set(CMAKE_POSITION_INDEPENDENT_CODE ON) + +option(BUILD_SHARED_LIBS "Build shared library" OFF) +option(LINK_STD_STATICALLY "Build shared library" OFF) +option(AS_NO_EXCEPTIONS "Disable exception handling in script context" OFF) + +if(MSVC) + option(MSVC_COMPILE_FLAGS "Compiler flags to use with MSVC" "/MP") +endif() + +if(APPLE) + option(BUILD_FRAMEWORK "Build Framework bundle for OSX" OFF) +endif() + +if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + add_link_options(-fuse-ld=lld) +endif () + + +file(READ ../../include/angelscript.h ANGELSCRIPT_H) +string(REGEX MATCH "#define ANGELSCRIPT_VERSION_STRING \"([0-9]*).([0-9]*).([0-9]*)" ANGELSCRIPT_VERSION_REGEX ${ANGELSCRIPT_H}) +set(ANGELSCRIPT_VERSION_MAJOR ${CMAKE_MATCH_1}) +set(ANGELSCRIPT_VERSION_MINOR ${CMAKE_MATCH_2}) +set(ANGELSCRIPT_VERSION_PATCH ${CMAKE_MATCH_3}) +set(PROJECT_VERSION ${ANGELSCRIPT_VERSION_MAJOR}.${ANGELSCRIPT_VERSION_MINOR}.${ANGELSCRIPT_VERSION_PATCH}) + +message(STATUS "Configuring angelscript ${PROJECT_VERSION}") + +set(ANGELSCRIPT_HEADERS + ../../include/angelscript.h + ../../source/as_array.h + ../../source/as_builder.h + ../../source/as_bytecode.h + ../../source/as_callfunc.h + ../../source/as_compiler.h + ../../source/as_config.h + ../../source/as_configgroup.h + ../../source/as_context.h + ../../source/as_criticalsection.h + ../../source/as_datatype.h + ../../source/as_debug.h + ../../source/as_generic.h + ../../source/as_map.h + ../../source/as_memory.h + ../../source/as_module.h + ../../source/as_objecttype.h + ../../source/as_outputbuffer.h + ../../source/as_parser.h + ../../source/as_property.h + ../../source/as_restore.h + ../../source/as_scriptcode.h + ../../source/as_scriptengine.h + ../../source/as_scriptfunction.h + ../../source/as_scriptnode.h + ../../source/as_scriptobject.h + ../../source/as_string.h + ../../source/as_string_util.h + ../../source/as_texts.h + ../../source/as_thread.h + ../../source/as_tokendef.h + ../../source/as_tokenizer.h + ../../source/as_typeinfo.h + ../../source/as_variablescope.h +) + +set(ANGELSCRIPT_SOURCE + ../../source/as_atomic.cpp + ../../source/as_builder.cpp + ../../source/as_bytecode.cpp + ../../source/as_callfunc.cpp + ../../source/as_callfunc_mips.cpp + ../../source/as_callfunc_x86.cpp + ../../source/as_callfunc_x64_gcc.cpp + ../../source/as_callfunc_x64_msvc.cpp + ../../source/as_callfunc_x64_mingw.cpp + ../../source/as_compiler.cpp + ../../source/as_configgroup.cpp + ../../source/as_context.cpp + ../../source/as_datatype.cpp + ../../source/as_gc.cpp + ../../source/as_generic.cpp + ../../source/as_globalproperty.cpp + ../../source/as_memory.cpp + ../../source/as_module.cpp + ../../source/as_objecttype.cpp + ../../source/as_outputbuffer.cpp + ../../source/as_parser.cpp + ../../source/as_restore.cpp + ../../source/as_scriptcode.cpp + ../../source/as_scriptengine.cpp + ../../source/as_scriptfunction.cpp + ../../source/as_scriptnode.cpp + ../../source/as_scriptobject.cpp + ../../source/as_string.cpp + ../../source/as_string_util.cpp + ../../source/as_thread.cpp + ../../source/as_tokenizer.cpp + ../../source/as_typeinfo.cpp + ../../source/as_variablescope.cpp +) + +if(MSVC AND CMAKE_CL_64) + enable_language(ASM_MASM) + if(CMAKE_ASM_MASM_COMPILER_WORKS) + set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_x64_msvc_asm.asm) + else() + message(FATAL ERROR "MSVC x86_64 target requires a working assembler") + endif() +endif() + +if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^arm") + enable_language(ASM) + if(CMAKE_ASM_COMPILER_WORKS) + set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_arm.cpp ../../source/as_callfunc_arm_gcc.S) + set_property(SOURCE ../../source/as_callfunc_arm_gcc.S APPEND PROPERTY COMPILE_FLAGS " -Wa,-mimplicit-it=always") + else() + message(FATAL ERROR "ARM target requires a working assembler") + endif() +endif() + +if(${CMAKE_SYSTEM_PROCESSOR} MATCHES "^aarch64") + enable_language(ASM) + if(CMAKE_ASM_COMPILER_WORKS) + set(ANGELSCRIPT_SOURCE ${ANGELSCRIPT_SOURCE} ../../source/as_callfunc_arm64.cpp ../../source/as_callfunc_arm64_gcc.S) + #set_property(SOURCE ../../source/as_callfunc_arm64_gcc.S APPEND PROPERTY COMPILE_FLAGS " -Wa") + else() + message(FATAL ERROR "ARM target requires a working assembler") + endif() +endif() + +if(MSVC) + set(CMAKE_DEBUG_POSTFIX "d") +endif() + +if(NOT BUILD_FRAMEWORK) + set(ANGELSCRIPT_LIBRARY_NAME angelscript) +else() + set(ANGELSCRIPT_LIBRARY_NAME Angelscript) # OS X frameworks should have capitalized name + set(BUILD_SHARED_LIBS TRUE) +endif() +set(ANGELSCRIPT_LIBRARY_NAME ${ANGELSCRIPT_LIBRARY_NAME} CACHE STRING "" FORCE) + +add_library(${ANGELSCRIPT_LIBRARY_NAME} ${ANGELSCRIPT_SOURCE} ${ANGELSCRIPT_HEADERS}) + +target_include_directories(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/../../include) + +if(MSVC) + target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -D_CRT_SECURE_NO_WARNINGS) +endif() + +target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE -DANGELSCRIPT_EXPORT -D_LIB) + +if(AS_NO_EXCEPTIONS) + target_compile_definitions(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE AS_NO_EXCEPTIONS) +endif() + +# Don't override the default library output path to avoid conflicts when building for multiple target platforms +#set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../../lib) + +if (LINK_STD_STATICALLY) + message(STATUS "Linking std libraries statically") + set (CMAKE_SHARED_LINKER_FLAGS "-Wl,--as-needed") + target_link_libraries(${ANGELSCRIPT_LIBRARY_NAME} -lpthread -static-libgcc -static-libstdc++ -Wl,-Bstatic -lstdc++ ) +else() + set(THREADS_PREFER_PTHREAD_FLAG ON) + find_package(Threads REQUIRED) + target_link_libraries(${ANGELSCRIPT_LIBRARY_NAME} -lpthread) +endif() + +set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES VERSION ${PROJECT_VERSION}) + +if(BUILD_FRAMEWORK) + set_target_properties(${ANGELSCRIPT_LIBRARY_NAME} PROPERTIES + FRAMEWORK TRUE + FRAMEWORK_VERSION ${PROJECT_VERSION} + MACOSX_FRAMEWORK_IDENTIFIER com.angelcode.Angelscript + MACOSX_FRAMEWORK_SHORT_VERSION_STRING ${PROJECT_VERSION} + MACOSX_FRAMEWORK_BUNDLE_VERSION ${PROJECT_VERSION} + XCODE_ATTRIBUTE_INSTALL_PATH "@rpath" + PUBLIC_HEADER ../../include/angelscript.h + ) +endif() + +if(MSVC AND MSVC_COMPILE_FLAGS) + target_compile_options(${ANGELSCRIPT_LIBRARY_NAME} PRIVATE "${MSVC_COMPILE_FLAGS}") +endif() + +# Don't override the default runtime output path to avoid conflicts when building for multiple target platforms +#set(RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/../../bin) + +#See https://cmake.org/cmake/help/latest/manual/cmake-packages.7.html#creating-packages for a detailed explanation about this part +install(TARGETS ${ANGELSCRIPT_LIBRARY_NAME} EXPORT AngelscriptTargets + RUNTIME DESTINATION bin + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + INCLUDES DESTINATION include +) + +install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/../../include/angelscript.h + DESTINATION include + COMPONENT Devel +) + +include(CMakePackageConfigHelpers) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake" + VERSION ${PROJECT_VERSION} + COMPATIBILITY AnyNewerVersion +) + +export(EXPORT AngelscriptTargets + FILE "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptTargets.cmake" + NAMESPACE Angelscript:: +) +configure_file(cmake/AngelscriptConfig.cmake + "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfig.cmake" + COPYONLY +) + +set(ConfigPackageLocation lib/cmake/Angelscript) +install(EXPORT AngelscriptTargets + FILE AngelscriptTargets.cmake + NAMESPACE Angelscript:: + DESTINATION ${ConfigPackageLocation} +) +install( + FILES + cmake/AngelscriptConfig.cmake + "${CMAKE_CURRENT_BINARY_DIR}/Angelscript/AngelscriptConfigVersion.cmake" + DESTINATION ${ConfigPackageLocation} + COMPONENT Devel +) + diff --git a/angelscript/projects/cmake/cmake/AngelscriptConfig.cmake b/angelscript/projects/cmake/cmake/AngelscriptConfig.cmake new file mode 100644 index 0000000..4d1ef0f --- /dev/null +++ b/angelscript/projects/cmake/cmake/AngelscriptConfig.cmake @@ -0,0 +1,2 @@ +include("${CMAKE_CURRENT_LIST_DIR}/AngelscriptTargets.cmake") + diff --git a/angelscript/projects/cmake/conan.lock b/angelscript/projects/cmake/conan.lock new file mode 100644 index 0000000..1157d96 --- /dev/null +++ b/angelscript/projects/cmake/conan.lock @@ -0,0 +1,15 @@ +{ + "graph_lock": { + "nodes": { + "0": { + "ref": "AngelScript/2.35", + "options": "link_std_statically=True\nshared=True", + "path": "conanfile.py", + "context": "host" + } + }, + "revisions_enabled": false + }, + "version": "0.4", + "profile_host": "[settings]\narch=x86_64\narch_build=x86_64\nbuild_type=Release\ncompiler=clang\ncompiler.libcxx=libstdc++11\ncompiler.version=11\nos=Linux\nos_build=Linux\n[options]\nlink_std_statically=True\nshared=True\n[build_requires]\n[env]\n" +} \ No newline at end of file diff --git a/angelscript/projects/cmake/conanbuildinfo.cmake b/angelscript/projects/cmake/conanbuildinfo.cmake new file mode 100644 index 0000000..cbc5d38 --- /dev/null +++ b/angelscript/projects/cmake/conanbuildinfo.cmake @@ -0,0 +1,675 @@ +include(CMakeParseArguments) + +macro(conan_find_apple_frameworks FRAMEWORKS_FOUND FRAMEWORKS SUFFIX BUILD_TYPE) + if(APPLE) + if(CMAKE_BUILD_TYPE) + set(_BTYPE ${CMAKE_BUILD_TYPE}) + elseif(NOT BUILD_TYPE STREQUAL "") + set(_BTYPE ${BUILD_TYPE}) + endif() + if(_BTYPE) + if(${_BTYPE} MATCHES "Debug|_DEBUG") + set(CONAN_FRAMEWORKS${SUFFIX} ${CONAN_FRAMEWORKS${SUFFIX}_DEBUG} ${CONAN_FRAMEWORKS${SUFFIX}}) + set(CONAN_FRAMEWORK_DIRS${SUFFIX} ${CONAN_FRAMEWORK_DIRS${SUFFIX}_DEBUG} ${CONAN_FRAMEWORK_DIRS${SUFFIX}}) + elseif(${_BTYPE} MATCHES "Release|_RELEASE") + set(CONAN_FRAMEWORKS${SUFFIX} ${CONAN_FRAMEWORKS${SUFFIX}_RELEASE} ${CONAN_FRAMEWORKS${SUFFIX}}) + set(CONAN_FRAMEWORK_DIRS${SUFFIX} ${CONAN_FRAMEWORK_DIRS${SUFFIX}_RELEASE} ${CONAN_FRAMEWORK_DIRS${SUFFIX}}) + elseif(${_BTYPE} MATCHES "RelWithDebInfo|_RELWITHDEBINFO") + set(CONAN_FRAMEWORKS${SUFFIX} ${CONAN_FRAMEWORKS${SUFFIX}_RELWITHDEBINFO} ${CONAN_FRAMEWORKS${SUFFIX}}) + set(CONAN_FRAMEWORK_DIRS${SUFFIX} ${CONAN_FRAMEWORK_DIRS${SUFFIX}_RELWITHDEBINFO} ${CONAN_FRAMEWORK_DIRS${SUFFIX}}) + elseif(${_BTYPE} MATCHES "MinSizeRel|_MINSIZEREL") + set(CONAN_FRAMEWORKS${SUFFIX} ${CONAN_FRAMEWORKS${SUFFIX}_MINSIZEREL} ${CONAN_FRAMEWORKS${SUFFIX}}) + set(CONAN_FRAMEWORK_DIRS${SUFFIX} ${CONAN_FRAMEWORK_DIRS${SUFFIX}_MINSIZEREL} ${CONAN_FRAMEWORK_DIRS${SUFFIX}}) + endif() + endif() + foreach(_FRAMEWORK ${FRAMEWORKS}) + # https://cmake.org/pipermail/cmake-developers/2017-August/030199.html + find_library(CONAN_FRAMEWORK_${_FRAMEWORK}_FOUND NAME ${_FRAMEWORK} PATHS ${CONAN_FRAMEWORK_DIRS${SUFFIX}} CMAKE_FIND_ROOT_PATH_BOTH) + if(CONAN_FRAMEWORK_${_FRAMEWORK}_FOUND) + list(APPEND ${FRAMEWORKS_FOUND} ${CONAN_FRAMEWORK_${_FRAMEWORK}_FOUND}) + else() + message(FATAL_ERROR "Framework library ${_FRAMEWORK} not found in paths: ${CONAN_FRAMEWORK_DIRS${SUFFIX}}") + endif() + endforeach() + endif() +endmacro() + + +### Definition of global aggregated variables ### + +set(CONAN_PACKAGE_NAME AngelScript) +set(CONAN_PACKAGE_VERSION 2.35) + +set(CONAN_SETTINGS_ARCH "x86_64") +set(CONAN_SETTINGS_BUILD_TYPE "Release") +set(CONAN_SETTINGS_COMPILER "clang") +set(CONAN_SETTINGS_COMPILER_LIBCXX "libstdc++11") +set(CONAN_SETTINGS_COMPILER_VERSION "11") +set(CONAN_SETTINGS_OS "Linux") + +set(CONAN_DEPENDENCIES ) +# Storing original command line args (CMake helper) flags +set(CONAN_CMD_CXX_FLAGS ${CONAN_CXX_FLAGS}) + +set(CONAN_CMD_SHARED_LINKER_FLAGS ${CONAN_SHARED_LINKER_FLAGS}) +set(CONAN_CMD_C_FLAGS ${CONAN_C_FLAGS}) +# Defining accumulated conan variables for all deps + +set(CONAN_INCLUDE_DIRS ${CONAN_INCLUDE_DIRS}) +set(CONAN_LIB_DIRS ${CONAN_LIB_DIRS}) +set(CONAN_BIN_DIRS ${CONAN_BIN_DIRS}) +set(CONAN_RES_DIRS ${CONAN_RES_DIRS}) +set(CONAN_FRAMEWORK_DIRS ${CONAN_FRAMEWORK_DIRS}) +set(CONAN_LIBS ${CONAN_LIBS}) +set(CONAN_PKG_LIBS ${CONAN_PKG_LIBS}) +set(CONAN_SYSTEM_LIBS ${CONAN_SYSTEM_LIBS}) +set(CONAN_FRAMEWORKS ${CONAN_FRAMEWORKS}) +set(CONAN_FRAMEWORKS_FOUND "") # Will be filled later +set(CONAN_DEFINES ${CONAN_DEFINES}) +set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS}) +set(CONAN_CMAKE_MODULE_PATH ${CONAN_CMAKE_MODULE_PATH}) + +set(CONAN_CXX_FLAGS " ${CONAN_CXX_FLAGS}") +set(CONAN_SHARED_LINKER_FLAGS " ${CONAN_SHARED_LINKER_FLAGS}") +set(CONAN_EXE_LINKER_FLAGS " ${CONAN_EXE_LINKER_FLAGS}") +set(CONAN_C_FLAGS " ${CONAN_C_FLAGS}") + +# Apple Frameworks +conan_find_apple_frameworks(CONAN_FRAMEWORKS_FOUND "${CONAN_FRAMEWORKS}" "" "") +# Append to aggregated values variable: Use CONAN_LIBS instead of CONAN_PKG_LIBS to include user appended vars +set(CONAN_LIBS ${CONAN_LIBS} ${CONAN_SYSTEM_LIBS} ${CONAN_FRAMEWORKS_FOUND}) + + +### Definition of macros and functions ### + +macro(conan_define_targets) + if(${CMAKE_VERSION} VERSION_LESS "3.1.2") + message(FATAL_ERROR "TARGETS not supported by your CMake version!") + endif() # CMAKE > 3.x + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${CONAN_CMD_CXX_FLAGS}") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${CONAN_CMD_C_FLAGS}") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${CONAN_CMD_SHARED_LINKER_FLAGS}") + + set(CONAN_TARGETS ) + +endmacro() + + +macro(conan_basic_setup) + set(options TARGETS NO_OUTPUT_DIRS SKIP_RPATH KEEP_RPATHS SKIP_STD SKIP_FPIC) + cmake_parse_arguments(ARGUMENTS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN} ) + + if(CONAN_EXPORTED) + conan_message(STATUS "Conan: called by CMake conan helper") + endif() + + if(CONAN_IN_LOCAL_CACHE) + conan_message(STATUS "Conan: called inside local cache") + endif() + + if(NOT ARGUMENTS_NO_OUTPUT_DIRS) + conan_message(STATUS "Conan: Adjusting output directories") + conan_output_dirs_setup() + endif() + + if(NOT ARGUMENTS_TARGETS) + conan_message(STATUS "Conan: Using cmake global configuration") + conan_global_flags() + else() + conan_message(STATUS "Conan: Using cmake targets configuration") + conan_define_targets() + endif() + + if(ARGUMENTS_SKIP_RPATH) + # Change by "DEPRECATION" or "SEND_ERROR" when we are ready + conan_message(WARNING "Conan: SKIP_RPATH is deprecated, it has been renamed to KEEP_RPATHS") + endif() + + if(NOT ARGUMENTS_SKIP_RPATH AND NOT ARGUMENTS_KEEP_RPATHS) + # Parameter has renamed, but we keep the compatibility with old SKIP_RPATH + conan_set_rpath() + endif() + + if(NOT ARGUMENTS_SKIP_STD) + conan_set_std() + endif() + + if(NOT ARGUMENTS_SKIP_FPIC) + conan_set_fpic() + endif() + + conan_check_compiler() + conan_set_libcxx() + conan_set_vs_runtime() + conan_set_find_paths() + conan_include_build_modules() + conan_set_find_library_paths() +endmacro() + + +macro(conan_set_find_paths) + # CMAKE_MODULE_PATH does not have Debug/Release config, but there are variables + # CONAN_CMAKE_MODULE_PATH_DEBUG to be used by the consumer + # CMake can find findXXX.cmake files in the root of packages + set(CMAKE_MODULE_PATH ${CONAN_CMAKE_MODULE_PATH} ${CMAKE_MODULE_PATH}) + + # Make find_package() to work + set(CMAKE_PREFIX_PATH ${CONAN_CMAKE_MODULE_PATH} ${CMAKE_PREFIX_PATH}) + + # Set the find root path (cross build) + set(CMAKE_FIND_ROOT_PATH ${CONAN_CMAKE_FIND_ROOT_PATH} ${CMAKE_FIND_ROOT_PATH}) + if(CONAN_CMAKE_FIND_ROOT_PATH_MODE_PROGRAM) + set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ${CONAN_CMAKE_FIND_ROOT_PATH_MODE_PROGRAM}) + endif() + if(CONAN_CMAKE_FIND_ROOT_PATH_MODE_LIBRARY) + set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ${CONAN_CMAKE_FIND_ROOT_PATH_MODE_LIBRARY}) + endif() + if(CONAN_CMAKE_FIND_ROOT_PATH_MODE_INCLUDE) + set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ${CONAN_CMAKE_FIND_ROOT_PATH_MODE_INCLUDE}) + endif() +endmacro() + + +macro(conan_set_find_library_paths) + # CMAKE_INCLUDE_PATH, CMAKE_LIBRARY_PATH does not have Debug/Release config, but there are variables + # CONAN_INCLUDE_DIRS_DEBUG/RELEASE CONAN_LIB_DIRS_DEBUG/RELEASE to be used by the consumer + # For find_library + set(CMAKE_INCLUDE_PATH ${CONAN_INCLUDE_DIRS} ${CMAKE_INCLUDE_PATH}) + set(CMAKE_LIBRARY_PATH ${CONAN_LIB_DIRS} ${CMAKE_LIBRARY_PATH}) +endmacro() + + +macro(conan_set_vs_runtime) + if(CONAN_LINK_RUNTIME) + conan_get_policy(CMP0091 policy_0091) + if(policy_0091 STREQUAL "NEW") + if(CONAN_LINK_RUNTIME MATCHES "MTd") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebug") + elseif(CONAN_LINK_RUNTIME MATCHES "MDd") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDebugDLL") + elseif(CONAN_LINK_RUNTIME MATCHES "MT") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded") + elseif(CONAN_LINK_RUNTIME MATCHES "MD") + set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreadedDLL") + endif() + else() + foreach(flag CMAKE_C_FLAGS_RELEASE CMAKE_CXX_FLAGS_RELEASE + CMAKE_C_FLAGS_RELWITHDEBINFO CMAKE_CXX_FLAGS_RELWITHDEBINFO + CMAKE_C_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_MINSIZEREL) + if(DEFINED ${flag}) + string(REPLACE "/MD" ${CONAN_LINK_RUNTIME} ${flag} "${${flag}}") + endif() + endforeach() + foreach(flag CMAKE_C_FLAGS_DEBUG CMAKE_CXX_FLAGS_DEBUG) + if(DEFINED ${flag}) + string(REPLACE "/MDd" ${CONAN_LINK_RUNTIME} ${flag} "${${flag}}") + endif() + endforeach() + endif() + endif() +endmacro() + + +macro(conan_flags_setup) + # Macro maintained for backwards compatibility + conan_set_find_library_paths() + conan_global_flags() + conan_set_rpath() + conan_set_vs_runtime() + conan_set_libcxx() +endmacro() + + +function(conan_message MESSAGE_OUTPUT) + if(NOT CONAN_CMAKE_SILENT_OUTPUT) + message(${ARGV${0}}) + endif() +endfunction() + + +function(conan_get_policy policy_id policy) + if(POLICY "${policy_id}") + cmake_policy(GET "${policy_id}" _policy) + set(${policy} "${_policy}" PARENT_SCOPE) + else() + set(${policy} "" PARENT_SCOPE) + endif() +endfunction() + + +function(conan_find_libraries_abs_path libraries package_libdir libraries_abs_path) + foreach(_LIBRARY_NAME ${libraries}) + find_library(CONAN_FOUND_LIBRARY NAME ${_LIBRARY_NAME} PATHS ${package_libdir} + NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + if(CONAN_FOUND_LIBRARY) + conan_message(STATUS "Library ${_LIBRARY_NAME} found ${CONAN_FOUND_LIBRARY}") + set(CONAN_FULLPATH_LIBS ${CONAN_FULLPATH_LIBS} ${CONAN_FOUND_LIBRARY}) + else() + conan_message(STATUS "Library ${_LIBRARY_NAME} not found in package, might be system one") + set(CONAN_FULLPATH_LIBS ${CONAN_FULLPATH_LIBS} ${_LIBRARY_NAME}) + endif() + unset(CONAN_FOUND_LIBRARY CACHE) + endforeach() + set(${libraries_abs_path} ${CONAN_FULLPATH_LIBS} PARENT_SCOPE) +endfunction() + + +function(conan_package_library_targets libraries package_libdir libraries_abs_path deps build_type package_name) + unset(_CONAN_ACTUAL_TARGETS CACHE) + unset(_CONAN_FOUND_SYSTEM_LIBS CACHE) + foreach(_LIBRARY_NAME ${libraries}) + find_library(CONAN_FOUND_LIBRARY NAME ${_LIBRARY_NAME} PATHS ${package_libdir} + NO_DEFAULT_PATH NO_CMAKE_FIND_ROOT_PATH) + if(CONAN_FOUND_LIBRARY) + conan_message(STATUS "Library ${_LIBRARY_NAME} found ${CONAN_FOUND_LIBRARY}") + set(_LIB_NAME CONAN_LIB::${package_name}_${_LIBRARY_NAME}${build_type}) + add_library(${_LIB_NAME} UNKNOWN IMPORTED) + set_target_properties(${_LIB_NAME} PROPERTIES IMPORTED_LOCATION ${CONAN_FOUND_LIBRARY}) + set(CONAN_FULLPATH_LIBS ${CONAN_FULLPATH_LIBS} ${_LIB_NAME}) + set(_CONAN_ACTUAL_TARGETS ${_CONAN_ACTUAL_TARGETS} ${_LIB_NAME}) + else() + conan_message(STATUS "Library ${_LIBRARY_NAME} not found in package, might be system one") + set(CONAN_FULLPATH_LIBS ${CONAN_FULLPATH_LIBS} ${_LIBRARY_NAME}) + set(_CONAN_FOUND_SYSTEM_LIBS "${_CONAN_FOUND_SYSTEM_LIBS};${_LIBRARY_NAME}") + endif() + unset(CONAN_FOUND_LIBRARY CACHE) + endforeach() + + # Add all dependencies to all targets + string(REPLACE " " ";" deps_list "${deps}") + foreach(_CONAN_ACTUAL_TARGET ${_CONAN_ACTUAL_TARGETS}) + set_property(TARGET ${_CONAN_ACTUAL_TARGET} PROPERTY INTERFACE_LINK_LIBRARIES "${_CONAN_FOUND_SYSTEM_LIBS};${deps_list}") + endforeach() + + set(${libraries_abs_path} ${CONAN_FULLPATH_LIBS} PARENT_SCOPE) +endfunction() + + +macro(conan_set_libcxx) + if(DEFINED CONAN_LIBCXX) + conan_message(STATUS "Conan: C++ stdlib: ${CONAN_LIBCXX}") + if(CONAN_COMPILER STREQUAL "clang" OR CONAN_COMPILER STREQUAL "apple-clang") + if(CONAN_LIBCXX STREQUAL "libstdc++" OR CONAN_LIBCXX STREQUAL "libstdc++11" ) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libstdc++") + elseif(CONAN_LIBCXX STREQUAL "libc++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++") + endif() + endif() + if(CONAN_COMPILER STREQUAL "sun-cc") + if(CONAN_LIBCXX STREQUAL "libCstd") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=Cstd") + elseif(CONAN_LIBCXX STREQUAL "libstdcxx") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stdcxx4") + elseif(CONAN_LIBCXX STREQUAL "libstlport") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stlport4") + elseif(CONAN_LIBCXX STREQUAL "libstdc++") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -library=stdcpp") + endif() + endif() + if(CONAN_LIBCXX STREQUAL "libstdc++11") + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=1) + elseif(CONAN_LIBCXX STREQUAL "libstdc++") + add_definitions(-D_GLIBCXX_USE_CXX11_ABI=0) + endif() + endif() +endmacro() + + +macro(conan_set_std) + conan_message(STATUS "Conan: Adjusting language standard") + # Do not warn "Manually-specified variables were not used by the project" + set(ignorevar "${CONAN_STD_CXX_FLAG}${CONAN_CMAKE_CXX_STANDARD}${CONAN_CMAKE_CXX_EXTENSIONS}") + if (CMAKE_VERSION VERSION_LESS "3.1" OR + (CMAKE_VERSION VERSION_LESS "3.12" AND ("${CONAN_CMAKE_CXX_STANDARD}" STREQUAL "20" OR "${CONAN_CMAKE_CXX_STANDARD}" STREQUAL "gnu20"))) + if(CONAN_STD_CXX_FLAG) + conan_message(STATUS "Conan setting CXX_FLAGS flags: ${CONAN_STD_CXX_FLAG}") + set(CMAKE_CXX_FLAGS "${CONAN_STD_CXX_FLAG} ${CMAKE_CXX_FLAGS}") + endif() + else() + if(CONAN_CMAKE_CXX_STANDARD) + conan_message(STATUS "Conan setting CPP STANDARD: ${CONAN_CMAKE_CXX_STANDARD} WITH EXTENSIONS ${CONAN_CMAKE_CXX_EXTENSIONS}") + set(CMAKE_CXX_STANDARD ${CONAN_CMAKE_CXX_STANDARD}) + set(CMAKE_CXX_EXTENSIONS ${CONAN_CMAKE_CXX_EXTENSIONS}) + endif() + endif() +endmacro() + + +macro(conan_set_rpath) + conan_message(STATUS "Conan: Adjusting default RPATHs Conan policies") + if(APPLE) + # https://cmake.org/Wiki/CMake_RPATH_handling + # CONAN GUIDE: All generated libraries should have the id and dependencies to other + # dylibs without path, just the name, EX: + # libMyLib1.dylib: + # libMyLib1.dylib (compatibility version 0.0.0, current version 0.0.0) + # libMyLib0.dylib (compatibility version 0.0.0, current version 0.0.0) + # /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0) + # /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1) + # AVOID RPATH FOR *.dylib, ALL LIBS BETWEEN THEM AND THE EXE + # SHOULD BE ON THE LINKER RESOLVER PATH (./ IS ONE OF THEM) + set(CMAKE_SKIP_RPATH 1 CACHE BOOL "rpaths" FORCE) + # Policy CMP0068 + # We want the old behavior, in CMake >= 3.9 CMAKE_SKIP_RPATH won't affect the install_name in OSX + set(CMAKE_INSTALL_NAME_DIR "") + endif() +endmacro() + + +macro(conan_set_fpic) + if(DEFINED CONAN_CMAKE_POSITION_INDEPENDENT_CODE) + conan_message(STATUS "Conan: Adjusting fPIC flag (${CONAN_CMAKE_POSITION_INDEPENDENT_CODE})") + set(CMAKE_POSITION_INDEPENDENT_CODE ${CONAN_CMAKE_POSITION_INDEPENDENT_CODE}) + endif() +endmacro() + + +macro(conan_output_dirs_setup) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) + + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_ARCHIVE_OUTPUT_DIRECTORY}) + + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_MINSIZEREL ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) + set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}) +endmacro() + + +macro(conan_split_version VERSION_STRING MAJOR MINOR) + #make a list from the version string + string(REPLACE "." ";" VERSION_LIST "${VERSION_STRING}") + + #write output values + list(LENGTH VERSION_LIST _version_len) + list(GET VERSION_LIST 0 ${MAJOR}) + if(${_version_len} GREATER 1) + list(GET VERSION_LIST 1 ${MINOR}) + endif() +endmacro() + + +macro(conan_error_compiler_version) + message(FATAL_ERROR "Detected a mismatch for the compiler version between your conan profile settings and CMake: \n" + "Compiler version specified in your conan profile: ${CONAN_COMPILER_VERSION}\n" + "Compiler version detected in CMake: ${VERSION_MAJOR}.${VERSION_MINOR}\n" + "Please check your conan profile settings (conan profile show [default|your_profile_name])\n" + "P.S. You may set CONAN_DISABLE_CHECK_COMPILER CMake variable in order to disable this check." + ) +endmacro() + +set(_CONAN_CURRENT_DIR ${CMAKE_CURRENT_LIST_DIR}) + +function(conan_get_compiler CONAN_INFO_COMPILER CONAN_INFO_COMPILER_VERSION) + conan_message(STATUS "Current conanbuildinfo.cmake directory: " ${_CONAN_CURRENT_DIR}) + if(NOT EXISTS ${_CONAN_CURRENT_DIR}/conaninfo.txt) + conan_message(STATUS "WARN: conaninfo.txt not found") + return() + endif() + + file (READ "${_CONAN_CURRENT_DIR}/conaninfo.txt" CONANINFO) + + # MATCHALL will match all, including the last one, which is the full_settings one + string(REGEX MATCH "full_settings.*" _FULL_SETTINGS_MATCHED ${CONANINFO}) + string(REGEX MATCH "compiler=([-A-Za-z0-9_ ]+)" _MATCHED ${_FULL_SETTINGS_MATCHED}) + if(DEFINED CMAKE_MATCH_1) + string(STRIP "${CMAKE_MATCH_1}" _CONAN_INFO_COMPILER) + set(${CONAN_INFO_COMPILER} ${_CONAN_INFO_COMPILER} PARENT_SCOPE) + endif() + + string(REGEX MATCH "compiler.version=([-A-Za-z0-9_.]+)" _MATCHED ${_FULL_SETTINGS_MATCHED}) + if(DEFINED CMAKE_MATCH_1) + string(STRIP "${CMAKE_MATCH_1}" _CONAN_INFO_COMPILER_VERSION) + set(${CONAN_INFO_COMPILER_VERSION} ${_CONAN_INFO_COMPILER_VERSION} PARENT_SCOPE) + endif() +endfunction() + + +function(check_compiler_version) + conan_split_version(${CMAKE_CXX_COMPILER_VERSION} VERSION_MAJOR VERSION_MINOR) + if(DEFINED CONAN_SETTINGS_COMPILER_TOOLSET) + conan_message(STATUS "Conan: Skipping compiler check: Declared 'compiler.toolset'") + return() + endif() + if(CMAKE_CXX_COMPILER_ID MATCHES MSVC) + # MSVC_VERSION is defined since 2.8.2 at least + # https://cmake.org/cmake/help/v2.8.2/cmake.html#variable:MSVC_VERSION + # https://cmake.org/cmake/help/v3.14/variable/MSVC_VERSION.html + if( + # 1920-1929 = VS 16.0 (v142 toolset) + (CONAN_COMPILER_VERSION STREQUAL "16" AND NOT((MSVC_VERSION GREATER 1919) AND (MSVC_VERSION LESS 1930))) OR + # 1910-1919 = VS 15.0 (v141 toolset) + (CONAN_COMPILER_VERSION STREQUAL "15" AND NOT((MSVC_VERSION GREATER 1909) AND (MSVC_VERSION LESS 1920))) OR + # 1900 = VS 14.0 (v140 toolset) + (CONAN_COMPILER_VERSION STREQUAL "14" AND NOT(MSVC_VERSION EQUAL 1900)) OR + # 1800 = VS 12.0 (v120 toolset) + (CONAN_COMPILER_VERSION STREQUAL "12" AND NOT VERSION_MAJOR STREQUAL "18") OR + # 1700 = VS 11.0 (v110 toolset) + (CONAN_COMPILER_VERSION STREQUAL "11" AND NOT VERSION_MAJOR STREQUAL "17") OR + # 1600 = VS 10.0 (v100 toolset) + (CONAN_COMPILER_VERSION STREQUAL "10" AND NOT VERSION_MAJOR STREQUAL "16") OR + # 1500 = VS 9.0 (v90 toolset) + (CONAN_COMPILER_VERSION STREQUAL "9" AND NOT VERSION_MAJOR STREQUAL "15") OR + # 1400 = VS 8.0 (v80 toolset) + (CONAN_COMPILER_VERSION STREQUAL "8" AND NOT VERSION_MAJOR STREQUAL "14") OR + # 1310 = VS 7.1, 1300 = VS 7.0 + (CONAN_COMPILER_VERSION STREQUAL "7" AND NOT VERSION_MAJOR STREQUAL "13") OR + # 1200 = VS 6.0 + (CONAN_COMPILER_VERSION STREQUAL "6" AND NOT VERSION_MAJOR STREQUAL "12") ) + conan_error_compiler_version() + endif() + elseif(CONAN_COMPILER STREQUAL "gcc") + conan_split_version(${CONAN_COMPILER_VERSION} CONAN_COMPILER_MAJOR CONAN_COMPILER_MINOR) + set(_CHECK_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}) + set(_CONAN_VERSION ${CONAN_COMPILER_MAJOR}.${CONAN_COMPILER_MINOR}) + if(NOT ${CONAN_COMPILER_VERSION} VERSION_LESS 5.0) + conan_message(STATUS "Conan: Compiler GCC>=5, checking major version ${CONAN_COMPILER_VERSION}") + conan_split_version(${CONAN_COMPILER_VERSION} CONAN_COMPILER_MAJOR CONAN_COMPILER_MINOR) + if("${CONAN_COMPILER_MINOR}" STREQUAL "") + set(_CHECK_VERSION ${VERSION_MAJOR}) + set(_CONAN_VERSION ${CONAN_COMPILER_MAJOR}) + endif() + endif() + conan_message(STATUS "Conan: Checking correct version: ${_CHECK_VERSION}") + if(NOT ${_CHECK_VERSION} VERSION_EQUAL ${_CONAN_VERSION}) + conan_error_compiler_version() + endif() + elseif(CONAN_COMPILER STREQUAL "clang") + conan_split_version(${CONAN_COMPILER_VERSION} CONAN_COMPILER_MAJOR CONAN_COMPILER_MINOR) + set(_CHECK_VERSION ${VERSION_MAJOR}.${VERSION_MINOR}) + set(_CONAN_VERSION ${CONAN_COMPILER_MAJOR}.${CONAN_COMPILER_MINOR}) + if(NOT ${CONAN_COMPILER_VERSION} VERSION_LESS 8.0) + conan_message(STATUS "Conan: Compiler Clang>=8, checking major version ${CONAN_COMPILER_VERSION}") + if("${CONAN_COMPILER_MINOR}" STREQUAL "") + set(_CHECK_VERSION ${VERSION_MAJOR}) + set(_CONAN_VERSION ${CONAN_COMPILER_MAJOR}) + endif() + endif() + conan_message(STATUS "Conan: Checking correct version: ${_CHECK_VERSION}") + if(NOT ${_CHECK_VERSION} VERSION_EQUAL ${_CONAN_VERSION}) + conan_error_compiler_version() + endif() + elseif(CONAN_COMPILER STREQUAL "apple-clang" OR CONAN_COMPILER STREQUAL "sun-cc" OR CONAN_COMPILER STREQUAL "mcst-lcc") + conan_split_version(${CONAN_COMPILER_VERSION} CONAN_COMPILER_MAJOR CONAN_COMPILER_MINOR) + if(NOT ${VERSION_MAJOR}.${VERSION_MINOR} VERSION_EQUAL ${CONAN_COMPILER_MAJOR}.${CONAN_COMPILER_MINOR}) + conan_error_compiler_version() + endif() + elseif(CONAN_COMPILER STREQUAL "intel") + conan_split_version(${CONAN_COMPILER_VERSION} CONAN_COMPILER_MAJOR CONAN_COMPILER_MINOR) + if(NOT ${CONAN_COMPILER_VERSION} VERSION_LESS 19.1) + if(NOT ${VERSION_MAJOR}.${VERSION_MINOR} VERSION_EQUAL ${CONAN_COMPILER_MAJOR}.${CONAN_COMPILER_MINOR}) + conan_error_compiler_version() + endif() + else() + if(NOT ${VERSION_MAJOR} VERSION_EQUAL ${CONAN_COMPILER_MAJOR}) + conan_error_compiler_version() + endif() + endif() + else() + conan_message(STATUS "WARN: Unknown compiler '${CONAN_COMPILER}', skipping the version check...") + endif() +endfunction() + + +function(conan_check_compiler) + if(CONAN_DISABLE_CHECK_COMPILER) + conan_message(STATUS "WARN: Disabled conan compiler checks") + return() + endif() + if(NOT DEFINED CMAKE_CXX_COMPILER_ID) + if(DEFINED CMAKE_C_COMPILER_ID) + conan_message(STATUS "This project seems to be plain C, using '${CMAKE_C_COMPILER_ID}' compiler") + set(CMAKE_CXX_COMPILER_ID ${CMAKE_C_COMPILER_ID}) + set(CMAKE_CXX_COMPILER_VERSION ${CMAKE_C_COMPILER_VERSION}) + else() + message(FATAL_ERROR "This project seems to be plain C, but no compiler defined") + endif() + endif() + if(NOT CMAKE_CXX_COMPILER_ID AND NOT CMAKE_C_COMPILER_ID) + # This use case happens when compiler is not identified by CMake, but the compilers are there and work + conan_message(STATUS "*** WARN: CMake was not able to identify a C or C++ compiler ***") + conan_message(STATUS "*** WARN: Disabling compiler checks. Please make sure your settings match your environment ***") + return() + endif() + if(NOT DEFINED CONAN_COMPILER) + conan_get_compiler(CONAN_COMPILER CONAN_COMPILER_VERSION) + if(NOT DEFINED CONAN_COMPILER) + conan_message(STATUS "WARN: CONAN_COMPILER variable not set, please make sure yourself that " + "your compiler and version matches your declared settings") + return() + endif() + endif() + + if(NOT CMAKE_HOST_SYSTEM_NAME STREQUAL ${CMAKE_SYSTEM_NAME}) + set(CROSS_BUILDING 1) + endif() + + # If using VS, verify toolset + if (CONAN_COMPILER STREQUAL "Visual Studio") + if (CONAN_SETTINGS_COMPILER_TOOLSET MATCHES "LLVM" OR + CONAN_SETTINGS_COMPILER_TOOLSET MATCHES "llvm" OR + CONAN_SETTINGS_COMPILER_TOOLSET MATCHES "clang" OR + CONAN_SETTINGS_COMPILER_TOOLSET MATCHES "Clang") + set(EXPECTED_CMAKE_CXX_COMPILER_ID "Clang") + elseif (CONAN_SETTINGS_COMPILER_TOOLSET MATCHES "Intel") + set(EXPECTED_CMAKE_CXX_COMPILER_ID "Intel") + else() + set(EXPECTED_CMAKE_CXX_COMPILER_ID "MSVC") + endif() + + if (NOT CMAKE_CXX_COMPILER_ID MATCHES ${EXPECTED_CMAKE_CXX_COMPILER_ID}) + message(FATAL_ERROR "Incorrect '${CONAN_COMPILER}'. Toolset specifies compiler as '${EXPECTED_CMAKE_CXX_COMPILER_ID}' " + "but CMake detected '${CMAKE_CXX_COMPILER_ID}'") + endif() + + # Avoid checks when cross compiling, apple-clang crashes because its APPLE but not apple-clang + # Actually CMake is detecting "clang" when you are using apple-clang, only if CMP0025 is set to NEW will detect apple-clang + elseif((CONAN_COMPILER STREQUAL "gcc" AND NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR + (CONAN_COMPILER STREQUAL "apple-clang" AND NOT CROSS_BUILDING AND (NOT APPLE OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang")) OR + (CONAN_COMPILER STREQUAL "clang" AND NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") OR + (CONAN_COMPILER STREQUAL "sun-cc" AND NOT CMAKE_CXX_COMPILER_ID MATCHES "SunPro") ) + message(FATAL_ERROR "Incorrect '${CONAN_COMPILER}', is not the one detected by CMake: '${CMAKE_CXX_COMPILER_ID}'") + endif() + + + if(NOT DEFINED CONAN_COMPILER_VERSION) + conan_message(STATUS "WARN: CONAN_COMPILER_VERSION variable not set, please make sure yourself " + "that your compiler version matches your declared settings") + return() + endif() + check_compiler_version() +endfunction() + + +macro(conan_set_flags build_type) + set(CMAKE_CXX_FLAGS${build_type} "${CMAKE_CXX_FLAGS${build_type}} ${CONAN_CXX_FLAGS${build_type}}") + set(CMAKE_C_FLAGS${build_type} "${CMAKE_C_FLAGS${build_type}} ${CONAN_C_FLAGS${build_type}}") + set(CMAKE_SHARED_LINKER_FLAGS${build_type} "${CMAKE_SHARED_LINKER_FLAGS${build_type}} ${CONAN_SHARED_LINKER_FLAGS${build_type}}") + set(CMAKE_EXE_LINKER_FLAGS${build_type} "${CMAKE_EXE_LINKER_FLAGS${build_type}} ${CONAN_EXE_LINKER_FLAGS${build_type}}") +endmacro() + + +macro(conan_global_flags) + if(CONAN_SYSTEM_INCLUDES) + include_directories(SYSTEM ${CONAN_INCLUDE_DIRS} + "$<$:${CONAN_INCLUDE_DIRS_RELEASE}>" + "$<$:${CONAN_INCLUDE_DIRS_RELWITHDEBINFO}>" + "$<$:${CONAN_INCLUDE_DIRS_MINSIZEREL}>" + "$<$:${CONAN_INCLUDE_DIRS_DEBUG}>") + else() + include_directories(${CONAN_INCLUDE_DIRS} + "$<$:${CONAN_INCLUDE_DIRS_RELEASE}>" + "$<$:${CONAN_INCLUDE_DIRS_RELWITHDEBINFO}>" + "$<$:${CONAN_INCLUDE_DIRS_MINSIZEREL}>" + "$<$:${CONAN_INCLUDE_DIRS_DEBUG}>") + endif() + + link_directories(${CONAN_LIB_DIRS}) + + conan_find_libraries_abs_path("${CONAN_LIBS_DEBUG}" "${CONAN_LIB_DIRS_DEBUG}" + CONAN_LIBS_DEBUG) + conan_find_libraries_abs_path("${CONAN_LIBS_RELEASE}" "${CONAN_LIB_DIRS_RELEASE}" + CONAN_LIBS_RELEASE) + conan_find_libraries_abs_path("${CONAN_LIBS_RELWITHDEBINFO}" "${CONAN_LIB_DIRS_RELWITHDEBINFO}" + CONAN_LIBS_RELWITHDEBINFO) + conan_find_libraries_abs_path("${CONAN_LIBS_MINSIZEREL}" "${CONAN_LIB_DIRS_MINSIZEREL}" + CONAN_LIBS_MINSIZEREL) + + add_compile_options(${CONAN_DEFINES} + "$<$:${CONAN_DEFINES_DEBUG}>" + "$<$:${CONAN_DEFINES_RELEASE}>" + "$<$:${CONAN_DEFINES_RELWITHDEBINFO}>" + "$<$:${CONAN_DEFINES_MINSIZEREL}>") + + conan_set_flags("") + conan_set_flags("_RELEASE") + conan_set_flags("_DEBUG") + +endmacro() + + +macro(conan_target_link_libraries target) + if(CONAN_TARGETS) + target_link_libraries(${target} ${CONAN_TARGETS}) + else() + target_link_libraries(${target} ${CONAN_LIBS}) + foreach(_LIB ${CONAN_LIBS_RELEASE}) + target_link_libraries(${target} optimized ${_LIB}) + endforeach() + foreach(_LIB ${CONAN_LIBS_DEBUG}) + target_link_libraries(${target} debug ${_LIB}) + endforeach() + endif() +endmacro() + + +macro(conan_include_build_modules) + if(CMAKE_BUILD_TYPE) + if(${CMAKE_BUILD_TYPE} MATCHES "Debug") + set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_DEBUG} ${CONAN_BUILD_MODULES_PATHS}) + elseif(${CMAKE_BUILD_TYPE} MATCHES "Release") + set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_RELEASE} ${CONAN_BUILD_MODULES_PATHS}) + elseif(${CMAKE_BUILD_TYPE} MATCHES "RelWithDebInfo") + set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_RELWITHDEBINFO} ${CONAN_BUILD_MODULES_PATHS}) + elseif(${CMAKE_BUILD_TYPE} MATCHES "MinSizeRel") + set(CONAN_BUILD_MODULES_PATHS ${CONAN_BUILD_MODULES_PATHS_MINSIZEREL} ${CONAN_BUILD_MODULES_PATHS}) + endif() + endif() + + foreach(_BUILD_MODULE_PATH ${CONAN_BUILD_MODULES_PATHS}) + include(${_BUILD_MODULE_PATH}) + endforeach() +endmacro() + + +### Definition of user declared vars (user_info) ### + diff --git a/angelscript/projects/cmake/conanbuildinfo.txt b/angelscript/projects/cmake/conanbuildinfo.txt new file mode 100644 index 0000000..4613226 --- /dev/null +++ b/angelscript/projects/cmake/conanbuildinfo.txt @@ -0,0 +1,49 @@ +[includedirs] + + +[libdirs] + + +[bindirs] + + +[resdirs] + + +[builddirs] + + +[libs] + + +[system_libs] + + +[defines] + + +[cppflags] + + +[cxxflags] + + +[cflags] + + +[sharedlinkflags] + + +[exelinkflags] + + +[sysroot] + + +[frameworks] + + +[frameworkdirs] + + + diff --git a/angelscript/projects/cmake/conanfile.py b/angelscript/projects/cmake/conanfile.py new file mode 100644 index 0000000..2e7df5a --- /dev/null +++ b/angelscript/projects/cmake/conanfile.py @@ -0,0 +1,42 @@ + +from conans import ConanFile, CMake, tools +import os + +class AngelScriptConan(ConanFile): + name = "AngelScript" + version = "2.35" + license = "" + url = "" + description = "" + settings = "os", "compiler", "build_type", "arch" + options = {"shared": [True, False], "link_std_statically": [True, False]} + default_options = {"shared": False, "link_std_statically": True} + generators = "cmake" + exports_sources = "../../*" + + + def build(self): + cmake = CMake(self) + if (self.options.shared): + self.output.info("Building shared lib.") + cmake.definitions["BUILD_SHARED_LIBS"] = 1 + else: + self.output.info("Building static lib.") + if (self.options.link_std_statically): + cmake.definitions["LINK_STD_STATICALLY"] = 1 + + cmake.configure(build_dir="./build", source_dir="../projects/cmake") + cmake.build() + + def package(self): + os.chdir(os.path.dirname(__file__)) + print(os.getcwd()) + self.copy("include/angelscript.h", dst="include", keep_path=False) + self.copy("*.dll", dst="bin", keep_path=False) + self.copy("*.so", dst="lib", keep_path=False) + self.copy("*.so.*", dst="lib", keep_path=False) + self.copy("*.dylib", dst="lib", keep_path=False) + self.copy("*.a", dst="lib", keep_path=False) + + def package_info(self): + self.cpp_info.libs = ["angelscript"] \ No newline at end of file diff --git a/angelscript/projects/cmake/conaninfo.txt b/angelscript/projects/cmake/conaninfo.txt new file mode 100644 index 0000000..de1b8d9 --- /dev/null +++ b/angelscript/projects/cmake/conaninfo.txt @@ -0,0 +1,35 @@ +[settings] + arch=x86_64 + build_type=Release + compiler=clang + compiler.libcxx=libstdc++11 + compiler.version=11 + os=Linux + +[requires] + + +[options] + link_std_statically=True + shared=True + +[full_settings] + arch=x86_64 + build_type=Release + compiler=clang + compiler.libcxx=libstdc++11 + compiler.version=11 + os=Linux + +[full_requires] + + +[full_options] + link_std_statically=True + shared=True + +[recipe_hash] + + +[env] + diff --git a/angelscript/projects/cmake/graph_info.json b/angelscript/projects/cmake/graph_info.json new file mode 100644 index 0000000..8db6fee --- /dev/null +++ b/angelscript/projects/cmake/graph_info.json @@ -0,0 +1,18 @@ +{ + "options": [ + [ + "link_std_statically", + "True" + ], + [ + "shared", + "True" + ] + ], + "root": { + "name": "AngelScript", + "version": "2.35", + "user": null, + "channel": null + } +} \ No newline at end of file diff --git a/angelscript/projects/codeblocks/angelscript.cbp b/angelscript/projects/codeblocks/angelscript.cbp new file mode 100644 index 0000000..050b405 --- /dev/null +++ b/angelscript/projects/codeblocks/angelscript.cbp @@ -0,0 +1,159 @@ + + + + + + diff --git a/angelscript/projects/gnuc macosx/makefile b/angelscript/projects/gnuc macosx/makefile new file mode 100644 index 0000000..4d3b7c4 --- /dev/null +++ b/angelscript/projects/gnuc macosx/makefile @@ -0,0 +1,131 @@ +# Angelscript makefile for linux (based on MingW makefile) +# Type 'make' then 'make install' to complete the installation of the library + +# For 'make install' to work, set LOCAL according to your system configuration +LOCAL = /usr/local + +# If you want to build a shared library, then run make with SHARED=1 and VERSION=version +LIB = libangelscript.a +DEVLIB = libangelscript.dylib +BUNDLE = libangelscript.so +INC = angelscript.h + +SRCDIR = ../../source +INCDIR = ../../include +OBJDIR = obj +LIBDIR = ../../lib +CXX = c++ +AFLAGS= -arch i386 -arch x86_64 +CXXFLAGS = -g -Wall -fPIC $(AFLAGS) +CXXBFLAGS = $(CXXFLAGS) -fno-common + +DELETER = rm -f +COPIER = cp -a + +SRCNAMES = \ + as_atomic.cpp \ + as_builder.cpp \ + as_bytecode.cpp \ + as_callfunc.cpp \ + as_callfunc_arm.cpp \ + as_callfunc_mips.cpp \ + as_callfunc_ppc.cpp \ + as_callfunc_ppc_64.cpp \ + as_callfunc_sh4.cpp \ + as_callfunc_x86.cpp \ + as_callfunc_x64_gcc.cpp \ + as_compiler.cpp \ + as_context.cpp \ + as_configgroup.cpp \ + as_datatype.cpp \ + as_generic.cpp \ + as_gc.cpp \ + as_globalproperty.cpp \ + as_memory.cpp \ + as_module.cpp \ + as_objecttype.cpp \ + as_outputbuffer.cpp \ + as_parser.cpp \ + as_restore.cpp \ + as_scriptcode.cpp \ + as_scriptengine.cpp \ + as_scriptfunction.cpp \ + as_scriptnode.cpp \ + as_scriptobject.cpp \ + as_string.cpp \ + as_string_util.cpp \ + as_thread.cpp \ + as_tokenizer.cpp \ + as_typeinfo.cpp \ + as_variablescope.cpp \ + +OBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRCNAMES:.cpp=.o))) +BOBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRCNAMES:.cpp=.lo))) +TARG = $(LIBDIR)/$(LIB) $(LIBDIR)/$(DEVLIB) $(LIBDIR)/$(BUNDLE) + + +all: $(TARG) +$(LIBDIR)/$(LIB): $(OBJDIR) $(LIBDIR) $(OBJ) + rm -f $(LIBDIR)/$(LIB) + ar r $(LIBDIR)/$(LIB) $(OBJ) + ranlib $(LIBDIR)/$(LIB) + file $(LIBDIR)/$(LIB) + +$(LIBDIR)/$(DEVLIB): $(OBJDIR) $(LIBDIR) $(OBJ) + rm -f $(LIBDIR)/$(DEVLIB) + $(CXX) $(AFLAGS) -dynamiclib -o $(DEVLIB) $(OBJ) + mv $(DEVLIB) $(LIBDIR)/$(DEVLIB) + file $(LIBDIR)/$(DEVLIB) + +$(LIBDIR)/$(BUNDLE): $(OBJDIR) $(LIBDIR) $(BOBJ) + rm -f $(LIBDIR)/$(BUNDLE) + $(CXX) $(AFLAGS) -bundle -flat_namespace -undefined suppress -o $(LIBDIR)/$(BUNDLE) $(BOBJ) + file $(LIBDIR)/$(BUNDLE) + + @echo ------------------------------------------------------------------- + @echo Done. As root, type 'make install' to install the library. + +$(OBJDIR): + mkdir $(OBJDIR) + +$(LIBDIR): + mkdir $(LIBDIR) + +$(OBJDIR)/%.o: $(SRCDIR)/%.cpp + $(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.S + $(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.s + $(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/%.lo: $(SRCDIR)/%.cpp + $(CXX) $(CXXBFLAGS) -o $@ -c $< + +$(OBJDIR)/%.lo: $(SRCDIR)/%.S + $(CXX) $(CXXBFLAGS) -o $@ -c $< + +$(OBJDIR)/%.lo: $(SRCDIR)/%.s + $(CXX) $(CXXBFLAGS) -o $@ -c $< + +clean: + $(DELETER) $(OBJ) $(BOBJ) $(TARG) + +install: $(TARG) + @echo Installing to: $(LOCAL)/lib and $(LOCAL)/include... + @echo ------------------------------------------------------------------- +ifdef SHARED + $(COPIER) $(LIBDIR)/$(DEVLIB) $(LOCAL)/lib +endif + $(COPIER) $(TARG) $(LOCAL)/lib + $(COPIER) $(INCDIR)/$(INC) $(LOCAL)/include + @echo ------------------------------------------------------------------- + @echo Angelscript library installed. Enjoy! + +uninstall: + $(DELETER) $(LOCAL)/include/$(INC) $(LOCAL)/lib/$(LIB) $(LOCAL)/lib/$(DEVLIB) + @echo ------------------------------------------------------------------- + @echo Angelscript library uninstalled. + +.PHONY: all clean install uninstall diff --git a/angelscript/projects/gnuc/FAQ b/angelscript/projects/gnuc/FAQ new file mode 100644 index 0000000..a1e5cab --- /dev/null +++ b/angelscript/projects/gnuc/FAQ @@ -0,0 +1,73 @@ +** (UN)FREQUENTLY ASKED QUESTIONS ** + +1. Why do you have to specify PREFIX= even when building +when overriding the default ? + +2. When overriding the default prefix, how do you compile +and link my program ? + +-- +1. Why do you have to specify PREFIX= even when building, + when overriding the default ? + +Because it allows easier linking. The way the Linux +link loader works, if the library name has a slash in it, +then it resolves it that way. If it doesn't it goes through +a series of steps which tries to find it. However, without +updating a certain file it won't find it under '/usr/local' +(and similar with '/tmp'). Therefore, as long as you have +the same PREFIX= (or don't specify it at all), all you need +to do to link to the shared version is link to it (and any +other dependencies; -lpthread comes to mind here). For +example the link options might be : +-langelscript_s -lpthread + +-- +2. When overriding the default prefix, how do you compile +and link my program ? + +An example scenario is the following : +You installed into /opt which means the following +files should exist : + +/opt/include/angelscript.h +/opt/lib/libangelscript.so (which is a symbolic link to + the current version installed) +/opt/lib/libangelscript.a (the static library). + +If you #include angelscript.h you might normally +have : + +#include + +However, when that file is not in the standard directories +the compiler searches, you have to either use : + +#include "/opt/include/angelscript.h" +(method one) +or alternatively keep the include (using the angle brackets) +but pass the include path (or paths actually but in this case +path) to the compiler so it knows to search an additional +location. If you're using g++ then the following option +will work (it also works for gcc but I am assuming you +are using C++) : + +-I/opt/include + +You must however still link. You therefore must pass another +option to the compiler (which will pass it to the linker) +and the option os -L which is used like so (to follow the +scenario) : + +-L/opt/lib + +The rest is the same. + +CONTACT INFO: +If you have any questions or concerns, by all +means have Andreas contact me (at this time I +don't have an email I feel okay sharing - if it +seems this is of use to others I will likely +create an email on my server for this very +purpose). For now Andreas can forward the +message to me. diff --git a/angelscript/projects/gnuc/Makefile b/angelscript/projects/gnuc/Makefile new file mode 100644 index 0000000..9bdb9d9 --- /dev/null +++ b/angelscript/projects/gnuc/Makefile @@ -0,0 +1,247 @@ +# AngelScript makefile for Linux. +# Type 'make' then 'make install' to complete +# the installation of the library. You no +# longer have to specify SHARED=1 VERSION=x.y.z +# (the Makefile automatically determines it +# and builds it and the static library). +# See README for how to use the shared library +# instead of the static. The README also +# contains other information and in particular +# specifies on how to override the install +# location should you desire this (you don't +# have to - nor should you - edit this +# file). +# +# One note: I don't have a way to test +# the phone builds. I am an old-timer +# and I _still_ miss customer-owned +# coin-operated telephones. In fact +# I still _miss_ the rotary telephone! + + +## library names and versions +LIBNAME=libangelscript +AS_VER:=$(shell awk -F\" '/\#define ANGELSCRIPT_VERSION_STRING/{print $$2}' ../../include/angelscript.h | cut -d" " -f1) +SHLIB=$(LIBNAME).so.$(AS_VER) +ARLIB=$(LIBNAME).a + + +## install directories +ifeq ($(PREFIX),) +PREFIX=/usr/local +endif +INCLUDEDIR_DEST=$(PREFIX)/include +LIBDIR_DEST=$(PREFIX)/lib +DOCDIR_BASEDIR=$(PREFIX)/share/doc/angelscript-$(AS_VER) +DOXYGEN_DEST=$(DOCDIR_BASEDIR)/html +SAMPLES_DEST=$(DOCDIR_BASEDIR)/samples + + +## install commands +INSTALL = install +INSTALL_DIR = $(INSTALL) -d +INSTALL_SHLIB = $(INSTALL) -m 755 +INSTALL_ARLIB = $(INSTALL) -m 644 +INSTALL_HEADER = $(INSTALL) -m 644 +CP_SYMLINK = cp --no-dereference --preserve=links +CP_R = cp -R + + +HEADER = angelscript.h +SRCDIR = ../../source +INCDIR = ../../include + + +## platform specific settings +ifeq ($(TARGETPLATFORM), iphone) + IPHONEBIN = /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin + OBJDIR = obj-iphone + LIBDIR = ../../lib-iphone + CXX ?= $(IPHONEBIN)/clang++ + CXXFLAGS += -Wall -fPIC -fno-strict-aliasing -arch armv7 -isysroot /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS5.0.sdk -miphoneos-version-min=3.0 +else ifeq ($(TARGETPLATFORM), iphonesimulator) + IPHONEBIN = /Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin + OBJDIR = obj-iphone + LIBDIR = ../../lib-iphone + CXX ?= $(IPHONEBIN)/clang++ + CXXFLAGS += -Wall -fPIC -fno-strict-aliasing -arch i386 -isysroot /Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator5.0.sdk -miphoneos-version-min=3.0 +else ifeq ($(TARGETPLATFORM), android) + ANDROIDNDKROOT = /cygdrive/c/android/android-ndk-1.6_r1 + ANDROIDBIN = $(ANDROIDNDKROOT)/build/prebuilt/windows/arm-eabi-4.2.1/bin + SYSROOT = $(ANDROIDNDKROOT)/build/platforms/android-4/arch-arm + OBJDIR = obj-android + LIBDIR = ../../lib-android + CXX ?= $(ANDROIDBIN)/arm-eabi-gcc + CXXFLAGS += -I$(SYSROOT)/usr/include \ + -Wall \ + -DANDROID \ + -fno-exceptions \ + -march=armv6 -mthumb-interwork \ + -mfloat-abi=softfp -fno-rtti +else + OBJDIR = obj + LIBDIR = ../../lib + CXX ?= g++ + # On i686 architecture you may need to add -march=i686 if you get + # an undefined symbol for __sync_sub_and_fetch_4 in as_atomic.cpp. + CXXFLAGS += -Wall -fPIC -fno-strict-aliasing +endif + +## Detect if targetting ARM CPU and if so tell assembler to accept implicit IT constructs in thumb mode +GCC_ARCH := $(shell $(CXX) -dumpmachine) +$(info GCC ARCH: $(GCC_ARCH)) +ifneq (,$(findstring arm-,$(GCC_ARCH))) + CXXFLAGS += -Wa,-mimplicit-it=thumb +else ifneq (,$(findstring armv7-, $(GCC_ARCH))) + CXXFLAGS += -Wa,-mimplicit-it=thumb +endif + +## toolchain +AR ?= ar +RANLIB ?= ranlib + + +SRCNAMES = \ + as_atomic.cpp \ + as_builder.cpp \ + as_bytecode.cpp \ + as_callfunc.cpp \ + as_callfunc_arm.cpp \ + as_callfunc_mips.cpp \ + as_callfunc_ppc.cpp \ + as_callfunc_ppc_64.cpp \ + as_callfunc_sh4.cpp \ + as_callfunc_x86.cpp \ + as_callfunc_x64_gcc.cpp \ + as_callfunc_x64_mingw.cpp \ + as_compiler.cpp \ + as_context.cpp \ + as_configgroup.cpp \ + as_datatype.cpp \ + as_generic.cpp \ + as_gc.cpp \ + as_globalproperty.cpp \ + as_memory.cpp \ + as_module.cpp \ + as_objecttype.cpp \ + as_outputbuffer.cpp \ + as_parser.cpp \ + as_restore.cpp \ + as_scriptcode.cpp \ + as_scriptengine.cpp \ + as_scriptfunction.cpp \ + as_scriptnode.cpp \ + as_scriptobject.cpp \ + as_string.cpp \ + as_string_util.cpp \ + as_thread.cpp \ + as_tokenizer.cpp \ + as_typeinfo.cpp \ + as_variablescope.cpp \ + +OBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRCNAMES:.cpp=.o))) + +ifeq ($(TARGETPLATFORM), iphone) + OBJ += $(OBJDIR)/as_callfunc_arm_xcode.o +else + OBJ += $(OBJDIR)/as_callfunc_arm_gcc.o +endif + + +default: all + +all: shared static + +shared: $(LIBDIR)/$(SHLIB) $(LIBDIR)/$(LIBNAME).so + +static: $(LIBDIR) $(OBJDIR) $(LIBDIR)/$(ARLIB) + +$(OBJDIR): + mkdir -p "$(OBJDIR)" + +$(LIBDIR): + mkdir -p "$(LIBDIR)" + +$(OBJDIR)/%.o: $(SRCDIR)/%.cpp + $(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.S + $(CXX) $(CXXFLAGS) -o $@ -c $< + +$(OBJDIR)/%.o: $(SRCDIR)/%.s + $(CXX) $(CXXFLAGS) -o $@ -c $< + +$(LIBDIR)/$(SHLIB): $(OBJ) + $(CXX) $(CXXFLAGS) $(LDFLAGS) -shared -Wl,-soname,$(SHLIB) -o "$(LIBDIR)"/$(SHLIB) $(OBJ) + +$(LIBDIR)/$(LIBNAME).so: $(LIBDIR)/$(SHLIB) + @( cd "$(LIBDIR)" && ln -s $(SHLIB) $(LIBNAME).so ) + +$(LIBDIR)/$(ARLIB): $(OBJ) + $(AR) r "$(LIBDIR)"/$(ARLIB) $(OBJ) + $(RANLIB) "$(LIBDIR)"/$(ARLIB) + + +## install rules +install_header: $(INCDIR)/$(HEADER) + $(INSTALL_DIR) "$(DESTDIR)/$(INCLUDEDIR_DEST)" + $(INSTALL_HEADER) "$(INCDIR)"/$(HEADER) "$(DESTDIR)/$(INCLUDEDIR_DEST)/"$(HEADER) + +install_shared: + $(INSTALL_DIR) "$(DESTDIR)/$(LIBDIR_DEST)" + $(INSTALL_SHLIB) "$(LIBDIR)"/$(SHLIB) "$(DESTDIR)/$(LIBDIR_DEST)/"$(SHLIB) + $(CP_SYMLINK) "$(LIBDIR)"/$(LIBNAME).so "$(DESTDIR)/$(LIBDIR_DEST)/"$(LIBNAME).so + +install_static: $(LIBDIR)/$(ARLIB) $(LIBDIR)/$(SHLIB) + $(INSTALL_DIR) "$(DESTDIR)/$(LIBDIR_DEST)" + $(INSTALL_ARLIB) "$(LIBDIR)"/$(ARLIB) "$(DESTDIR)/$(LIBDIR_DEST)/"$(ARLIB) + +install_docs: ./../../../docs + $(INSTALL_DIR) "$(DESTDIR)/$(DOCDIR_BASEDIR)" + $(CP_R) ./../../../docs "$(DESTDIR)/$(DOXYGEN_DEST)" + +install_samples: ./../../../samples + $(INSTALL_DIR) "$(DESTDIR)/$(DOCDIR_BASEDIR)" + $(CP_R) ./../../../samples "$(DESTDIR)/$(SAMPLES_DEST)" + +install_all: install_docs install_samples install + +install: install_header install_shared install_static + +uninstall: + rm -f "$(DESTDIR)/$(INCLUDEDIR_DEST)/$(HEADER)" "$(DESTDIR)/$(LIBDIR_DEST)"/$(LIBNAME)* + +help: + @echo ------------------------------------------------------------------- + @echo 'BUILDING:' + @echo ' make all: build shared and static libs' + @echo ' make shared: build shared lib only' + @echo ' make static: build static lib only' + @echo + @echo 'INSTALLING:' + @echo ' make install: install headers, shared and static libs' + @echo ' make install_header: install only the headers' + @echo ' make install_shared: install only the shared libs' + @echo ' make install_static: install only the static libs' + @echo ' make install_docs: install only the documentation' + @echo ' make install_samples: install only the samples' + @echo ' make install_all: install everything, including docs and samples' + @echo + @echo 'PARAMETERS (pass to make, as in PARAM=value):' + @echo ' PREFIX: installation prefix (default /usr/local)' + @echo ' INCLUDEDIR_DEST: where to install headers (default PREFIX/include)' + @echo ' LIBDIR_DEST: where to install libraries (default PREFIX/lib)' + @echo ' DOCDIR_BASEDIR: where the basedir of the documentation lies' + @echo ' (default PREFIX/share/doc/angelscript-AS_VER)' + @echo ' DOXYGEN_DEST: where to install doxygen documentation' + @echo ' (default DOCDIR_BASEDIR/html)' + @echo ' SAMPLES_DEST: where to install samples' + @echo ' (default DOCDIR_BASEDIR/samples)' + @echo ' DESTDIR: destination, prepended to PREFIX, usually used by' + @echo ' package managers (default empty)' + @echo ------------------------------------------------------------------- + +clean: + rm -f $(OBJ) "$(LIBDIR)"/$(ARLIB) "$(LIBDIR)"/$(SHLIB) "$(LIBDIR)"/$(LIBNAME).so + +.PHONY: all clean install install_all install_docs install_header install_samples install_shared install_static shared static uninstall diff --git a/angelscript/projects/gnuc/README b/angelscript/projects/gnuc/README new file mode 100644 index 0000000..837bc11 --- /dev/null +++ b/angelscript/projects/gnuc/README @@ -0,0 +1,63 @@ +If you want to override /usr/local as the default prefix +(which means /usr/local/include would have the header file and +/usr/local/lib would have the library files), then run +make, make install and make uninstall (to build, to +install and uninstall respectively - you need it for +all three as I explain below) : + +make PREFIX=/tmp +make PREFIX=/tmp install +make PREFIX=/tmp uninstall + +The last two will of course have to be done +as root if you need permissions to write to +the directory (for /tmp you wouldn't unless +the files already existed by someone else and +you didn't have permission). + +In any case, the above would install header file +under '/tmp/include' and the library file(s) under +'/tmp/lib'. + +If you want to know the technical details as to why +you have to (when overriding the install location) +specify PREFIX= even when building, see the FAQ +file (summary: it makes it easier for you when linking +in the shared library). + +A word of caution to those overriding prefix : +-- +You are more than welcome to disregard this but I feel +it is something I should bring up. If you do override +the prefix I strongly recommend you do not specify +'/usr'. Why one might ask. The typical way is +that user-compiled programs/libraries/etc. go under +'/usr/local' (other times '/opt'). This has multiple +benefits: you keep '/usr' clean and if you have a +package manager then it makes it easy to say: +"The only files under /usr/include and /usr/lib are +those that belong to a package." +In other words it is easier to maintain integrity +and verify everything. Most important of it all +(aside the security implications) is this: +You have less chance of name clashes. If there ever +is a package that installs to /usr and it includes +the files (maybe a package for AngelScript) then you +will have issues. +-- + +Lastly: I don't have a way to test the phone builds +so I cannot verify the build process (it really +depends on the environment and architecture, like +most things); I'm an old-timer that hates the +"smart" trend (besides: it is a horrible misuse +of the world 'smart'). + +CONTACT: +If you have any questions or concerns, by all +means have Andreas contact me (at this time I +don't have an email I feel okay sharing - if it +seems this is of use to others I will likely +create an email on my server for this very +purpose). For now Andreas can forward the +message to me. diff --git a/angelscript/projects/gnuc/obj/delete.me b/angelscript/projects/gnuc/obj/delete.me new file mode 100644 index 0000000..2d6ab1a --- /dev/null +++ b/angelscript/projects/gnuc/obj/delete.me @@ -0,0 +1,2 @@ +This file is here just in case your unarchiver does not extract empty directories. +Feel free to remove it. \ No newline at end of file diff --git a/angelscript/projects/marmalade/angelscript_lib.mkb b/angelscript/projects/marmalade/angelscript_lib.mkb new file mode 100644 index 0000000..dddbc68 --- /dev/null +++ b/angelscript/projects/marmalade/angelscript_lib.mkb @@ -0,0 +1,111 @@ +#!/usr/bin/env mkb + +options +{ + enable-exceptions=1 + lib + module_path="../../source" +} + +subproject angelscript_lib + +defines +{ +} + +if {{ defined I3D_ARCH_ARM }} +{ + files + { + (../../source) + as_callfunc_arm_gcc.S + } + option buildenv=scons +} +else +{ + files + { + (../../source) + #as_callfunc_x64_msvc_asm.asm + as_callfunc_arm_msvc.asm + } +} + +files +{ + (../../source) + as_array.h + as_atomic.cpp + as_atomic.h + as_builder.cpp + as_builder.h + as_bytecode.cpp + as_bytecode.h + as_callfunc.cpp + as_callfunc.h + as_callfunc_arm.cpp + as_callfunc_mips.cpp + as_callfunc_ppc.cpp + as_callfunc_ppc_64.cpp + as_callfunc_sh4.cpp + as_callfunc_x64_gcc.cpp + as_callfunc_x64_mingw.cpp + as_callfunc_x64_msvc.cpp + as_callfunc_x86.cpp + as_callfunc_xenon.cpp + as_compiler.cpp + as_compiler.h + as_config.h + as_configgroup.cpp + as_configgroup.h + as_context.cpp + as_context.h + as_criticalsection.h + as_datatype.cpp + as_datatype.h + as_debug.h + as_gc.cpp + as_gc.h + as_generic.cpp + as_generic.h + as_globalproperty.cpp + as_map.h + as_memory.cpp + as_memory.h + as_module.cpp + as_module.h + as_objecttype.cpp + as_objecttype.h + as_outputbuffer.cpp + as_outputbuffer.h + as_parser.cpp + as_parser.h + as_property.h + as_restore.cpp + as_restore.h + as_scriptcode.cpp + as_scriptcode.h + as_scriptengine.cpp + as_scriptengine.h + as_scriptfunction.cpp + as_scriptfunction.h + as_scriptnode.cpp + as_scriptnode.h + as_scriptobject.cpp + as_scriptobject.h + as_string.cpp + as_string.h + as_string_util.cpp + as_string_util.h + as_texts.h + as_thread.cpp + as_thread.h + as_tokendef.h + as_tokenizer.cpp + as_tokenizer.h + as_typeinfo.cpp + as_typeinfo.h + as_variablescope.cpp + as_variablescope.h +} diff --git a/angelscript/projects/marmalade/angelscript_lib.mkf b/angelscript/projects/marmalade/angelscript_lib.mkf new file mode 100644 index 0000000..191e6fe --- /dev/null +++ b/angelscript/projects/marmalade/angelscript_lib.mkf @@ -0,0 +1,24 @@ +#!/usr/bin/env mkb + +display_name "AngelScript_Lib" + +includepath +{ + ../../include + ../../sdk/add_on +} + +defines +{ +} + +library +{ + ".,angelscript_lib" +} + +files +{ + (../../include) + angelscript.h +} \ No newline at end of file diff --git a/angelscript/projects/meson/detect_ver.py b/angelscript/projects/meson/detect_ver.py new file mode 100644 index 0000000..2e05ddf --- /dev/null +++ b/angelscript/projects/meson/detect_ver.py @@ -0,0 +1,28 @@ +import argparse +import os +import re + +HEADER = os.path.join(os.path.dirname(os.path.abspath(__file__)), + "..", "..", "include", "angelscript.h") + +def main(): + parser = argparse.ArgumentParser() + parser.add_argument("--num", action="store_true", help="Print numeric version") + args = parser.parse_args() + + if args.num: + regex = re.compile(r'^#define ANGELSCRIPT_VERSION\s+(\d+)') + else: + regex = re.compile(r'^#define ANGELSCRIPT_VERSION_STRING\s+"(\d+\.\d+\.\d+.*)"') + + with open(HEADER, "r") as fobj: + for l in fobj: + match = re.match(regex, l) + if match is not None: + print(match.group(1)) + return + + assert False, "Can't find version" + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/angelscript/projects/meson/meson.build b/angelscript/projects/meson/meson.build new file mode 100644 index 0000000..9dea003 --- /dev/null +++ b/angelscript/projects/meson/meson.build @@ -0,0 +1,68 @@ +project('angelscript', 'cpp', + version : run_command(find_program('python3'), 'detect_ver.py').stdout().strip(), + meson_version : '>=0.28.0', + license : 'zlib') + +threads = dependency('threads') + +angel_srcs = [ + '../../source/as_atomic.cpp', + '../../source/as_builder.cpp', + '../../source/as_bytecode.cpp', + '../../source/as_callfunc.cpp', + '../../source/as_callfunc_mips.cpp', + '../../source/as_callfunc_ppc.cpp', + '../../source/as_callfunc_ppc_64.cpp', + '../../source/as_callfunc_sh4.cpp', + '../../source/as_callfunc_x86.cpp', + '../../source/as_callfunc_x64_gcc.cpp', + '../../source/as_callfunc_x64_mingw.cpp', + '../../source/as_compiler.cpp', + '../../source/as_context.cpp', + '../../source/as_configgroup.cpp', + '../../source/as_datatype.cpp', + '../../source/as_generic.cpp', + '../../source/as_gc.cpp', + '../../source/as_globalproperty.cpp', + '../../source/as_memory.cpp', + '../../source/as_module.cpp', + '../../source/as_objecttype.cpp', + '../../source/as_outputbuffer.cpp', + '../../source/as_parser.cpp', + '../../source/as_restore.cpp', + '../../source/as_scriptcode.cpp', + '../../source/as_scriptengine.cpp', + '../../source/as_scriptfunction.cpp', + '../../source/as_scriptnode.cpp', + '../../source/as_scriptobject.cpp', + '../../source/as_string.cpp', + '../../source/as_string_util.cpp', + '../../source/as_thread.cpp', + '../../source/as_tokenizer.cpp', + '../../source/as_typeinfo.cpp', + '../../source/as_variablescope.cpp', +] +if host_machine.cpu_family() == 'arm' + add_languages('c') + angel_srcs += [ + '../../source/as_callfunc_arm.cpp', + '../../source/as_callfunc_arm_gcc.S', + ] +endif + +angelscript_version_num = run_command(find_program('python3'), 'detect_ver.py', '--num').stdout().strip() +angelscript_lib = library( + 'angelscript', + sources : angel_srcs, + dependencies : threads, + version : angelscript_version_num, + install : true, +) +angelscript_inc = include_directories('../../include') +angelscript_dep = declare_dependency( + link_with : angelscript_lib, + include_directories : angelscript_inc, + version : meson.project_version(), +) + +install_headers('../../include/angelscript.h') diff --git a/angelscript/projects/mingw/makefile b/angelscript/projects/mingw/makefile new file mode 100644 index 0000000..58bc07b --- /dev/null +++ b/angelscript/projects/mingw/makefile @@ -0,0 +1,83 @@ +# Angelscript MingW makefile +# Type 'make' then 'make install' to complete the installation of the library + +CXX ?= g++ +AR ?= ar +# Debug flags: -ggdb -DAS_DEBUG +# Release flags: -O2 +# to exclude the script compiler: -DAS_NO_COMPILER +# to use only generic calling convention: -DAS_MAX_PORTABILITY +CXXFLAGS ?= -O2 +SRCDIR = ../../source +OBJDIR = obj +SRCNAMES = \ + as_atomic.cpp \ + as_builder.cpp \ + as_bytecode.cpp \ + as_callfunc.cpp \ + as_callfunc_mips.cpp \ + as_callfunc_ppc_64.cpp \ + as_callfunc_ppc.cpp \ + as_callfunc_sh4.cpp \ + as_callfunc_x86.cpp \ + as_callfunc_x64_mingw.cpp \ + as_compiler.cpp \ + as_configgroup.cpp \ + as_context.cpp \ + as_datatype.cpp \ + as_generic.cpp \ + as_gc.cpp \ + as_globalproperty.cpp \ + as_memory.cpp \ + as_module.cpp \ + as_objecttype.cpp \ + as_outputbuffer.cpp \ + as_parser.cpp \ + as_restore.cpp \ + as_scriptcode.cpp \ + as_scriptengine.cpp \ + as_scriptfunction.cpp \ + as_scriptnode.cpp \ + as_scriptobject.cpp \ + as_string.cpp \ + as_string_util.cpp \ + as_thread.cpp \ + as_tokenizer.cpp \ + as_typeinfo.cpp \ + as_variablescope.cpp \ + +OBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRCNAMES:.cpp=.o))) +BIN = ../../lib/libangelscript.a +OBJ_D = $(subst /,\,$(OBJ)) +BIN_D = $(subst /,\,$(BIN)) +DELETER = del /f +COPIER = copy /y +INCLUDEFILES_D = ..\..\include\angelscript.h +UNINSTALLFILES_D = $(MINGDIR)\lib\libangelscript.a $(MINGDIR)\include\angelscript.h + +all: $(BIN) + +$(BIN): $(OBJ) + $(AR) rcs $(BIN) $(OBJ) + @echo ------------------------------------------------------------------- + @echo Done. Now type 'make install' to install the library on your MinGW. + +$(OBJDIR)/%.o: $(SRCDIR)/%.cpp + $(CXX) $(CXXFLAGS) -o $@ -c $< + + +clean: + $(DELETER) $(OBJ_D) $(BIN_D) + +install: $(BIN) + $(COPIER) $(BIN_D) $(MINGDIR)\lib + $(COPIER) $(INCLUDEFILES_D) $(MINGDIR)\include + @echo ------------------------------------------------------------------- + @echo Angelscript library installed. Enjoy! + +uninstall: + $(DELETER) $(UNINSTALLFILES_D) + @echo ------------------------------------------------------------------- + @echo Angelscript library uninstalled. + +.PHONY: all clean install uninstall diff --git a/angelscript/projects/mingw/obj/delete.me b/angelscript/projects/mingw/obj/delete.me new file mode 100644 index 0000000..2d6ab1a --- /dev/null +++ b/angelscript/projects/mingw/obj/delete.me @@ -0,0 +1,2 @@ +This file is here just in case your unarchiver does not extract empty directories. +Feel free to remove it. \ No newline at end of file diff --git a/angelscript/projects/mingw/readme.txt b/angelscript/projects/mingw/readme.txt new file mode 100644 index 0000000..fe22d09 --- /dev/null +++ b/angelscript/projects/mingw/readme.txt @@ -0,0 +1,9 @@ +If you haven't done that already set up an environment variable named MINGDIR +pointing the the directory where your MinGW is, e.g. "C:\MINGW" + +To compile the library, just type in the command line: + +make +make install + +Sent in by Jakub "krajzega" Wasilewski \ No newline at end of file diff --git a/angelscript/projects/msvc2015/angelscript.sln b/angelscript/projects/msvc2015/angelscript.sln new file mode 100644 index 0000000..db199aa --- /dev/null +++ b/angelscript/projects/msvc2015/angelscript.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "angelscript", "angelscript.vcxproj", "{39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|Win32.ActiveCfg = Debug|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|Win32.Build.0 = Debug|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|x64.ActiveCfg = Debug|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|x64.Build.0 = Debug|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|Win32.ActiveCfg = Release|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|Win32.Build.0 = Release|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|x64.ActiveCfg = Release|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/angelscript/projects/msvc2015/angelscript.vcxproj b/angelscript/projects/msvc2015/angelscript.vcxproj new file mode 100644 index 0000000..987cb7b --- /dev/null +++ b/angelscript/projects/msvc2015/angelscript.vcxproj @@ -0,0 +1,438 @@ + + + + + clang_debug + ARM + + + clang_debug + Win32 + + + clang_debug + x64 + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD} + angelscript + + + + StaticLibrary + v140 + + + StaticLibrary + v120 + + + StaticLibrary + NotSet + true + v140 + + + StaticLibrary + true + NotSet + v140 + + + StaticLibrary + true + NotSet + v140_clang_3_7 + + + StaticLibrary + true + NotSet + v120 + + + StaticLibrary + true + NotSet + v140_clang_3_7 + + + StaticLibrary + true + NotSet + v140 + + + StaticLibrary + true + NotSet + v140_Clang_3_7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\lib\ + ..\..\lib\ + ..\..\lib\ + ..\..\lib\ + $(Configuration)\ + $(Configuration)\ + ../../lib\ + ../../lib\ + $(Configuration)\ + $(ProjectName)64d + $(ProjectName)64d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d_arm + $(ProjectName)d_arm + $(ProjectName)64 + + + $(ProjectName)_arm + ..\..\lib\ + + + ..\..\lib\ + + + ..\..\lib\ + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + MultiThreadedDebug + false + Level4 + ProgramDatabase + Fast + + + $(OutDir)$(ProjectName)d.lib + + + + + Disabled + false + AS_MAX_PORTABILITY;ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Enabled + EnableFastChecks + false + MultiThreadedDebug + false + EnableAllWarnings + FullDebug + Fast + + + $(OutDir)$(ProjectName)d.lib + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + MultiThreadedDebug + false + Level4 + ProgramDatabase + Fast + true + + + $(OutDir)$(ProjectName)64d.lib + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Enabled + EnableFastChecks + false + MultiThreadedDebug + false + EnableAllWarnings + FullDebug + Fast + true + + + $(OutDir)$(ProjectName)64d.lib + + + + + true + ANGELSCRIPT_EXPORT;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + false + false + Level3 + Full + AnySuitable + Speed + StreamingSIMDExtensions2 + Fast + + + + + true + ANGELSCRIPT_EXPORT;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + false + false + Level3 + Full + AnySuitable + Speed + + + Fast + + + + + true + ANGELSCRIPT_EXPORT;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + false + false + Level4 + Full + AnySuitable + true + Speed + + + Fast + + + + + ..\..\lib\angelscript64.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + + + + + + Document + armasm.exe -g -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + armasm.exe -g -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + armasm.exe -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + + + + + + + + \ No newline at end of file diff --git a/angelscript/projects/msvc2015/angelscript.vcxproj.filters b/angelscript/projects/msvc2015/angelscript.vcxproj.filters new file mode 100644 index 0000000..8e421a5 --- /dev/null +++ b/angelscript/projects/msvc2015/angelscript.vcxproj.filters @@ -0,0 +1,268 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/angelscript/projects/msvc2017/angelscript.sln b/angelscript/projects/msvc2017/angelscript.sln new file mode 100644 index 0000000..db199aa --- /dev/null +++ b/angelscript/projects/msvc2017/angelscript.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "angelscript", "angelscript.vcxproj", "{39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|Win32.ActiveCfg = Debug|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|Win32.Build.0 = Debug|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|x64.ActiveCfg = Debug|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|x64.Build.0 = Debug|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|Win32.ActiveCfg = Release|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|Win32.Build.0 = Release|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|x64.ActiveCfg = Release|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/angelscript/projects/msvc2017/angelscript.vcxproj b/angelscript/projects/msvc2017/angelscript.vcxproj new file mode 100644 index 0000000..9535a3a --- /dev/null +++ b/angelscript/projects/msvc2017/angelscript.vcxproj @@ -0,0 +1,439 @@ + + + + + clang_debug + ARM + + + clang_debug + Win32 + + + clang_debug + x64 + + + Debug + ARM + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + Win32 + + + Release + x64 + + + + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD} + angelscript + 10.0.16299.0 + + + + StaticLibrary + v141 + + + StaticLibrary + v141 + + + StaticLibrary + NotSet + true + v141 + + + StaticLibrary + true + NotSet + v141 + + + StaticLibrary + true + NotSet + v140_clang_3_7 + + + StaticLibrary + true + NotSet + v141 + + + StaticLibrary + true + NotSet + v140_clang_3_7 + + + StaticLibrary + true + NotSet + v141 + + + StaticLibrary + true + NotSet + v140_Clang_3_7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\lib\ + ..\..\lib\ + ..\..\lib\ + ..\..\lib\ + $(Configuration)\ + $(Configuration)\ + ../../lib\ + ../../lib\ + $(Configuration)\ + $(ProjectName)64d + $(ProjectName)64d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d_arm + $(ProjectName)d_arm + $(ProjectName)64 + + + $(ProjectName)_arm + ..\..\lib\ + + + ..\..\lib\ + + + ..\..\lib\ + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + MultiThreadedDebug + false + Level4 + ProgramDatabase + Fast + + + $(OutDir)$(ProjectName)d.lib + + + + + Disabled + false + AS_MAX_PORTABILITY;ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Enabled + EnableFastChecks + false + MultiThreadedDebug + false + EnableAllWarnings + FullDebug + Fast + + + $(OutDir)$(ProjectName)d.lib + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + MultiThreadedDebug + false + Level4 + ProgramDatabase + Fast + true + + + $(OutDir)$(ProjectName)64d.lib + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Enabled + EnableFastChecks + false + MultiThreadedDebug + false + EnableAllWarnings + FullDebug + Fast + true + + + $(OutDir)$(ProjectName)64d.lib + + + + + true + ANGELSCRIPT_EXPORT;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + false + false + Level3 + Full + AnySuitable + Speed + StreamingSIMDExtensions2 + Fast + + + + + true + ANGELSCRIPT_EXPORT;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + false + false + Level3 + Full + AnySuitable + Speed + + + Fast + + + + + true + ANGELSCRIPT_EXPORT;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + false + false + Level4 + Full + AnySuitable + true + Speed + + + Fast + + + + + ..\..\lib\angelscript64.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + + + + + + Document + armasm.exe -g -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + armasm.exe -g -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + armasm.exe -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + + + + + + + + \ No newline at end of file diff --git a/angelscript/projects/msvc2017/angelscript.vcxproj.filters b/angelscript/projects/msvc2017/angelscript.vcxproj.filters new file mode 100644 index 0000000..8e421a5 --- /dev/null +++ b/angelscript/projects/msvc2017/angelscript.vcxproj.filters @@ -0,0 +1,268 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/angelscript/projects/msvc2017/angelscript.vcxproj.user b/angelscript/projects/msvc2017/angelscript.vcxproj.user new file mode 100644 index 0000000..be25078 --- /dev/null +++ b/angelscript/projects/msvc2017/angelscript.vcxproj.user @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/angelscript/projects/msvc2019/angelscript.sln b/angelscript/projects/msvc2019/angelscript.sln new file mode 100644 index 0000000..db199aa --- /dev/null +++ b/angelscript/projects/msvc2019/angelscript.sln @@ -0,0 +1,26 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "angelscript", "angelscript.vcxproj", "{39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Debug|x64 = Debug|x64 + Release|Win32 = Release|Win32 + Release|x64 = Release|x64 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|Win32.ActiveCfg = Debug|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|Win32.Build.0 = Debug|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|x64.ActiveCfg = Debug|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Debug|x64.Build.0 = Debug|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|Win32.ActiveCfg = Release|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|Win32.Build.0 = Release|Win32 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|x64.ActiveCfg = Release|x64 + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD}.Release|x64.Build.0 = Release|x64 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/angelscript/projects/msvc2019/angelscript.vcxproj b/angelscript/projects/msvc2019/angelscript.vcxproj new file mode 100644 index 0000000..296779b --- /dev/null +++ b/angelscript/projects/msvc2019/angelscript.vcxproj @@ -0,0 +1,554 @@ + + + + + clang_debug + ARM + + + clang_debug + ARM64 + + + clang_debug + Win32 + + + clang_debug + x64 + + + Debug + ARM + + + Debug + ARM64 + + + Debug + Win32 + + + Debug + x64 + + + Release + ARM + + + Release + ARM64 + + + Release + Win32 + + + Release + x64 + + + + {39E6AF97-6BA3-4A72-8C61-BCEBF214EBFD} + angelscript + 10.0 + + + + StaticLibrary + v142 + + + StaticLibrary + v142 + + + StaticLibrary + v142 + + + StaticLibrary + NotSet + true + v142 + + + StaticLibrary + true + NotSet + v142 + + + StaticLibrary + true + NotSet + v140_clang_3_7 + + + StaticLibrary + true + NotSet + v142 + + + StaticLibrary + true + NotSet + v142 + + + StaticLibrary + true + NotSet + v140_clang_3_7 + + + StaticLibrary + true + NotSet + v140_clang_3_7 + + + StaticLibrary + true + NotSet + v142 + + + StaticLibrary + true + NotSet + v140_Clang_3_7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + ..\..\lib\ + ..\..\lib\ + ..\..\lib\ + ..\..\lib\ + $(Configuration)\ + $(Configuration)\ + ../../lib\ + ../../lib\ + $(Configuration)\ + $(ProjectName)64d + $(ProjectName)64d + $(ProjectName)d + $(ProjectName)d + $(ProjectName)d_arm + $(ProjectName)d_arm64 + $(ProjectName)d_arm + $(ProjectName)d_arm64 + $(ProjectName)64 + + + $(ProjectName)_arm + ..\..\lib\ + + + $(ProjectName)_arm64 + ..\..\lib\ + + + ..\..\lib\ + + + ..\..\lib\ + + + ..\..\lib\ + + + ..\..\lib\ + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + MultiThreadedDebug + false + Level4 + ProgramDatabase + Fast + + + $(OutDir)$(ProjectName)d.lib + + + + + Disabled + false + AS_MAX_PORTABILITY;ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Enabled + EnableFastChecks + false + MultiThreadedDebug + false + EnableAllWarnings + FullDebug + Fast + + + $(OutDir)$(ProjectName)d.lib + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + false + Level3 + ProgramDatabase + Fast + MultiThreadedDebugDLL + + + $(OutDir)$(TargetName)$(TargetExt) + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + EnableFastChecks + false + MultiThreadedDebug + false + Level4 + ProgramDatabase + Fast + true + + + $(OutDir)$(ProjectName)64d.lib + + + + + Disabled + false + ANGELSCRIPT_EXPORT;AS_DEBUG;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) + true + Enabled + EnableFastChecks + false + MultiThreadedDebug + false + EnableAllWarnings + FullDebug + Fast + true + + + $(OutDir)$(ProjectName)64d.lib + + + + + true + ANGELSCRIPT_EXPORT;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + false + false + Level3 + Full + AnySuitable + Speed + StreamingSIMDExtensions2 + Fast + + + + + true + ANGELSCRIPT_EXPORT;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + false + false + Level3 + Full + AnySuitable + Speed + + + Fast + + + + + true + ANGELSCRIPT_EXPORT;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + false + false + Level3 + Full + AnySuitable + Speed + + + Fast + + + + + true + ANGELSCRIPT_EXPORT;NDEBUG;_LIB;%(PreprocessorDefinitions) + true + Sync + MultiThreaded + false + false + Level4 + Full + AnySuitable + true + Speed + + + Fast + + + + + ..\..\lib\angelscript64.lib + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Document + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + ml64.exe /c /nologo /Fo"$(Configuration)\as_callfunc_x64_msvc_asm.obj" /W3 /Zi /Ta "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + $(Configuration)\as_callfunc_x64_msvc_asm.obj;%(Outputs) + + + + + Document + armasm64.exe -g -o "$(Platform)\$(Configuration)\as_callfunc_arm64_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + armasm64.exe -g -o "$(Platform)\$(Configuration)\as_callfunc_arm64_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + armasm64.exe -o "$(Platform)\$(Configuration)\as_callfunc_arm64_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Platform)\$(Configuration)\as_callfunc_arm64_msvc.obj;%(Outputs) + $(Platform)\$(Configuration)\as_callfunc_arm64_msvc.obj;%(Outputs) + $(Platform)\$(Configuration)\as_callfunc_arm64_msvc.obj;%(Outputs) + + + + + Document + armasm.exe -g -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + armasm.exe -g -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + armasm.exe -32 -o "$(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj" "%(RootDir)%(Directory)\%(Filename)%(Extension)" + $(Platform)\$(Configuration)\as_callfunc_arm_msvc.obj;%(Outputs) + + + + + + + + \ No newline at end of file diff --git a/angelscript/projects/msvc2019/angelscript.vcxproj.filters b/angelscript/projects/msvc2019/angelscript.vcxproj.filters new file mode 100644 index 0000000..c651435 --- /dev/null +++ b/angelscript/projects/msvc2019/angelscript.vcxproj.filters @@ -0,0 +1,277 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + \ No newline at end of file diff --git a/angelscript/projects/trolltechqt/angelscript.pro b/angelscript/projects/trolltechqt/angelscript.pro new file mode 100644 index 0000000..652ed5e --- /dev/null +++ b/angelscript/projects/trolltechqt/angelscript.pro @@ -0,0 +1,136 @@ +TEMPLATE = lib + +DEPENDPATH += ../../source ../../include +INCLUDEPATH += ../../include + +QMAKE_CXXFLAGS += -Wno-strict-aliasing + +CONFIG -= debug debug_and_release release app_bundle qt dll + +CONFIG += staticlib release + +DEFINES += _CRT_SECURE_NO_WARNINGS + +DESTDIR = ../../lib + +win32: LIBS += -lwinmm + +HEADERS += ../../include/angelscript.h \ + ../../source/as_array.h \ + ../../source/as_atomic.h \ + ../../source/as_builder.h \ + ../../source/as_bytecode.h \ + ../../source/as_callfunc.h \ + ../../source/as_compiler.h \ + ../../source/as_config.h \ + ../../source/as_configgroup.h \ + ../../source/as_context.h \ + ../../source/as_criticalsection.h \ + ../../source/as_datatype.h \ + ../../source/as_debug.h \ + ../../source/as_gc.h \ + ../../source/as_generic.h \ + ../../source/as_map.h \ + ../../source/as_memory.h \ + ../../source/as_module.h \ + ../../source/as_objecttype.h \ + ../../source/as_outputbuffer.h \ + ../../source/as_parser.h \ + ../../source/as_property.h \ + ../../source/as_restore.h \ + ../../source/as_scriptcode.h \ + ../../source/as_scriptengine.h \ + ../../source/as_scriptfunction.h \ + ../../source/as_scriptnode.h \ + ../../source/as_scriptobject.h \ + ../../source/as_string.h \ + ../../source/as_string_util.h \ + ../../source/as_symboltable.h \ + ../../source/as_texts.h \ + ../../source/as_thread.h \ + ../../source/as_tokendef.h \ + ../../source/as_tokenizer.h \ + ../../source/as_typeinfo.h \ + ../../source/as_variablescope.h + +SOURCES += ../../source/as_atomic.cpp \ + ../../source/as_builder.cpp \ + ../../source/as_bytecode.cpp \ + ../../source/as_callfunc.cpp \ + ../../source/as_callfunc_mips.cpp \ + ../../source/as_callfunc_ppc.cpp \ + ../../source/as_callfunc_ppc_64.cpp \ + ../../source/as_callfunc_sh4.cpp \ + ../../source/as_callfunc_x64_gcc.cpp \ + ../../source/as_callfunc_x64_mingw.cpp \ + ../../source/as_callfunc_x64_msvc.cpp \ + ../../source/as_callfunc_x86.cpp \ + ../../source/as_callfunc_xenon.cpp \ + ../../source/as_compiler.cpp \ + ../../source/as_configgroup.cpp \ + ../../source/as_context.cpp \ + ../../source/as_datatype.cpp \ + ../../source/as_gc.cpp \ + ../../source/as_generic.cpp \ + ../../source/as_globalproperty.cpp \ + ../../source/as_memory.cpp \ + ../../source/as_module.cpp \ + ../../source/as_objecttype.cpp \ + ../../source/as_outputbuffer.cpp \ + ../../source/as_parser.cpp \ + ../../source/as_restore.cpp \ + ../../source/as_scriptcode.cpp \ + ../../source/as_scriptengine.cpp \ + ../../source/as_scriptfunction.cpp \ + ../../source/as_scriptnode.cpp \ + ../../source/as_scriptobject.cpp \ + ../../source/as_string.cpp \ + ../../source/as_string_util.cpp \ + ../../source/as_thread.cpp \ + ../../source/as_tokenizer.cpp \ + ../../source/as_typeinfo.cpp \ + ../../source/as_variablescope.cpp + +HEADERS += ../../../add_on/scriptany/scriptany.h \ + ../../../add_on/scriptarray/scriptarray.h \ + ../../../add_on/scriptdictionary/scriptdictionary.h \ + ../../../add_on/scriptmath/scriptmath.h \ + ../../../add_on/scripthandle/scripthandle.h \ + ../../../add_on/scriptstdstring/scriptstdstring.h \ + ../../../add_on/scriptbuilder/scriptbuilder.h + +SOURCES += ../../../add_on/scriptany/scriptany.cpp \ + ../../../add_on/scriptarray/scriptarray.cpp \ + ../../../add_on/scriptdictionary/scriptdictionary.cpp \ + ../../../add_on/scriptmath/scriptmath.cpp \ + ../../../add_on/scripthandle/scripthandle.cpp \ + ../../../add_on/scriptstdstring/scriptstdstring.cpp \ + ../../../add_on/scriptstdstring/scriptstdstring_utils.cpp \ + ../../../add_on/scriptbuilder/scriptbuilder.cpp + +OBJECTS_DIR = tmp +MOC_DIR = tmp +UI_DIR = tmp +RCC_DIR = tmp + +!win32-g++:win32:contains(QMAKE_HOST.arch, x86_64):{ + asm_compiler.commands = ml64 /c + asm_compiler.commands += /Fo ${QMAKE_FILE_OUT} ${QMAKE_FILE_IN} + asm_compiler.output = ${QMAKE_VAR_OBJECTS_DIR}${QMAKE_FILE_BASE}$${first(QMAKE_EXT_OBJ)} + asm_compiler.input = ASM_SOURCES + asm_compiler.variable_out = OBJECTS + asm_compiler.name = compiling[asm] ${QMAKE_FILE_IN} + silent:asm_compiler.commands = @echo compiling[asm] ${QMAKE_FILE_IN} && $$asm_compiler.commands + QMAKE_EXTRA_COMPILERS += asm_compiler + + ASM_SOURCES += \ + $$PWD/angelscript/source/as_callfunc_x64_msvc_asm.asm + + if(win32-msvc2008|win32-msvc2010):equals(TEMPLATE_PREFIX, "vc") { + SOURCES += \ + $$PWD/angelscript/source/as_callfunc_x64_msvc_asm.asm + } +} + +# QMAKE_CXXFLAGS_RELEASE += /MP + diff --git a/angelscript/projects/xcode/angelscript.xcodeproj/project.pbxproj b/angelscript/projects/xcode/angelscript.xcodeproj/project.pbxproj new file mode 100644 index 0000000..14a2b51 --- /dev/null +++ b/angelscript/projects/xcode/angelscript.xcodeproj/project.pbxproj @@ -0,0 +1,768 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 6E91005C1823FC7000D59009 /* angelscript.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E91005B1823FC7000D59009 /* angelscript.h */; }; + 6E91005D1823FC7000D59009 /* angelscript.h in Headers */ = {isa = PBXBuildFile; fileRef = 6E91005B1823FC7000D59009 /* angelscript.h */; }; + 6E91FF911823DA0D00D59009 /* as_array.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCF51523FF2300EFAB3F /* as_array.h */; }; + 6E91FF921823DA0D00D59009 /* as_atomic.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCF71523FF2300EFAB3F /* as_atomic.h */; }; + 6E91FF931823DA0D00D59009 /* as_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCF91523FF2300EFAB3F /* as_builder.h */; }; + 6E91FF941823DA0D00D59009 /* as_bytecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCFB1523FF2300EFAB3F /* as_bytecode.h */; }; + 6E91FF951823DA0D00D59009 /* as_callfunc.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCFD1523FF2300EFAB3F /* as_callfunc.h */; }; + 6E91FF961823DA0D00D59009 /* as_compiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD0D1523FF2300EFAB3F /* as_compiler.h */; }; + 6E91FF971823DA0D00D59009 /* as_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD0E1523FF2300EFAB3F /* as_config.h */; }; + 6E91FF981823DA0D00D59009 /* as_configgroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD111523FF2300EFAB3F /* as_configgroup.h */; }; + 6E91FF991823DA0D00D59009 /* as_context.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD131523FF2300EFAB3F /* as_context.h */; }; + 6E91FF9A1823DA0D00D59009 /* as_criticalsection.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD141523FF2300EFAB3F /* as_criticalsection.h */; }; + 6E91FF9B1823DA0D00D59009 /* as_datatype.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD161523FF2300EFAB3F /* as_datatype.h */; }; + 6E91FF9C1823DA0D00D59009 /* as_debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD171523FF2300EFAB3F /* as_debug.h */; }; + 6E91FF9D1823DA0D00D59009 /* as_gc.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD191523FF2300EFAB3F /* as_gc.h */; }; + 6E91FF9E1823DA0D00D59009 /* as_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD1B1523FF2300EFAB3F /* as_generic.h */; }; + 6E91FF9F1823DA0D00D59009 /* as_map.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD1D1523FF2300EFAB3F /* as_map.h */; }; + 6E91FFA01823DA0D00D59009 /* as_memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD1F1523FF2300EFAB3F /* as_memory.h */; }; + 6E91FFA11823DA0D00D59009 /* as_module.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD211523FF2300EFAB3F /* as_module.h */; }; + 6E91FFA21823DA0D00D59009 /* as_objecttype.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD231523FF2300EFAB3F /* as_objecttype.h */; }; + 6E91FFA31823DA0D00D59009 /* as_outputbuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD251523FF2300EFAB3F /* as_outputbuffer.h */; }; + 6E91FFA41823DA0D00D59009 /* as_parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD271523FF2300EFAB3F /* as_parser.h */; }; + 6E91FFA51823DA0D00D59009 /* as_property.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD281523FF2300EFAB3F /* as_property.h */; }; + 6E91FFA61823DA0D00D59009 /* as_restore.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD2A1523FF2300EFAB3F /* as_restore.h */; }; + 6E91FFA71823DA0D00D59009 /* as_scriptcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD2C1523FF2300EFAB3F /* as_scriptcode.h */; }; + 6E91FFA81823DA0D00D59009 /* as_scriptengine.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD2E1523FF2300EFAB3F /* as_scriptengine.h */; }; + 6E91FFA91823DA0D00D59009 /* as_scriptfunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD301523FF2300EFAB3F /* as_scriptfunction.h */; }; + 6E91FFAA1823DA0D00D59009 /* as_scriptnode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD321523FF2300EFAB3F /* as_scriptnode.h */; }; + 6E91FFAB1823DA0D00D59009 /* as_scriptobject.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD341523FF2300EFAB3F /* as_scriptobject.h */; }; + 6E91FFAC1823DA0D00D59009 /* as_string.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD361523FF2300EFAB3F /* as_string.h */; }; + 6E91FFAD1823DA0D00D59009 /* as_string_util.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD381523FF2300EFAB3F /* as_string_util.h */; }; + 6E91FFAE1823DA0D00D59009 /* as_texts.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD391523FF2300EFAB3F /* as_texts.h */; }; + 6E91FFAF1823DA0D00D59009 /* as_thread.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD3B1523FF2300EFAB3F /* as_thread.h */; }; + 6E91FFB01823DA0D00D59009 /* as_tokendef.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD3C1523FF2300EFAB3F /* as_tokendef.h */; }; + 6E91FFB11823DA0D00D59009 /* as_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD3E1523FF2300EFAB3F /* as_tokenizer.h */; }; + 6E91FFB21823DA0D00D59009 /* as_typeinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD401523FF2300EFAB3F /* as_typeinfo.h */; }; + 6E91FFB31823DA0D00D59009 /* as_variablescope.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD421523FF2300EFAB3F /* as_variablescope.h */; }; + 6E91FFB51823DA0D00D59009 /* as_atomic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCF61523FF2300EFAB3F /* as_atomic.cpp */; }; + 6E91FFB61823DA0D00D59009 /* as_builder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCF81523FF2300EFAB3F /* as_builder.cpp */; }; + 6E91FFB71823DA0D00D59009 /* as_bytecode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFA1523FF2300EFAB3F /* as_bytecode.cpp */; }; + 6E91FFB81823DA0D00D59009 /* as_callfunc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFC1523FF2300EFAB3F /* as_callfunc.cpp */; }; + 6E91FFB91823DA0D00D59009 /* as_callfunc_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFE1523FF2300EFAB3F /* as_callfunc_arm.cpp */; }; + 6E91FFBA1823DA0D00D59009 /* as_callfunc_arm_gcc.S in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFF1523FF2300EFAB3F /* as_callfunc_arm_gcc.S */; }; + 6E91FFBC1823DA0D00D59009 /* as_callfunc_arm_xcode.S in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD011523FF2300EFAB3F /* as_callfunc_arm_xcode.S */; }; + 6E91FFBD1823DA0D00D59009 /* as_callfunc_mips.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD021523FF2300EFAB3F /* as_callfunc_mips.cpp */; }; + 6E91FFBE1823DA0D00D59009 /* as_callfunc_ppc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD031523FF2300EFAB3F /* as_callfunc_ppc.cpp */; }; + 6E91FFBF1823DA0D00D59009 /* as_callfunc_ppc_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD041523FF2300EFAB3F /* as_callfunc_ppc_64.cpp */; }; + 6E91FFC01823DA0D00D59009 /* as_callfunc_sh4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD051523FF2300EFAB3F /* as_callfunc_sh4.cpp */; }; + 6E91FFC11823DA0D00D59009 /* as_callfunc_x64_gcc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD061523FF2300EFAB3F /* as_callfunc_x64_gcc.cpp */; }; + 6E91FFC51823DA0D00D59009 /* as_callfunc_x86.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD0A1523FF2300EFAB3F /* as_callfunc_x86.cpp */; }; + 6E91FFC71823DA0D00D59009 /* as_compiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD0C1523FF2300EFAB3F /* as_compiler.cpp */; }; + 6E91FFC81823DA0D00D59009 /* as_configgroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD101523FF2300EFAB3F /* as_configgroup.cpp */; }; + 6E91FFC91823DA0D00D59009 /* as_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD121523FF2300EFAB3F /* as_context.cpp */; }; + 6E91FFCA1823DA0D00D59009 /* as_datatype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD151523FF2300EFAB3F /* as_datatype.cpp */; }; + 6E91FFCB1823DA0D00D59009 /* as_gc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD181523FF2300EFAB3F /* as_gc.cpp */; }; + 6E91FFCC1823DA0D00D59009 /* as_generic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD1A1523FF2300EFAB3F /* as_generic.cpp */; }; + 6E91FFCD1823DA0D00D59009 /* as_globalproperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD1C1523FF2300EFAB3F /* as_globalproperty.cpp */; }; + 6E91FFCE1823DA0D00D59009 /* as_memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD1E1523FF2300EFAB3F /* as_memory.cpp */; }; + 6E91FFCF1823DA0D00D59009 /* as_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD201523FF2300EFAB3F /* as_module.cpp */; }; + 6E91FFD01823DA0D00D59009 /* as_objecttype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD221523FF2300EFAB3F /* as_objecttype.cpp */; }; + 6E91FFD11823DA0D00D59009 /* as_outputbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD241523FF2300EFAB3F /* as_outputbuffer.cpp */; }; + 6E91FFD21823DA0D00D59009 /* as_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD261523FF2300EFAB3F /* as_parser.cpp */; }; + 6E91FFD31823DA0D00D59009 /* as_restore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD291523FF2300EFAB3F /* as_restore.cpp */; }; + 6E91FFD41823DA0D00D59009 /* as_scriptcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD2B1523FF2300EFAB3F /* as_scriptcode.cpp */; }; + 6E91FFD51823DA0D00D59009 /* as_scriptengine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD2D1523FF2300EFAB3F /* as_scriptengine.cpp */; }; + 6E91FFD61823DA0D00D59009 /* as_scriptfunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD2F1523FF2300EFAB3F /* as_scriptfunction.cpp */; }; + 6E91FFD71823DA0D00D59009 /* as_scriptnode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD311523FF2300EFAB3F /* as_scriptnode.cpp */; }; + 6E91FFD81823DA0D00D59009 /* as_scriptobject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD331523FF2300EFAB3F /* as_scriptobject.cpp */; }; + 6E91FFD91823DA0D00D59009 /* as_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD351523FF2300EFAB3F /* as_string.cpp */; }; + 6E91FFDA1823DA0D00D59009 /* as_string_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD371523FF2300EFAB3F /* as_string_util.cpp */; }; + 6E91FFDB1823DA0D00D59009 /* as_thread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD3A1523FF2300EFAB3F /* as_thread.cpp */; }; + 6E91FFDC1823DA0D00D59009 /* as_tokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD3D1523FF2300EFAB3F /* as_tokenizer.cpp */; }; + 6E91FFDD1823DA0D00D59009 /* as_typeinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD3F1523FF2300EFAB3F /* as_typeinfo.cpp */; }; + 6E91FFDE1823DA0D00D59009 /* as_variablescope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD411523FF2300EFAB3F /* as_variablescope.cpp */; }; + 7547BD451523FF2300EFAB3F /* as_array.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCF51523FF2300EFAB3F /* as_array.h */; }; + 7547BD461523FF2300EFAB3F /* as_atomic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCF61523FF2300EFAB3F /* as_atomic.cpp */; }; + 7547BD471523FF2300EFAB3F /* as_atomic.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCF71523FF2300EFAB3F /* as_atomic.h */; }; + 7547BD481523FF2300EFAB3F /* as_builder.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCF81523FF2300EFAB3F /* as_builder.cpp */; }; + 7547BD491523FF2300EFAB3F /* as_builder.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCF91523FF2300EFAB3F /* as_builder.h */; }; + 7547BD4A1523FF2300EFAB3F /* as_bytecode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFA1523FF2300EFAB3F /* as_bytecode.cpp */; }; + 7547BD4B1523FF2300EFAB3F /* as_bytecode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCFB1523FF2300EFAB3F /* as_bytecode.h */; }; + 7547BD4C1523FF2300EFAB3F /* as_callfunc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFC1523FF2300EFAB3F /* as_callfunc.cpp */; }; + 7547BD4D1523FF2300EFAB3F /* as_callfunc.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BCFD1523FF2300EFAB3F /* as_callfunc.h */; }; + 7547BD4E1523FF2300EFAB3F /* as_callfunc_arm.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFE1523FF2300EFAB3F /* as_callfunc_arm.cpp */; }; + 7547BD4F1523FF2300EFAB3F /* as_callfunc_arm_gcc.S in Sources */ = {isa = PBXBuildFile; fileRef = 7547BCFF1523FF2300EFAB3F /* as_callfunc_arm_gcc.S */; }; + 7547BD521523FF2300EFAB3F /* as_callfunc_mips.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD021523FF2300EFAB3F /* as_callfunc_mips.cpp */; }; + 7547BD531523FF2300EFAB3F /* as_callfunc_ppc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD031523FF2300EFAB3F /* as_callfunc_ppc.cpp */; }; + 7547BD541523FF2300EFAB3F /* as_callfunc_ppc_64.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD041523FF2300EFAB3F /* as_callfunc_ppc_64.cpp */; }; + 7547BD551523FF2300EFAB3F /* as_callfunc_sh4.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD051523FF2300EFAB3F /* as_callfunc_sh4.cpp */; }; + 7547BD561523FF2300EFAB3F /* as_callfunc_x64_gcc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD061523FF2300EFAB3F /* as_callfunc_x64_gcc.cpp */; }; + 7547BD5A1523FF2300EFAB3F /* as_callfunc_x86.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD0A1523FF2300EFAB3F /* as_callfunc_x86.cpp */; }; + 7547BD5C1523FF2300EFAB3F /* as_compiler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD0C1523FF2300EFAB3F /* as_compiler.cpp */; }; + 7547BD5D1523FF2300EFAB3F /* as_compiler.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD0D1523FF2300EFAB3F /* as_compiler.h */; }; + 7547BD5E1523FF2300EFAB3F /* as_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD0E1523FF2300EFAB3F /* as_config.h */; }; + 7547BD5F1523FF2300EFAB3F /* as_configgroup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD101523FF2300EFAB3F /* as_configgroup.cpp */; }; + 7547BD601523FF2300EFAB3F /* as_configgroup.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD111523FF2300EFAB3F /* as_configgroup.h */; }; + 7547BD611523FF2300EFAB3F /* as_context.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD121523FF2300EFAB3F /* as_context.cpp */; }; + 7547BD621523FF2300EFAB3F /* as_context.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD131523FF2300EFAB3F /* as_context.h */; }; + 7547BD631523FF2300EFAB3F /* as_criticalsection.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD141523FF2300EFAB3F /* as_criticalsection.h */; }; + 7547BD641523FF2300EFAB3F /* as_datatype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD151523FF2300EFAB3F /* as_datatype.cpp */; }; + 7547BD651523FF2300EFAB3F /* as_datatype.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD161523FF2300EFAB3F /* as_datatype.h */; }; + 7547BD661523FF2300EFAB3F /* as_debug.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD171523FF2300EFAB3F /* as_debug.h */; }; + 7547BD671523FF2300EFAB3F /* as_gc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD181523FF2300EFAB3F /* as_gc.cpp */; }; + 7547BD681523FF2300EFAB3F /* as_gc.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD191523FF2300EFAB3F /* as_gc.h */; }; + 7547BD691523FF2300EFAB3F /* as_generic.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD1A1523FF2300EFAB3F /* as_generic.cpp */; }; + 7547BD6A1523FF2300EFAB3F /* as_generic.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD1B1523FF2300EFAB3F /* as_generic.h */; }; + 7547BD6B1523FF2300EFAB3F /* as_globalproperty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD1C1523FF2300EFAB3F /* as_globalproperty.cpp */; }; + 7547BD6C1523FF2300EFAB3F /* as_map.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD1D1523FF2300EFAB3F /* as_map.h */; }; + 7547BD6D1523FF2300EFAB3F /* as_memory.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD1E1523FF2300EFAB3F /* as_memory.cpp */; }; + 7547BD6E1523FF2300EFAB3F /* as_memory.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD1F1523FF2300EFAB3F /* as_memory.h */; }; + 7547BD6F1523FF2300EFAB3F /* as_module.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD201523FF2300EFAB3F /* as_module.cpp */; }; + 7547BD701523FF2300EFAB3F /* as_module.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD211523FF2300EFAB3F /* as_module.h */; }; + 7547BD711523FF2300EFAB3F /* as_objecttype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD221523FF2300EFAB3F /* as_objecttype.cpp */; }; + 7547BD721523FF2300EFAB3F /* as_objecttype.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD231523FF2300EFAB3F /* as_objecttype.h */; }; + 7547BD731523FF2300EFAB3F /* as_outputbuffer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD241523FF2300EFAB3F /* as_outputbuffer.cpp */; }; + 7547BD741523FF2300EFAB3F /* as_outputbuffer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD251523FF2300EFAB3F /* as_outputbuffer.h */; }; + 7547BD751523FF2300EFAB3F /* as_parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD261523FF2300EFAB3F /* as_parser.cpp */; }; + 7547BD761523FF2300EFAB3F /* as_parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD271523FF2300EFAB3F /* as_parser.h */; }; + 7547BD771523FF2300EFAB3F /* as_property.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD281523FF2300EFAB3F /* as_property.h */; }; + 7547BD781523FF2300EFAB3F /* as_restore.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD291523FF2300EFAB3F /* as_restore.cpp */; }; + 7547BD791523FF2300EFAB3F /* as_restore.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD2A1523FF2300EFAB3F /* as_restore.h */; }; + 7547BD7A1523FF2300EFAB3F /* as_scriptcode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD2B1523FF2300EFAB3F /* as_scriptcode.cpp */; }; + 7547BD7B1523FF2300EFAB3F /* as_scriptcode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD2C1523FF2300EFAB3F /* as_scriptcode.h */; }; + 7547BD7C1523FF2300EFAB3F /* as_scriptengine.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD2D1523FF2300EFAB3F /* as_scriptengine.cpp */; }; + 7547BD7D1523FF2300EFAB3F /* as_scriptengine.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD2E1523FF2300EFAB3F /* as_scriptengine.h */; }; + 7547BD7E1523FF2300EFAB3F /* as_scriptfunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD2F1523FF2300EFAB3F /* as_scriptfunction.cpp */; }; + 7547BD7F1523FF2300EFAB3F /* as_scriptfunction.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD301523FF2300EFAB3F /* as_scriptfunction.h */; }; + 7547BD801523FF2300EFAB3F /* as_scriptnode.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD311523FF2300EFAB3F /* as_scriptnode.cpp */; }; + 7547BD811523FF2300EFAB3F /* as_scriptnode.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD321523FF2300EFAB3F /* as_scriptnode.h */; }; + 7547BD821523FF2300EFAB3F /* as_scriptobject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD331523FF2300EFAB3F /* as_scriptobject.cpp */; }; + 7547BD831523FF2300EFAB3F /* as_scriptobject.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD341523FF2300EFAB3F /* as_scriptobject.h */; }; + 7547BD841523FF2300EFAB3F /* as_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD351523FF2300EFAB3F /* as_string.cpp */; }; + 7547BD851523FF2300EFAB3F /* as_string.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD361523FF2300EFAB3F /* as_string.h */; }; + 7547BD861523FF2300EFAB3F /* as_string_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD371523FF2300EFAB3F /* as_string_util.cpp */; }; + 7547BD871523FF2300EFAB3F /* as_string_util.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD381523FF2300EFAB3F /* as_string_util.h */; }; + 7547BD881523FF2300EFAB3F /* as_texts.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD391523FF2300EFAB3F /* as_texts.h */; }; + 7547BD891523FF2300EFAB3F /* as_thread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD3A1523FF2300EFAB3F /* as_thread.cpp */; }; + 7547BD8A1523FF2300EFAB3F /* as_thread.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD3B1523FF2300EFAB3F /* as_thread.h */; }; + 7547BD8B1523FF2300EFAB3F /* as_tokendef.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD3C1523FF2300EFAB3F /* as_tokendef.h */; }; + 7547BD8C1523FF2300EFAB3F /* as_tokenizer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD3D1523FF2300EFAB3F /* as_tokenizer.cpp */; }; + 7547BD8D1523FF2300EFAB3F /* as_tokenizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD3E1523FF2300EFAB3F /* as_tokenizer.h */; }; + 7547BD8E1523FF2300EFAB3F /* as_typeinfo.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD3F1523FF2300EFAB3F /* as_typeinfo.cpp */; }; + 7547BD8F1523FF2300EFAB3F /* as_typeinfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD401523FF2300EFAB3F /* as_typeinfo.h */; }; + 7547BD901523FF2300EFAB3F /* as_variablescope.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 7547BD411523FF2300EFAB3F /* as_variablescope.cpp */; }; + 7547BD911523FF2300EFAB3F /* as_variablescope.h in Headers */ = {isa = PBXBuildFile; fileRef = 7547BD421523FF2300EFAB3F /* as_variablescope.h */; }; +/* End PBXBuildFile section */ + +/* Begin PBXFileReference section */ + 6E91005B1823FC7000D59009 /* angelscript.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = angelscript.h; sourceTree = ""; }; + 6E91FFE31823DA0D00D59009 /* libangelscript.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libangelscript.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 7547BCF51523FF2300EFAB3F /* as_array.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_array.h; sourceTree = ""; }; + 7547BCF61523FF2300EFAB3F /* as_atomic.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_atomic.cpp; sourceTree = ""; }; + 7547BCF71523FF2300EFAB3F /* as_atomic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_atomic.h; sourceTree = ""; }; + 7547BCF81523FF2300EFAB3F /* as_builder.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_builder.cpp; sourceTree = ""; }; + 7547BCF91523FF2300EFAB3F /* as_builder.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_builder.h; sourceTree = ""; }; + 7547BCFA1523FF2300EFAB3F /* as_bytecode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_bytecode.cpp; sourceTree = ""; }; + 7547BCFB1523FF2300EFAB3F /* as_bytecode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_bytecode.h; sourceTree = ""; }; + 7547BCFC1523FF2300EFAB3F /* as_callfunc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc.cpp; sourceTree = ""; }; + 7547BCFD1523FF2300EFAB3F /* as_callfunc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_callfunc.h; sourceTree = ""; }; + 7547BCFE1523FF2300EFAB3F /* as_callfunc_arm.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_arm.cpp; sourceTree = ""; }; + 7547BCFF1523FF2300EFAB3F /* as_callfunc_arm_gcc.S */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.asm; path = as_callfunc_arm_gcc.S; sourceTree = ""; }; + 7547BD001523FF2300EFAB3F /* as_callfunc_arm_msvc.asm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.asm.asm; path = as_callfunc_arm_msvc.asm; sourceTree = ""; }; + 7547BD011523FF2300EFAB3F /* as_callfunc_arm_xcode.S */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.asm; path = as_callfunc_arm_xcode.S; sourceTree = ""; }; + 7547BD021523FF2300EFAB3F /* as_callfunc_mips.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_mips.cpp; sourceTree = ""; }; + 7547BD031523FF2300EFAB3F /* as_callfunc_ppc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_ppc.cpp; sourceTree = ""; }; + 7547BD041523FF2300EFAB3F /* as_callfunc_ppc_64.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_ppc_64.cpp; sourceTree = ""; }; + 7547BD051523FF2300EFAB3F /* as_callfunc_sh4.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_sh4.cpp; sourceTree = ""; }; + 7547BD061523FF2300EFAB3F /* as_callfunc_x64_gcc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_x64_gcc.cpp; sourceTree = ""; }; + 7547BD071523FF2300EFAB3F /* as_callfunc_x64_mingw.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_x64_mingw.cpp; sourceTree = ""; }; + 7547BD081523FF2300EFAB3F /* as_callfunc_x64_msvc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_x64_msvc.cpp; sourceTree = ""; }; + 7547BD091523FF2300EFAB3F /* as_callfunc_x64_msvc_asm.asm */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.asm.asm; path = as_callfunc_x64_msvc_asm.asm; sourceTree = ""; }; + 7547BD0A1523FF2300EFAB3F /* as_callfunc_x86.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_x86.cpp; sourceTree = ""; }; + 7547BD0B1523FF2300EFAB3F /* as_callfunc_xenon.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_callfunc_xenon.cpp; sourceTree = ""; }; + 7547BD0C1523FF2300EFAB3F /* as_compiler.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_compiler.cpp; sourceTree = ""; }; + 7547BD0D1523FF2300EFAB3F /* as_compiler.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_compiler.h; sourceTree = ""; }; + 7547BD0E1523FF2300EFAB3F /* as_config.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_config.h; sourceTree = ""; }; + 7547BD101523FF2300EFAB3F /* as_configgroup.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_configgroup.cpp; sourceTree = ""; }; + 7547BD111523FF2300EFAB3F /* as_configgroup.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_configgroup.h; sourceTree = ""; }; + 7547BD121523FF2300EFAB3F /* as_context.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_context.cpp; sourceTree = ""; }; + 7547BD131523FF2300EFAB3F /* as_context.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_context.h; sourceTree = ""; }; + 7547BD141523FF2300EFAB3F /* as_criticalsection.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_criticalsection.h; sourceTree = ""; }; + 7547BD151523FF2300EFAB3F /* as_datatype.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_datatype.cpp; sourceTree = ""; }; + 7547BD161523FF2300EFAB3F /* as_datatype.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_datatype.h; sourceTree = ""; }; + 7547BD171523FF2300EFAB3F /* as_debug.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_debug.h; sourceTree = ""; }; + 7547BD181523FF2300EFAB3F /* as_gc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_gc.cpp; sourceTree = ""; }; + 7547BD191523FF2300EFAB3F /* as_gc.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_gc.h; sourceTree = ""; }; + 7547BD1A1523FF2300EFAB3F /* as_generic.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_generic.cpp; sourceTree = ""; }; + 7547BD1B1523FF2300EFAB3F /* as_generic.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_generic.h; sourceTree = ""; }; + 7547BD1C1523FF2300EFAB3F /* as_globalproperty.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_globalproperty.cpp; sourceTree = ""; }; + 7547BD1D1523FF2300EFAB3F /* as_map.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_map.h; sourceTree = ""; }; + 7547BD1E1523FF2300EFAB3F /* as_memory.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_memory.cpp; sourceTree = ""; }; + 7547BD1F1523FF2300EFAB3F /* as_memory.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_memory.h; sourceTree = ""; }; + 7547BD201523FF2300EFAB3F /* as_module.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_module.cpp; sourceTree = ""; }; + 7547BD211523FF2300EFAB3F /* as_module.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_module.h; sourceTree = ""; }; + 7547BD221523FF2300EFAB3F /* as_objecttype.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_objecttype.cpp; sourceTree = ""; }; + 7547BD231523FF2300EFAB3F /* as_objecttype.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_objecttype.h; sourceTree = ""; }; + 7547BD241523FF2300EFAB3F /* as_outputbuffer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_outputbuffer.cpp; sourceTree = ""; }; + 7547BD251523FF2300EFAB3F /* as_outputbuffer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_outputbuffer.h; sourceTree = ""; }; + 7547BD261523FF2300EFAB3F /* as_parser.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_parser.cpp; sourceTree = ""; }; + 7547BD271523FF2300EFAB3F /* as_parser.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_parser.h; sourceTree = ""; }; + 7547BD281523FF2300EFAB3F /* as_property.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_property.h; sourceTree = ""; }; + 7547BD291523FF2300EFAB3F /* as_restore.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_restore.cpp; sourceTree = ""; }; + 7547BD2A1523FF2300EFAB3F /* as_restore.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_restore.h; sourceTree = ""; }; + 7547BD2B1523FF2300EFAB3F /* as_scriptcode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_scriptcode.cpp; sourceTree = ""; }; + 7547BD2C1523FF2300EFAB3F /* as_scriptcode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_scriptcode.h; sourceTree = ""; }; + 7547BD2D1523FF2300EFAB3F /* as_scriptengine.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_scriptengine.cpp; sourceTree = ""; }; + 7547BD2E1523FF2300EFAB3F /* as_scriptengine.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_scriptengine.h; sourceTree = ""; }; + 7547BD2F1523FF2300EFAB3F /* as_scriptfunction.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_scriptfunction.cpp; sourceTree = ""; }; + 7547BD301523FF2300EFAB3F /* as_scriptfunction.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_scriptfunction.h; sourceTree = ""; }; + 7547BD311523FF2300EFAB3F /* as_scriptnode.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_scriptnode.cpp; sourceTree = ""; }; + 7547BD321523FF2300EFAB3F /* as_scriptnode.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_scriptnode.h; sourceTree = ""; }; + 7547BD331523FF2300EFAB3F /* as_scriptobject.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_scriptobject.cpp; sourceTree = ""; }; + 7547BD341523FF2300EFAB3F /* as_scriptobject.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_scriptobject.h; sourceTree = ""; }; + 7547BD351523FF2300EFAB3F /* as_string.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_string.cpp; sourceTree = ""; }; + 7547BD361523FF2300EFAB3F /* as_string.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_string.h; sourceTree = ""; }; + 7547BD371523FF2300EFAB3F /* as_string_util.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_string_util.cpp; sourceTree = ""; }; + 7547BD381523FF2300EFAB3F /* as_string_util.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_string_util.h; sourceTree = ""; }; + 7547BD391523FF2300EFAB3F /* as_texts.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_texts.h; sourceTree = ""; }; + 7547BD3A1523FF2300EFAB3F /* as_thread.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_thread.cpp; sourceTree = ""; }; + 7547BD3B1523FF2300EFAB3F /* as_thread.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_thread.h; sourceTree = ""; }; + 7547BD3C1523FF2300EFAB3F /* as_tokendef.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_tokendef.h; sourceTree = ""; }; + 7547BD3D1523FF2300EFAB3F /* as_tokenizer.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_tokenizer.cpp; sourceTree = ""; }; + 7547BD3E1523FF2300EFAB3F /* as_tokenizer.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_tokenizer.h; sourceTree = ""; }; + 7547BD3F1523FF2300EFAB3F /* as_typeinfo.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_typeinfo.cpp; sourceTree = ""; }; + 7547BD401523FF2300EFAB3F /* as_typeinfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_typeinfo.h; sourceTree = ""; }; + 7547BD411523FF2300EFAB3F /* as_variablescope.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = as_variablescope.cpp; sourceTree = ""; }; + 7547BD421523FF2300EFAB3F /* as_variablescope.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = as_variablescope.h; sourceTree = ""; }; + D2AAC07E0554694100DB518D /* libangelscript.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libangelscript.a; sourceTree = BUILT_PRODUCTS_DIR; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 6E91FFDF1823DA0D00D59009 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D2AAC07C0554694100DB518D /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 034768DFFF38A50411DB9C8B /* Products */ = { + isa = PBXGroup; + children = ( + D2AAC07E0554694100DB518D /* libangelscript.a */, + 6E91FFE31823DA0D00D59009 /* libangelscript.a */, + ); + name = Products; + sourceTree = ""; + }; + 0867D691FE84028FC02AAC07 /* angelscript */ = { + isa = PBXGroup; + children = ( + 6E91005A1823FC7000D59009 /* include */, + 7547BCF41523FF2300EFAB3F /* source */, + 08FB77AEFE84172EC02AAC07 /* Classes */, + 0867D69AFE84028FC02AAC07 /* Frameworks */, + 034768DFFF38A50411DB9C8B /* Products */, + ); + name = angelscript; + sourceTree = ""; + }; + 0867D69AFE84028FC02AAC07 /* Frameworks */ = { + isa = PBXGroup; + children = ( + ); + name = Frameworks; + sourceTree = ""; + }; + 08FB77AEFE84172EC02AAC07 /* Classes */ = { + isa = PBXGroup; + children = ( + ); + name = Classes; + sourceTree = ""; + }; + 6E91005A1823FC7000D59009 /* include */ = { + isa = PBXGroup; + children = ( + 6E91005B1823FC7000D59009 /* angelscript.h */, + ); + name = include; + path = ../../include; + sourceTree = ""; + }; + 7547BCF41523FF2300EFAB3F /* source */ = { + isa = PBXGroup; + children = ( + 7547BCF51523FF2300EFAB3F /* as_array.h */, + 7547BCF61523FF2300EFAB3F /* as_atomic.cpp */, + 7547BCF71523FF2300EFAB3F /* as_atomic.h */, + 7547BCF81523FF2300EFAB3F /* as_builder.cpp */, + 7547BCF91523FF2300EFAB3F /* as_builder.h */, + 7547BCFA1523FF2300EFAB3F /* as_bytecode.cpp */, + 7547BCFB1523FF2300EFAB3F /* as_bytecode.h */, + 7547BCFC1523FF2300EFAB3F /* as_callfunc.cpp */, + 7547BCFD1523FF2300EFAB3F /* as_callfunc.h */, + 7547BCFE1523FF2300EFAB3F /* as_callfunc_arm.cpp */, + 7547BCFF1523FF2300EFAB3F /* as_callfunc_arm_gcc.S */, + 7547BD001523FF2300EFAB3F /* as_callfunc_arm_msvc.asm */, + 7547BD011523FF2300EFAB3F /* as_callfunc_arm_xcode.S */, + 7547BD021523FF2300EFAB3F /* as_callfunc_mips.cpp */, + 7547BD031523FF2300EFAB3F /* as_callfunc_ppc.cpp */, + 7547BD041523FF2300EFAB3F /* as_callfunc_ppc_64.cpp */, + 7547BD051523FF2300EFAB3F /* as_callfunc_sh4.cpp */, + 7547BD061523FF2300EFAB3F /* as_callfunc_x64_gcc.cpp */, + 7547BD071523FF2300EFAB3F /* as_callfunc_x64_mingw.cpp */, + 7547BD081523FF2300EFAB3F /* as_callfunc_x64_msvc.cpp */, + 7547BD091523FF2300EFAB3F /* as_callfunc_x64_msvc_asm.asm */, + 7547BD0A1523FF2300EFAB3F /* as_callfunc_x86.cpp */, + 7547BD0B1523FF2300EFAB3F /* as_callfunc_xenon.cpp */, + 7547BD0C1523FF2300EFAB3F /* as_compiler.cpp */, + 7547BD0D1523FF2300EFAB3F /* as_compiler.h */, + 7547BD0E1523FF2300EFAB3F /* as_config.h */, + 7547BD101523FF2300EFAB3F /* as_configgroup.cpp */, + 7547BD111523FF2300EFAB3F /* as_configgroup.h */, + 7547BD121523FF2300EFAB3F /* as_context.cpp */, + 7547BD131523FF2300EFAB3F /* as_context.h */, + 7547BD141523FF2300EFAB3F /* as_criticalsection.h */, + 7547BD151523FF2300EFAB3F /* as_datatype.cpp */, + 7547BD161523FF2300EFAB3F /* as_datatype.h */, + 7547BD171523FF2300EFAB3F /* as_debug.h */, + 7547BD181523FF2300EFAB3F /* as_gc.cpp */, + 7547BD191523FF2300EFAB3F /* as_gc.h */, + 7547BD1A1523FF2300EFAB3F /* as_generic.cpp */, + 7547BD1B1523FF2300EFAB3F /* as_generic.h */, + 7547BD1C1523FF2300EFAB3F /* as_globalproperty.cpp */, + 7547BD1D1523FF2300EFAB3F /* as_map.h */, + 7547BD1E1523FF2300EFAB3F /* as_memory.cpp */, + 7547BD1F1523FF2300EFAB3F /* as_memory.h */, + 7547BD201523FF2300EFAB3F /* as_module.cpp */, + 7547BD211523FF2300EFAB3F /* as_module.h */, + 7547BD221523FF2300EFAB3F /* as_objecttype.cpp */, + 7547BD231523FF2300EFAB3F /* as_objecttype.h */, + 7547BD241523FF2300EFAB3F /* as_outputbuffer.cpp */, + 7547BD251523FF2300EFAB3F /* as_outputbuffer.h */, + 7547BD261523FF2300EFAB3F /* as_parser.cpp */, + 7547BD271523FF2300EFAB3F /* as_parser.h */, + 7547BD281523FF2300EFAB3F /* as_property.h */, + 7547BD291523FF2300EFAB3F /* as_restore.cpp */, + 7547BD2A1523FF2300EFAB3F /* as_restore.h */, + 7547BD2B1523FF2300EFAB3F /* as_scriptcode.cpp */, + 7547BD2C1523FF2300EFAB3F /* as_scriptcode.h */, + 7547BD2D1523FF2300EFAB3F /* as_scriptengine.cpp */, + 7547BD2E1523FF2300EFAB3F /* as_scriptengine.h */, + 7547BD2F1523FF2300EFAB3F /* as_scriptfunction.cpp */, + 7547BD301523FF2300EFAB3F /* as_scriptfunction.h */, + 7547BD311523FF2300EFAB3F /* as_scriptnode.cpp */, + 7547BD321523FF2300EFAB3F /* as_scriptnode.h */, + 7547BD331523FF2300EFAB3F /* as_scriptobject.cpp */, + 7547BD341523FF2300EFAB3F /* as_scriptobject.h */, + 7547BD351523FF2300EFAB3F /* as_string.cpp */, + 7547BD361523FF2300EFAB3F /* as_string.h */, + 7547BD371523FF2300EFAB3F /* as_string_util.cpp */, + 7547BD381523FF2300EFAB3F /* as_string_util.h */, + 7547BD391523FF2300EFAB3F /* as_texts.h */, + 7547BD3A1523FF2300EFAB3F /* as_thread.cpp */, + 7547BD3B1523FF2300EFAB3F /* as_thread.h */, + 7547BD3C1523FF2300EFAB3F /* as_tokendef.h */, + 7547BD3D1523FF2300EFAB3F /* as_tokenizer.cpp */, + 7547BD3E1523FF2300EFAB3F /* as_tokenizer.h */, + 7547BD3F1523FF2300EFAB3F /* as_typeinfo.cpp */, + 7547BD401523FF2300EFAB3F /* as_typeinfo.h */, + 7547BD411523FF2300EFAB3F /* as_variablescope.cpp */, + 7547BD421523FF2300EFAB3F /* as_variablescope.h */, + ); + name = source; + path = ../../source; + sourceTree = SOURCE_ROOT; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 6E91FF901823DA0D00D59009 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 6E91FF911823DA0D00D59009 /* as_array.h in Headers */, + 6E91FF921823DA0D00D59009 /* as_atomic.h in Headers */, + 6E91FF931823DA0D00D59009 /* as_builder.h in Headers */, + 6E91FF941823DA0D00D59009 /* as_bytecode.h in Headers */, + 6E91FF951823DA0D00D59009 /* as_callfunc.h in Headers */, + 6E91FF961823DA0D00D59009 /* as_compiler.h in Headers */, + 6E91FF971823DA0D00D59009 /* as_config.h in Headers */, + 6E91FF981823DA0D00D59009 /* as_configgroup.h in Headers */, + 6E91FF991823DA0D00D59009 /* as_context.h in Headers */, + 6E91FF9A1823DA0D00D59009 /* as_criticalsection.h in Headers */, + 6E91FF9B1823DA0D00D59009 /* as_datatype.h in Headers */, + 6E91FF9C1823DA0D00D59009 /* as_debug.h in Headers */, + 6E91FF9D1823DA0D00D59009 /* as_gc.h in Headers */, + 6E91FF9E1823DA0D00D59009 /* as_generic.h in Headers */, + 6E91FF9F1823DA0D00D59009 /* as_map.h in Headers */, + 6E91FFA01823DA0D00D59009 /* as_memory.h in Headers */, + 6E91FFA11823DA0D00D59009 /* as_module.h in Headers */, + 6E91FFA21823DA0D00D59009 /* as_objecttype.h in Headers */, + 6E91FFA31823DA0D00D59009 /* as_outputbuffer.h in Headers */, + 6E91FFA41823DA0D00D59009 /* as_parser.h in Headers */, + 6E91FFA51823DA0D00D59009 /* as_property.h in Headers */, + 6E91FFA61823DA0D00D59009 /* as_restore.h in Headers */, + 6E91FFA71823DA0D00D59009 /* as_scriptcode.h in Headers */, + 6E91FFA81823DA0D00D59009 /* as_scriptengine.h in Headers */, + 6E91FFA91823DA0D00D59009 /* as_scriptfunction.h in Headers */, + 6E91005D1823FC7000D59009 /* angelscript.h in Headers */, + 6E91FFAA1823DA0D00D59009 /* as_scriptnode.h in Headers */, + 6E91FFAB1823DA0D00D59009 /* as_scriptobject.h in Headers */, + 6E91FFAC1823DA0D00D59009 /* as_string.h in Headers */, + 6E91FFAD1823DA0D00D59009 /* as_string_util.h in Headers */, + 6E91FFAE1823DA0D00D59009 /* as_texts.h in Headers */, + 6E91FFAF1823DA0D00D59009 /* as_thread.h in Headers */, + 6E91FFB01823DA0D00D59009 /* as_tokendef.h in Headers */, + 6E91FFB11823DA0D00D59009 /* as_tokenizer.h in Headers */, + 6E91FFB21823DA0D00D59009 /* as_typeinfo.h in Headers */, + 6E91FFB31823DA0D00D59009 /* as_variablescope.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D2AAC07A0554694100DB518D /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 7547BD451523FF2300EFAB3F /* as_array.h in Headers */, + 7547BD471523FF2300EFAB3F /* as_atomic.h in Headers */, + 7547BD491523FF2300EFAB3F /* as_builder.h in Headers */, + 7547BD4B1523FF2300EFAB3F /* as_bytecode.h in Headers */, + 7547BD4D1523FF2300EFAB3F /* as_callfunc.h in Headers */, + 7547BD5D1523FF2300EFAB3F /* as_compiler.h in Headers */, + 7547BD5E1523FF2300EFAB3F /* as_config.h in Headers */, + 7547BD601523FF2300EFAB3F /* as_configgroup.h in Headers */, + 7547BD621523FF2300EFAB3F /* as_context.h in Headers */, + 7547BD631523FF2300EFAB3F /* as_criticalsection.h in Headers */, + 7547BD651523FF2300EFAB3F /* as_datatype.h in Headers */, + 7547BD661523FF2300EFAB3F /* as_debug.h in Headers */, + 7547BD681523FF2300EFAB3F /* as_gc.h in Headers */, + 7547BD6A1523FF2300EFAB3F /* as_generic.h in Headers */, + 7547BD6C1523FF2300EFAB3F /* as_map.h in Headers */, + 7547BD6E1523FF2300EFAB3F /* as_memory.h in Headers */, + 7547BD701523FF2300EFAB3F /* as_module.h in Headers */, + 7547BD721523FF2300EFAB3F /* as_objecttype.h in Headers */, + 7547BD741523FF2300EFAB3F /* as_outputbuffer.h in Headers */, + 7547BD761523FF2300EFAB3F /* as_parser.h in Headers */, + 7547BD771523FF2300EFAB3F /* as_property.h in Headers */, + 7547BD791523FF2300EFAB3F /* as_restore.h in Headers */, + 7547BD7B1523FF2300EFAB3F /* as_scriptcode.h in Headers */, + 7547BD7D1523FF2300EFAB3F /* as_scriptengine.h in Headers */, + 7547BD7F1523FF2300EFAB3F /* as_scriptfunction.h in Headers */, + 6E91005C1823FC7000D59009 /* angelscript.h in Headers */, + 7547BD811523FF2300EFAB3F /* as_scriptnode.h in Headers */, + 7547BD831523FF2300EFAB3F /* as_scriptobject.h in Headers */, + 7547BD851523FF2300EFAB3F /* as_string.h in Headers */, + 7547BD871523FF2300EFAB3F /* as_string_util.h in Headers */, + 7547BD881523FF2300EFAB3F /* as_texts.h in Headers */, + 7547BD8A1523FF2300EFAB3F /* as_thread.h in Headers */, + 7547BD8B1523FF2300EFAB3F /* as_tokendef.h in Headers */, + 7547BD8D1523FF2300EFAB3F /* as_tokenizer.h in Headers */, + 7547BD8F1523FF2300EFAB3F /* as_typeinfo.h in Headers */, + 7547BD911523FF2300EFAB3F /* as_variablescope.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 6E91FF8F1823DA0D00D59009 /* angelscript iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = 6E91FFE01823DA0D00D59009 /* Build configuration list for PBXNativeTarget "angelscript iOS" */; + buildPhases = ( + 6E91FF901823DA0D00D59009 /* Headers */, + 6E91FFB41823DA0D00D59009 /* Sources */, + 6E91FFDF1823DA0D00D59009 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "angelscript iOS"; + productName = angelscript; + productReference = 6E91FFE31823DA0D00D59009 /* libangelscript.a */; + productType = "com.apple.product-type.library.static"; + }; + D2AAC07D0554694100DB518D /* angelscript OSX */ = { + isa = PBXNativeTarget; + buildConfigurationList = 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "angelscript OSX" */; + buildPhases = ( + D2AAC07A0554694100DB518D /* Headers */, + D2AAC07B0554694100DB518D /* Sources */, + D2AAC07C0554694100DB518D /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = "angelscript OSX"; + productName = angelscript; + productReference = D2AAC07E0554694100DB518D /* libangelscript.a */; + productType = "com.apple.product-type.library.static"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0867D690FE84028FC02AAC07 /* Project object */ = { + isa = PBXProject; + attributes = { + LastUpgradeCheck = 0510; + }; + buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "angelscript" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 1; + knownRegions = ( + English, + Japanese, + French, + German, + ); + mainGroup = 0867D691FE84028FC02AAC07 /* angelscript */; + productRefGroup = 034768DFFF38A50411DB9C8B /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + D2AAC07D0554694100DB518D /* angelscript OSX */, + 6E91FF8F1823DA0D00D59009 /* angelscript iOS */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + 6E91FFB41823DA0D00D59009 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 6E91FFB51823DA0D00D59009 /* as_atomic.cpp in Sources */, + 6E91FFB61823DA0D00D59009 /* as_builder.cpp in Sources */, + 6E91FFB71823DA0D00D59009 /* as_bytecode.cpp in Sources */, + 6E91FFB81823DA0D00D59009 /* as_callfunc.cpp in Sources */, + 6E91FFB91823DA0D00D59009 /* as_callfunc_arm.cpp in Sources */, + 6E91FFBA1823DA0D00D59009 /* as_callfunc_arm_gcc.S in Sources */, + 6E91FFBC1823DA0D00D59009 /* as_callfunc_arm_xcode.S in Sources */, + 6E91FFBD1823DA0D00D59009 /* as_callfunc_mips.cpp in Sources */, + 6E91FFBE1823DA0D00D59009 /* as_callfunc_ppc.cpp in Sources */, + 6E91FFBF1823DA0D00D59009 /* as_callfunc_ppc_64.cpp in Sources */, + 6E91FFC01823DA0D00D59009 /* as_callfunc_sh4.cpp in Sources */, + 6E91FFC11823DA0D00D59009 /* as_callfunc_x64_gcc.cpp in Sources */, + 6E91FFC51823DA0D00D59009 /* as_callfunc_x86.cpp in Sources */, + 6E91FFC71823DA0D00D59009 /* as_compiler.cpp in Sources */, + 6E91FFC81823DA0D00D59009 /* as_configgroup.cpp in Sources */, + 6E91FFC91823DA0D00D59009 /* as_context.cpp in Sources */, + 6E91FFCA1823DA0D00D59009 /* as_datatype.cpp in Sources */, + 6E91FFCB1823DA0D00D59009 /* as_gc.cpp in Sources */, + 6E91FFCC1823DA0D00D59009 /* as_generic.cpp in Sources */, + 6E91FFCD1823DA0D00D59009 /* as_globalproperty.cpp in Sources */, + 6E91FFCE1823DA0D00D59009 /* as_memory.cpp in Sources */, + 6E91FFCF1823DA0D00D59009 /* as_module.cpp in Sources */, + 6E91FFD01823DA0D00D59009 /* as_objecttype.cpp in Sources */, + 6E91FFD11823DA0D00D59009 /* as_outputbuffer.cpp in Sources */, + 6E91FFD21823DA0D00D59009 /* as_parser.cpp in Sources */, + 6E91FFD31823DA0D00D59009 /* as_restore.cpp in Sources */, + 6E91FFD41823DA0D00D59009 /* as_scriptcode.cpp in Sources */, + 6E91FFD51823DA0D00D59009 /* as_scriptengine.cpp in Sources */, + 6E91FFD61823DA0D00D59009 /* as_scriptfunction.cpp in Sources */, + 6E91FFD71823DA0D00D59009 /* as_scriptnode.cpp in Sources */, + 6E91FFD81823DA0D00D59009 /* as_scriptobject.cpp in Sources */, + 6E91FFD91823DA0D00D59009 /* as_string.cpp in Sources */, + 6E91FFDA1823DA0D00D59009 /* as_string_util.cpp in Sources */, + 6E91FFDB1823DA0D00D59009 /* as_thread.cpp in Sources */, + 6E91FFDC1823DA0D00D59009 /* as_tokenizer.cpp in Sources */, + 6E91FFDD1823DA0D00D59009 /* as_typeinfo.cpp in Sources */, + 6E91FFDE1823DA0D00D59009 /* as_variablescope.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + D2AAC07B0554694100DB518D /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 7547BD461523FF2300EFAB3F /* as_atomic.cpp in Sources */, + 7547BD481523FF2300EFAB3F /* as_builder.cpp in Sources */, + 7547BD4A1523FF2300EFAB3F /* as_bytecode.cpp in Sources */, + 7547BD4C1523FF2300EFAB3F /* as_callfunc.cpp in Sources */, + 7547BD4E1523FF2300EFAB3F /* as_callfunc_arm.cpp in Sources */, + 7547BD4F1523FF2300EFAB3F /* as_callfunc_arm_gcc.S in Sources */, + 7547BD521523FF2300EFAB3F /* as_callfunc_mips.cpp in Sources */, + 7547BD531523FF2300EFAB3F /* as_callfunc_ppc.cpp in Sources */, + 7547BD541523FF2300EFAB3F /* as_callfunc_ppc_64.cpp in Sources */, + 7547BD551523FF2300EFAB3F /* as_callfunc_sh4.cpp in Sources */, + 7547BD561523FF2300EFAB3F /* as_callfunc_x64_gcc.cpp in Sources */, + 7547BD5A1523FF2300EFAB3F /* as_callfunc_x86.cpp in Sources */, + 7547BD5C1523FF2300EFAB3F /* as_compiler.cpp in Sources */, + 7547BD5F1523FF2300EFAB3F /* as_configgroup.cpp in Sources */, + 7547BD611523FF2300EFAB3F /* as_context.cpp in Sources */, + 7547BD641523FF2300EFAB3F /* as_datatype.cpp in Sources */, + 7547BD671523FF2300EFAB3F /* as_gc.cpp in Sources */, + 7547BD691523FF2300EFAB3F /* as_generic.cpp in Sources */, + 7547BD6B1523FF2300EFAB3F /* as_globalproperty.cpp in Sources */, + 7547BD6D1523FF2300EFAB3F /* as_memory.cpp in Sources */, + 7547BD6F1523FF2300EFAB3F /* as_module.cpp in Sources */, + 7547BD711523FF2300EFAB3F /* as_objecttype.cpp in Sources */, + 7547BD731523FF2300EFAB3F /* as_outputbuffer.cpp in Sources */, + 7547BD751523FF2300EFAB3F /* as_parser.cpp in Sources */, + 7547BD781523FF2300EFAB3F /* as_restore.cpp in Sources */, + 7547BD7A1523FF2300EFAB3F /* as_scriptcode.cpp in Sources */, + 7547BD7C1523FF2300EFAB3F /* as_scriptengine.cpp in Sources */, + 7547BD7E1523FF2300EFAB3F /* as_scriptfunction.cpp in Sources */, + 7547BD801523FF2300EFAB3F /* as_scriptnode.cpp in Sources */, + 7547BD821523FF2300EFAB3F /* as_scriptobject.cpp in Sources */, + 7547BD841523FF2300EFAB3F /* as_string.cpp in Sources */, + 7547BD861523FF2300EFAB3F /* as_string_util.cpp in Sources */, + 7547BD891523FF2300EFAB3F /* as_thread.cpp in Sources */, + 7547BD8C1523FF2300EFAB3F /* as_tokenizer.cpp in Sources */, + 7547BD8E1523FF2300EFAB3F /* as_typeinfo.cpp in Sources */, + 7547BD901523FF2300EFAB3F /* as_variablescope.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin XCBuildConfiguration section */ + 1DEB921F08733DC00010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LIBRARY = "compiler-default"; + COPY_PHASE_STRIP = NO; + DSTROOT = /tmp/angelscript.dst; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = angelscript_Prefix.pch; + INSTALL_PATH = /usr/local/lib/OSX/x86_64/Debug; + PRODUCT_NAME = angelscript; + SDKROOT = macosx; + }; + name = Debug; + }; + 1DEB922008733DC00010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "compiler-default"; + CLANG_CXX_LIBRARY = "compiler-default"; + DSTROOT = /tmp/angelscript.dst; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = angelscript_Prefix.pch; + INSTALL_PATH = /usr/local/lib/OSX/x86_64/Release; + PRODUCT_NAME = angelscript; + SDKROOT = macosx; + }; + name = Release; + }; + 1DEB922308733DC00010E9CD /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; + CLANG_CXX_LIBRARY = "libstdc++"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = "-ObjC"; + PREBINDING = NO; + }; + name = Debug; + }; + 1DEB922408733DC00010E9CD /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ARCHS = "$(ARCHS_STANDARD_32_BIT)"; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++98"; + CLANG_CXX_LIBRARY = "libstdc++"; + GCC_C_LANGUAGE_STANDARD = c99; + GCC_WARN_ABOUT_RETURN_TYPE = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + OTHER_LDFLAGS = "-ObjC"; + PREBINDING = NO; + }; + name = Release; + }; + 6E91FFE11823DA0D00D59009 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + COPY_PHASE_STRIP = NO; + DSTROOT = /tmp/angelscript.dst; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_FIX_AND_CONTINUE = YES; + GCC_MODEL_TUNING = G5; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = angelscript_Prefix.pch; + INSTALL_PATH = /usr/local/lib/iOS/arm64/Debug; + "INSTALL_PATH[sdk=iphonesimulator*]" = /usr/local/lib/iOS/x86_64/Debug; + PRODUCT_NAME = angelscript; + SDKROOT = iphoneos; + }; + name = Debug; + }; + 6E91FFE21823DA0D00D59009 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + DSTROOT = /tmp/angelscript.dst; + GCC_MODEL_TUNING = G5; + GCC_PRECOMPILE_PREFIX_HEADER = YES; + GCC_PREFIX_HEADER = angelscript_Prefix.pch; + INSTALL_PATH = /usr/local/lib/iOS/arm64/Release; + "INSTALL_PATH[sdk=iphonesimulator*]" = /usr/local/lib/iOS/x86_64/Release; + PRODUCT_NAME = angelscript; + SDKROOT = iphoneos; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 1DEB921E08733DC00010E9CD /* Build configuration list for PBXNativeTarget "angelscript OSX" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB921F08733DC00010E9CD /* Debug */, + 1DEB922008733DC00010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "angelscript" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 1DEB922308733DC00010E9CD /* Debug */, + 1DEB922408733DC00010E9CD /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 6E91FFE01823DA0D00D59009 /* Build configuration list for PBXNativeTarget "angelscript iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 6E91FFE11823DA0D00D59009 /* Debug */, + 6E91FFE21823DA0D00D59009 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0867D690FE84028FC02AAC07 /* Project object */; +} diff --git a/angelscript/projects/xcode/angelscript.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/angelscript/projects/xcode/angelscript.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..5dbc4b8 --- /dev/null +++ b/angelscript/projects/xcode/angelscript.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/angelscript/projects/xcode/angelscript.xcodeproj/project.xcworkspace/xcuserdata/elastic.xcuserdatad/WorkspaceSettings.xcsettings b/angelscript/projects/xcode/angelscript.xcodeproj/project.xcworkspace/xcuserdata/elastic.xcuserdatad/WorkspaceSettings.xcsettings new file mode 100644 index 0000000..eda6af3 --- /dev/null +++ b/angelscript/projects/xcode/angelscript.xcodeproj/project.xcworkspace/xcuserdata/elastic.xcuserdatad/WorkspaceSettings.xcsettings @@ -0,0 +1,26 @@ + + + + + BuildLocationStyle + CustomLocation + CustomBuildIntermediatesPath + tmp + CustomBuildLocationType + RelativeToWorkspace + CustomBuildProductsPath + ../../lib/ + DerivedDataLocationStyle + Default + HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges + + IssueFilterStyle + ShowActiveSchemeOnly + LiveSourceIssuesEnabled + + SnapshotAutomaticallyBeforeSignificantChanges + + SnapshotLocationStyle + Default + + diff --git a/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/angelscript OSX.xcscheme b/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/angelscript OSX.xcscheme new file mode 100644 index 0000000..d4dff3d --- /dev/null +++ b/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/angelscript OSX.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/angelscript iOS.xcscheme b/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/angelscript iOS.xcscheme new file mode 100644 index 0000000..8697a1d --- /dev/null +++ b/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/angelscript iOS.xcscheme @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/xcschememanagement.plist b/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/xcschememanagement.plist new file mode 100644 index 0000000..1209805 --- /dev/null +++ b/angelscript/projects/xcode/angelscript.xcodeproj/xcuserdata/elastic.xcuserdatad/xcschemes/xcschememanagement.plist @@ -0,0 +1,32 @@ + + + + + SchemeUserState + + angelscript OSX.xcscheme + + orderHint + 0 + + angelscript iOS.xcscheme + + orderHint + 1 + + + SuppressBuildableAutocreation + + 6E91FF8F1823DA0D00D59009 + + primary + + + D2AAC07D0554694100DB518D + + primary + + + + + diff --git a/angelscript/projects/xcode/angelscript_Prefix.pch b/angelscript/projects/xcode/angelscript_Prefix.pch new file mode 100644 index 0000000..bfb7394 --- /dev/null +++ b/angelscript/projects/xcode/angelscript_Prefix.pch @@ -0,0 +1,7 @@ +// +// Prefix header for all source files of the 'CocoaTouchStaticLibrary' target in the 'CocoaTouchStaticLibrary' project. +// + +#ifdef __OBJC__ + #import +#endif diff --git a/angelscript/source/as_array.h b/angelscript/source/as_array.h new file mode 100644 index 0000000..6474951 --- /dev/null +++ b/angelscript/source/as_array.h @@ -0,0 +1,528 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +#ifndef AS_ARRAY_H +#define AS_ARRAY_H + +#if !defined(AS_NO_MEMORY_H) +#include +#endif +#include // some compilers declare memcpy() here + +#ifdef _MSC_VER +#pragma warning(disable:4345) // warning about a change in how the code is handled in this version +#endif + +BEGIN_AS_NAMESPACE + +template class asCArray +{ +public: + asCArray(); + asCArray(const asCArray &); + asCArray(asUINT reserve); + ~asCArray(); + + void Allocate(asUINT numElements, bool keepData); + void AllocateNoConstruct(asUINT numElements, bool keepData); + asUINT GetCapacity() const; + + void PushLast(const T &element); + T PopLast(); + + bool SetLength(asUINT numElements); + bool SetLengthNoConstruct(asUINT numElements); + asUINT GetLength() const; + + void Copy(const T*, asUINT count); + asCArray &operator =(const asCArray &); + void SwapWith(asCArray &other); + + const T &operator [](asUINT index) const; + T &operator [](asUINT index); + T *AddressOf(); + const T *AddressOf() const; + + bool Concatenate(const asCArray &); + void Concatenate(T*, unsigned int count); + + bool Exists(const T &element) const; + int IndexOf(const T &element) const; + void RemoveIndex(asUINT index); // Removes the entry without reordering the array + void RemoveValue(const T &element); // Removes the value without reordering the array + void RemoveIndexUnordered(asUINT index); // Removes the entry without keeping the order + + bool operator==(const asCArray &) const; + bool operator!=(const asCArray &) const; + +protected: + T *array; + asUINT length; // 32bits is enough for all uses of this array + asUINT maxLength; + char buf[2*4*AS_PTR_SIZE]; // Avoid dynamically allocated memory for tiny arrays +}; + +// Implementation + +template +T *asCArray::AddressOf() +{ + return array; +} + +template +const T *asCArray::AddressOf() const +{ + return array; +} + +template +asCArray::asCArray(void) +{ + array = 0; + length = 0; + maxLength = 0; +} + +template +asCArray::asCArray(const asCArray ©) +{ + array = 0; + length = 0; + maxLength = 0; + + *this = copy; +} + +template +asCArray::asCArray(asUINT reserve) +{ + array = 0; + length = 0; + maxLength = 0; + + Allocate(reserve, false); +} + +template +asCArray::~asCArray(void) +{ + // Allocating a zero length array will free all memory + Allocate(0,0); +} + +template +asUINT asCArray::GetLength() const +{ + return length; +} + +template +const T &asCArray::operator [](asUINT index) const +{ + asASSERT(index < length); + + return array[index]; +} + +template +T &asCArray::operator [](asUINT index) +{ + asASSERT(index < length); + + return array[index]; +} + +template +void asCArray::PushLast(const T &element) +{ + if( length == maxLength ) + { + if( maxLength == 0 ) + Allocate(1, false); + else + Allocate(2*maxLength, true); + + if( length == maxLength ) + { + // Out of memory. Return without doing anything + return; + } + } + + array[length++] = element; +} + +template +T asCArray::PopLast() +{ + asASSERT(length > 0); + + return array[--length]; +} + +template +void asCArray::Allocate(asUINT numElements, bool keepData) +{ + // We have 4 situations + // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller + // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes + // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller + // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes + + T *tmp = 0; + if( numElements ) + { + if( sizeof(T)*numElements <= sizeof(buf) ) + // Use the internal buffer + tmp = reinterpret_cast(buf); + else + { + // Allocate the array and construct each of the elements + tmp = asNEWARRAY(T,numElements); + if( tmp == 0 ) + { + // Out of memory. Return without doing anything + return; + } + } + + if( array == tmp ) + { + // Construct only the newly allocated elements + for( asUINT n = length; n < numElements; n++ ) + new (&tmp[n]) T(); + } + else + { + // Construct all elements + for( asUINT n = 0; n < numElements; n++ ) + new (&tmp[n]) T(); + } + } + + if( array ) + { + asUINT oldLength = length; + + if( array == tmp ) + { + if( keepData ) + { + if( length > numElements ) + length = numElements; + } + else + length = 0; + + // Call the destructor for elements that are no longer used + for( asUINT n = length; n < oldLength; n++ ) + array[n].~T(); + } + else + { + if( keepData ) + { + if( length > numElements ) + length = numElements; + + for( asUINT n = 0; n < length; n++ ) + tmp[n] = array[n]; + } + else + length = 0; + + // Call the destructor for all elements + for( asUINT n = 0; n < oldLength; n++ ) + array[n].~T(); + + if( array != reinterpret_cast(buf) ) + asDELETEARRAY(array); + } + } + + array = tmp; + maxLength = numElements; +} + +template +void asCArray::AllocateNoConstruct(asUINT numElements, bool keepData) +{ + // We have 4 situations + // 1. The previous array is 8 bytes or smaller and the new array is also 8 bytes or smaller + // 2. The previous array is 8 bytes or smaller and the new array is larger than 8 bytes + // 3. The previous array is larger than 8 bytes and the new array is 8 bytes or smaller + // 4. The previous array is larger than 8 bytes and the new array is also larger than 8 bytes + + T *tmp = 0; + if( numElements ) + { + if( sizeof(T)*numElements <= sizeof(buf) ) + // Use the internal buffer + tmp = reinterpret_cast(buf); + else + { + // Allocate the array and construct each of the elements + tmp = asNEWARRAY(T,numElements); + if( tmp == 0 ) + { + // Out of memory. Return without doing anything + return; + } + } + } + + if( array ) + { + if( array == tmp ) + { + if( keepData ) + { + if( length > numElements ) + length = numElements; + } + else + length = 0; + } + else + { + if( keepData ) + { + if( length > numElements ) + length = numElements; + + memcpy(tmp, array, sizeof(T)*length); + } + else + length = 0; + + if( array != reinterpret_cast(buf) ) + asDELETEARRAY(array); + } + } + + array = tmp; + maxLength = numElements; +} + +template +asUINT asCArray::GetCapacity() const +{ + return maxLength; +} + +template +bool asCArray::SetLength(asUINT numElements) +{ + if( numElements > maxLength ) + { + Allocate(numElements, true); + if( numElements > maxLength ) + { + // Out of memory. Return without doing anything + return false; + } + } + + length = numElements; + return true; +} + +template +bool asCArray::SetLengthNoConstruct(asUINT numElements) +{ + if( numElements > maxLength ) + { + AllocateNoConstruct(numElements, true); + if( numElements > maxLength ) + { + // Out of memory. Return without doing anything + return false; + } + } + + length = numElements; + return true; +} + +template +void asCArray::Copy(const T *data, asUINT count) +{ + if( maxLength < count ) + { + Allocate(count, false); + if( maxLength < count ) + { + // Out of memory. Return without doing anything + return; + } + } + + for( asUINT n = 0; n < count; n++ ) + array[n] = data[n]; + + length = count; +} + +template +asCArray &asCArray::operator =(const asCArray ©) +{ + Copy(copy.array, copy.length); + + return *this; +} + +template +void asCArray::SwapWith(asCArray &other) +{ + T *tmpArray = array; + asUINT tmpLength = length; + asUINT tmpMaxLength = maxLength; + char tmpBuf[sizeof(buf)]; + memcpy(tmpBuf, buf, sizeof(buf)); + + array = other.array; + length = other.length; + maxLength = other.maxLength; + memcpy(buf, other.buf, sizeof(buf)); + + other.array = tmpArray; + other.length = tmpLength; + other.maxLength = tmpMaxLength; + memcpy(other.buf, tmpBuf, sizeof(buf)); + + // If the data is in the internal buffer, then the array pointer must refer to it + if( array == reinterpret_cast(other.buf) ) + array = reinterpret_cast(buf); + if( other.array == reinterpret_cast(buf) ) + other.array = reinterpret_cast(other.buf); +} + +template +bool asCArray::operator ==(const asCArray &other) const +{ + if( length != other.length ) return false; + + for( asUINT n = 0; n < length; n++ ) + if( array[n] != other.array[n] ) + return false; + + return true; +} + +template +bool asCArray::operator !=(const asCArray &other) const +{ + return !(*this == other); +} + + +// Returns false if the concatenation wasn't successful due to out of memory +template +bool asCArray::Concatenate(const asCArray &other) +{ + if( maxLength < length + other.length ) + { + Allocate(length + other.length, true); + if( maxLength < length + other.length ) + { + // Out of memory + return false; + } + } + + for( asUINT n = 0; n < other.length; n++ ) + array[length+n] = other.array[n]; + + length += other.length; + + // Success + return true; +} + +template +void asCArray::Concatenate(T* other, unsigned int count) +{ + for( unsigned int c = 0; c < count; c++ ) + PushLast(other[c]); +} + +template +bool asCArray::Exists(const T &e) const +{ + return IndexOf(e) == -1 ? false : true; +} + +template +int asCArray::IndexOf(const T &e) const +{ + for( asUINT n = 0; n < length; n++ ) + if( array[n] == e ) return static_cast(n); + + return -1; +} + +template +void asCArray::RemoveIndex(asUINT index) +{ + if( index < length ) + { + for( asUINT n = index; n < length-1; n++ ) + array[n] = array[n+1]; + + PopLast(); + } +} + +template +void asCArray::RemoveValue(const T &e) +{ + for( asUINT n = 0; n < length; n++ ) + { + if( array[n] == e ) + { + RemoveIndex(n); + break; + } + } +} + +template +void asCArray::RemoveIndexUnordered(asUINT index) +{ + if( index == length - 1 ) + PopLast(); + else if( index < length ) + array[index] = PopLast(); +} + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_atomic.cpp b/angelscript/source/as_atomic.cpp new file mode 100644 index 0000000..e110b3f --- /dev/null +++ b/angelscript/source/as_atomic.cpp @@ -0,0 +1,179 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2014 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +// +// as_atomic.cpp +// +// The implementation of the atomic class for thread safe reference counting +// + +#include "as_atomic.h" + +BEGIN_AS_NAMESPACE + +asCAtomic::asCAtomic() +{ + value = 0; +} + +asDWORD asCAtomic::get() const +{ + // A very high ref count is highly unlikely. It most likely a problem with + // memory that has been overwritten or is being accessed after it was deleted. + asASSERT(value < 1000000); + + return value; +} + +void asCAtomic::set(asDWORD val) +{ + // A very high ref count is highly unlikely. It most likely a problem with + // memory that has been overwritten or is being accessed after it was deleted. + asASSERT(value < 1000000); + + value = val; +} + +asDWORD asCAtomic::atomicInc() +{ + // A very high ref count is highly unlikely. It most likely a problem with + // memory that has been overwritten or is being accessed after it was deleted. + asASSERT(value < 1000000); + + return asAtomicInc((int&)value); +} + +asDWORD asCAtomic::atomicDec() +{ + // A very high ref count is highly unlikely. It most likely a problem with + // memory that has been overwritten or is being accessed after it was deleted. + asASSERT(value < 1000000); + + return asAtomicDec((int&)value); +} + +// +// The following code implements the atomicInc and atomicDec on different platforms +// +#if defined(AS_NO_THREADS) || defined(AS_NO_ATOMIC) + +int asAtomicInc(int &value) +{ + return ++value; +} + +int asAtomicDec(int &value) +{ + return --value; +} + +#elif defined(AS_XENON) /// XBox360 + +END_AS_NAMESPACE +#include +BEGIN_AS_NAMESPACE + +int asAtomicInc(int &value) +{ + return InterlockedIncrement((LONG*)&value); +} + +int asAtomicDec(int &value) +{ + return InterlockedDecrement((LONG*)&value); +} + +#elif defined(AS_WIN) + +END_AS_NAMESPACE +#define WIN32_MEAN_AND_LEAN +#include +BEGIN_AS_NAMESPACE + +int asAtomicInc(int &value) +{ + return InterlockedIncrement((LONG*)&value); +} + +int asAtomicDec(int &value) +{ + asASSERT(value > 0); + return InterlockedDecrement((LONG*)&value); +} + +#elif defined(AS_LINUX) || defined(AS_BSD) || defined(AS_ILLUMOS) || defined(AS_ANDROID) + +// +// atomic_inc_and_test() and atomic_dec_and_test() from asm/atomic.h is not meant +// to be used outside the Linux kernel. Instead we should use the GNUC provided +// __sync_add_and_fetch() and __sync_sub_and_fetch() functions. +// +// Reference: http://golubenco.org/blog/atomic-operations/ +// +// These are only available in GCC 4.1 and above, so for older versions we +// use the critical sections, though it is a lot slower. +// + +int asAtomicInc(int &value) +{ + return __sync_add_and_fetch(&value, 1); +} + +int asAtomicDec(int &value) +{ + return __sync_sub_and_fetch(&value, 1); +} + +#elif defined(AS_MAC) || defined(AS_IPHONE) + +END_AS_NAMESPACE +#include +BEGIN_AS_NAMESPACE + +int asAtomicInc(int &value) +{ + return OSAtomicIncrement32((int32_t*)&value); +} + +int asAtomicDec(int &value) +{ + return OSAtomicDecrement32((int32_t*)&value); +} + +#else + +// If we get here, then the configuration in as_config.h +// is wrong for the compiler/platform combination. +int ERROR_PleaseFixTheConfig[-1]; + +#endif + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_atomic.h b/angelscript/source/as_atomic.h new file mode 100644 index 0000000..c6fea88 --- /dev/null +++ b/angelscript/source/as_atomic.h @@ -0,0 +1,69 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2013 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_atomic.h +// +// The asCAtomic class provides methods for performing threadsafe +// operations on a single dword, e.g. reference counting and +// bitfields. +// + + + +#ifndef AS_ATOMIC_H +#define AS_ATOMIC_H + +#include "as_config.h" + +BEGIN_AS_NAMESPACE + +class asCAtomic +{ +public: + asCAtomic(); + + asDWORD get() const; + void set(asDWORD val); + + // Increase and return new value + asDWORD atomicInc(); + + // Decrease and return new value + asDWORD atomicDec(); + +protected: + asDWORD value; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_builder.cpp b/angelscript/source/as_builder.cpp new file mode 100644 index 0000000..73c66e6 --- /dev/null +++ b/angelscript/source/as_builder.cpp @@ -0,0 +1,6451 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_builder.cpp +// +// This is the class that manages the compilation of the scripts +// + + +#include "as_config.h" +#include "as_builder.h" +#include "as_parser.h" +#include "as_compiler.h" +#include "as_tokendef.h" +#include "as_string_util.h" +#include "as_outputbuffer.h" +#include "as_texts.h" +#include "as_scriptobject.h" +#include "as_debug.h" + +BEGIN_AS_NAMESPACE + +#ifndef AS_NO_COMPILER + +// asCSymbolTable template specializations for sGlobalVariableDescription entries +template<> +void asCSymbolTable::GetKey(const sGlobalVariableDescription *entry, asSNameSpaceNamePair &key) const +{ + asSNameSpace *ns = entry->ns; + asCString name = entry->name; + key = asSNameSpaceNamePair(ns, name); +} + +// Comparator for exact variable search +class asCCompGlobVarType : public asIFilter +{ +public: + const asCDataType &m_type; + asCCompGlobVarType(const asCDataType &type) : m_type(type) {} + + bool operator()(const void *p) const + { + const sGlobalVariableDescription* desc = reinterpret_cast(p); + return desc->datatype == m_type; + } + +private: + // The assignment operator is required for MSVC9, otherwise it will complain that it is not possible to auto generate the operator + asCCompGlobVarType &operator=(const asCCompGlobVarType &) {return *this;} +}; + +#endif + +asCBuilder::asCBuilder(asCScriptEngine *_engine, asCModule *_module) +{ + this->engine = _engine; + this->module = _module; + silent = false; +} + +asCBuilder::~asCBuilder() +{ +#ifndef AS_NO_COMPILER + asUINT n; + + // Free all functions + for( n = 0; n < functions.GetLength(); n++ ) + { + if( functions[n] ) + { + if( functions[n]->node ) + functions[n]->node->Destroy(engine); + + asDELETE(functions[n],sFunctionDescription); + } + + functions[n] = 0; + } + + // Free all global variables + CleanupEnumValues(); + asCSymbolTable::iterator it = globVariables.List(); + while( it ) + { + if( (*it)->declaredAtNode ) + (*it)->declaredAtNode->Destroy(engine); + if( (*it)->initializationNode ) + (*it)->initializationNode->Destroy(engine); + asDELETE((*it),sGlobalVariableDescription); + it++; + } + globVariables.Clear(); + + // Free all the loaded files + for( n = 0; n < scripts.GetLength(); n++ ) + { + if( scripts[n] ) + asDELETE(scripts[n],asCScriptCode); + + scripts[n] = 0; + } + + // Free all class declarations + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + if( classDeclarations[n] ) + { + if( classDeclarations[n]->node ) + classDeclarations[n]->node->Destroy(engine); + + asDELETE(classDeclarations[n],sClassDeclaration); + classDeclarations[n] = 0; + } + } + + for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) + { + if( interfaceDeclarations[n] ) + { + if( interfaceDeclarations[n]->node ) + interfaceDeclarations[n]->node->Destroy(engine); + + asDELETE(interfaceDeclarations[n],sClassDeclaration); + interfaceDeclarations[n] = 0; + } + } + + for( n = 0; n < namedTypeDeclarations.GetLength(); n++ ) + { + if( namedTypeDeclarations[n] ) + { + if( namedTypeDeclarations[n]->node ) + namedTypeDeclarations[n]->node->Destroy(engine); + + asDELETE(namedTypeDeclarations[n],sClassDeclaration); + namedTypeDeclarations[n] = 0; + } + } + + for( n = 0; n < funcDefs.GetLength(); n++ ) + { + if( funcDefs[n] ) + { + if( funcDefs[n]->node ) + funcDefs[n]->node->Destroy(engine); + + asDELETE(funcDefs[n],sFuncDef); + funcDefs[n] = 0; + } + } + + for( n = 0; n < mixinClasses.GetLength(); n++ ) + { + if( mixinClasses[n] ) + { + if( mixinClasses[n]->node ) + mixinClasses[n]->node->Destroy(engine); + + asDELETE(mixinClasses[n],sMixinClass); + mixinClasses[n] = 0; + } + } + +#endif // AS_NO_COMPILER +} + +void asCBuilder::Reset() +{ + numErrors = 0; + numWarnings = 0; + engine->preMessage.isSet = false; + +#ifndef AS_NO_COMPILER + // Clear the cache of known types + hasCachedKnownTypes = false; + knownTypes.EraseAll(); +#endif +} + +#ifndef AS_NO_COMPILER +int asCBuilder::AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy) +{ + asCScriptCode *script = asNEW(asCScriptCode); + if( script == 0 ) + return asOUT_OF_MEMORY; + + int r = script->SetCode(name, code, codeLength, makeCopy); + if( r < 0 ) + { + asDELETE(script, asCScriptCode); + return r; + } + + script->lineOffset = lineOffset; + script->idx = sectionIdx; + scripts.PushLast(script); + + return 0; +} + +asCScriptCode *asCBuilder::FindOrAddCode(const char *name, const char *code, size_t length) +{ + for (asUINT n = 0; n < scripts.GetLength(); n++) + if( scripts[n]->name == name && scripts[n]->codeLength == length && memcmp(scripts[n]->code, code, length) == 0 ) + return scripts[n]; + + asCScriptCode *script = asNEW(asCScriptCode); + if (script == 0) + return 0; + + int r = script->SetCode(name, code, length, true); + if (r < 0) + { + asDELETE(script, asCScriptCode); + return 0; + } + + script->idx = engine->GetScriptSectionNameIndex(name); + scripts.PushLast(script); + return script; +} + +void asCBuilder::EvaluateTemplateInstances(asUINT startIdx, bool keepSilent) +{ + // Backup the original message stream + bool msgCallback = engine->msgCallback; + asSSystemFunctionInterface msgCallbackFunc = engine->msgCallbackFunc; + void *msgCallbackObj = engine->msgCallbackObj; + + // Set the new temporary message stream + asCOutputBuffer outBuffer; + if( keepSilent ) + engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL); + + // Evaluate each of the template instances that have been created since the start of the build + // TODO: This is not exactly correct, since another thread may have created template instances in parallel + for( asUINT n = startIdx; n < engine->templateInstanceTypes.GetLength(); n++ ) + { + bool dontGarbageCollect = false; + asCObjectType *tmpl = engine->templateInstanceTypes[n]; + asCScriptFunction *callback = engine->scriptFunctions[tmpl->beh.templateCallback]; + if( callback && !engine->CallGlobalFunctionRetBool(tmpl, &dontGarbageCollect, callback->sysFuncIntf, callback) ) + { + asCString sub = tmpl->templateSubTypes[0].Format(engine->nameSpaces[0]); + for( asUINT m = 1; m < tmpl->templateSubTypes.GetLength(); m++ ) + { + sub += ","; + sub += tmpl->templateSubTypes[m].Format(engine->nameSpaces[0]); + } + asCString str; + str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, tmpl->name.AddressOf(), sub.AddressOf()); + WriteError(tmpl->scriptSectionIdx >= 0 ? engine->scriptSectionNames[tmpl->scriptSectionIdx]->AddressOf() : "", str, tmpl->declaredAt&0xFFFFF, (tmpl->declaredAt>>20)&0xFFF); + } + else + { + // If the callback said this template instance won't be garbage collected then remove the flag + if( dontGarbageCollect ) + tmpl->flags &= ~asOBJ_GC; + } + } + + // Restore message callback + if( keepSilent ) + { + engine->msgCallback = msgCallback; + engine->msgCallbackFunc = msgCallbackFunc; + engine->msgCallbackObj = msgCallbackObj; + } +} + +int asCBuilder::Build() +{ + Reset(); + + // The template callbacks must only be called after the subtypes have a known structure, + // otherwise the callback may think it is not possible to create the template instance, + // even though it is. + // TODO: This flag shouldn't be set globally in the engine, as it would mean that another + // thread requesting a template instance in parallel to the compilation wouldn't + // evaluate the template instance. + engine->deferValidationOfTemplateTypes = true; + asUINT numTempl = (asUINT)engine->templateInstanceTypes.GetLength(); + + ParseScripts(); + if (numErrors > 0) + return asERROR; + + // Compile the types first + CompileInterfaces(); + CompileClasses(numTempl); + + // Evaluate the template instances one last time, this time with error messages, as we know + // all classes have been fully built and it is known which ones will need garbage collection. + EvaluateTemplateInstances(numTempl, false); + engine->deferValidationOfTemplateTypes = false; + if (numErrors > 0) + return asERROR; + + // Then the global variables. Here the variables declared with auto + // will be resolved, so they can be accessed properly in the functions + CompileGlobalVariables(); + + // Finally the global functions and class methods + CompileFunctions(); + + // TODO: Attempt to reorder the initialization of global variables so that + // they do not access other uninitialized global variables out-of-order + // The builder needs to check for each of the global variable, what functions + // that are accessed, and what global variables are access by these functions. + + if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) + WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); + + if( numErrors > 0 ) + return asERROR; + + // Make sure something was compiled, otherwise return an error + if( module->IsEmpty() ) + { + WriteError(TXT_NOTHING_WAS_BUILT, 0, 0); + return asERROR; + } + + return asSUCCESS; +} + +int asCBuilder::CompileGlobalVar(const char *sectionName, const char *code, int lineOffset) +{ + Reset(); + + // Add the string to the script code + asCScriptCode *script = asNEW(asCScriptCode); + if( script == 0 ) + return asOUT_OF_MEMORY; + + script->SetCode(sectionName, code, true); + script->lineOffset = lineOffset; + script->idx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : ""); + scripts.PushLast(script); + + // Parse the string + asCParser parser(this); + if( parser.ParseScript(scripts[0]) < 0 ) + return asERROR; + + asCScriptNode *node = parser.GetScriptNode(); + + // Make sure there is nothing else than the global variable in the script code + if( node == 0 || + node->firstChild == 0 || + node->firstChild != node->lastChild || + node->firstChild->nodeType != snDeclaration ) + { + WriteError(TXT_ONLY_ONE_VARIABLE_ALLOWED, script, 0); + return asERROR; + } + + node = node->firstChild; + node->DisconnectParent(); + RegisterGlobalVar(node, script, module->m_defaultNamespace); + + CompileGlobalVariables(); + + // It is possible that the global variable initialization included anonymous functions that must be compiled too + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCCompiler compiler(engine); + asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; + int r = compiler.CompileFunction(this, functions[n]->script, func->parameterNames, functions[n]->node, func, 0); + if( r < 0 ) + break; + } + + if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) + WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); + + // None of the functions should be added to the module if any error occurred, + // or it was requested that the functions wouldn't be added to the scope + if( numErrors > 0 ) + { + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[functions[n]->funcId]; + if( module->m_globalFunctions.GetIndex(func) >= 0 ) + { + module->m_globalFunctions.Erase(module->m_globalFunctions.GetIndex(func)); + module->m_scriptFunctions.RemoveValue(func); + func->ReleaseInternal(); + } + } + } + + if( numErrors > 0 ) + { + // Remove the variable from the module, if it was registered + if( globVariables.GetSize() > 0 ) + module->RemoveGlobalVar(module->GetGlobalVarCount()-1); + + return asERROR; + } + + return 0; +} +#endif + +int asCBuilder::ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func) +{ + int firstArgWithDefaultValue = -1; + for( asUINT n = 0; n < func->defaultArgs.GetLength(); n++ ) + { + if( func->defaultArgs[n] ) + firstArgWithDefaultValue = n; + else if( firstArgWithDefaultValue >= 0 ) + { + asCString str; + str.Format(TXT_DEF_ARG_MISSING_IN_FUNC_s, func->GetDeclaration()); + WriteError(str, script, node); + return asINVALID_DECLARATION; + } + } + + return 0; +} + +#ifndef AS_NO_COMPILER +// This function will verify if the newly created function will conflict another overload due to having +// identical function arguments that are not default args, e.g: foo(int) and foo(int, int=0) +int asCBuilder::CheckForConflictsDueToDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func, asCObjectType *objType) +{ + // TODO: Implement for global functions too + if( func->objectType == 0 || objType == 0 ) return 0; + + asCArray funcs; + GetObjectMethodDescriptions(func->name.AddressOf(), objType, funcs, false); + for( asUINT n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *func2 = engine->scriptFunctions[funcs[n]]; + if( func == func2 ) + continue; + + if( func->IsReadOnly() != func2->IsReadOnly() ) + continue; + + bool match = true; + asUINT p = 0; + for( ; p < func->parameterTypes.GetLength() && p < func2->parameterTypes.GetLength(); p++ ) + { + // Only verify until the first argument with default args + if( (func->defaultArgs.GetLength() > p && func->defaultArgs[p]) || + (func2->defaultArgs.GetLength() > p && func2->defaultArgs[p]) ) + break; + + if( func->parameterTypes[p] != func2->parameterTypes[p] || + func->inOutFlags[p] != func2->inOutFlags[p] ) + { + match = false; + break; + } + } + + if( match ) + { + if( !((p >= func->parameterTypes.GetLength() && p < func2->defaultArgs.GetLength() && func2->defaultArgs[p]) || + (p >= func2->parameterTypes.GetLength() && p < func->defaultArgs.GetLength() && func->defaultArgs[p])) ) + { + // The argument lists match for the full length of the shorter, but the next + // argument on the longer does not have a default arg so there is no conflict + match = false; + } + } + + if( match ) + { + WriteWarning(TXT_OVERLOAD_CONFLICTS_DUE_TO_DEFAULT_ARGS, script, node); + WriteInfo(func->GetDeclaration(), script, node); + WriteInfo(func2->GetDeclaration(), script, node); + break; + } + } + + return 0; +} + +int asCBuilder::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc) +{ + asASSERT(outFunc != 0); + + Reset(); + + // Add the string to the script code + asCScriptCode *script = asNEW(asCScriptCode); + if( script == 0 ) + return asOUT_OF_MEMORY; + + script->SetCode(sectionName, code, true); + script->lineOffset = lineOffset; + script->idx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : ""); + scripts.PushLast(script); + + // Parse the string + asCParser parser(this); + if( parser.ParseScript(scripts[0]) < 0 ) + return asERROR; + + asCScriptNode *node = parser.GetScriptNode(); + + // Make sure there is nothing else than the function in the script code + if( node == 0 || + node->firstChild == 0 || + node->firstChild != node->lastChild || + node->firstChild->nodeType != snFunction ) + { + WriteError(TXT_ONLY_ONE_FUNCTION_ALLOWED, script, 0); + return asERROR; + } + + // Find the function node + node = node->firstChild; + + // Create the function + asSFunctionTraits funcTraits; + asCScriptFunction *func = asNEW(asCScriptFunction)(engine, compileFlags & asCOMP_ADD_TO_MODULE ? module : 0, asFUNC_SCRIPT); + if( func == 0 ) + return asOUT_OF_MEMORY; + + GetParsedFunctionDetails(node, scripts[0], 0, func->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, func->defaultArgs, funcTraits, module->m_defaultNamespace); + func->id = engine->GetNextScriptFunctionId(); + func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(sectionName ? sectionName : ""); + int row, col; + scripts[0]->ConvertPosToRowCol(node->tokenPos, &row, &col); + func->scriptData->declaredAt = (row & 0xFFFFF)|((col & 0xFFF)<<20); + func->nameSpace = module->m_defaultNamespace; + + // Make sure the default args are declared correctly + int r = ValidateDefaultArgs(script, node, func); + if( r < 0 ) + { + func->ReleaseInternal(); + return asERROR; + } + + // Tell the engine that the function exists already so the compiler can access it + if( compileFlags & asCOMP_ADD_TO_MODULE ) + { + r = CheckNameConflict(func->name.AddressOf(), node, scripts[0], module->m_defaultNamespace, false, false); + if( r < 0 ) + { + func->ReleaseInternal(); + return asERROR; + } + + module->m_globalFunctions.Put(func); + + module->AddScriptFunction(func); + } + else + engine->AddScriptFunction(func); + + // Fill in the function info for the builder too + node->DisconnectParent(); + sFunctionDescription *funcDesc = asNEW(sFunctionDescription); + if( funcDesc == 0 ) + { + func->ReleaseInternal(); + return asOUT_OF_MEMORY; + } + + functions.PushLast(funcDesc); + funcDesc->script = scripts[0]; + funcDesc->node = node; + funcDesc->name = func->name; + funcDesc->funcId = func->id; + funcDesc->paramNames = func->parameterNames; + funcDesc->isExistingShared = false; + + // This must be done in a loop, as it is possible that additional functions get declared as lambda's in the code + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCCompiler compiler(engine); + asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; + r = compiler.CompileFunction(this, functions[n]->script, f->parameterNames, functions[n]->node, f, 0); + if( r < 0 ) + break; + } + + if( numWarnings > 0 && engine->ep.compilerWarnings == 2 ) + WriteError(TXT_WARNINGS_TREATED_AS_ERROR, 0, 0); + + // None of the functions should be added to the module if any error occurred, + // or it was requested that the functions wouldn't be added to the scope + if( !(compileFlags & asCOMP_ADD_TO_MODULE) || numErrors > 0 ) + { + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[functions[n]->funcId]; + if( module->m_globalFunctions.GetIndex(f) >= 0 ) + { + module->m_globalFunctions.Erase(module->m_globalFunctions.GetIndex(f)); + module->m_scriptFunctions.RemoveValue(f); + f->ReleaseInternal(); + } + } + } + + if( numErrors > 0 ) + { + // Release the function pointer that would otherwise be returned if no errors occured + func->ReleaseInternal(); + + return asERROR; + } + + // Return the function + *outFunc = func; + + return asSUCCESS; +} + +void asCBuilder::ParseScripts() +{ + TimeIt("asCBuilder::ParseScripts"); + + asCArray parsers((int)scripts.GetLength()); + + // Parse all the files as if they were one + asUINT n = 0; + for( n = 0; n < scripts.GetLength(); n++ ) + { + asCParser *parser = asNEW(asCParser)(this); + if( parser != 0 ) + { + parsers.PushLast(parser); + + // Parse the script file + parser->ParseScript(scripts[n]); + } + } + + if (numErrors == 0) + { + // Find all type declarations + for (n = 0; n < scripts.GetLength(); n++) + { + asCScriptNode *node = parsers[n]->GetScriptNode(); + RegisterTypesFromScript(node, scripts[n], engine->nameSpaces[0]); + } + + // Before moving forward the builder must establish the relationship between types + // so that a derived type can see the child types of the parent type. + DetermineTypeRelations(); + + // Complete function definitions (defining returntype and parameters) + for( n = 0; n < funcDefs.GetLength(); n++ ) + CompleteFuncDef(funcDefs[n]); + + // Find other global nodes + for (n = 0; n < scripts.GetLength(); n++) + { + // Find other global nodes + asCScriptNode *node = parsers[n]->GetScriptNode(); + RegisterNonTypesFromScript(node, scripts[n], engine->nameSpaces[0]); + } + + // Register script methods found in the interfaces + for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) + { + sClassDeclaration *decl = interfaceDeclarations[n]; + asCScriptNode *node = decl->node->firstChild->next; + + // Skip list of inherited interfaces + while( node && node->nodeType == snIdentifier ) + node = node->next; + + while( node ) + { + asCScriptNode *next = node->next; + if( node->nodeType == snFunction ) + { + node->DisconnectParent(); + RegisterScriptFunctionFromNode(node, decl->script, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared); + } + else if( node->nodeType == snVirtualProperty ) + { + node->DisconnectParent(); + RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), true, false, 0, decl->isExistingShared); + } + + node = next; + } + } + + // Register script methods found in the classes + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + sClassDeclaration *decl = classDeclarations[n]; + + asCScriptNode *node = decl->node->firstChild->next; + + // Skip list of classes and interfaces + while( node && node->nodeType == snIdentifier ) + node = node->next; + + while( node ) + { + asCScriptNode *next = node->next; + if( node->nodeType == snFunction ) + { + node->DisconnectParent(); + RegisterScriptFunctionFromNode(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); + } + else if( node->nodeType == snVirtualProperty ) + { + node->DisconnectParent(); + RegisterVirtualProperty(node, decl->script, CastToObjectType(decl->typeInfo), false, false, 0, decl->isExistingShared); + } + + node = next; + } + + // Make sure the default factory & constructor exists for classes + asCObjectType *ot = CastToObjectType(decl->typeInfo); + if( ot->beh.construct == engine->scriptTypeBehaviours.beh.construct ) + { + if( ot->beh.constructors.GetLength() == 1 || engine->ep.alwaysImplDefaultConstruct ) + { + AddDefaultConstructor(ot, decl->script); + } + else + { + // As the class has another constructor we shouldn't provide the default constructor + if( ot->beh.construct ) + { + engine->scriptFunctions[ot->beh.construct]->ReleaseInternal(); + ot->beh.construct = 0; + ot->beh.constructors.RemoveIndex(0); + } + if( ot->beh.factory ) + { + engine->scriptFunctions[ot->beh.factory]->ReleaseInternal(); + ot->beh.factory = 0; + ot->beh.factories.RemoveIndex(0); + } + // Only remove the opAssign method if the script hasn't provided one + if( ot->beh.copy == engine->scriptTypeBehaviours.beh.copy ) + { + engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); + ot->beh.copy = 0; + } + } + } + } + } + + for( n = 0; n < parsers.GetLength(); n++ ) + { + asDELETE(parsers[n],asCParser); + } +} + +void asCBuilder::RegisterTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns) +{ + asASSERT(node->nodeType == snScript); + + // Find structure definitions first + node = node->firstChild; + while( node ) + { + asCScriptNode *next = node->next; + if( node->nodeType == snNamespace ) + { + // Recursively register the entities defined in the namespace + asCString nsName; + nsName.Assign(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength); + if( ns->name != "" ) + nsName = ns->name + "::" + nsName; + + asSNameSpace *nsChild = engine->AddNameSpace(nsName.AddressOf()); + RegisterTypesFromScript(node->lastChild, script, nsChild); + } + else + { + if( node->nodeType == snClass ) + { + node->DisconnectParent(); + RegisterClass(node, script, ns); + } + else if( node->nodeType == snInterface ) + { + node->DisconnectParent(); + RegisterInterface(node, script, ns); + } + else if( node->nodeType == snEnum ) + { + node->DisconnectParent(); + RegisterEnum(node, script, ns); + } + else if( node->nodeType == snTypedef ) + { + node->DisconnectParent(); + RegisterTypedef(node, script, ns); + } + else if( node->nodeType == snFuncDef ) + { + node->DisconnectParent(); + RegisterFuncDef(node, script, ns, 0); + } + else if( node->nodeType == snMixin ) + { + node->DisconnectParent(); + RegisterMixinClass(node, script, ns); + } + } + + node = next; + } +} + +void asCBuilder::RegisterNonTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns) +{ + node = node->firstChild; + while( node ) + { + asCScriptNode *next = node->next; + if( node->nodeType == snNamespace ) + { + // Determine the name of the namespace + asCString nsName; + nsName.Assign(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength); + if( ns->name != "" ) + nsName = ns->name + "::" + nsName; + + // Declare the namespace, then add the entities + asSNameSpace *nsChild = engine->AddNameSpace(nsName.AddressOf()); + RegisterNonTypesFromScript(node->lastChild, script, nsChild); + } + else + { + node->DisconnectParent(); + if( node->nodeType == snFunction ) + RegisterScriptFunctionFromNode(node, script, 0, false, true, ns); + else if( node->nodeType == snDeclaration ) + RegisterGlobalVar(node, script, ns); + else if( node->nodeType == snVirtualProperty ) + RegisterVirtualProperty(node, script, 0, false, true, ns); + else if( node->nodeType == snImport ) + RegisterImportedFunction(module->GetNextImportedFunctionId(), node, script, ns); + else + { + // Unused script node + int r, c; + script->ConvertPosToRowCol(node->tokenPos, &r, &c); + + WriteWarning(script->name, TXT_UNUSED_SCRIPT_NODE, r, c); + + node->Destroy(engine); + } + } + + node = next; + } +} + +void asCBuilder::CompileFunctions() +{ + // Compile each function + for( asUINT n = 0; n < functions.GetLength(); n++ ) + { + sFunctionDescription *current = functions[n]; + if( current == 0 ) continue; + + // Don't compile the function again if it was an existing shared function + if( current->isExistingShared ) continue; + + // Don't compile if there is no statement block + if (current->node && !(current->node->nodeType == snStatementBlock || current->node->lastChild->nodeType == snStatementBlock)) + continue; + + asCCompiler compiler(engine); + asCScriptFunction *func = engine->scriptFunctions[current->funcId]; + + // Find the class declaration for constructors + sClassDeclaration *classDecl = 0; + if( current->objType && current->name == current->objType->name ) + { + for( asUINT c = 0; c < classDeclarations.GetLength(); c++ ) + { + if( classDeclarations[c]->typeInfo == current->objType ) + { + classDecl = classDeclarations[c]; + break; + } + } + + asASSERT( classDecl ); + } + + if( current->node ) + { + int r, c; + current->script->ConvertPosToRowCol(current->node->tokenPos, &r, &c); + + asCString str = func->GetDeclarationStr(); + str.Format(TXT_COMPILING_s, str.AddressOf()); + WriteInfo(current->script->name, str, r, c, true); + + // When compiling a constructor need to pass the class declaration for member initializations + compiler.CompileFunction(this, current->script, current->paramNames, current->node, func, classDecl); + + engine->preMessage.isSet = false; + } + else if( current->objType && current->name == current->objType->name ) + { + asCScriptNode *node = classDecl->node; + + int r = 0, c = 0; + if( node ) + current->script->ConvertPosToRowCol(node->tokenPos, &r, &c); + + asCString str = func->GetDeclarationStr(); + str.Format(TXT_COMPILING_s, str.AddressOf()); + WriteInfo(current->script->name, str, r, c, true); + + // This is the default constructor that is generated + // automatically if not implemented by the user. + compiler.CompileDefaultConstructor(this, current->script, node, func, classDecl); + + engine->preMessage.isSet = false; + } + else + { + asASSERT( false ); + } + } +} +#endif + +// Called from module and engine +int asCBuilder::ParseDataType(const char *datatype, asCDataType *result, asSNameSpace *implicitNamespace, bool isReturnType) +{ + Reset(); + + asCScriptCode source; + source.SetCode("", datatype, true); + + asCParser parser(this); + int r = parser.ParseDataType(&source, isReturnType); + if( r < 0 ) + return asINVALID_TYPE; + + // Get data type and property name + asCScriptNode *dataType = parser.GetScriptNode()->firstChild; + + *result = CreateDataTypeFromNode(dataType, &source, implicitNamespace, true); + if( isReturnType ) + *result = ModifyDataTypeFromNode(*result, dataType->next, &source, 0, 0); + + if( numErrors > 0 ) + return asINVALID_TYPE; + + return asSUCCESS; +} + +int asCBuilder::ParseTemplateDecl(const char *decl, asCString *name, asCArray &subtypeNames) +{ + Reset(); + + asCScriptCode source; + source.SetCode("", decl, true); + + asCParser parser(this); + int r = parser.ParseTemplateDecl(&source); + if( r < 0 ) + return asINVALID_TYPE; + + // Get the template name and subtype names + asCScriptNode *node = parser.GetScriptNode()->firstChild; + + name->Assign(&decl[node->tokenPos], node->tokenLength); + while( (node = node->next) != 0 ) + { + asCString subtypeName; + subtypeName.Assign(&decl[node->tokenPos], node->tokenLength); + subtypeNames.PushLast(subtypeName); + } + + // TODO: template: check for name conflicts + + if( numErrors > 0 ) + return asINVALID_DECLARATION; + + return asSUCCESS; +} + +int asCBuilder::VerifyProperty(asCDataType *dt, const char *decl, asCString &name, asCDataType &type, asSNameSpace *ns) +{ + // Either datatype or namespace must be informed + asASSERT( dt || ns ); + + Reset(); + + if( dt ) + { + // Verify that the object type exist + if( CastToObjectType(dt->GetTypeInfo()) == 0 ) + return asINVALID_OBJECT; + } + + // Check property declaration and type + asCScriptCode source; + source.SetCode(TXT_PROPERTY, decl, true); + + asCParser parser(this); + int r = parser.ParsePropertyDeclaration(&source); + if( r < 0 ) + return asINVALID_DECLARATION; + + // Get data type + asCScriptNode *dataType = parser.GetScriptNode()->firstChild; + + // Check if the property is declared 'by reference' + bool isReference = (dataType->next->tokenType == ttAmp); + + // Get the name of the property + asCScriptNode *nameNode = isReference ? dataType->next->next : dataType->next; + + // If an object property is registered, then use the + // object's namespace, otherwise use the specified namespace + type = CreateDataTypeFromNode(dataType, &source, dt ? dt->GetTypeInfo()->nameSpace : ns); + name.Assign(&decl[nameNode->tokenPos], nameNode->tokenLength); + type.MakeReference(isReference); + + // Validate that the type really can be a registered property + // We cannot use CanBeInstantiated, as it is allowed to register + // properties of type that cannot otherwise be instantiated + if( type.IsFuncdef() && !type.IsObjectHandle() ) + { + // Function definitions must always be handles + return asINVALID_DECLARATION; + } + + // Verify property name + if( dt ) + { + if( CheckNameConflictMember(dt->GetTypeInfo(), name.AddressOf(), nameNode, &source, true, false) < 0 ) + return asNAME_TAKEN; + } + else + { + if( CheckNameConflict(name.AddressOf(), nameNode, &source, ns, true, false) < 0 ) + return asNAME_TAKEN; + } + + if( numErrors > 0 ) + return asINVALID_DECLARATION; + + return asSUCCESS; +} + +#ifndef AS_NO_COMPILER +asCObjectProperty *asCBuilder::GetObjectProperty(asCDataType &obj, const char *prop) +{ + asASSERT(CastToObjectType(obj.GetTypeInfo()) != 0); + + // TODO: optimize: Improve linear search + asCArray &props = CastToObjectType(obj.GetTypeInfo())->properties; + for( asUINT n = 0; n < props.GetLength(); n++ ) + { + if( props[n]->name == prop ) + { + if( module->m_accessMask & props[n]->accessMask ) + return props[n]; + else + return 0; + } + } + + return 0; +} +#endif + +bool asCBuilder::DoesGlobalPropertyExist(const char *prop, asSNameSpace *ns, asCGlobalProperty **outProp, sGlobalVariableDescription **outDesc, bool *isAppProp) +{ + if( outProp ) *outProp = 0; + if( outDesc ) *outDesc = 0; + if( isAppProp ) *isAppProp = false; + + // Check application registered properties + asCString name(prop); + asCGlobalProperty *globProp = engine->registeredGlobalProps.GetFirst(ns, name); + if( globProp ) + { + if( isAppProp ) *isAppProp = true; + if( outProp ) *outProp = globProp; + return true; + } + +#ifndef AS_NO_COMPILER + // Check properties being compiled now + sGlobalVariableDescription* desc = globVariables.GetFirst(ns, prop); + if( desc && !desc->isEnumValue ) + { + if( outProp ) *outProp = desc->property; + if( outDesc ) *outDesc = desc; + return true; + } +#endif + + // Check previously compiled global variables + if( module ) + { + globProp = module->m_scriptGlobals.GetFirst(ns, prop); + if( globProp ) + { + if( outProp ) *outProp = globProp; + return true; + } + } + + return false; +} + +asCGlobalProperty *asCBuilder::GetGlobalProperty(const char *prop, asSNameSpace *ns, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue, bool *isAppProp) +{ + if( isCompiled ) *isCompiled = true; + if( isPureConstant ) *isPureConstant = false; + if( isAppProp ) *isAppProp = false; + if( constantValue ) *constantValue = 0; + + asCGlobalProperty *globProp = 0; + sGlobalVariableDescription *globDesc = 0; + if( DoesGlobalPropertyExist(prop, ns, &globProp, &globDesc, isAppProp) ) + { +#ifndef AS_NO_COMPILER + if( globDesc ) + { + // The property was declared in this build call, check if it has been compiled successfully already + if( isCompiled ) *isCompiled = globDesc->isCompiled; + if( isPureConstant ) *isPureConstant = globDesc->isPureConstant; + if( constantValue ) *constantValue = globDesc->constantValue; + } + else +#endif + if( isAppProp ) + { + // Don't return the property if the module doesn't have access to it + if( !(module->m_accessMask & globProp->accessMask) ) + globProp = 0; + } + return globProp; + } + + return 0; +} + +int asCBuilder::ParseFunctionDeclaration(asCObjectType *objType, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles, bool *returnAutoHandle, asSNameSpace *ns, asCScriptNode **listPattern, asCObjectType **outParentClass) +{ + asASSERT( objType || ns ); + + if (listPattern) + *listPattern = 0; + if (outParentClass) + *outParentClass = 0; + + // TODO: Can't we use GetParsedFunctionDetails to do most of what is done in this function? + + Reset(); + + asCScriptCode source; + source.SetCode(TXT_SYSTEM_FUNCTION, decl, true); + + asCParser parser(this); + int r = parser.ParseFunctionDefinition(&source, listPattern != 0); + if( r < 0 ) + return asINVALID_DECLARATION; + + asCScriptNode *node = parser.GetScriptNode(); + + // Determine scope + asCScriptNode *n = node->firstChild->next->next; + asCObjectType *parentClass = 0; + func->nameSpace = GetNameSpaceFromNode(n, &source, ns, &n, &parentClass); + if( func->nameSpace == 0 && parentClass == 0 ) + return asINVALID_DECLARATION; + if (parentClass && func->funcType != asFUNC_FUNCDEF) + return asINVALID_DECLARATION; + + if (outParentClass) + *outParentClass = parentClass; + + // Find name + func->name.Assign(&source.code[n->tokenPos], n->tokenLength); + + // Initialize a script function object for registration + bool autoHandle; + + // Scoped reference types are allowed to use handle when returned from application functions + func->returnType = CreateDataTypeFromNode(node->firstChild, &source, objType ? objType->nameSpace : ns, true, parentClass ? parentClass : objType); + func->returnType = ModifyDataTypeFromNode(func->returnType, node->firstChild->next, &source, 0, &autoHandle); + if( autoHandle && (!func->returnType.IsObjectHandle() || func->returnType.IsReference()) ) + return asINVALID_DECLARATION; + if( returnAutoHandle ) *returnAutoHandle = autoHandle; + + // Reference types cannot be returned by value from system functions + if( isSystemFunction && + (func->returnType.GetTypeInfo() && + (func->returnType.GetTypeInfo()->flags & asOBJ_REF)) && + !(func->returnType.IsReference() || + func->returnType.IsObjectHandle()) ) + return asINVALID_DECLARATION; + + // Count number of parameters + int paramCount = 0; + asCScriptNode *paramList = n->next; + n = paramList->firstChild; + while( n ) + { + paramCount++; + n = n->next->next; + if( n && n->nodeType == snIdentifier ) + n = n->next; + + if( n && n->nodeType == snExpression ) + n = n->next; + } + + // Preallocate memory + func->parameterTypes.Allocate(paramCount, false); + func->parameterNames.SetLength(paramCount); + func->inOutFlags.Allocate(paramCount, false); + func->defaultArgs.Allocate(paramCount, false); + if( paramAutoHandles ) paramAutoHandles->Allocate(paramCount, false); + + n = paramList->firstChild; + asUINT index = 0; + while( n ) + { + asETypeModifiers inOutFlags; + asCDataType type = CreateDataTypeFromNode(n, &source, objType ? objType->nameSpace : ns, false, parentClass ? parentClass : objType); + type = ModifyDataTypeFromNode(type, n->next, &source, &inOutFlags, &autoHandle); + + // Reference types cannot be passed by value to system functions + if( isSystemFunction && + (type.GetTypeInfo() && + (type.GetTypeInfo()->flags & asOBJ_REF)) && + !(type.IsReference() || + type.IsObjectHandle()) ) + return asINVALID_DECLARATION; + + // Store the parameter type + func->parameterTypes.PushLast(type); + func->inOutFlags.PushLast(inOutFlags); + + // Don't permit void parameters + if( type.GetTokenType() == ttVoid ) + return asINVALID_DECLARATION; + + if( autoHandle && (!type.IsObjectHandle() || type.IsReference()) ) + return asINVALID_DECLARATION; + + if( paramAutoHandles ) paramAutoHandles->PushLast(autoHandle); + + // Make sure that var type parameters are references + if( type.GetTokenType() == ttQuestion && + !type.IsReference() ) + return asINVALID_DECLARATION; + + // Move to next parameter + n = n->next->next; + if( n && n->nodeType == snIdentifier ) + { + func->parameterNames[index] = asCString(&source.code[n->tokenPos], n->tokenLength); + n = n->next; + } + ++index; + + if( n && n->nodeType == snExpression ) + { + // Strip out white space and comments to better share the string + asCString *defaultArgStr = asNEW(asCString); + if( defaultArgStr ) + { + *defaultArgStr = GetCleanExpressionString(n, &source); + func->defaultArgs.PushLast(defaultArgStr); + } + + n = n->next; + } + else + func->defaultArgs.PushLast(0); + } + + // Set the read-only flag if const is declared after parameter list + n = paramList->next; + if( n && n->nodeType == snUndefined && n->tokenType == ttConst ) + { + if( objType == 0 ) + return asINVALID_DECLARATION; + func->SetReadOnly(true); + + n = n->next; + } + else + func->SetReadOnly(false); + + // Check for additional function traits + while (n && n->nodeType == snIdentifier) + { + if (source.TokenEquals(n->tokenPos, n->tokenLength, EXPLICIT_TOKEN)) + func->SetExplicit(true); + else if( source.TokenEquals(n->tokenPos, n->tokenLength, PROPERTY_TOKEN)) + func->SetProperty(true); + else + return asINVALID_DECLARATION; + + n = n->next; + } + + // If the caller expects a list pattern, check for the existence, else report an error if not + if( listPattern ) + { + if( n == 0 || n->nodeType != snListPattern ) + return asINVALID_DECLARATION; + else + { + *listPattern = n; + n->DisconnectParent(); + } + } + else + { + if( n ) + return asINVALID_DECLARATION; + } + + // Make sure the default args are declared correctly + ValidateDefaultArgs(&source, node, func); + + if( numErrors > 0 || numWarnings > 0 ) + return asINVALID_DECLARATION; + + return 0; +} + +int asCBuilder::ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt) +{ + Reset(); + + asCScriptCode source; + source.SetCode(TXT_VARIABLE_DECL, decl, true); + + asCParser parser(this); + + int r = parser.ParsePropertyDeclaration(&source); + if( r < 0 ) + return asINVALID_DECLARATION; + + asCScriptNode *node = parser.GetScriptNode(); + + // Determine the scope from declaration + asCScriptNode *n = node->firstChild->next; + // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace + outNamespace = GetNameSpaceFromNode(n, &source, implicitNamespace, &n); + if( outNamespace == 0 ) + return asINVALID_DECLARATION; + + // Find name + outName.Assign(&source.code[n->tokenPos], n->tokenLength); + + // Initialize a script variable object for registration + outDt = CreateDataTypeFromNode(node->firstChild, &source, implicitNamespace); + + if( numErrors > 0 || numWarnings > 0 ) + return asINVALID_DECLARATION; + + return 0; +} + +// TODO: This should use SymbolLookupMember, which should be available in the TypeInfo class +int asCBuilder::CheckNameConflictMember(asCTypeInfo *t, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty, bool isVirtualProperty) +{ + // It's not necessary to check against object types + + asCObjectType *ot = CastToObjectType(t); + if (!ot) + return 0; + + // Check against properties + // TODO: optimize: Improve linear search + // Properties are allowed to have the same name as virtual properties + if( !isVirtualProperty ) + { + asCArray &props = ot->properties; + for( asUINT n = 0; n < props.GetLength(); n++ ) + { + if( props[n]->name == name ) + { + if( code ) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // Check against virtual properties + // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties + // Properties are allowed to have the same name as virtual properties + if( !isProperty && !isVirtualProperty ) + { + asCArray methods = ot->methods; + for( asUINT n = 0; n < methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[methods[n]]; + if( func->IsProperty() && func->name.SubString(4) == name ) + { + if( code ) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_OBJ_PROPERTY, name); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // Check against child types + asCArray &funcdefs = ot->childFuncDefs; + for (asUINT n = 0; n < funcdefs.GetLength(); n++) + { + if (funcdefs[n]->name == name) + { + if (code) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, name); + WriteError(str, code, node); + } + + return -1; + } + } + + // Property names must be checked against method names + if( isProperty ) + { + asCArray methods = ot->methods; + for( asUINT n = 0; n < methods.GetLength(); n++ ) + { + if( engine->scriptFunctions[methods[n]]->name == name ) + { + if( code ) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_METHOD, name); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // If there is a namespace at the same level with the same name as the class, then need to check for conflicts with symbols in that namespace too + // TODO: When classes can have static members, the code should change so that class name cannot be the same as a namespace + asCString scope; + if (ot->nameSpace->name != "") + scope = ot->nameSpace->name + "::" + ot->name; + else + scope = ot->name; + asSNameSpace *ns = engine->FindNameSpace(scope.AddressOf()); + if (ns) + { + // Check as if not a function as it doesn't matter the function signature + return CheckNameConflict(name, node, code, ns, true, isVirtualProperty); + } + + return 0; +} + +// TODO: This should use SymbolLookup +int asCBuilder::CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isProperty, bool isVirtualProperty) +{ + // Check against registered object types + if( engine->GetRegisteredType(name, ns) != 0 ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_EXTENDED_TYPE, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + + // Check against global properties + // Virtual properties are allowed to have the same name as a real property + if( !isVirtualProperty && DoesGlobalPropertyExist(name, ns) ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + + // Check against registered global virtual properties + // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties + if( !isProperty || !isVirtualProperty ) + { + for (asUINT n = 0; n < engine->registeredGlobalFuncs.GetSize(); n++) + { + asCScriptFunction *func = engine->registeredGlobalFuncs.Get(n); + if (func->IsProperty() && + func->nameSpace == ns && + func->name.SubString(4) == name) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_VIRTPROP, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // Property names must be checked against function names + if (isProperty) + { + for (asUINT n = 0; n < engine->registeredGlobalFuncs.GetSize(); n++) + { + if (engine->registeredGlobalFuncs.Get(n)->name == name && + engine->registeredGlobalFuncs.Get(n)->nameSpace == ns) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } + +#ifndef AS_NO_COMPILER + // Check against class types + asUINT n; + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + if( classDeclarations[n]->name == name && + classDeclarations[n]->typeInfo->nameSpace == ns ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_STRUCT, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + + // Check against named types + for( n = 0; n < namedTypeDeclarations.GetLength(); n++ ) + { + if( namedTypeDeclarations[n]->name == name && + namedTypeDeclarations[n]->typeInfo->nameSpace == ns ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_NAMED_TYPE, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + + // Must check for name conflicts with funcdefs + for( n = 0; n < funcDefs.GetLength(); n++ ) + { + if( funcDefs[n]->name == name && + module->m_funcDefs[funcDefs[n]->idx]->nameSpace == ns ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCDEF, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + + // Check against mixin classes + if( GetMixinClass(name, ns) ) + { + if( code ) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_MIXIN, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + + // Check against virtual properties + // Don't do this when the check is for a virtual property, as it is allowed to have multiple overloads for virtual properties + if( !isProperty && !isVirtualProperty ) + { + for (n = 0; n < functions.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[functions[n] ? functions[n]->funcId : 0]; + if (func && + func->IsProperty() && + func->objectType == 0 && + func->nameSpace == ns && + func->name.SubString(4) == name) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_VIRTPROP, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } + + // Property names must be checked against function names + if (isProperty) + { + for (n = 0; n < functions.GetLength(); n++) + { + if (functions[n] && + functions[n]->objType == 0 && + functions[n]->name == name && + engine->scriptFunctions[functions[n]->funcId]->nameSpace == ns ) + { + if (code) + { + asCString str; + if (ns->name != "") + str = ns->name + "::" + name; + else + str = name; + str.Format(TXT_NAME_CONFLICT_s_IS_FUNCTION, str.AddressOf()); + WriteError(str, code, node); + } + + return -1; + } + } + } +#endif + + return 0; +} + +// Returns a negative value on invalid property +// -2 incorrect prefix +// -3 invalid signature +// -4 mismatching type for get/set +// -5 name conflict +int asCBuilder::ValidateVirtualProperty(asCScriptFunction *func) +{ + asASSERT( func->IsProperty() ); + + // A virtual property must have the prefix "get_" or "set_" + asCString prefix = func->name.SubString(0, 4); + if( prefix != "get_" && prefix != "set_" ) + return -2; + + // A getter must return a non-void type and have at most 1 argument (indexed property) + if( prefix == "get_" && (func->returnType == asCDataType::CreatePrimitive(ttVoid, false) || func->parameterTypes.GetLength() > 1) ) + return -3; + + // A setter must return a void and have 1 or 2 arguments (indexed property) + if( prefix == "set_" && (func->returnType != asCDataType::CreatePrimitive(ttVoid, false) || func->parameterTypes.GetLength() < 1 || func->parameterTypes.GetLength() > 2) ) + return -3; + + // Check matching getter/setter + asCDataType getType, setType; + bool found = false; + if( prefix == "get_" ) + { + getType = func->returnType; + + // Find if there is a set accessor in the same scope, and then validate the type of it + // TODO: optimize search + asCString setName = "set_" + func->name.SubString(4); + for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *setFunc = engine->scriptFunctions[n]; + if( setFunc == 0 || setFunc->name != setName || !setFunc->IsProperty() ) + continue; + + // Is it the same scope? + if( func->module != setFunc->module || func->nameSpace != setFunc->nameSpace || func->objectType != setFunc->objectType ) + continue; + + setType = setFunc->parameterTypes[setFunc->parameterTypes.GetLength() - 1]; + found = true; + break; + } + } + else + { + setType = func->parameterTypes[func->parameterTypes.GetLength() - 1]; + + // Find if there is a get accessor in the same scope and then validate the type of it + // TODO: optimize search + asCString getName = "get_" + func->name.SubString(4); + for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *getFunc = engine->scriptFunctions[n]; + if( getFunc == 0 || getFunc->name != getName || !getFunc->IsProperty() ) + continue; + + // Is it the same scope? + if( func->module != getFunc->module || func->nameSpace != getFunc->nameSpace || func->objectType != getFunc->objectType ) + continue; + + getType = getFunc->returnType; + found = true; + break; + } + } + + if( found ) + { + // Check that the type matches + // It is permitted for a getter to return a handle and the setter to take a reference + if( !getType.IsEqualExceptRefAndConst(setType) && + !((getType.IsObjectHandle() && !setType.IsObjectHandle()) && + (getType.GetTypeInfo() == setType.GetTypeInfo())) ) + { + return -4; + } + } + + // Check name conflict with other entities in the same scope + // It is allowed to have a real property of the same name, in which case the virtual property hides the real one. + int r; + if( func->objectType ) + r = CheckNameConflictMember(func->objectType, func->name.SubString(4).AddressOf(), 0, 0, true, true); + else + r = CheckNameConflict(func->name.SubString(4).AddressOf(), 0, 0, func->nameSpace, true, true); + if( r < 0 ) + return -5; + + // Everything is OK + return 0; +} + +#ifndef AS_NO_COMPILER +sMixinClass *asCBuilder::GetMixinClass(const char *name, asSNameSpace *ns) +{ + for( asUINT n = 0; n < mixinClasses.GetLength(); n++ ) + if( mixinClasses[n]->name == name && + mixinClasses[n]->ns == ns ) + return mixinClasses[n]; + + return 0; +} + +int asCBuilder::RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent) +{ + // namespace and parent are exclusively mutual + asASSERT((ns == 0 && parent) || (ns && parent == 0)); + + // Skip leading 'shared' and 'external' keywords + asCScriptNode *n = node->firstChild; + while (n->nodeType == snIdentifier) + n = n->next; + + // Find the name + asASSERT( n->nodeType == snDataType ); + n = n->next->next; + + asCString name; + name.Assign(&file->code[n->tokenPos], n->tokenLength); + + // Check for name conflict with other types + if (ns) + { + int r = CheckNameConflict(name.AddressOf(), node, file, ns, true, false); + if (asSUCCESS != r) + { + node->Destroy(engine); + return r; + } + } + else + { + int r = CheckNameConflictMember(parent, name.AddressOf(), node, file, false, false); + if (asSUCCESS != r) + { + node->Destroy(engine); + return r; + } + } + + // The function definition should be stored as a asCScriptFunction so that the application + // can use the asIScriptFunction interface to enumerate the return type and parameters + + // The return type and parameter types aren't determined in this function. A second pass is + // necessary after all type declarations have been identified. The second pass is implemented + // in CompleteFuncDef(). + + sFuncDef *fd = asNEW(sFuncDef); + if( fd == 0 ) + { + node->Destroy(engine); + return asOUT_OF_MEMORY; + } + + fd->name = name; + fd->node = node; + fd->script = file; + fd->idx = module->AddFuncDef(name, ns, parent); + + funcDefs.PushLast(fd); + + return 0; +} + +void asCBuilder::CompleteFuncDef(sFuncDef *funcDef) +{ + asCArray defaultArgs; + asSFunctionTraits funcTraits; + + asCFuncdefType *fdt = module->m_funcDefs[funcDef->idx]; + asASSERT( fdt ); + asCScriptFunction *func = fdt->funcdef; + + asSNameSpace *implicitNs = func->nameSpace ? func->nameSpace : fdt->parentClass->nameSpace; + GetParsedFunctionDetails(funcDef->node, funcDef->script, fdt->parentClass, funcDef->name, func->returnType, func->parameterNames, func->parameterTypes, func->inOutFlags, defaultArgs, funcTraits, implicitNs); + + // There should not be any defaultArgs, but if there are any we need to delete them to avoid leaks + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + // All funcdefs are shared, unless one of the parameter types or return type is not shared + bool declaredShared = funcTraits.GetTrait(asTRAIT_SHARED); + funcTraits.SetTrait(asTRAIT_SHARED, true); + if (func->returnType.GetTypeInfo() && !func->returnType.GetTypeInfo()->IsShared()) + { + if (declaredShared) + { + asCString s; + s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->returnType.GetTypeInfo()->name.AddressOf()); + WriteError(s.AddressOf(), funcDef->script, funcDef->node); + } + funcTraits.SetTrait(asTRAIT_SHARED, false); + } + for( asUINT n = 0; funcTraits.GetTrait(asTRAIT_SHARED) && n < func->parameterTypes.GetLength(); n++ ) + if (func->parameterTypes[n].GetTypeInfo() && !func->parameterTypes[n].GetTypeInfo()->IsShared()) + { + if (declaredShared) + { + asCString s; + s.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); + WriteError(s.AddressOf(), funcDef->script, funcDef->node); + } + funcTraits.SetTrait(asTRAIT_SHARED, false); + } + func->SetShared(funcTraits.GetTrait(asTRAIT_SHARED)); + + // Check if there is another identical funcdef from another module and if so reuse that instead + bool found = false; + if( func->IsShared() ) + { + for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) + { + asCFuncdefType *fdt2 = engine->funcDefs[n]; + if( fdt2 == 0 || fdt == fdt2 ) + continue; + + if( !fdt2->funcdef->IsShared() ) + continue; + + if( fdt2->name == fdt->name && + fdt2->nameSpace == fdt->nameSpace && + fdt2->funcdef->IsSignatureExceptNameEqual(func) ) + { + // Replace our funcdef for the existing one + funcDef->idx = fdt2->funcdef->id; + module->ReplaceFuncDef(fdt, fdt2); + fdt2->AddRefInternal(); + + engine->funcDefs.RemoveValue(fdt); + + fdt->ReleaseInternal(); + found = true; + break; + } + } + } + + // If the funcdef was declared as external then the existing shared declaration must have been found + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !found) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); + WriteError(str, funcDef->script, funcDef->node); + } + + // Remember if the type was declared as external so the saved bytecode can be flagged accordingly + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && found) + module->m_externalTypes.PushLast(engine->scriptFunctions[funcDef->idx]->funcdefType); +} + +int asCBuilder::RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +{ + // Has the application disabled global vars? + if( engine->ep.disallowGlobalVars ) + WriteError(TXT_GLOBAL_VARS_NOT_ALLOWED, file, node); + + // What data type is it? + asCDataType type = CreateDataTypeFromNode(node->firstChild, file, ns); + + if( !type.CanBeInstantiated() ) + { + asCString str; + if( type.IsAbstractClass() ) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(ns).AddressOf()); + else if( type.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(ns).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(ns).AddressOf()); + + WriteError(str, file, node); + } + + asCScriptNode *n = node->firstChild->next; + + while( n ) + { + // Verify that the name isn't taken + asCString name(&file->code[n->tokenPos], n->tokenLength); + CheckNameConflict(name.AddressOf(), n, file, ns, true, false); + + // Register the global variable + sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription); + if( gvar == 0 ) + { + node->Destroy(engine); + return asOUT_OF_MEMORY; + } + + gvar->script = file; + gvar->name = name; + gvar->isCompiled = false; + gvar->datatype = type; + gvar->isEnumValue = false; + gvar->ns = ns; + + // TODO: Give error message if wrong + asASSERT(!gvar->datatype.IsReference()); + + // Allocation is done when the variable is compiled, to allow for autos + gvar->property = 0; + gvar->index = 0; + + globVariables.Put(gvar); + + + gvar->declaredAtNode = n; + n = n->next; + gvar->declaredAtNode->DisconnectParent(); + gvar->initializationNode = 0; + if( n && + ( n->nodeType == snAssignment || + n->nodeType == snArgList || + n->nodeType == snInitList ) ) + { + gvar->initializationNode = n; + n = n->next; + gvar->initializationNode->DisconnectParent(); + } + } + + node->Destroy(engine); + + return 0; +} + +int asCBuilder::RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +{ + asCScriptNode *cl = node->firstChild; + asASSERT( cl->nodeType == snClass ); + + asCScriptNode *n = cl->firstChild; + + // Skip potential 'final' and 'shared' tokens + while( n->tokenType == ttIdentifier && + (file->TokenEquals(n->tokenPos, n->tokenLength, FINAL_TOKEN) || + file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) ) + { + // Report error, because mixin class cannot be final or shared + asCString msg; + msg.Format(TXT_MIXIN_CANNOT_BE_DECLARED_AS_s, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); + WriteError(msg, file, n); + + asCScriptNode *tmp = n; + n = n->next; + + // Remove the invalid node, so compilation can continue as if it wasn't there + tmp->DisconnectParent(); + tmp->Destroy(engine); + } + + asCString name(&file->code[n->tokenPos], n->tokenLength); + + int r, c; + file->ConvertPosToRowCol(n->tokenPos, &r, &c); + + CheckNameConflict(name.AddressOf(), n, file, ns, true, false); + + sMixinClass *decl = asNEW(sMixinClass); + if( decl == 0 ) + { + node->Destroy(engine); + return asOUT_OF_MEMORY; + } + + mixinClasses.PushLast(decl); + decl->name = name; + decl->ns = ns; + decl->node = cl; + decl->script = file; + + // Clean up memory + cl->DisconnectParent(); + node->Destroy(engine); + + // Check that the mixin class doesn't contain any child types + // TODO: Add support for child types in mixin classes + n = cl->firstChild; + while (n) + { + if (n->nodeType == snFuncDef) + { + WriteError(TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES, file, n); + break; + } + n = n->next; + } + + return 0; +} + +int asCBuilder::RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +{ + asCScriptNode *n = node->firstChild; + bool isFinal = false; + bool isShared = false; + bool isAbstract = false; + bool isExternal = false; + + // Check the class modifiers + while( n->tokenType == ttIdentifier ) + { + if( file->TokenEquals(n->tokenPos, n->tokenLength, FINAL_TOKEN) ) + { + if( isAbstract ) + WriteError(TXT_CLASS_CANT_BE_FINAL_AND_ABSTRACT, file, n); + else + { + if( isFinal ) + { + asCString msg; + msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); + WriteWarning(msg, file, n); + } + isFinal = true; + } + } + else if( file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN) ) + { + if( isShared ) + { + asCString msg; + msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); + WriteWarning(msg, file, n); + } + isShared = true; + } + else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) + { + if (isExternal) + { + asCString msg; + msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); + WriteWarning(msg, file, n); + } + isExternal = true; + } + else if( file->TokenEquals(n->tokenPos, n->tokenLength, ABSTRACT_TOKEN) ) + { + if( isFinal ) + WriteError(TXT_CLASS_CANT_BE_FINAL_AND_ABSTRACT, file, n); + else + { + if( isAbstract ) + { + asCString msg; + msg.Format(TXT_ATTR_s_INFORMED_MULTIPLE_TIMES, asCString(&file->code[n->tokenPos], n->tokenLength).AddressOf()); + WriteWarning(msg, file, n); + } + isAbstract = true; + } + } + else + { + // This is the name of the class + break; + } + + n = n->next; + } + + asCString name(&file->code[n->tokenPos], n->tokenLength); + + int r, c; + file->ConvertPosToRowCol(n->tokenPos, &r, &c); + + CheckNameConflict(name.AddressOf(), n, file, ns, true, false); + + sClassDeclaration *decl = asNEW(sClassDeclaration); + if( decl == 0 ) + { + node->Destroy(engine); + return asOUT_OF_MEMORY; + } + + classDeclarations.PushLast(decl); + decl->name = name; + decl->script = file; + decl->node = node; + + // External shared interfaces must not try to redefine the interface + if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement)) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, n); + } + else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, n); + } + + // If this type is shared and there already exist another shared + // type of the same name, then that one should be used instead of + // creating a new one. + asCObjectType *st = 0; + if( isShared ) + { + for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) + { + st = CastToObjectType(engine->sharedScriptTypes[i]); + if( st && + st->IsShared() && + st->name == name && + st->nameSpace == ns && + !st->IsInterface() ) + { + // We'll use the existing type + decl->isExistingShared = true; + decl->typeInfo = st; + module->AddClassType(st); + st->AddRefInternal(); + break; + } + } + } + + // If the class was declared as external then it must have been compiled in a different module first + if (isExternal && decl->typeInfo == 0) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, n); + } + + // Remember if the class was declared as external so the saved bytecode can be flagged accordingly + if (isExternal) + module->m_externalTypes.PushLast(st); + + if (!decl->isExistingShared) + { + // Create a new object type for this class + st = asNEW(asCObjectType)(engine); + if (st == 0) + return asOUT_OF_MEMORY; + + // By default all script classes are marked as garbage collected. + // Only after the complete structure and relationship between classes + // is known, can the flag be cleared for those objects that truly cannot + // form circular references. This is important because a template + // callback may be called with a script class before the compilation + // completes, and until it is known, the callback must assume the class + // is garbage collected. + st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_GC; + + if (isShared) + st->flags |= asOBJ_SHARED; + + if (isFinal) + st->flags |= asOBJ_NOINHERIT; + + if (isAbstract) + st->flags |= asOBJ_ABSTRACT; + + if (node->tokenType == ttHandle) + st->flags |= asOBJ_IMPLICIT_HANDLE; + + st->size = sizeof(asCScriptObject); + st->name = name; + st->nameSpace = ns; + st->module = module; + module->AddClassType(st); + if (isShared) + { + engine->sharedScriptTypes.PushLast(st); + st->AddRefInternal(); + } + decl->typeInfo = st; + + // Use the default script class behaviours + st->beh = engine->scriptTypeBehaviours.beh; + + // TODO: Move this to asCObjectType so that the asCRestore can reuse it + engine->scriptFunctions[st->beh.addref]->AddRefInternal(); + engine->scriptFunctions[st->beh.release]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcEnumReferences]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcGetFlag]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcGetRefCount]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcReleaseAllReferences]->AddRefInternal(); + engine->scriptFunctions[st->beh.gcSetFlag]->AddRefInternal(); + engine->scriptFunctions[st->beh.copy]->AddRefInternal(); + engine->scriptFunctions[st->beh.factory]->AddRefInternal(); + engine->scriptFunctions[st->beh.construct]->AddRefInternal(); + // TODO: weak: Should not do this if the class has been declared with noweak + engine->scriptFunctions[st->beh.getWeakRefFlag]->AddRefInternal(); + + // Skip to the content of the class + while (n && n->nodeType == snIdentifier) + n = n->next; + } + + // Register possible child types + while (n) + { + node = n->next; + if (n->nodeType == snFuncDef) + { + n->DisconnectParent(); + if (!decl->isExistingShared) + RegisterFuncDef(n, file, 0, st); + else + { + // Destroy the node, since it won't be used + // TODO: Should verify that the funcdef is identical to the one in the existing shared class + n->Destroy(engine); + } + } + n = node; + } + + return 0; +} + +int asCBuilder::RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +{ + asCScriptNode *n = node->firstChild; + + bool isShared = false; + bool isExternal = false; + while( n->nodeType == snIdentifier ) + { + if (file->TokenEquals(n->tokenPos, n->tokenLength, SHARED_TOKEN)) + isShared = true; + else if (file->TokenEquals(n->tokenPos, n->tokenLength, EXTERNAL_TOKEN)) + isExternal = true; + else + break; + n = n->next; + } + + int r, c; + file->ConvertPosToRowCol(n->tokenPos, &r, &c); + + asCString name; + name.Assign(&file->code[n->tokenPos], n->tokenLength); + CheckNameConflict(name.AddressOf(), n, file, ns, true, false); + + sClassDeclaration *decl = asNEW(sClassDeclaration); + if( decl == 0 ) + { + node->Destroy(engine); + return asOUT_OF_MEMORY; + } + + interfaceDeclarations.PushLast(decl); + decl->name = name; + decl->script = file; + decl->node = node; + + // External shared interfaces must not try to redefine the interface + if (isExternal && (n->next == 0 || n->next->tokenType != ttEndStatement) ) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, n); + } + else if (!isExternal && n->next && n->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, n); + } + + // If this type is shared and there already exist another shared + // type of the same name, then that one should be used instead of + // creating a new one. + if( isShared ) + { + for( asUINT i = 0; i < engine->sharedScriptTypes.GetLength(); i++ ) + { + asCObjectType *st = CastToObjectType(engine->sharedScriptTypes[i]); + if( st && + st->IsShared() && + st->name == name && + st->nameSpace == ns && + st->IsInterface() ) + { + // We'll use the existing type + decl->isExistingShared = true; + decl->typeInfo = st; + module->AddClassType(st); + st->AddRefInternal(); + + // Remember if the interface was declared as external so the saved bytecode can be flagged accordingly + if (isExternal) + module->m_externalTypes.PushLast(st); + + return 0; + } + } + } + + // If the interface was declared as external then it must have been compiled in a different module first + if (isExternal) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, n); + } + + // Register the object type for the interface + asCObjectType *st = asNEW(asCObjectType)(engine); + if( st == 0 ) + return asOUT_OF_MEMORY; + + st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT; + + if( isShared ) + st->flags |= asOBJ_SHARED; + + st->size = 0; // Cannot be instantiated + st->name = name; + st->nameSpace = ns; + st->module = module; + module->AddClassType(st); + if( isShared ) + { + engine->sharedScriptTypes.PushLast(st); + st->AddRefInternal(); + } + decl->typeInfo = st; + + // Use the default script class behaviours + st->beh.construct = 0; + st->beh.addref = engine->scriptTypeBehaviours.beh.addref; + engine->scriptFunctions[st->beh.addref]->AddRefInternal(); + st->beh.release = engine->scriptTypeBehaviours.beh.release; + engine->scriptFunctions[st->beh.release]->AddRefInternal(); + st->beh.copy = 0; + + return 0; +} + +void asCBuilder::CompileGlobalVariables() +{ + bool compileSucceeded = true; + + // Store state of compilation (errors, warning, output) + int currNumErrors = numErrors; + int currNumWarnings = numWarnings; + + // Backup the original message stream + bool msgCallback = engine->msgCallback; + asSSystemFunctionInterface msgCallbackFunc = engine->msgCallbackFunc; + void *msgCallbackObj = engine->msgCallbackObj; + + // Set the new temporary message stream + asCOutputBuffer outBuffer; + engine->SetMessageCallback(asMETHOD(asCOutputBuffer, Callback), &outBuffer, asCALL_THISCALL); + + asCOutputBuffer finalOutput; + asCScriptFunction *initFunc = 0; + + asCSymbolTable initOrder; + + // We first try to compile all the primitive global variables, and only after that + // compile the non-primitive global variables. This permits the constructors + // for the complex types to use the already initialized variables of primitive + // type. Note, we currently don't know which global variables are used in the + // constructors, so we cannot guarantee that variables of complex types are + // initialized in the correct order, so we won't reorder those. + bool compilingPrimitives = true; + + // Compile each global variable + while( compileSucceeded ) + { + compileSucceeded = false; + + int accumErrors = 0; + int accumWarnings = 0; + + // Restore state of compilation + finalOutput.Clear(); + asCSymbolTable::iterator it = globVariables.List(); + for( ; it; it++ ) + { + sGlobalVariableDescription *gvar = *it; + if( gvar->isCompiled ) + continue; + + asCByteCode init(engine); + numWarnings = 0; + numErrors = 0; + outBuffer.Clear(); + + // Skip this for now if we're not compiling complex types yet + if( compilingPrimitives && !gvar->datatype.IsPrimitive() ) + continue; + + if( gvar->declaredAtNode ) + { + int r, c; + gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &r, &c); + asCString str = gvar->datatype.Format(gvar->ns); + str += " " + gvar->name; + str.Format(TXT_COMPILING_s, str.AddressOf()); + WriteInfo(gvar->script->name, str, r, c, true); + } + + if( gvar->isEnumValue ) + { + int r; + if( gvar->initializationNode ) + { + asCCompiler comp(engine); + asCScriptFunction func(engine, module, asFUNC_SCRIPT); + + // Set the namespace that should be used during the compilation + func.nameSpace = gvar->datatype.GetTypeInfo()->nameSpace; + + // Temporarily switch the type of the variable to int so it can be compiled properly + asCDataType saveType; + saveType = gvar->datatype; + gvar->datatype = asCDataType::CreatePrimitive(ttInt, true); + r = comp.CompileGlobalVariable(this, gvar->script, gvar->initializationNode, gvar, &func); + gvar->datatype = saveType; + + // Make the function a dummy so it doesn't try to release objects while destroying the function + func.funcType = asFUNC_DUMMY; + } + else + { + r = 0; + + // When there is no assignment the value is the last + 1 + int enumVal = 0; + asCSymbolTable::iterator prev_it = it; + prev_it--; + if( prev_it ) + { + sGlobalVariableDescription *gvar2 = *prev_it; + if(gvar2->datatype == gvar->datatype ) + { + enumVal = int(gvar2->constantValue) + 1; + + if( !gvar2->isCompiled ) + { + int row, col; + gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &row, &col); + + asCString str = gvar->datatype.Format(gvar->ns); + str += " " + gvar->name; + str.Format(TXT_COMPILING_s, str.AddressOf()); + WriteInfo(gvar->script->name, str, row, col, true); + + str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, gvar2->name.AddressOf()); + WriteError(gvar->script->name, str, row, col); + r = -1; + } + } + } + + gvar->constantValue = enumVal; + } + + if( r >= 0 ) + { + // Set the value as compiled + gvar->isCompiled = true; + compileSucceeded = true; + } + } + else + { + // Compile the global variable + initFunc = asNEW(asCScriptFunction)(engine, module, asFUNC_SCRIPT); + if( initFunc == 0 ) + { + // Out of memory + return; + } + + // Set the namespace that should be used for this function + initFunc->nameSpace = gvar->ns; + + asCCompiler comp(engine); + int r = comp.CompileGlobalVariable(this, gvar->script, gvar->initializationNode, gvar, initFunc); + if( r >= 0 ) + { + // Compilation succeeded + gvar->isCompiled = true; + compileSucceeded = true; + } + else + { + // Compilation failed + initFunc->funcType = asFUNC_DUMMY; + asDELETE(initFunc, asCScriptFunction); + initFunc = 0; + } + } + + if( gvar->isCompiled ) + { + // Add warnings for this constant to the total build + if( numWarnings ) + { + currNumWarnings += numWarnings; + if( msgCallback ) + outBuffer.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj); + } + + // Determine order of variable initializations + if( gvar->property && !gvar->isEnumValue ) + initOrder.Put(gvar->property); + + // Does the function contain more than just a SUSPEND followed by a RET instruction? + if( initFunc && initFunc->scriptData->byteCode.GetLength() > 2 ) + { + // Create the init function for this variable + initFunc->id = engine->GetNextScriptFunctionId(); + engine->AddScriptFunction(initFunc); + + // Finalize the init function for this variable + initFunc->returnType = asCDataType::CreatePrimitive(ttVoid, false); + initFunc->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(gvar->script->name.AddressOf()); + if( gvar->declaredAtNode ) + { + int row, col; + gvar->script->ConvertPosToRowCol(gvar->declaredAtNode->tokenPos, &row, &col); + initFunc->scriptData->declaredAt = (row & 0xFFFFF)|((col & 0xFFF)<<20); + } + + gvar->property->SetInitFunc(initFunc); + + initFunc->ReleaseInternal(); + initFunc = 0; + } + else if( initFunc ) + { + // Destroy the function as it won't be used + initFunc->funcType = asFUNC_DUMMY; + asDELETE(initFunc, asCScriptFunction); + initFunc = 0; + } + + // Convert enums to true enum values, so subsequent compilations can access it as an enum + if( gvar->isEnumValue ) + { + asCEnumType *enumType = CastToEnumType(gvar->datatype.GetTypeInfo()); + asASSERT(NULL != enumType); + + asSEnumValue *e = asNEW(asSEnumValue); + if( e == 0 ) + { + // Out of memory + numErrors++; + return; + } + + e->name = gvar->name; + e->value = int(gvar->constantValue); + + enumType->enumValues.PushLast(e); + } + } + else + { + // Add output to final output + finalOutput.Append(outBuffer); + accumErrors += numErrors; + accumWarnings += numWarnings; + } + + engine->preMessage.isSet = false; + } + + if( !compileSucceeded ) + { + if( compilingPrimitives ) + { + // No more primitives could be compiled, so + // switch to compiling the complex variables + compilingPrimitives = false; + compileSucceeded = true; + } + else + { + // No more variables can be compiled + // Add errors and warnings to total build + currNumWarnings += accumWarnings; + currNumErrors += accumErrors; + if( msgCallback ) + finalOutput.SendToCallback(engine, &msgCallbackFunc, msgCallbackObj); + } + } + } + + // Restore states + engine->msgCallback = msgCallback; + engine->msgCallbackFunc = msgCallbackFunc; + engine->msgCallbackObj = msgCallbackObj; + + numWarnings = currNumWarnings; + numErrors = currNumErrors; + + // Set the correct order of initialization + if( numErrors == 0 ) + { + // If the length of the arrays are not the same, then this is the compilation + // of a single variable, in which case the initialization order of the previous + // variables must be preserved. + if( module->m_scriptGlobals.GetSize() == initOrder.GetSize() ) + module->m_scriptGlobals.SwapWith(initOrder); + } + + CleanupEnumValues(); +} + +void asCBuilder::CleanupEnumValues() +{ + // Delete the enum expressions + asCSymbolTableIterator it = globVariables.List(); + while (it) + { + sGlobalVariableDescription *gvar = *it; + if (gvar->isEnumValue) + { + // Remove from symboltable. This has to be done prior to freeing the memeory + globVariables.Erase(it.GetIndex()); + + // Destroy the gvar property + if (gvar->declaredAtNode) + { + gvar->declaredAtNode->Destroy(engine); + gvar->declaredAtNode = 0; + } + if (gvar->initializationNode) + { + gvar->initializationNode->Destroy(engine); + gvar->initializationNode = 0; + } + if (gvar->property) + { + asDELETE(gvar->property, asCGlobalProperty); + gvar->property = 0; + } + + asDELETE(gvar, sGlobalVariableDescription); + } + else + it++; + } +} + +int asCBuilder::GetNamespaceAndNameFromNode(asCScriptNode *n, asCScriptCode *script, asSNameSpace *implicitNs, asSNameSpace *&outNs, asCString &outName) +{ + // TODO: child funcdef: The node might be a snScope now + asASSERT( n->nodeType == snIdentifier ); + + // Get the optional scope from the node + // TODO: child funcdef: The parentType will be set if the scope is actually a type rather than a namespace + asSNameSpace *ns = GetNameSpaceFromNode(n->firstChild, script, implicitNs, 0); + if( ns == 0 ) + return -1; + + // Get the name + asCString name(&script->code[n->lastChild->tokenPos], n->lastChild->tokenLength); + + outNs = ns; + outName = name; + + return 0; +} + +void asCBuilder::AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScriptNode *errNode, sMixinClass *mixin) +{ + // Determine what interfaces that the mixin implements + asCScriptNode *node = mixin->node; + asASSERT(node->nodeType == snClass); + + // Skip the name of the mixin + node = node->firstChild->next; + + + while( node && node->nodeType == snIdentifier ) + { + bool ok = true; + asSNameSpace *ns; + asCString name; + if( GetNamespaceAndNameFromNode(node, mixin->script, mixin->ns, ns, name) < 0 ) + ok = false; + else + { + // Find the object type for the interface + asCObjectType *objType = GetObjectType(name.AddressOf(), ns); + + // Check that the object type is an interface + if( objType && objType->IsInterface() ) + { + // Only add the interface if the class doesn't already implement it + if( !decl->typeInfo->Implements(objType) ) + AddInterfaceToClass(decl, errNode, objType); + } + else + { + WriteError(TXT_MIXIN_CLASS_CANNOT_INHERIT, mixin->script, node); + ok = false; + } + } + + if( !ok ) + { + // Remove this node so the error isn't reported again + asCScriptNode *delNode = node; + node = node->prev; + delNode->DisconnectParent(); + delNode->Destroy(engine); + } + + node = node->next; + } +} + +void asCBuilder::AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *errNode, asCObjectType *intfType) +{ + // A shared type may only implement from shared interfaces + if( decl->typeInfo->IsShared() && !intfType->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, intfType->name.AddressOf()); + WriteError(msg, decl->script, errNode); + return; + } + + if( decl->isExistingShared ) + { + // If the class is an existing shared class, then just check if the + // interface exists in the original declaration too + if( !decl->typeInfo->Implements(intfType) ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); + WriteError(str, decl->script, errNode); + return; + } + } + else + { + // If the interface is already in the class then don't add it again + if( decl->typeInfo->Implements(intfType) ) + return; + + // Add the interface to the class + CastToObjectType(decl->typeInfo)->interfaces.PushLast(intfType); + + // Add the inherited interfaces too + // For interfaces this will be done outside to handle out-of-order declarations + if( !CastToObjectType(decl->typeInfo)->IsInterface() ) + { + for( asUINT n = 0; n < intfType->interfaces.GetLength(); n++ ) + AddInterfaceToClass(decl, errNode, intfType->interfaces[n]); + } + } +} + +void asCBuilder::CompileInterfaces() +{ + asUINT n; + + // Order the interfaces with inheritances so that the inherited + // of inherited interfaces can be added properly + for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) + { + sClassDeclaration *intfDecl = interfaceDeclarations[n]; + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); + + if( intfType->interfaces.GetLength() == 0 ) continue; + + // If any of the derived interfaces are found after this interface, then move this to the end of the list + for( asUINT m = n+1; m < interfaceDeclarations.GetLength(); m++ ) + { + if( intfType->Implements(interfaceDeclarations[m]->typeInfo) ) + { + interfaceDeclarations.RemoveIndex(n); + interfaceDeclarations.PushLast(intfDecl); + + // Decrease index so that we don't skip an entry + n--; + break; + } + } + } + + // Now recursively add the additional inherited interfaces + for( n = 0; n < interfaceDeclarations.GetLength(); n++ ) + { + sClassDeclaration *intfDecl = interfaceDeclarations[n]; + if( intfDecl->isExistingShared ) + { + // Set the declaration as validated already, so that other + // types that contain this will accept this type + intfDecl->validState = 1; + continue; + } + + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); + + // TODO: Is this really at the correct place? Hasn't the vfTableIdx already been set here? + // Co-opt the vfTableIdx value in our own methods to indicate the + // index the function should have in the table chunk for this interface. + for( asUINT d = 0; d < intfType->methods.GetLength(); d++ ) + { + asCScriptFunction *func = GetFunctionDescription(intfType->methods[d]); + func->vfTableIdx = d; + + asASSERT(func->objectType == intfType); + } + + // As new interfaces will be added to the end of the list, all + // interfaces will be traversed the same as recursively + for( asUINT m = 0; m < intfType->interfaces.GetLength(); m++ ) + { + asCObjectType *base = intfType->interfaces[m]; + + // Add any interfaces not already implemented + for( asUINT l = 0; l < base->interfaces.GetLength(); l++ ) + AddInterfaceToClass(intfDecl, intfDecl->node, base->interfaces[l]); + + // Add the methods from the implemented interface + for( asUINT l = 0; l < base->methods.GetLength(); l++ ) + { + // If the derived interface implements the same method, then don't add the base interface' method + asCScriptFunction *baseFunc = GetFunctionDescription(base->methods[l]); + asCScriptFunction *derivedFunc = 0; + bool found = false; + for( asUINT d = 0; d < intfType->methods.GetLength(); d++ ) + { + derivedFunc = GetFunctionDescription(intfType->methods[d]); + if( derivedFunc->IsSignatureEqual(baseFunc) ) + { + found = true; + break; + } + } + + if( !found ) + { + // Add the method + intfType->methods.PushLast(baseFunc->id); + baseFunc->AddRefInternal(); + } + } + } + } +} + +void asCBuilder::DetermineTypeRelations() +{ + // Determine inheritance between interfaces + for (asUINT n = 0; n < interfaceDeclarations.GetLength(); n++) + { + sClassDeclaration *intfDecl = interfaceDeclarations[n]; + asCObjectType *intfType = CastToObjectType(intfDecl->typeInfo); + + asCScriptNode *node = intfDecl->node; + asASSERT(node && node->nodeType == snInterface); + node = node->firstChild; + + // Skip the 'shared' & 'external' keywords + while( node->nodeType == snIdentifier && + (intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) || + intfDecl->script->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) ) + node = node->next; + + // Skip the name + node = node->next; + + // Verify the inherited interfaces + while (node && node->nodeType == snIdentifier) + { + asSNameSpace *ns; + asCString name; + if (GetNamespaceAndNameFromNode(node, intfDecl->script, intfType->nameSpace, ns, name) < 0) + { + node = node->next; + continue; + } + + // Find the object type for the interface + asCObjectType *objType = 0; + while (ns) + { + objType = GetObjectType(name.AddressOf(), ns); + if (objType) break; + + ns = engine->GetParentNameSpace(ns); + } + + // Check that the object type is an interface + bool ok = true; + if (objType && objType->IsInterface()) + { + // Check that the implemented interface is shared if the base interface is shared + if (intfType->IsShared() && !objType->IsShared()) + { + asCString str; + str.Format(TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s, objType->GetName()); + WriteError(str, intfDecl->script, node); + ok = false; + } + } + else + { + WriteError(TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE, intfDecl->script, node); + ok = false; + } + + if (ok) + { + // Make sure none of the implemented interfaces implement from this one + asCObjectType *base = objType; + while (base != 0) + { + if (base == intfType) + { + WriteError(TXT_CANNOT_IMPLEMENT_SELF, intfDecl->script, node); + ok = false; + break; + } + + // At this point there is at most one implemented interface + if (base->interfaces.GetLength()) + base = base->interfaces[0]; + else + break; + } + } + + if (ok) + AddInterfaceToClass(intfDecl, node, objType); + + // Remove the nodes so they aren't parsed again + asCScriptNode *delNode = node; + node = node->next; + delNode->DisconnectParent(); + delNode->Destroy(engine); + } + } + + // Determine class inheritances and interfaces + for (asUINT n = 0; n < classDeclarations.GetLength(); n++) + { + sClassDeclaration *decl = classDeclarations[n]; + asCScriptCode *file = decl->script; + + // Find the base class that this class inherits from + bool multipleInheritance = false; + asCScriptNode *node = decl->node->firstChild; + + while (file->TokenEquals(node->tokenPos, node->tokenLength, FINAL_TOKEN) || + file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN) || + file->TokenEquals(node->tokenPos, node->tokenLength, ABSTRACT_TOKEN) || + file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) + { + node = node->next; + } + + // Skip the name of the class + asASSERT(node->tokenType == ttIdentifier); + node = node->next; + + while (node && node->nodeType == snIdentifier) + { + asSNameSpace *ns; + asCString name; + if (GetNamespaceAndNameFromNode(node, file, decl->typeInfo->nameSpace, ns, name) < 0) + { + node = node->next; + continue; + } + + // Find the object type for the interface + asCObjectType *objType = 0; + sMixinClass *mixin = 0; + asSNameSpace *origNs = ns; + while (ns) + { + objType = GetObjectType(name.AddressOf(), ns); + if (objType == 0) + mixin = GetMixinClass(name.AddressOf(), ns); + + if (objType || mixin) + break; + + ns = engine->GetParentNameSpace(ns); + } + + if (objType == 0 && mixin == 0) + { + asCString str; + if (origNs->name == "") + str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, name.AddressOf()); + else + str.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, name.AddressOf(), origNs->name.AddressOf()); + WriteError(str, file, node); + } + else if (mixin) + { + AddInterfaceFromMixinToClass(decl, node, mixin); + } + else if (!(objType->flags & asOBJ_SCRIPT_OBJECT) || + (objType->flags & asOBJ_NOINHERIT)) + { + // Either the class is not a script class or interface + // or the class has been declared as 'final' + asCString str; + str.Format(TXT_CANNOT_INHERIT_FROM_s_FINAL, objType->name.AddressOf()); + WriteError(str, file, node); + } + else if (objType->size != 0) + { + // The class inherits from another script class + if (!decl->isExistingShared && CastToObjectType(decl->typeInfo)->derivedFrom != 0) + { + if (!multipleInheritance) + { + WriteError(TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES, file, node); + multipleInheritance = true; + } + } + else + { + // Make sure none of the base classes inherit from this one + asCObjectType *base = objType; + bool error = false; + while (base != 0) + { + if (base == decl->typeInfo) + { + WriteError(TXT_CANNOT_INHERIT_FROM_SELF, file, node); + error = true; + break; + } + + base = base->derivedFrom; + } + + if (!error) + { + // A shared type may only inherit from other shared types + if ((decl->typeInfo->IsShared()) && !(objType->IsShared())) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s, objType->name.AddressOf()); + WriteError(msg, file, node); + error = true; + } + } + + if (!error) + { + if (decl->isExistingShared) + { + // Verify that the base class is the same as the original shared type + if (CastToObjectType(decl->typeInfo)->derivedFrom != objType) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, decl->typeInfo->GetName()); + WriteError(str, file, node); + } + } + else + { + // Set the base class + CastToObjectType(decl->typeInfo)->derivedFrom = objType; + objType->AddRefInternal(); + } + } + } + } + else + { + // The class implements an interface + AddInterfaceToClass(decl, node, objType); + } + + node = node->next; + } + } +} + +// numTempl is the number of template instances that existed in the engine before the build begun +void asCBuilder::CompileClasses(asUINT numTempl) +{ + asUINT n; + asCArray toValidate((int)classDeclarations.GetLength()); + + // Order class declarations so that base classes are compiled before derived classes. + // This will allow the derived classes to copy properties and methods in the next step. + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + sClassDeclaration *decl = classDeclarations[n]; + asCObjectType *derived = CastToObjectType(decl->typeInfo); + asCObjectType *base = derived->derivedFrom; + + if( base == 0 ) continue; + + // If the base class is found after the derived class, then move the derived class to the end of the list + for( asUINT m = n+1; m < classDeclarations.GetLength(); m++ ) + { + sClassDeclaration *declBase = classDeclarations[m]; + if( base == declBase->typeInfo ) + { + classDeclarations.RemoveIndex(n); + classDeclarations.PushLast(decl); + + // Decrease index so that we don't skip an entry + n--; + break; + } + } + } + + // Go through each of the classes and register the object type descriptions + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + sClassDeclaration *decl = classDeclarations[n]; + asCObjectType *ot = CastToObjectType(decl->typeInfo); + if( decl->isExistingShared ) + { + // Set the declaration as validated already, so that other + // types that contain this will accept this type + decl->validState = 1; + + // We'll still validate the declaration to make sure nothing new is + // added to the shared class that wasn't there in the previous + // compilation. We do not care if something that is there in the previous + // declaration is not included in the new declaration though. + + asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); + } + + // Methods included from mixin classes should take precedence over inherited methods + IncludeMethodsFromMixins(decl); + + // Add all properties and methods from the base class + if( !decl->isExistingShared && ot->derivedFrom ) + { + asCObjectType *baseType = ot->derivedFrom; + + // The derived class inherits all interfaces from the base class + for( unsigned int m = 0; m < baseType->interfaces.GetLength(); m++ ) + { + if( !ot->Implements(baseType->interfaces[m]) ) + ot->interfaces.PushLast(baseType->interfaces[m]); + } + + // TODO: Need to check for name conflict with new class methods + + // Copy properties from base class to derived class + for( asUINT p = 0; p < baseType->properties.GetLength(); p++ ) + { + asCObjectProperty *prop = AddPropertyToClass(decl, baseType->properties[p]->name, baseType->properties[p]->type, baseType->properties[p]->isPrivate, baseType->properties[p]->isProtected, true); + + // The properties must maintain the same offset + asASSERT(prop && prop->byteOffset == baseType->properties[p]->byteOffset); UNUSED_VAR(prop); + } + + // Copy methods from base class to derived class + for( asUINT m = 0; m < baseType->methods.GetLength(); m++ ) + { + // If the derived class implements the same method, then don't add the base class' method + asCScriptFunction *baseFunc = GetFunctionDescription(baseType->methods[m]); + asCScriptFunction *derivedFunc = 0; + bool found = false; + for( asUINT d = 0; d < ot->methods.GetLength(); d++ ) + { + derivedFunc = GetFunctionDescription(ot->methods[d]); + if( baseFunc->name == "opConv" || baseFunc->name == "opImplConv" || + baseFunc->name == "opCast" || baseFunc->name == "opImplCast" ) + { + // For the opConv and opCast methods, the return type can differ if they are different methods + if( derivedFunc->name == baseFunc->name && + derivedFunc->IsSignatureExceptNameEqual(baseFunc) ) + { + if( baseFunc->IsFinal() ) + { + asCString msg; + msg.Format(TXT_METHOD_CANNOT_OVERRIDE_s, baseFunc->GetDeclaration()); + WriteError(msg, decl->script, decl->node); + } + + // Move the function from the methods array to the virtualFunctionTable + ot->methods.RemoveIndex(d); + ot->virtualFunctionTable.PushLast(derivedFunc); + found = true; + break; + } + } + else + { + if( derivedFunc->name == baseFunc->name && + derivedFunc->IsSignatureExceptNameAndReturnTypeEqual(baseFunc) ) + { + if( baseFunc->returnType != derivedFunc->returnType ) + { + asCString msg; + msg.Format(TXT_DERIVED_METHOD_MUST_HAVE_SAME_RETTYPE_s, baseFunc->GetDeclaration()); + WriteError(msg, decl->script, decl->node); + } + + if( baseFunc->IsFinal() ) + { + asCString msg; + msg.Format(TXT_METHOD_CANNOT_OVERRIDE_s, baseFunc->GetDeclaration()); + WriteError(msg, decl->script, decl->node); + } + + // Move the function from the methods array to the virtualFunctionTable + ot->methods.RemoveIndex(d); + ot->virtualFunctionTable.PushLast(derivedFunc); + found = true; + break; + } + } + } + + if( !found ) + { + // Push the base class function on the virtual function table + ot->virtualFunctionTable.PushLast(baseType->virtualFunctionTable[m]); + baseType->virtualFunctionTable[m]->AddRefInternal(); + + CheckForConflictsDueToDefaultArgs(decl->script, decl->node, baseType->virtualFunctionTable[m], ot); + } + + ot->methods.PushLast(baseType->methods[m]); + engine->scriptFunctions[baseType->methods[m]]->AddRefInternal(); + } + } + + if( !decl->isExistingShared ) + { + // Move this class' methods into the virtual function table + for( asUINT m = 0; m < ot->methods.GetLength(); m++ ) + { + asCScriptFunction *func = GetFunctionDescription(ot->methods[m]); + if( func->funcType != asFUNC_VIRTUAL ) + { + // Move the reference from the method list to the virtual function list + ot->methods.RemoveIndex(m); + ot->virtualFunctionTable.PushLast(func); + + // Substitute the function description in the method list for a virtual method + // Make sure the methods are in the same order as the virtual function table + ot->methods.PushLast(CreateVirtualFunction(func, (int)ot->virtualFunctionTable.GetLength() - 1)); + m--; + } + } + + // Make virtual function table chunks for each implemented interface + for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) + { + asCObjectType *intf = ot->interfaces[m]; + + // Add all the interface's functions to the virtual function table + asUINT offset = asUINT(ot->virtualFunctionTable.GetLength()); + ot->interfaceVFTOffsets.PushLast(offset); + + for( asUINT j = 0; j < intf->methods.GetLength(); j++ ) + { + asCScriptFunction *intfFunc = GetFunctionDescription(intf->methods[j]); + + // Only create the table for functions that are explicitly from this interface, + // inherited interface methods will be put in that interface's table. + if( intfFunc->objectType != intf ) + continue; + + asASSERT((asUINT)intfFunc->vfTableIdx == j); + + //Find the interface function in the list of methods + asCScriptFunction *realFunc = 0; + for( asUINT p = 0; p < ot->methods.GetLength(); p++ ) + { + asCScriptFunction *func = GetFunctionDescription(ot->methods[p]); + + if( func->signatureId == intfFunc->signatureId ) + { + if( func->funcType == asFUNC_VIRTUAL ) + { + realFunc = ot->virtualFunctionTable[func->vfTableIdx]; + } + else + { + // This should not happen, all methods were moved into the virtual table + asASSERT(false); + } + break; + } + } + + // If realFunc is still null, the interface was not + // implemented and we error out later in the checks. + ot->virtualFunctionTable.PushLast(realFunc); + if( realFunc ) + realFunc->AddRefInternal(); + } + } + } + + // Enumerate each of the declared properties + asCScriptNode *node = decl->node->firstChild->next; + + // Skip list of classes and interfaces + while( node && node->nodeType == snIdentifier ) + node = node->next; + + while( node && node->nodeType == snDeclaration ) + { + asCScriptNode *nd = node->firstChild; + + // Is the property declared as private or protected? + bool isPrivate = false, isProtected = false; + if( nd && nd->tokenType == ttPrivate ) + { + isPrivate = true; + nd = nd->next; + } + else if( nd && nd->tokenType == ttProtected ) + { + isProtected = true; + nd = nd->next; + } + + // Determine the type of the property + asCScriptCode *file = decl->script; + asCDataType dt = CreateDataTypeFromNode(nd, file, ot->nameSpace, false, ot); + if( ot->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + WriteError(msg, file, node); + } + + if( dt.IsReadOnly() ) + WriteError(TXT_PROPERTY_CANT_BE_CONST, file, node); + + // Multiple properties can be declared separated by , + nd = nd->next; + while( nd ) + { + asCString name(&file->code[nd->tokenPos], nd->tokenLength); + + if( !decl->isExistingShared ) + { + CheckNameConflictMember(ot, name.AddressOf(), nd, file, true, false); + AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, nd); + } + else + { + // Verify that the property exists in the original declaration + bool found = false; + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + { + asCObjectProperty *prop = ot->properties[p]; + if( prop->isPrivate == isPrivate && + prop->isProtected == isProtected && + prop->name == name && + prop->type.IsEqualExceptRef(dt) ) + { + found = true; + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + WriteError(str, file, nd); + } + } + + // Skip the initialization node + if( nd->next && nd->next->nodeType != snIdentifier ) + nd = nd->next; + + nd = nd->next; + } + + node = node->next; + } + + // Add properties from included mixin classes that don't conflict with existing properties + IncludePropertiesFromMixins(decl); + + if( !decl->isExistingShared ) + toValidate.PushLast(decl); + + asASSERT( ot->interfaces.GetLength() == ot->interfaceVFTOffsets.GetLength() ); + } + + // TODO: Warn if a method overrides a base method without marking it as 'override'. + // It must be possible to turn off this warning through engine property. + + // TODO: A base class should be able to mark a method as 'abstract'. This will + // allow a base class to provide a partial implementation, but still force + // derived classes to implement specific methods. + + // Verify that all interface methods are implemented in the classes + // We do this here so the base class' methods have already been inherited + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + sClassDeclaration *decl = classDeclarations[n]; + if( decl->isExistingShared ) continue; + + asCObjectType *ot = CastToObjectType(decl->typeInfo); + asCArray overrideValidations(ot->GetMethodCount()); + for( asUINT k = 0; k < ot->methods.GetLength(); k++ ) + overrideValidations.PushLast( !static_cast(ot->GetMethodByIndex(k, false))->IsOverride() ); + + for( asUINT m = 0; m < ot->interfaces.GetLength(); m++ ) + { + asCObjectType *objType = ot->interfaces[m]; + for( asUINT i = 0; i < objType->methods.GetLength(); i++ ) + { + // Only check the interface methods that was explicitly declared in this interface + // Methods that was inherited from other interfaces will be checked in those interfaces + if( objType != engine->scriptFunctions[objType->methods[i]]->objectType ) + continue; + + asUINT overrideIndex; + if( !DoesMethodExist(ot, objType->methods[i], &overrideIndex) ) + { + asCString str; + str.Format(TXT_MISSING_IMPLEMENTATION_OF_s, + engine->GetFunctionDeclaration(objType->methods[i]).AddressOf()); + WriteError(str, decl->script, decl->node); + } + else + overrideValidations[overrideIndex] = true; + } + } + + bool hasBaseClass = ot->derivedFrom != 0; + + for( asUINT j = 0; j < overrideValidations.GetLength(); j++ ) + { + if( !overrideValidations[j] && (!hasBaseClass || !DoesMethodExist(ot->derivedFrom, ot->methods[j])) ) + { + asCString msg; + msg.Format(TXT_METHOD_s_DOES_NOT_OVERRIDE, ot->GetMethodByIndex(j, false)->GetDeclaration()); + WriteError(msg, decl->script, decl->node); + } + } + } + + // Verify that the declared structures are valid, e.g. that the structure + // doesn't contain a member of its own type directly or indirectly + while( toValidate.GetLength() > 0 ) + { + asUINT numClasses = (asUINT)toValidate.GetLength(); + + asCArray toValidateNext((int)toValidate.GetLength()); + while( toValidate.GetLength() > 0 ) + { + sClassDeclaration *decl = toValidate[toValidate.GetLength()-1]; + asCObjectType *ot = CastToObjectType(decl->typeInfo); + int validState = 1; + for( n = 0; n < ot->properties.GetLength(); n++ ) + { + // A valid structure is one that uses only primitives or other valid objects + asCObjectProperty *prop = ot->properties[n]; + asCDataType dt = prop->type; + + // TODO: Add this check again, once solving the issues commented below + /* + if( dt.IsTemplate() ) + { + // TODO: This must verify all sub types, not just the first one + // TODO: Just because the subtype is not a handle doesn't mean the template will actually instance the object + // this it shouldn't automatically raise an error for this, e.g. weakref should be legal as member + // of the Object class + asCDataType sub = dt; + while( sub.IsTemplate() && !sub.IsObjectHandle() ) + sub = sub.GetSubType(); + + dt = sub; + } + */ + + if( dt.IsObject() && !dt.IsObjectHandle() ) + { + // Find the class declaration + sClassDeclaration *pdecl = 0; + for( asUINT p = 0; p < classDeclarations.GetLength(); p++ ) + { + if( classDeclarations[p]->typeInfo == dt.GetTypeInfo() ) + { + pdecl = classDeclarations[p]; + break; + } + } + + if( pdecl ) + { + if( pdecl->typeInfo == decl->typeInfo ) + { + WriteError(TXT_ILLEGAL_MEMBER_TYPE, decl->script, decl->node); + validState = 2; + break; + } + else if( pdecl->validState != 1 ) + { + validState = pdecl->validState; + break; + } + } + } + } + + if( validState == 1 ) + { + decl->validState = 1; + toValidate.PopLast(); + } + else if( validState == 2 ) + { + decl->validState = 2; + toValidate.PopLast(); + } + else + { + toValidateNext.PushLast(toValidate.PopLast()); + } + } + + toValidate = toValidateNext; + toValidateNext.SetLength(0); + + if( numClasses == toValidate.GetLength() ) + { + WriteError(TXT_ILLEGAL_MEMBER_TYPE, toValidate[0]->script, toValidate[0]->node); + break; + } + } + + if( numErrors > 0 ) return; + + // Verify which script classes can really form circular references, and mark only those as garbage collected. + // This must be done in the correct order, so that a class that contains another class isn't needlessly marked + // as garbage collected, just because the contained class was evaluated afterwards. + + // TODO: runtime optimize: This algorithm can be further improved by checking the types that inherits from + // a base class. If the base class is not shared all the classes that derive from it + // are known at compile time, and can thus be checked for potential circular references too. + // + // Observe, that doing this would conflict with another potential future feature, which is to + // allow incremental builds, i.e. allow application to add or replace classes in an + // existing module. However, the applications that want to use that should use a special + // build flag to not finalize the module. + + asCArray typesToValidate; + for( n = 0; n < classDeclarations.GetLength(); n++ ) + { + // Existing shared classes won't need evaluating, nor interfaces + sClassDeclaration *decl = classDeclarations[n]; + if( decl->isExistingShared ) continue; + + asCObjectType *ot = CastToObjectType(decl->typeInfo); + if( ot->IsInterface() ) continue; + + typesToValidate.PushLast(ot); + } + + asUINT numReevaluations = 0; + while( typesToValidate.GetLength() ) + { + if( numReevaluations > typesToValidate.GetLength() ) + { + // No types could be completely evaluated in the last iteration so + // we consider the remaining types in the array as garbage collected + break; + } + + asCObjectType *type = typesToValidate[0]; + typesToValidate.RemoveIndex(0); + + // If the type inherits from another type that is yet to be validated, then reinsert it at the end + if( type->derivedFrom && typesToValidate.Exists(type->derivedFrom) ) + { + typesToValidate.PushLast(type); + numReevaluations++; + continue; + } + + // If the type inherits from a known garbage collected type, then this type must also be garbage collected + if( type->derivedFrom && (type->derivedFrom->flags & asOBJ_GC) ) + { + type->flags |= asOBJ_GC; + continue; + } + + // Evaluate template instances (silently) before verifying each of the classes, since it is possible that + // a class will be marked as non-garbage collected, which in turn will mark the template instance that uses + // it as non-garbage collected, which in turn means the class that contains the array also do not have to be + // garbage collected + EvaluateTemplateInstances(numTempl, true); + + // Is there some path in which this structure is involved in circular references? + // If the type contains a member of a type that is yet to be validated, then reinsert it at the end + bool mustReevaluate = false; + bool gc = false; + for( asUINT p = 0; p < type->properties.GetLength(); p++ ) + { + asCDataType dt = type->properties[p]->type; + + if (dt.IsFuncdef()) + { + // If a class holds a function pointer as member then the class must be garbage collected as the + // function pointer can form circular references with the class through use of a delegate. Example: + // + // class A { B @b; void f(); } + // class B { F @f; } + // funcdef void F(); + // + // A a; + // @a.b = B(); // instance of A refers to instance of B + // @a.b.f = F(a.f); // instance of B refers to delegate that refers to instance of A + // + gc = true; + break; + } + + if( !dt.IsObject() ) + continue; + + if( typesToValidate.Exists(CastToObjectType(dt.GetTypeInfo())) ) + mustReevaluate = true; + else + { + if( dt.IsTemplate() ) + { + // Check if any of the subtypes are yet to be evaluated + bool skip = false; + for( asUINT s = 0; s < dt.GetTypeInfo()->GetSubTypeCount(); s++ ) + { + asCObjectType *t = reinterpret_cast(dt.GetTypeInfo()->GetSubType(s)); + if( typesToValidate.Exists(t) ) + { + mustReevaluate = true; + skip = true; + break; + } + } + if( skip ) + continue; + } + + if( dt.IsObjectHandle() ) + { + // If it is known that the handle can't be involved in a circular reference + // then this object doesn't need to be marked as garbage collected. + asCObjectType *prop = CastToObjectType(dt.GetTypeInfo()); + + if( prop->flags & asOBJ_SCRIPT_OBJECT ) + { + // For script objects, treat non-final classes as if they can contain references + // as it is not known what derived classes might do. For final types, check all + // properties to determine if any of those can cause a circular reference with this + // class. + if( prop->flags & asOBJ_NOINHERIT ) + { + for( asUINT sp = 0; sp < prop->properties.GetLength(); sp++ ) + { + asCDataType sdt = prop->properties[sp]->type; + + if( sdt.IsObject() ) + { + if( sdt.IsObjectHandle() ) + { + // TODO: runtime optimize: If the handle is again to a final class, then we can recursively check if the circular reference can occur + if( sdt.GetTypeInfo()->flags & (asOBJ_SCRIPT_OBJECT | asOBJ_GC) ) + { + gc = true; + break; + } + } + else if( sdt.GetTypeInfo()->flags & asOBJ_GC ) + { + // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. + // Only if the object is of a type that can reference this type, either directly or indirectly + gc = true; + break; + } + } + } + + if( gc ) + break; + } + else + { + // Assume it is garbage collected as it is not known at compile time what might inherit from this type + gc = true; + break; + } + } + else if( prop->flags & asOBJ_GC ) + { + // If a type is not a script object, adopt its GC flag + // TODO: runtime optimize: Just because an application registered class is garbage collected, doesn't mean it + // can form a circular reference with this script class. Perhaps need a flag to tell + // if the script classes that contains the type should be garbage collected or not. + gc = true; + break; + } + } + else if( dt.GetTypeInfo()->flags & asOBJ_GC ) + { + // TODO: runtime optimize: Just because the member type is a potential circle doesn't mean that this one is. + // Only if the object is of a type that can reference this type, either directly or indirectly + gc = true; + break; + } + } + } + + // If the class wasn't found to require garbage collection, but it + // contains another type that has yet to be evaluated then it must be + // re-evaluated. + if( !gc && mustReevaluate ) + { + typesToValidate.PushLast(type); + numReevaluations++; + continue; + } + + // Update the flag in the object type + if( gc ) + type->flags |= asOBJ_GC; + else + type->flags &= ~asOBJ_GC; + + // Reset the counter + numReevaluations = 0; + } +} + +void asCBuilder::IncludeMethodsFromMixins(sClassDeclaration *decl) +{ + asCScriptNode *node = decl->node->firstChild; + + // Skip the class attributes + while( node->nodeType == snIdentifier && + !decl->script->TokenEquals(node->tokenPos, node->tokenLength, decl->name.AddressOf()) ) + node = node->next; + + // Skip the name of the class + node = node->next; + + // Find the included mixin classes + while( node && node->nodeType == snIdentifier ) + { + asSNameSpace *ns; + asCString name; + if( GetNamespaceAndNameFromNode(node, decl->script, decl->typeInfo->nameSpace, ns, name) < 0 ) + { + node = node->next; + continue; + } + + sMixinClass *mixin = 0; + while( ns ) + { + // Need to make sure the name is not an object type + asCObjectType *objType = GetObjectType(name.AddressOf(), ns); + if( objType == 0 ) + mixin = GetMixinClass(name.AddressOf(), ns); + + if( objType || mixin ) + break; + + ns = engine->GetParentNameSpace(ns); + } + + if( mixin ) + { + // Find methods from mixin declaration + asCScriptNode *n = mixin->node->firstChild; + + // Skip to the member declarations + // Possible keywords 'final' and 'shared' are removed in RegisterMixinClass so we don't need to worry about those here + while( n && n->nodeType == snIdentifier ) + n = n->next; + + // Add methods from the mixin that are not already existing in the class + while( n ) + { + if( n->nodeType == snFunction ) + { + // Instead of disconnecting the node, we need to clone it, otherwise other + // classes that include the same mixin will not see the methods + asCScriptNode *copy = n->CreateCopy(engine); + + // Register the method, but only if it doesn't already exist in the class + RegisterScriptFunctionFromNode(copy, mixin->script, CastToObjectType(decl->typeInfo), false, false, mixin->ns, false, true); + } + else if( n->nodeType == snVirtualProperty ) + { + // TODO: mixin: Support virtual properties too + WriteError("The virtual property syntax is currently not supported for mixin classes", mixin->script, n); + //RegisterVirtualProperty(node, decl->script, decl->objType, false, false); + } + + n = n->next; + } + } + + node = node->next; + } +} + +void asCBuilder::IncludePropertiesFromMixins(sClassDeclaration *decl) +{ + asCScriptNode *node = decl->node->firstChild; + + // Skip the class attributes + while( node->nodeType == snIdentifier && + !decl->script->TokenEquals(node->tokenPos, node->tokenLength, decl->name.AddressOf()) ) + node = node->next; + + // Skip the name of the class + node = node->next; + + // Find the included mixin classes + while( node && node->nodeType == snIdentifier ) + { + asSNameSpace *ns; + asCString name; + if( GetNamespaceAndNameFromNode(node, decl->script, decl->typeInfo->nameSpace, ns, name) < 0 ) + { + node = node->next; + continue; + } + + sMixinClass *mixin = 0; + while( ns ) + { + // Need to make sure the name is not an object type + asCObjectType *objType = GetObjectType(name.AddressOf(), ns); + if( objType == 0 ) + mixin = GetMixinClass(name.AddressOf(), ns); + + if( objType || mixin ) + break; + + ns = engine->GetParentNameSpace(ns); + } + + if( mixin ) + { + // Find properties from mixin declaration + asCScriptNode *n = mixin->node->firstChild; + + // Skip to the member declarations + // Possible keywords 'final' and 'shared' are removed in RegisterMixinClass so we don't need to worry about those here + while( n && n->nodeType == snIdentifier ) + n = n->next; + + // Add properties from the mixin that are not already existing in the class + while( n ) + { + if( n->nodeType == snDeclaration ) + { + asCScriptNode *n2 = n->firstChild; + bool isPrivate = false, isProtected = false; + if( n2 && n2->tokenType == ttPrivate ) + { + isPrivate = true; + n2 = n2->next; + } + else if( n2 && n2->tokenType == ttProtected ) + { + isProtected = true; + n2 = n2->next; + } + + asCScriptCode *file = mixin->script; + asCDataType dt = CreateDataTypeFromNode(n2, file, mixin->ns); + + if( decl->typeInfo->IsShared() && dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + WriteError(msg, file, n); + WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); + } + + if( dt.IsReadOnly() ) + WriteError(TXT_PROPERTY_CANT_BE_CONST, file, n); + + n2 = n2->next; + while( n2 ) + { + name.Assign(&file->code[n2->tokenPos], n2->tokenLength); + + // Add the property only if it doesn't already exist in the class + bool exists = false; + asCObjectType *ot = CastToObjectType(decl->typeInfo); + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + if( ot->properties[p]->name == name ) + { + exists = true; + break; + } + + if( !exists ) + { + if( !decl->isExistingShared ) + { + // It must not conflict with the name of methods + int r = CheckNameConflictMember(ot, name.AddressOf(), n2, file, true, false); + if( r < 0 ) + WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); + + AddPropertyToClass(decl, name, dt, isPrivate, isProtected, false, file, n2); + } + else + { + // Verify that the property exists in the original declaration + bool found = false; + for( asUINT p = 0; p < ot->properties.GetLength(); p++ ) + { + asCObjectProperty *prop = ot->properties[p]; + if( prop->isPrivate == isPrivate && + prop->isProtected == isProtected && + prop->name == name && + prop->type == dt ) + { + found = true; + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, ot->GetName()); + WriteError(str, decl->script, decl->node); + WriteInfo(TXT_WHILE_INCLUDING_MIXIN, decl->script, node); + } + } + } + + // Skip the initialization expression + if( n2->next && n2->next->nodeType != snIdentifier ) + n2 = n2->next; + + n2 = n2->next; + } + } + + n = n->next; + } + } + + node = node->next; + } +} + +int asCBuilder::CreateVirtualFunction(asCScriptFunction *func, int idx) +{ + asCScriptFunction *vf = asNEW(asCScriptFunction)(engine, module, asFUNC_VIRTUAL); + if( vf == 0 ) + return asOUT_OF_MEMORY; + + vf->name = func->name; + vf->nameSpace = func->nameSpace; + vf->returnType = func->returnType; + vf->parameterTypes = func->parameterTypes; + vf->inOutFlags = func->inOutFlags; + vf->id = engine->GetNextScriptFunctionId(); + vf->objectType = func->objectType; + vf->objectType->AddRefInternal(); + vf->signatureId = func->signatureId; + vf->vfTableIdx = idx; + vf->traits = func->traits; + + // Clear the shared trait since the virtual function should not have that + vf->SetShared(false); + + // It is not necessary to copy the default args, as they have no meaning in the virtual function + + module->AddScriptFunction(vf); + + // Add a dummy to the builder so that it doesn't mix up function ids + functions.PushLast(0); + + return vf->id; +} + +asCObjectProperty *asCBuilder::AddPropertyToClass(sClassDeclaration *decl, const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file, asCScriptNode *node) +{ + if( node ) + { + asASSERT(!isInherited); + + // Check if the property is allowed + if( !dt.CanBeInstantiated() ) + { + if( file && node ) + { + asCString str; + if( dt.IsAbstractClass() ) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf()); + else if( dt.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(decl->typeInfo->nameSpace).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(decl->typeInfo->nameSpace).AddressOf()); + WriteError(str, file, node); + } + return 0; + } + + // Register the initialization expression (if any) to be compiled later + asCScriptNode *declNode = node; + asCScriptNode *initNode = 0; + if( node->next && node->next->nodeType != snIdentifier ) + { + asASSERT( node->next->nodeType == snAssignment ); + initNode = node->next; + } + + sPropertyInitializer p(name, declNode, initNode, file); + decl->propInits.PushLast(p); + } + else + { + // If the declaration node is not given, then + // this property is inherited from a base class + asASSERT(isInherited); + } + + // Add the property to the object type + return CastToObjectType(decl->typeInfo)->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); +} + +bool asCBuilder::DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex) +{ + asCScriptFunction *method = GetFunctionDescription(methodId); + + for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) + { + asCScriptFunction *m = GetFunctionDescription(objType->methods[n]); + + if( m->name != method->name ) continue; + if( m->returnType != method->returnType ) continue; + if( m->IsReadOnly() != method->IsReadOnly() ) continue; + if( m->parameterTypes != method->parameterTypes ) continue; + if( m->inOutFlags != method->inOutFlags ) continue; + + if( methodIndex ) + *methodIndex = n; + + return true; + } + + return false; +} + +void asCBuilder::AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file) +{ + int funcId = engine->GetNextScriptFunctionId(); + + asCDataType returnType = asCDataType::CreatePrimitive(ttVoid, false); + asCArray parameterTypes; + asCArray inOutFlags; + asCArray defaultArgs; + asCArray parameterNames; + + // Add the script function + // TODO: declaredAt should be set to where the class has been declared + module->AddScriptFunction(file->idx, 0, funcId, objType->name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, false, objType, false, asSFunctionTraits(), objType->nameSpace); + + // Set it as default constructor + if( objType->beh.construct ) + engine->scriptFunctions[objType->beh.construct]->ReleaseInternal(); + objType->beh.construct = funcId; + objType->beh.constructors[0] = funcId; + engine->scriptFunctions[funcId]->AddRefInternal(); + + // The bytecode for the default constructor will be generated + // only after the potential inheritance has been established + sFunctionDescription *func = asNEW(sFunctionDescription); + if( func == 0 ) + { + // Out of memory + return; + } + + functions.PushLast(func); + + func->script = file; + func->node = 0; + func->name = objType->name; + func->objType = objType; + func->funcId = funcId; + func->isExistingShared = false; + + // Add a default factory as well + funcId = engine->GetNextScriptFunctionId(); + if( objType->beh.factory ) + engine->scriptFunctions[objType->beh.factory]->ReleaseInternal(); + objType->beh.factory = funcId; + objType->beh.factories[0] = funcId; + returnType = asCDataType::CreateObjectHandle(objType, false); + // TODO: should be the same as the constructor + module->AddScriptFunction(file->idx, 0, funcId, objType->name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, false); + functions.PushLast(0); + asCCompiler compiler(engine); + compiler.CompileFactory(this, file, engine->scriptFunctions[funcId]); + engine->scriptFunctions[funcId]->AddRefInternal(); + + // If the object is shared, then the factory must also be marked as shared + if( objType->flags & asOBJ_SHARED ) + engine->scriptFunctions[funcId]->SetShared(true); +} + +int asCBuilder::RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +{ + // Is it a shared enum? + bool isShared = false; + bool isExternal = false; + asCEnumType *existingSharedType = 0; + asCScriptNode *tmp = node->firstChild; + while( tmp->nodeType == snIdentifier ) + { + if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, SHARED_TOKEN)) + isShared = true; + else if (file->TokenEquals(tmp->tokenPos, tmp->tokenLength, EXTERNAL_TOKEN)) + isExternal = true; + else + break; + tmp = tmp->next; + } + + // Grab the name of the enumeration + asCString name; + asASSERT(snDataType == tmp->nodeType); + asASSERT(snIdentifier == tmp->firstChild->nodeType); + name.Assign(&file->code[tmp->firstChild->tokenPos], tmp->firstChild->tokenLength); + + if( isShared ) + { + // Look for a pre-existing shared enum with the same signature + for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) + { + asCTypeInfo *o = engine->sharedScriptTypes[n]; + if( o && + o->IsShared() && + (o->flags & asOBJ_ENUM) && + o->name == name && + o->nameSpace == ns ) + { + existingSharedType = CastToEnumType(o); + break; + } + } + } + + // If the enum was declared as external then it must have been compiled in a different module first + if (isExternal && existingSharedType == 0) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, tmp); + } + + // Remember if the type was declared as external so the saved bytecode can be flagged accordingly + if (isExternal && existingSharedType) + module->m_externalTypes.PushLast(existingSharedType); + + // Check the name and add the enum + int r = CheckNameConflict(name.AddressOf(), tmp->firstChild, file, ns, true, false); + if( asSUCCESS == r ) + { + asCEnumType *st; + + if( existingSharedType ) + { + st = existingSharedType; + st->AddRefInternal(); + } + else + { + st = asNEW(asCEnumType)(engine); + if( st == 0 ) + return asOUT_OF_MEMORY; + + st->flags = asOBJ_ENUM; + if( isShared ) + st->flags |= asOBJ_SHARED; + st->size = 4; + st->name = name; + st->nameSpace = ns; + st->module = module; + } + module->AddEnumType(st); + + if( !existingSharedType && isShared ) + { + engine->sharedScriptTypes.PushLast(st); + st->AddRefInternal(); + } + + // Store the location of this declaration for reference in name collisions + sClassDeclaration *decl = asNEW(sClassDeclaration); + if( decl == 0 ) + return asOUT_OF_MEMORY; + + decl->name = name; + decl->script = file; + decl->typeInfo = st; + namedTypeDeclarations.PushLast(decl); + + asCDataType type = CreateDataTypeFromNode(tmp, file, ns); + asASSERT(!type.IsReference()); + + // External shared enums must not redeclare the enum values + if (isExternal && (tmp->next == 0 || tmp->next->tokenType != ttEndStatement) ) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, tmp); + } + else if (!isExternal && tmp->next && tmp->next->tokenType == ttEndStatement) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, tmp); + } + + // Register the enum values + tmp = tmp->next; + while( tmp && tmp->nodeType == snIdentifier ) + { + name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength); + + if( existingSharedType ) + { + // If this is a pre-existent shared enum, then just double check + // that the value is already defined in the original declaration + bool found = false; + for( asUINT n = 0; n < st->enumValues.GetLength(); n++ ) + if( st->enumValues[n]->name == name ) + { + found = true; + break; + } + + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, st->GetName()); + WriteError(str, file, tmp); + break; + } + + tmp = tmp->next; + if( tmp && tmp->nodeType == snAssignment ) + tmp = tmp->next; + continue; + } + else + { + // Check for name conflict errors with other values in the enum + if( globVariables.GetFirst(ns, name, asCCompGlobVarType(type)) ) + { + asCString str; + str.Format(TXT_NAME_CONFLICT_s_ALREADY_USED, name.AddressOf()); + WriteError(str, file, tmp); + + tmp = tmp->next; + if( tmp && tmp->nodeType == snAssignment ) + tmp = tmp->next; + continue; + } + + // Check for assignment + asCScriptNode *asnNode = tmp->next; + if( asnNode && snAssignment == asnNode->nodeType ) + asnNode->DisconnectParent(); + else + asnNode = 0; + + // Create the global variable description so the enum value can be evaluated + sGlobalVariableDescription *gvar = asNEW(sGlobalVariableDescription); + if( gvar == 0 ) + return asOUT_OF_MEMORY; + + gvar->script = file; + gvar->declaredAtNode = tmp; + tmp = tmp->next; + gvar->declaredAtNode->DisconnectParent(); + gvar->initializationNode = asnNode; + gvar->name = name; + gvar->datatype = type; + gvar->ns = ns; + // No need to allocate space on the global memory stack since the values are stored in the asCObjectType + // Set the index to a negative to allow compiler to diferentiate from ordinary global var when compiling the initialization + gvar->index = -1; + gvar->isCompiled = false; + gvar->isPureConstant = true; + gvar->isEnumValue = true; + gvar->constantValue = 0xdeadbeef; + + // Allocate dummy property so we can compile the value. + // This will be removed later on so we don't add it to the engine. + gvar->property = asNEW(asCGlobalProperty); + if( gvar->property == 0 ) + return asOUT_OF_MEMORY; + + gvar->property->name = name; + gvar->property->nameSpace = ns; + gvar->property->type = gvar->datatype; + gvar->property->id = 0; + + globVariables.Put(gvar); + } + } + } + + node->Destroy(engine); + + return r; +} + +int asCBuilder::RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +{ + // Get the native data type + asCScriptNode *tmp = node->firstChild; + asASSERT(NULL != tmp && snDataType == tmp->nodeType); + asCDataType dataType; + dataType.CreatePrimitive(tmp->tokenType, false); + dataType.SetTokenType(tmp->tokenType); + tmp = tmp->next; + + // Grab the name of the typedef + asASSERT(NULL != tmp && NULL == tmp->next); + asCString name; + name.Assign(&file->code[tmp->tokenPos], tmp->tokenLength); + + // If the name is not already in use add it + int r = CheckNameConflict(name.AddressOf(), tmp, file, ns, true, false); + + asCTypedefType *st = 0; + if( asSUCCESS == r ) + { + // Create the new type + st = asNEW(asCTypedefType)(engine); + if( st == 0 ) + r = asOUT_OF_MEMORY; + } + + if( asSUCCESS == r ) + { + st->flags = asOBJ_TYPEDEF; + st->size = dataType.GetSizeInMemoryBytes(); + st->name = name; + st->nameSpace = ns; + st->aliasForType = dataType; + st->module = module; + + module->AddTypeDef(st); + + // Store the location of this declaration for reference in name collisions + sClassDeclaration *decl = asNEW(sClassDeclaration); + if( decl == 0 ) + r = asOUT_OF_MEMORY; + else + { + decl->name = name; + decl->script = file; + decl->typeInfo = st; + namedTypeDeclarations.PushLast(decl); + } + } + + node->Destroy(engine); + + return r; +} + +void asCBuilder::GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &funcTraits, asSNameSpace *implicitNamespace) +{ + node = node->firstChild; + + // Is the function shared? + funcTraits.SetTrait(asTRAIT_SHARED, false); + funcTraits.SetTrait(asTRAIT_EXTERNAL, false); + while (node->tokenType == ttIdentifier) + { + if (file->TokenEquals(node->tokenPos, node->tokenLength, SHARED_TOKEN)) + funcTraits.SetTrait(asTRAIT_SHARED, true); + else if (file->TokenEquals(node->tokenPos, node->tokenLength, EXTERNAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_EXTERNAL, true); + else + break; + node = node->next; + } + + // Is the function a private or protected class method? + funcTraits.SetTrait(asTRAIT_PRIVATE, false); + funcTraits.SetTrait(asTRAIT_PROTECTED, false); + if( node->tokenType == ttPrivate ) + { + funcTraits.SetTrait(asTRAIT_PRIVATE, true); + node = node->next; + } + else if( node->tokenType == ttProtected ) + { + funcTraits.SetTrait(asTRAIT_PROTECTED, true); + node = node->next; + } + + // Find the name + funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, false); + funcTraits.SetTrait(asTRAIT_DESTRUCTOR, false); + asCScriptNode *n = 0; + if( node->nodeType == snDataType ) + n = node->next->next; + else + { + // If the first node is a ~ token, then we know it is a destructor + if( node->tokenType == ttBitNot ) + { + n = node->next; + funcTraits.SetTrait(asTRAIT_DESTRUCTOR, true); + } + else + { + n = node; + funcTraits.SetTrait(asTRAIT_CONSTRUCTOR, true); + } + } + name.Assign(&file->code[n->tokenPos], n->tokenLength); + + if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + { + returnType = CreateDataTypeFromNode(node, file, implicitNamespace, false, objType); + returnType = ModifyDataTypeFromNode(returnType, node->next, file, 0, 0); + + if( engine->ep.disallowValueAssignForRefType && + returnType.GetTypeInfo() && + (returnType.GetTypeInfo()->flags & asOBJ_REF) && + !(returnType.GetTypeInfo()->flags & asOBJ_SCOPED) && + !returnType.IsReference() && + !returnType.IsObjectHandle() ) + { + WriteError(TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL, file, node); + } + } + else + returnType = asCDataType::CreatePrimitive(ttVoid, false); + + funcTraits.SetTrait(asTRAIT_CONST, false); + funcTraits.SetTrait(asTRAIT_FINAL, false); + funcTraits.SetTrait(asTRAIT_OVERRIDE, false); + funcTraits.SetTrait(asTRAIT_EXPLICIT, false); + funcTraits.SetTrait(asTRAIT_PROPERTY, false); + + if( n->next->next ) + { + asCScriptNode *decorator = n->next->next; + + // Is this a const method? + if( objType && decorator->tokenType == ttConst ) + { + funcTraits.SetTrait(asTRAIT_CONST, true); + decorator = decorator->next; + } + + while( decorator && decorator->tokenType == ttIdentifier ) + { + if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, FINAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_FINAL, true); + else if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, OVERRIDE_TOKEN)) + funcTraits.SetTrait(asTRAIT_OVERRIDE, true); + else if (objType && file->TokenEquals(decorator->tokenPos, decorator->tokenLength, EXPLICIT_TOKEN)) + funcTraits.SetTrait(asTRAIT_EXPLICIT, true); + else if (file->TokenEquals(decorator->tokenPos, decorator->tokenLength, PROPERTY_TOKEN)) + funcTraits.SetTrait(asTRAIT_PROPERTY, true); + else + { + asCString msg(&file->code[decorator->tokenPos], decorator->tokenLength); + msg.Format(TXT_UNEXPECTED_TOKEN_s, msg.AddressOf()); + WriteError(msg.AddressOf(), file, decorator); + } + + decorator = decorator->next; + } + } + + // Count the number of parameters + int count = 0; + asCScriptNode *c = n->next->firstChild; + while( c ) + { + count++; + c = c->next->next; + if( c && c->nodeType == snIdentifier ) + c = c->next; + if( c && c->nodeType == snExpression ) + c = c->next; + } + + // Get the parameter types + parameterNames.Allocate(count, false); + parameterTypes.Allocate(count, false); + inOutFlags.Allocate(count, false); + defaultArgs.Allocate(count, false); + n = n->next->firstChild; + while( n ) + { + asETypeModifiers inOutFlag; + asCDataType type = CreateDataTypeFromNode(n, file, implicitNamespace, false, objType); + type = ModifyDataTypeFromNode(type, n->next, file, &inOutFlag, 0); + + if( engine->ep.disallowValueAssignForRefType && + type.GetTypeInfo() && + (type.GetTypeInfo()->flags & asOBJ_REF) && + !(type.GetTypeInfo()->flags & asOBJ_SCOPED) && + !type.IsReference() && + !type.IsObjectHandle() ) + { + WriteError(TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL, file, node); + } + + // Store the parameter type + parameterTypes.PushLast(type); + inOutFlags.PushLast(inOutFlag); + + // Move to next parameter + n = n->next->next; + if( n && n->nodeType == snIdentifier ) + { + asCString paramName(&file->code[n->tokenPos], n->tokenLength); + parameterNames.PushLast(paramName); + n = n->next; + } + else + { + // No name was given for the parameter + parameterNames.PushLast(asCString()); + } + + if( n && n->nodeType == snExpression ) + { + // Strip out white space and comments to better share the string + asCString *defaultArgStr = asNEW(asCString); + if( defaultArgStr ) + *defaultArgStr = GetCleanExpressionString(n, file); + defaultArgs.PushLast(defaultArgStr); + + n = n->next; + } + else + defaultArgs.PushLast(0); + } +} +#endif + +asCString asCBuilder::GetCleanExpressionString(asCScriptNode *node, asCScriptCode *file) +{ + asASSERT(node && node->nodeType == snExpression); + + asCString str; + str.Assign(file->code + node->tokenPos, node->tokenLength); + + asCString cleanStr; + for( asUINT n = 0; n < str.GetLength(); ) + { + asUINT len = 0; + asETokenClass tok = engine->ParseToken(str.AddressOf() + n, str.GetLength() - n, &len); + if( tok != asTC_COMMENT && tok != asTC_WHITESPACE ) + { + if( cleanStr.GetLength() ) cleanStr += " "; + cleanStr.Concatenate(str.AddressOf() + n, len); + } + n += len; + } + + return cleanStr; +} + +#ifndef AS_NO_COMPILER +int asCBuilder::RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin) +{ + asCString name; + asCDataType returnType; + asCArray parameterNames; + asCArray parameterTypes; + asCArray inOutFlags; + asCArray defaultArgs; + asSFunctionTraits funcTraits; + + asASSERT( (objType && ns == 0) || isGlobalFunction || isMixin ); + + // Set the default namespace + if( ns == 0 ) + { + if( objType ) + ns = objType->nameSpace; + else + ns = engine->nameSpaces[0]; + } + + GetParsedFunctionDetails(node, file, objType, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns); + + return RegisterScriptFunction(node, file, objType, isInterface, isGlobalFunction, ns, isExistingShared, isMixin, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits); +} + +asCScriptFunction *asCBuilder::RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns) +{ + // Get the parameter names from the node + asCArray parameterNames; + asCArray defaultArgs; + asCScriptNode *args = node->firstChild; + while( args && args->nodeType != snStatementBlock ) + { + if (args->nodeType == snIdentifier) + { + asCString argName; + argName.Assign(&file->code[args->tokenPos], args->tokenLength); + parameterNames.PushLast(argName); + defaultArgs.PushLast(0); + } + args = args->next; + } + + // The statement block for the function must be disconnected, as the builder is going to be the owner of it + args->DisconnectParent(); + + // Get the return and parameter types from the funcDef + asCString funcName = name; + int r = RegisterScriptFunction(args, file, 0, 0, true, ns, false, false, funcName, funcDef->returnType, parameterNames, funcDef->parameterTypes, funcDef->inOutFlags, defaultArgs, asSFunctionTraits()); + if( r < 0 ) + return 0; + + // Return the function that was just created (but that will be compiled later) + return engine->scriptFunctions[functions[functions.GetLength()-1]->funcId]; +} + +int asCBuilder::RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits funcTraits) +{ + // Determine default namespace if not specified + if( ns == 0 ) + { + if( objType ) + ns = objType->nameSpace; + else + ns = engine->nameSpaces[0]; + } + + if( isExistingShared ) + { + asASSERT( objType ); + + // Should validate that the function really exists in the class/interface + bool found = false; + if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) || funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + { + // TODO: shared: Should check the existance of these too + found = true; + } + else + { + for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]]; + if( func->name == name && + func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + // Add the shared function in this module too + module->AddScriptFunction(func); + + found = true; + break; + } + } + } + + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, objType->GetName()); + WriteError(str, file, node); + } + + // Free the default args + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + node->Destroy(engine); + return 0; + } + + // Check for name conflicts + if( !funcTraits.GetTrait(asTRAIT_CONSTRUCTOR) && !funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + { + if( objType ) + { + CheckNameConflictMember(objType, name.AddressOf(), node, file, false, false); + + if( name == objType->name ) + WriteError(TXT_METHOD_CANT_HAVE_NAME_OF_CLASS, file, node); + } + else + CheckNameConflict(name.AddressOf(), node, file, ns, false, false); + } + else + { + if( isMixin ) + { + // Mixins cannot implement constructors/destructors + WriteError(TXT_MIXIN_CANNOT_HAVE_CONSTRUCTOR, file, node); + + // Free the default args + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + node->Destroy(engine); + return 0; + } + + // Verify that the name of the constructor/destructor is the same as the class + if( name != objType->name ) + { + asCString str; + if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR) ) + str.Format(TXT_DESTRUCTOR_s_s_NAME_ERROR, objType->name.AddressOf(), name.AddressOf()); + else + str.Format(TXT_METHOD_s_s_HAS_NO_RETURN_TYPE, objType->name.AddressOf(), name.AddressOf()); + WriteError(str, file, node); + } + + if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) + name = "~" + name; + } + + // Validate virtual properties signature + if( funcTraits.GetTrait(asTRAIT_PROPERTY) ) + { + asCScriptFunction func(engine, module, asFUNC_SCRIPT); + func.name = name; + func.nameSpace = ns; + func.objectType = objType; + if( objType ) + objType->AddRefInternal(); + func.traits = funcTraits; + func.returnType = returnType; + func.parameterTypes = parameterTypes; + + int r = ValidateVirtualProperty(&func); + if( r < 0 ) + { + asCString str; + if( r == -2 || r == -3 ) + str.Format(TXT_INVALID_SIG_FOR_VIRTPROP); + else if( r == -4 ) + str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.SubString(4).AddressOf()); + else if( r == -5 ) + str.Format(TXT_NAME_CONFLICT_s_ALREADY_USED, name.SubString(4).AddressOf()); + WriteError(str, file, node); + } + + func.funcType = asFUNC_DUMMY; + } + + isExistingShared = false; + int funcId = engine->GetNextScriptFunctionId(); + if( !isInterface ) + { + sFunctionDescription *func = asNEW(sFunctionDescription); + if( func == 0 ) + { + // Free the default args + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + return asOUT_OF_MEMORY; + } + + functions.PushLast(func); + + func->script = file; + func->node = node; + func->name = name; + func->objType = objType; + func->funcId = funcId; + func->isExistingShared = false; + func->paramNames = parameterNames; + + if(funcTraits.GetTrait(asTRAIT_SHARED)) + { + // Look for a pre-existing shared function with the same signature + for( asUINT n = 0; n < engine->scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[n]; + if( f && + f->IsShared() && + f->name == name && + f->nameSpace == ns && + f->objectType == objType && + f->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, 0, false) ) + { + funcId = func->funcId = f->id; + isExistingShared = func->isExistingShared = true; + break; + } + } + } + + // Remember if the function was declared as external so the saved bytecode can be flagged accordingly + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && func->isExistingShared) + module->m_externalFunctions.PushLast(engine->scriptFunctions[func->funcId]); + + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !func->isExistingShared) + { + // Mark it as existing shared to avoid compiling it + func->isExistingShared = true; + + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, name.AddressOf()); + WriteError(str, file, node); + } + + // External shared function must not try to redefine the interface + if (funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->tokenType == ttEndStatement || node->lastChild->tokenType == ttEndStatement)) + { + asCString str; + str.Format(TXT_EXTERNAL_SHARED_s_CANNOT_REDEF, name.AddressOf()); + WriteError(str, file, node); + } + else if (!funcTraits.GetTrait(asTRAIT_EXTERNAL) && !(node->nodeType == snStatementBlock || node->lastChild->nodeType == snStatementBlock) ) + { + asCString str; + str.Format(TXT_MISSING_DEFINITION_OF_s, name.AddressOf()); + WriteError(str, file, node); + } + } + + // Destructors may not have any parameters + if (funcTraits.GetTrait(asTRAIT_DESTRUCTOR) && parameterTypes.GetLength() > 0) + WriteError(TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM, file, node); + + // If a function, class, or interface is shared then only shared types may be used in the signature + if( (objType && objType->IsShared()) || funcTraits.GetTrait(asTRAIT_SHARED)) + { + asCTypeInfo *ti = returnType.GetTypeInfo(); + if( ti && !ti->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf()); + WriteError(msg, file, node); + } + + for( asUINT p = 0; p < parameterTypes.GetLength(); ++p ) + { + ti = parameterTypes[p].GetTypeInfo(); + if( ti && !ti->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ti->name.AddressOf()); + WriteError(msg, file, node); + } + } + } + + // Check that the same function hasn't been registered already in the namespace + asCArray funcs; + if( objType ) + GetObjectMethodDescriptions(name.AddressOf(), objType, funcs, false); + else + GetFunctionDescriptions(name.AddressOf(), funcs, ns); + if( objType && (name == "opConv" || name == "opImplConv" || name == "opCast" || name == "opImplCast") && parameterTypes.GetLength() == 0 ) + { + // opConv and opCast are special methods used for type casts + for( asUINT n = 0; n < funcs.GetLength(); ++n ) + { + asCScriptFunction *func = GetFunctionDescription(funcs[n]); + if( func->IsSignatureExceptNameEqual(returnType, parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + // TODO: clean up: Reuse the same error handling for both opConv and normal methods + if( isMixin ) + { + // Clean up the memory, as the function will not be registered + if( node ) + node->Destroy(engine); + sFunctionDescription *funcDesc = functions.PopLast(); + asDELETE(funcDesc, sFunctionDescription); + + // Free the default args + for( n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + return 0; + } + + WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); + break; + } + } + } + else + { + for( asUINT n = 0; n < funcs.GetLength(); ++n ) + { + asCScriptFunction *func = GetFunctionDescription(funcs[n]); + if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + if( isMixin ) + { + // Clean up the memory, as the function will not be registered + if( node ) + node->Destroy(engine); + sFunctionDescription *funcDesc = functions.PopLast(); + asDELETE(funcDesc, sFunctionDescription); + + // Free the default args + for( n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + return 0; + } + + WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); + break; + } + } + } + + // Register the function + if( isExistingShared ) + { + // Delete the default args as they won't be used anymore + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + asCScriptFunction *f = engine->scriptFunctions[funcId]; + module->AddScriptFunction(f); + + // TODO: clean up: This should be done by AddScriptFunction() itself + module->m_globalFunctions.Put(f); + } + else + { + int row = 0, col = 0; + if( node ) + file->ConvertPosToRowCol(node->tokenPos, &row, &col); + module->AddScriptFunction(file->idx, (row&0xFFFFF)|((col&0xFFF)<<20), funcId, name, returnType, parameterTypes, parameterNames, inOutFlags, defaultArgs, isInterface, objType, isGlobalFunction, funcTraits, ns); + } + + // Make sure the default args are declared correctly + ValidateDefaultArgs(file, node, engine->scriptFunctions[funcId]); + CheckForConflictsDueToDefaultArgs(file, node, engine->scriptFunctions[funcId], objType); + + if( objType ) + { + asASSERT( !isExistingShared ); + + engine->scriptFunctions[funcId]->AddRefInternal(); + if(funcTraits.GetTrait(asTRAIT_CONSTRUCTOR)) + { + int factoryId = engine->GetNextScriptFunctionId(); + if( parameterTypes.GetLength() == 0 ) + { + // Overload the default constructor + engine->scriptFunctions[objType->beh.construct]->ReleaseInternal(); + objType->beh.construct = funcId; + objType->beh.constructors[0] = funcId; + + // Register the default factory as well + engine->scriptFunctions[objType->beh.factory]->ReleaseInternal(); + objType->beh.factory = factoryId; + objType->beh.factories[0] = factoryId; + } + else + { + // The copy constructor needs to be marked for easy finding + if( parameterTypes.GetLength() == 1 && + parameterTypes[0].GetTypeInfo() == objType && + (parameterTypes[0].IsReference() || parameterTypes[0].IsObjectHandle()) ) + { + // Verify that there are not multiple options matching the copy constructor + // TODO: Need a better message, since the parameters can be slightly different, e.g. & vs @ + if( objType->beh.copyconstruct ) + WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); + + objType->beh.copyconstruct = funcId; + objType->beh.copyfactory = factoryId; + } + + // Register as a normal constructor + objType->beh.constructors.PushLast(funcId); + + // Register the factory as well + objType->beh.factories.PushLast(factoryId); + } + + // We must copy the default arg strings to avoid deleting the same object multiple times + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + defaultArgs[n] = asNEW(asCString)(*defaultArgs[n]); + + asCDataType dt = asCDataType::CreateObjectHandle(objType, false); + module->AddScriptFunction(file->idx, engine->scriptFunctions[funcId]->scriptData->declaredAt, factoryId, name, dt, parameterTypes, parameterNames, inOutFlags, defaultArgs, false, 0, false, funcTraits); + + // If the object is shared, then the factory must also be marked as shared + if( objType->flags & asOBJ_SHARED ) + engine->scriptFunctions[factoryId]->SetShared(true); + + // Add a dummy function to the builder so that it doesn't mix up the fund Ids + functions.PushLast(0); + + // Compile the factory immediately + asCCompiler compiler(engine); + compiler.CompileFactory(this, file, engine->scriptFunctions[factoryId]); + engine->scriptFunctions[factoryId]->AddRefInternal(); + } + else if(funcTraits.GetTrait(asTRAIT_DESTRUCTOR)) + objType->beh.destruct = funcId; + else + { + // If the method is the assignment operator we need to replace the default implementation + asCScriptFunction *f = engine->scriptFunctions[funcId]; + if( f->name == "opAssign" && f->parameterTypes.GetLength() == 1 && + f->parameterTypes[0].GetTypeInfo() == f->objectType && + (f->inOutFlags[0] & asTM_INREF) ) + { + engine->scriptFunctions[objType->beh.copy]->ReleaseInternal(); + objType->beh.copy = funcId; + f->AddRefInternal(); + } + + objType->methods.PushLast(funcId); + } + } + + // We need to delete the node already if this is an interface method + if( isInterface && node ) + node->Destroy(engine); + + return 0; +} + +int asCBuilder::RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared) +{ + if( engine->ep.propertyAccessorMode < 2 ) + { + WriteError(TXT_PROPERTY_ACCESSOR_DISABLED, file, node); + node->Destroy(engine); + return 0; + } + + asASSERT( (objType && ns == 0) || isGlobalFunction ); + + if( ns == 0 ) + { + if( objType ) + ns = objType->nameSpace; + else + ns = engine->nameSpaces[0]; + } + + bool isPrivate = false, isProtected = false; + asCString emulatedName; + asCDataType emulatedType; + + asCScriptNode *mainNode = node; + node = node->firstChild; + + if( !isGlobalFunction && node->tokenType == ttPrivate ) + { + isPrivate = true; + node = node->next; + } + else if( !isGlobalFunction && node->tokenType == ttProtected ) + { + isProtected = true; + node = node->next; + } + + emulatedType = CreateDataTypeFromNode(node, file, ns); + emulatedType = ModifyDataTypeFromNode(emulatedType, node->next, file, 0, 0); + node = node->next->next; + emulatedName.Assign(&file->code[node->tokenPos], node->tokenLength); + + if( node->next == 0 ) + WriteError(TXT_PROPERTY_WITHOUT_ACCESSOR, file, node); + + node = node->next; + while (node) + { + asCScriptNode *next = node->next; + asCScriptNode *funcNode = 0; + bool success = false; + asSFunctionTraits funcTraits; + asCDataType returnType; + asCArray paramNames; + asCArray paramTypes; + asCArray paramModifiers; + asCArray defaultArgs; + asCString name; + + funcTraits.SetTrait(asTRAIT_PRIVATE, isPrivate); + funcTraits.SetTrait(asTRAIT_PROTECTED, isProtected); + funcTraits.SetTrait(asTRAIT_PROPERTY, true); + + if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, GET_TOKEN)) + name = "get_"; + else if (node->firstChild->nodeType == snIdentifier && file->TokenEquals(node->firstChild->tokenPos, node->firstChild->tokenLength, SET_TOKEN)) + name = "set_"; + else + WriteError(TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE, file, node); + + if (name != "") + { + success = true; + funcNode = node->firstChild->next; + + if (funcNode && funcNode->tokenType == ttConst) + { + funcTraits.SetTrait(asTRAIT_CONST, true); + funcNode = funcNode->next; + } + + while (funcNode && funcNode->nodeType != snStatementBlock) + { + if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, FINAL_TOKEN)) + funcTraits.SetTrait(asTRAIT_FINAL, true); + else if (funcNode->tokenType == ttIdentifier && file->TokenEquals(funcNode->tokenPos, funcNode->tokenLength, OVERRIDE_TOKEN)) + funcTraits.SetTrait(asTRAIT_OVERRIDE, true); + else + { + asCString msg(&file->code[funcNode->tokenPos], funcNode->tokenLength);; + msg.Format(TXT_UNEXPECTED_TOKEN_s, msg.AddressOf()); + WriteError(msg.AddressOf(), file, node); + } + + funcNode = funcNode->next; + } + + if (funcNode) + funcNode->DisconnectParent(); + + if (funcNode == 0 && (objType == 0 || !objType->IsInterface())) + { + // TODO: getset: If no implementation is supplied the builder should provide an automatically generated implementation + // The compiler needs to be able to handle the different types, primitive, value type, and handle + // The code is also different for global property accessors + WriteError(TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED, file, node); + } + + if (name == "get_") + { + // Setup the signature for the get accessor method + returnType = emulatedType; + name = "get_" + emulatedName; + } + else if (name == "set_") + { + // Setup the signature for the set accessor method + returnType = asCDataType::CreatePrimitive(ttVoid, false); + paramModifiers.PushLast(asTM_NONE); + paramNames.PushLast("value"); + paramTypes.PushLast(emulatedType); + defaultArgs.PushLast(0); + name = "set_" + emulatedName; + } + } + + if( success ) + { + if( !isExistingShared ) + RegisterScriptFunction(funcNode, file, objType, isInterface, isGlobalFunction, ns, false, false, name, returnType, paramNames, paramTypes, paramModifiers, defaultArgs, funcTraits); + else + { + // Free the funcNode as it won't be used + if( funcNode ) funcNode->Destroy(engine); + + // Should validate that the function really exists in the class/interface + bool found = false; + for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[objType->methods[n]]; + if( func->name == name && + func->IsSignatureExceptNameEqual(returnType, paramTypes, paramModifiers, objType, funcTraits.GetTrait(asTRAIT_CONST)) ) + { + found = true; + break; + } + } + + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, objType->GetName()); + WriteError(str, file, node); + } + } + } + + node = next; + }; + + mainNode->Destroy(engine); + + return 0; +} + +int asCBuilder::RegisterImportedFunction(int importID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns) +{ + asCString name; + asCDataType returnType; + asCArray parameterNames; + asCArray parameterTypes; + asCArray inOutFlags; + asCArray defaultArgs; + asSFunctionTraits funcTraits; + + if( ns == 0 ) + ns = engine->nameSpaces[0]; + + GetParsedFunctionDetails(node->firstChild, file, 0, name, returnType, parameterNames, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns); + CheckNameConflict(name.AddressOf(), node, file, ns, false, false); + + // Check that the same function hasn't been registered already in the namespace + asCArray funcs; + GetFunctionDescriptions(name.AddressOf(), funcs, ns); + for( asUINT n = 0; n < funcs.GetLength(); ++n ) + { + asCScriptFunction *func = GetFunctionDescription(funcs[n]); + if( func->IsSignatureExceptNameAndReturnTypeEqual(parameterTypes, inOutFlags, 0, false) ) + { + WriteError(TXT_FUNCTION_ALREADY_EXIST, file, node); + break; + } + } + + // Read the module name as well + asCScriptNode *nd = node->lastChild; + asASSERT( nd->nodeType == snConstant && nd->tokenType == ttStringConstant ); + asCString moduleName; + moduleName.Assign(&file->code[nd->tokenPos+1], nd->tokenLength-2); + + node->Destroy(engine); + + // Register the function + module->AddImportedFunction(importID, name, returnType, parameterTypes, inOutFlags, defaultArgs, funcTraits, ns, moduleName); + + return 0; +} + +asCScriptFunction *asCBuilder::GetFunctionDescription(int id) +{ + // TODO: import: This should be improved when the imported functions are removed + // Get the description from the engine + if( (id & FUNC_IMPORTED) == 0 ) + return engine->scriptFunctions[id]; + else + return engine->importedFunctions[id & ~FUNC_IMPORTED]->importedFunctionSignature; +} + +void asCBuilder::GetFunctionDescriptions(const char *name, asCArray &funcs, asSNameSpace *ns) +{ + asUINT n; + + // Get the script declared global functions + const asCArray &idxs = module->m_globalFunctions.GetIndexes(ns, name); + for( n = 0; n < idxs.GetLength(); n++ ) + { + const asCScriptFunction *f = module->m_globalFunctions.Get(idxs[n]); + asASSERT( f->objectType == 0 ); + funcs.PushLast(f->id); + } + + // Add the imported functions + // TODO: optimize: Linear search: This is probably not that critial. Also bindInformation will probably be removed in near future + for( n = 0; n < module->m_bindInformations.GetLength(); n++ ) + { + if( module->m_bindInformations[n]->importedFunctionSignature->name == name && + module->m_bindInformations[n]->importedFunctionSignature->nameSpace == ns ) + funcs.PushLast(module->m_bindInformations[n]->importedFunctionSignature->id); + } + + // Add the registered global functions + const asCArray &idxs2 = engine->registeredGlobalFuncs.GetIndexes(ns, name); + for( n = 0; n < idxs2.GetLength(); n++ ) + { + asCScriptFunction *f = engine->registeredGlobalFuncs.Get(idxs2[n]); + + // Verify if the module has access to the function + if( module->m_accessMask & f->accessMask ) + { + funcs.PushLast(f->id); + } + } +} + +// scope is only informed when looking for a base class' method +void asCBuilder::GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray &methods, bool objIsConst, const asCString &scope, asCScriptNode *errNode, asCScriptCode *script) +{ + asASSERT(objectType); + + if( scope != "" ) + { + // If searching with a scope informed, then the node and script must also be informed for potential error reporting + asASSERT( errNode && script ); + + // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace + // TODO: child funcdef: A scope can include a template type, e.g. array + int n = scope.FindLast("::"); + asCString className = n >= 0 ? scope.SubString(n+2) : scope; + asCString nsName = n >= 0 ? scope.SubString(0, n) : ""; + + // If a namespace was specifically defined, then this must be used + asSNameSpace *ns = 0; + if (n >= 0) + { + if (nsName == "") + ns = engine->nameSpaces[0]; + else + ns = GetNameSpaceByString(nsName, objectType->nameSpace, errNode, script, 0, false); + + // If the namespace isn't found return silently and let the calling + // function report the error if it cannot resolve the symbol + if (ns == 0) + return; + } + + // Find the base class with the specified scope + while (objectType) + { + // If the name and namespace matches it is the correct class. If no + // specific namespace was given, then don't compare the namespace + if (objectType->name == className && (ns == 0 || objectType->nameSpace == ns)) + break; + + objectType = objectType->derivedFrom; + } + + // If the scope is not any of the base classes, then return no methods + if( objectType == 0 ) + return; + } + + // Find the methods in the object that match the name + // TODO: optimize: Improve linear search + for( asUINT n = 0; n < objectType->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[objectType->methods[n]]; + if( func->name == name && + (!objIsConst || func->IsReadOnly()) && + (func->accessMask & module->m_accessMask) ) + { + // When the scope is defined the returned methods should be the true methods, not the virtual method stubs + if( scope == "" ) + methods.PushLast(engine->scriptFunctions[objectType->methods[n]]->id); + else + { + asCScriptFunction *f = engine->scriptFunctions[objectType->methods[n]]; + if( f && f->funcType == asFUNC_VIRTUAL ) + f = objectType->virtualFunctionTable[f->vfTableIdx]; + methods.PushLast(f->id); + } + } + } +} +#endif + +void asCBuilder::WriteInfo(const asCString &scriptname, const asCString &message, int r, int c, bool pre) +{ + // Need to store the pre message in a structure + if( pre ) + { + engine->preMessage.isSet = true; + engine->preMessage.c = c; + engine->preMessage.r = r; + engine->preMessage.message = message; + engine->preMessage.scriptname = scriptname; + } + else + { + engine->preMessage.isSet = false; + + if( !silent ) + engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_INFORMATION, message.AddressOf()); + } +} + +void asCBuilder::WriteInfo(const asCString &message, asCScriptCode *file, asCScriptNode *node) +{ + int r = 0, c = 0; + if( node ) + file->ConvertPosToRowCol(node->tokenPos, &r, &c); + + WriteInfo(file->name, message, r, c, false); +} + +void asCBuilder::WriteError(const asCString &message, asCScriptCode *file, asCScriptNode *node) +{ + int r = 0, c = 0; + if( node && file ) + file->ConvertPosToRowCol(node->tokenPos, &r, &c); + + WriteError(file ? file->name : asCString(""), message, r, c); +} + +void asCBuilder::WriteError(const asCString &scriptname, const asCString &message, int r, int c) +{ + numErrors++; + + if( !silent ) + engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_ERROR, message.AddressOf()); +} + +void asCBuilder::WriteWarning(const asCString &scriptname, const asCString &message, int r, int c) +{ + if( engine->ep.compilerWarnings ) + { + numWarnings++; + + if( !silent ) + engine->WriteMessage(scriptname.AddressOf(), r, c, asMSGTYPE_WARNING, message.AddressOf()); + } +} + +void asCBuilder::WriteWarning(const asCString &message, asCScriptCode *file, asCScriptNode *node) +{ + int r = 0, c = 0; + if( node && file ) + file->ConvertPosToRowCol(node->tokenPos, &r, &c); + + WriteWarning(file ? file->name : asCString(""), message, r, c); +} + +// TODO: child funcdef: Should try to eliminate this function. GetNameSpaceFromNode is more complete +asCString asCBuilder::GetScopeFromNode(asCScriptNode *node, asCScriptCode *script, asCScriptNode **next) +{ + if (node->nodeType != snScope) + { + if (next) + *next = node; + return ""; + } + + asCString scope; + asCScriptNode *sn = node->firstChild; + if( sn->tokenType == ttScope ) + { + scope = "::"; + sn = sn->next; + } + + // TODO: child funcdef: A scope can have a template type as the innermost + while( sn && sn->next && sn->next->tokenType == ttScope ) + { + asCString tmp; + tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); + if( scope != "" && scope != "::" ) + scope += "::"; + scope += tmp; + sn = sn->next->next; + } + + if( next ) + *next = node->next; + + return scope; +} + +asSNameSpace *asCBuilder::GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next, asCObjectType **objType) +{ + if (objType) + *objType = 0; + + // If no scope has been informed, then return the implicit namespace + if (node->nodeType != snScope) + { + if (next) + *next = node; + return implicitNs ? implicitNs : engine->nameSpaces[0]; + } + + if (next) + *next = node->next; + + asCString scope; + asCScriptNode *sn = node->firstChild; + if (sn && sn->tokenType == ttScope) + { + scope = "::"; + sn = sn->next; + } + + while (sn) + { + if (sn->next->tokenType == ttScope) + { + asCString tmp; + tmp.Assign(&script->code[sn->tokenPos], sn->tokenLength); + if (scope != "" && scope != "::") + scope += "::"; + scope += tmp; + sn = sn->next->next; + } + else + { + // This is a template type + asASSERT(sn->next->nodeType == snDataType); + + asSNameSpace *ns = implicitNs; + if (scope != "") + ns = engine->FindNameSpace(scope.AddressOf()); + + asCString templateName(&script->code[sn->tokenPos], sn->tokenLength); + asCObjectType *templateType = GetObjectType(templateName.AddressOf(), ns); + if (templateType == 0 || (templateType->flags & asOBJ_TEMPLATE) == 0) + { + // TODO: child funcdef: Report error + return ns; + } + + if (objType) + *objType = GetTemplateInstanceFromNode(sn, script, templateType, implicitNs, 0); + + // Return no namespace, since this is an object type + return 0; + } + } + + asCTypeInfo *ti = 0; + asSNameSpace *ns = GetNameSpaceByString(scope, implicitNs ? implicitNs : engine->nameSpaces[0], node, script, &ti); + if (ti && objType) + *objType = CastToObjectType(ti); + return ns; +} + +asSNameSpace *asCBuilder::GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType, bool isRequired) +{ + if( scopeType ) + *scopeType = 0; + + asSNameSpace *ns = implicitNs; + if( nsName == "::" ) + ns = engine->nameSpaces[0]; + else if( nsName != "" ) + { + ns = engine->FindNameSpace(nsName.AddressOf()); + if (ns == 0 && scopeType) + { + asCString typeName; + asCString searchNs; + + // Split the scope with at the inner most :: + int pos = nsName.FindLast("::"); + bool recursive = false; + if (pos >= 0) + { + // Fully qualified namespace + typeName = nsName.SubString(pos + 2); + searchNs = nsName.SubString(0, pos); + } + else + { + // Partially qualified, use the implicit namespace and then search recursively for the type + typeName = nsName; + searchNs = implicitNs->name; + recursive = true; + } + + asSNameSpace *nsTmp = searchNs == "::" ? engine->nameSpaces[0] : engine->FindNameSpace(searchNs.AddressOf()); + asCTypeInfo *ti = 0; + while( !ti && nsTmp ) + { + // Check if the typeName is an existing type in the namespace + ti = GetType(typeName.AddressOf(), nsTmp, 0); + if (ti) + { + // The informed scope is not a namespace, but it does match a type + *scopeType = ti; + return 0; + } + nsTmp = recursive ? engine->GetParentNameSpace(nsTmp) : 0; + } + } + + if (ns == 0 && isRequired) + { + asCString msg; + msg.Format(TXT_NAMESPACE_s_DOESNT_EXIST, nsName.AddressOf()); + WriteError(msg, script, errNode); + } + } + + return ns; +} + +asCDataType asCBuilder::CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope, asCObjectType *currentType, bool reportError, bool *isValid) +{ + asASSERT(node->nodeType == snDataType || node->nodeType == snIdentifier || node->nodeType == snScope ); + + asCDataType dt; + + asCScriptNode *n = node->firstChild; + + if (isValid) + *isValid = true; + + // If the informed node is an identifier or scope, then the + // datatype should be identified directly from that + if (node->nodeType != snDataType) + n = node; + + bool isConst = false; + bool isImplicitHandle = false; + if( n->tokenType == ttConst ) + { + isConst = true; + n = n->next; + } + + // Determine namespace (or parent type) to search for the data type in + asCObjectType *parentType = 0; + asSNameSpace *ns = GetNameSpaceFromNode(n, file, implicitNamespace, &n, &parentType); + if( ns == 0 && parentType == 0 ) + { + // The namespace and parent type doesn't exist. Return a dummy type instead. + dt = asCDataType::CreatePrimitive(ttInt, false); + if (isValid) + *isValid = false; + return dt; + } + + if( n->tokenType == ttIdentifier ) + { + bool found = false; + + asCString str; + str.Assign(&file->code[n->tokenPos], n->tokenLength); + + // Recursively search parent namespaces for matching type + asSNameSpace *origNs = ns; + asCObjectType *origParentType = parentType; + while( (ns || parentType) && !found ) + { + asCTypeInfo *ti = 0; + + if (currentType) + { + // If this is for a template type, then we must first determine if the + // identifier matches any of the template subtypes + if (currentType->flags & asOBJ_TEMPLATE) + { + for (asUINT subtypeIndex = 0; subtypeIndex < currentType->templateSubTypes.GetLength(); subtypeIndex++) + { + asCTypeInfo *type = currentType->templateSubTypes[subtypeIndex].GetTypeInfo(); + if (type && str == type->name) + { + ti = type; + break; + } + } + } + + if (ti == 0) + { + // Check if the type is a child type of the current type + ti = GetFuncDef(str.AddressOf(), 0, currentType); + if (ti) + { + dt = asCDataType::CreateType(ti, false); + found = true; + } + } + } + + if( ti == 0 ) + ti = GetType(str.AddressOf(), ns, parentType); + if( ti == 0 && !module && currentType ) + ti = GetTypeFromTypesKnownByObject(str.AddressOf(), currentType); + + if( ti && !found ) + { + found = true; + + if( ti->flags & asOBJ_IMPLICIT_HANDLE ) + isImplicitHandle = true; + + // Make sure the module has access to the object type + if( !module || (module->m_accessMask & ti->accessMask) ) + { + if( asOBJ_TYPEDEF == (ti->flags & asOBJ_TYPEDEF) ) + { + // TODO: typedef: A typedef should be considered different from the original type (though with implicit conversions between the two) + // Create primitive data type based on object flags + dt = CastToTypedefType(ti)->aliasForType; + dt.MakeReadOnly(isConst); + } + else + { + if( ti->flags & asOBJ_TEMPLATE ) + { + ti = GetTemplateInstanceFromNode(n, file, CastToObjectType(ti), implicitNamespace, currentType, &n); + if (ti == 0) + { + if (isValid) + *isValid = false; + + // Return a dummy + return asCDataType::CreatePrimitive(ttInt, false); + } + } + else if( n && n->next && n->next->nodeType == snDataType ) + { + if (reportError) + { + asCString msg; + msg.Format(TXT_TYPE_s_NOT_TEMPLATE, ti->name.AddressOf()); + WriteError(msg, file, n); + } + if (isValid) + *isValid = false; + } + + // Create object data type + if( ti ) + dt = asCDataType::CreateType(ti, isConst); + else + dt = asCDataType::CreatePrimitive(ttInt, isConst); + } + } + else + { + if (reportError) + { + asCString msg; + msg.Format(TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE, (const char *)str.AddressOf()); + WriteError(msg, file, n); + } + + dt.SetTokenType(ttInt); + if (isValid) + *isValid = false; + } + } + + if( !found ) + { + // Try to find it in the parent namespace + if( ns ) + ns = engine->GetParentNameSpace(ns); + if (parentType) + parentType = 0; + } + } + + if( !found ) + { + if (reportError) + { + asCString msg; + if (origNs && origNs->name == "") + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS, str.AddressOf()); + else if (origNs) + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), origNs->name.AddressOf()); + else + { + // TODO: child funcdef: Message should explain that the identifier is not a type of the parent type + asCDataType pt = asCDataType::CreateType(origParentType, false); + msg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s, str.AddressOf(), pt.Format(origParentType->nameSpace, false).AddressOf()); + } + WriteError(msg, file, n); + } + + dt = asCDataType::CreatePrimitive(ttInt, isConst); + if (isValid) + *isValid = false; + return dt; + } + } + else if( n->tokenType == ttAuto ) + { + dt = asCDataType::CreateAuto(isConst); + } + else + { + // Create primitive data type + dt = asCDataType::CreatePrimitive(n->tokenType, isConst); + } + + // Determine array dimensions and object handles + n = n->next; + while( n && (n->tokenType == ttOpenBracket || n->tokenType == ttHandle) ) + { + if( n->tokenType == ttOpenBracket ) + { + // Make sure the sub type can be instantiated + if( !dt.CanBeInstantiated() ) + { + if (reportError) + { + asCString str; + if (dt.IsAbstractClass()) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); + else if (dt.IsInterface()) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(ns).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(ns).AddressOf()); + + WriteError(str, file, n); + } + if (isValid) + *isValid = false; + } + + // Make the type an array (or multidimensional array) + if( dt.MakeArray(engine, module) < 0 ) + { + if( reportError ) + WriteError(TXT_NO_DEFAULT_ARRAY_TYPE, file, n); + if (isValid) + *isValid = false; + break; + } + } + else + { + // Make the type a handle + if( dt.IsObjectHandle() ) + { + if( reportError ) + WriteError(TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED, file, n); + if (isValid) + *isValid = false; + break; + } + else + { + if( dt.MakeHandle(true, acceptHandleForScope) < 0 ) + { + if( reportError ) + WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (isValid) + *isValid = false; + break; + } + + // Check if the handle should be read-only + if( n && n->next && n->next->tokenType == ttConst ) + dt.MakeReadOnly(true); + } + } + n = n->next; + } + + if( isImplicitHandle ) + { + // Make the type a handle + if (dt.MakeHandle(true, acceptHandleForScope) < 0) + { + if( reportError ) + WriteError(TXT_OBJECT_HANDLE_NOT_SUPPORTED, file, n); + if (isValid) + *isValid = false; + } + } + + return dt; +} + +asCObjectType *asCBuilder::GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next) +{ + // Check if the subtype is a type or the template's subtype + // if it is the template's subtype then this is the actual template type, + // orderwise it is a template instance. + // Only do this for application registered interface, as the + // scripts cannot implement templates. + asCArray subTypes; + asUINT subtypeIndex; + asCScriptNode *n = node; + while (n && n->next && n->next->nodeType == snDataType) + { + n = n->next; + + // When parsing function definitions for template registrations (currentType != 0) it is necessary + // to pass in the current template type to the recursive call since it is this ones sub-template types + // that should be allowed. + asCDataType subType = CreateDataTypeFromNode(n, file, implicitNamespace, false, module ? 0 : (currentType ? currentType : templateType)); + subTypes.PushLast(subType); + + if (subType.IsReadOnly()) + { + asCString msg; + msg.Format(TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY); + WriteError(msg, file, n); + + // Return a dummy + return 0; + } + } + + if (next) + *next = n; + + if (subTypes.GetLength() != templateType->templateSubTypes.GetLength()) + { + asCString msg; + msg.Format(TXT_TMPL_s_EXPECTS_d_SUBTYPES, templateType->name.AddressOf(), int(templateType->templateSubTypes.GetLength())); + WriteError(msg, file, node); + + // Return a dummy + return 0; + } + + // Check if any of the given subtypes are different from the template's declared subtypes + bool isDifferent = false; + for (subtypeIndex = 0; subtypeIndex < subTypes.GetLength(); subtypeIndex++) + { + if (subTypes[subtypeIndex].GetTypeInfo() != templateType->templateSubTypes[subtypeIndex].GetTypeInfo()) + { + isDifferent = true; + break; + } + } + + if (isDifferent) + { + // This is a template instance + // Need to find the correct object type + asCObjectType *otInstance = engine->GetTemplateInstanceType(templateType, subTypes, module); + + if (otInstance && otInstance->scriptSectionIdx < 0) + { + // If this is the first time the template instance is used, store where it was declared from + otInstance->scriptSectionIdx = engine->GetScriptSectionNameIndex(file->name.AddressOf()); + int row, column; + file->ConvertPosToRowCol(n->tokenPos, &row, &column); + otInstance->declaredAt = (row & 0xFFFFF) | (column << 20); + } + + if (!otInstance) + { + asCString sub = subTypes[0].Format(templateType->nameSpace); + for (asUINT s = 1; s < subTypes.GetLength(); s++) + { + sub += ","; + sub += subTypes[s].Format(templateType->nameSpace); + } + asCString msg; + msg.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, templateType->name.AddressOf(), sub.AddressOf()); + WriteError(msg, file, n); + } + + return otInstance; + } + + return templateType; +} + +asCDataType asCBuilder::ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlags, bool *autoHandle) +{ + asCDataType dt = type; + + if( inOutFlags ) *inOutFlags = asTM_NONE; + + // Is the argument sent by reference? + asCScriptNode *n = node->firstChild; + if( n && n->tokenType == ttAmp ) + { + if (dt.GetTokenType() == ttVoid) + { + asCString msg; + msg.Format(TXT_TYPE_s_CANNOT_BE_REFERENCE, type.Format(0).AddressOf()); + WriteError(msg, file, node->firstChild); + return dt; + } + + dt.MakeReference(true); + n = n->next; + + if( n ) + { + if( inOutFlags ) + { + if( n->tokenType == ttIn ) + *inOutFlags = asTM_INREF; + else if( n->tokenType == ttOut ) + *inOutFlags = asTM_OUTREF; + else if( n->tokenType == ttInOut ) + *inOutFlags = asTM_INOUTREF; + else + asASSERT(false); + } + + n = n->next; + } + else + { + if( inOutFlags ) + *inOutFlags = asTM_INOUTREF; // ttInOut + } + + if( !engine->ep.allowUnsafeReferences && + inOutFlags && *inOutFlags == asTM_INOUTREF && + !(dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + { + // Verify that the base type support &inout parameter types + if( !dt.IsObject() || dt.IsObjectHandle() || + !((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || (CastToObjectType(dt.GetTypeInfo())->beh.addref && CastToObjectType(dt.GetTypeInfo())->beh.release)) ) + WriteError(TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT, file, node->firstChild); + } + } + + if( autoHandle ) *autoHandle = false; + + if( n && n->tokenType == ttPlus ) + { + // Autohandles are not supported for types with NOCOUNT + // If the type is not a handle then there was an error with building the type, but + // this error would already have been reported so no need to report another error here + if( dt.IsObjectHandle() && (dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) ) + WriteError(TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT, file, node->firstChild); + + if( autoHandle ) *autoHandle = true; + } + + if (n && n->tokenType == ttIdentifier) + { + asCString str; + str.Assign(&file->code[n->tokenPos], n->tokenLength); + if (str == IF_HANDLE_TOKEN) + dt.SetIfHandleThenConst(true); + else + { + // TODO: Should give error if not currently parsing template registration + asCString msg; + msg.Format(TXT_UNEXPECTED_TOKEN_s, str.AddressOf()); + WriteError(msg, file, node->firstChild); + } + } + + return dt; +} + +asCTypeInfo *asCBuilder::GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType) +{ + asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); + + if (ns) + { + asCTypeInfo *ti = engine->GetRegisteredType(type, ns); + if (!ti && module) + ti = module->GetType(type, ns); + return ti; + } + else + { + // Recursively check base classes + asCObjectType *currType = parentType; + while (currType) + { + for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = currType->childFuncDefs[n]; + if (funcDef && funcDef->name == type) + return funcDef; + } + currType = currType->derivedFrom; + } + } + + return 0; +} + +asCObjectType *asCBuilder::GetObjectType(const char *type, asSNameSpace *ns) +{ + return CastToObjectType(GetType(type, ns, 0)); +} + +#ifndef AS_NO_COMPILER +// This function will return true if there are any types in the engine or module +// with the given name. The namespace is ignored in this verification. +bool asCBuilder::DoesTypeExist(const asCString &type) +{ + asUINT n; + + // This function is only used when parsing expressions for building bytecode + // and this is only done after all types are known. For this reason the types + // can be safely cached in a map for quick lookup. Once the builder is released + // the cache will also be destroyed thus avoiding unnecessary memory consumption. + if( !hasCachedKnownTypes ) + { + // Only do this once + hasCachedKnownTypes = true; + + // Add registered types + asSMapNode *cursor; + engine->allRegisteredTypes.MoveFirst(&cursor); + while( cursor ) + { + if( !knownTypes.MoveTo(0, cursor->key.name) ) + knownTypes.Insert(cursor->key.name, true); + + engine->allRegisteredTypes.MoveNext(&cursor, cursor); + } + + if (module) + { + // Add script classes and interfaces + for (n = 0; n < module->m_classTypes.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_classTypes[n]->name)) + knownTypes.Insert(module->m_classTypes[n]->name, true); + + // Add script enums + for (n = 0; n < module->m_enumTypes.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_enumTypes[n]->name)) + knownTypes.Insert(module->m_enumTypes[n]->name, true); + + // Add script typedefs + for (n = 0; n < module->m_typeDefs.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_typeDefs[n]->name)) + knownTypes.Insert(module->m_typeDefs[n]->name, true); + + // Add script funcdefs + for (n = 0; n < module->m_funcDefs.GetLength(); n++) + if (!knownTypes.MoveTo(0, module->m_funcDefs[n]->name)) + knownTypes.Insert(module->m_funcDefs[n]->name, true); + } + } + + // Check if the type is known + return knownTypes.MoveTo(0, type); +} +#endif + +asCTypeInfo *asCBuilder::GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType) +{ + if (currentType->name == type) + return currentType; + + asUINT n; + + asCTypeInfo *found = 0; + + for (n = 0; found == 0 && n < currentType->properties.GetLength(); n++) + if (currentType->properties[n]->type.GetTypeInfo() && + currentType->properties[n]->type.GetTypeInfo()->name == type) + found = currentType->properties[n]->type.GetTypeInfo(); + + for (n = 0; found == 0 && n < currentType->methods.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[currentType->methods[n]]; + if (func->returnType.GetTypeInfo() && + func->returnType.GetTypeInfo()->name == type) + found = func->returnType.GetTypeInfo(); + + for (asUINT f = 0; found == 0 && f < func->parameterTypes.GetLength(); f++) + if (func->parameterTypes[f].GetTypeInfo() && + func->parameterTypes[f].GetTypeInfo()->name == type) + found = func->parameterTypes[f].GetTypeInfo(); + } + + if (found) + { + // In case we find a template instance it mustn't be returned + // because it is not known if the subtype is really matching + if (found->flags & asOBJ_TEMPLATE) + return 0; + } + + return found; +} + +asCFuncdefType *asCBuilder::GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType) +{ + asASSERT((ns == 0 && parentType) || (ns && parentType == 0)); + + if (ns) + { + for (asUINT n = 0; n < engine->registeredFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = engine->registeredFuncDefs[n]; + // TODO: access: Only return the definitions that the module has access to + if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) + return funcDef; + } + + if (module) + { + for (asUINT n = 0; n < module->m_funcDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = module->m_funcDefs[n]; + if (funcDef && funcDef->nameSpace == ns && funcDef->name == type) + return funcDef; + } + } + } + else + { + // Recursively check base classes + asCObjectType *currType = parentType; + while (currType) + { + for (asUINT n = 0; n < currType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcDef = currType->childFuncDefs[n]; + if (funcDef && funcDef->name == type) + return funcDef; + } + currType = currType->derivedFrom; + } + } + + return 0; +} + +#ifndef AS_NO_COMPILER + +int asCBuilder::GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue) +{ + if( !type || !(type->flags & asOBJ_ENUM) ) + return 0; + + for( asUINT n = 0; n < type->enumValues.GetLength(); ++n ) + { + if( type->enumValues[n]->name == name ) + { + outDt = asCDataType::CreateType(type, true); + outValue = type->enumValues[n]->value; + return 1; + } + } + + return 0; +} + +int asCBuilder::GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns) +{ + bool found = false; + + // Search all available enum types + asUINT t; + for( t = 0; t < engine->registeredEnums.GetLength(); t++ ) + { + asCEnumType *et = engine->registeredEnums[t]; + if( ns != et->nameSpace ) continue; + + // Don't bother with types the module doesn't have access to + if( (et->accessMask & module->m_accessMask) == 0 ) + continue; + + if( GetEnumValueFromType(et, name, outDt, outValue) ) + { + if( !found ) + found = true; + else + { + // Found more than one value in different enum types + return 2; + } + } + } + + for( t = 0; t < module->m_enumTypes.GetLength(); t++ ) + { + asCEnumType *et = module->m_enumTypes[t]; + if( ns != et->nameSpace ) continue; + + if( GetEnumValueFromType(et, name, outDt, outValue) ) + { + if( !found ) + found = true; + else + { + // Found more than one value in different enum types + return 2; + } + } + } + + if( found ) + return 1; + + // Didn't find any value + return 0; +} + +#endif // AS_NO_COMPILER + +END_AS_NAMESPACE diff --git a/angelscript/source/as_builder.h b/angelscript/source/as_builder.h new file mode 100644 index 0000000..3b2f5c7 --- /dev/null +++ b/angelscript/source/as_builder.h @@ -0,0 +1,262 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_builder.h +// +// This is the class that manages the compilation of the scripts +// + + +#ifndef AS_BUILDER_H +#define AS_BUILDER_H + +#include "as_config.h" +#include "as_symboltable.h" +#include "as_scriptengine.h" +#include "as_module.h" +#include "as_array.h" +#include "as_scriptcode.h" +#include "as_scriptnode.h" +#include "as_datatype.h" +#include "as_property.h" + +BEGIN_AS_NAMESPACE + +#ifdef AS_NO_COMPILER +// Forward declare the structure, as it is part of some function signatures used even without the compiler +struct sGlobalVariableDescription; +#endif + +#ifndef AS_NO_COMPILER + +struct sFunctionDescription +{ + asCScriptCode *script; + asCScriptNode *node; + asCString name; + asCObjectType *objType; + asCArray paramNames; + int funcId; + bool isExistingShared; +}; + +struct sGlobalVariableDescription +{ + asCScriptCode *script; + asCScriptNode *declaredAtNode; + asCScriptNode *initializationNode; + asCString name; + asCGlobalProperty *property; + asCDataType datatype; + asSNameSpace *ns; + int index; + bool isCompiled; + bool isPureConstant; + bool isEnumValue; + asQWORD constantValue; +}; + +struct sPropertyInitializer +{ + sPropertyInitializer() : declNode(0), initNode(0), file(0) {} + sPropertyInitializer(const asCString &nm, asCScriptNode *decl, asCScriptNode *init, asCScriptCode *f) : name(nm), declNode(decl), initNode(init), file(f) {} + sPropertyInitializer &operator=(const sPropertyInitializer &o) {name = o.name; declNode = o.declNode; initNode = o.initNode; file = o.file; return *this;} + + asCString name; + asCScriptNode *declNode; + asCScriptNode *initNode; + asCScriptCode *file; +}; + +struct sClassDeclaration +{ + sClassDeclaration() {script = 0; node = 0; validState = 0; typeInfo = 0; isExistingShared = false; isFinal = false;} + + asCScriptCode *script; + asCScriptNode *node; + asCString name; + int validState; + asCTypeInfo *typeInfo; + bool isExistingShared; + bool isFinal; + + asCArray propInits; +}; + +struct sFuncDef +{ + asCScriptCode *script; + asCScriptNode *node; + asCString name; + int idx; +}; + +struct sMixinClass +{ + asCScriptCode *script; + asCScriptNode *node; + asCString name; + asSNameSpace *ns; +}; + +#endif // AS_NO_COMPILER + +class asCBuilder +{ +public: + asCBuilder(asCScriptEngine *engine, asCModule *module); + ~asCBuilder(); + + // These methods are used by the application interface + int VerifyProperty(asCDataType *dt, const char *decl, asCString &outName, asCDataType &outType, asSNameSpace *ns); + int ParseDataType(const char *datatype, asCDataType *result, asSNameSpace *implicitNamespace, bool isReturnType = false); + int ParseTemplateDecl(const char *decl, asCString *name, asCArray &subtypeNames); + int ParseFunctionDeclaration(asCObjectType *type, const char *decl, asCScriptFunction *func, bool isSystemFunction, asCArray *paramAutoHandles = 0, bool *returnAutoHandle = 0, asSNameSpace *ns = 0, asCScriptNode **outListPattern = 0, asCObjectType **outParentClass = 0); + int ParseVariableDeclaration(const char *decl, asSNameSpace *implicitNamespace, asCString &outName, asSNameSpace *&outNamespace, asCDataType &outDt); + int CheckNameConflict(const char *name, asCScriptNode *node, asCScriptCode *code, asSNameSpace *ns, bool isProperty, bool isVirtualProperty); + int CheckNameConflictMember(asCTypeInfo *type, const char *name, asCScriptNode *node, asCScriptCode *code, bool isProperty, bool isVirtualProperty); + int ValidateVirtualProperty(asCScriptFunction *func); + +#ifndef AS_NO_COMPILER + int AddCode(const char *name, const char *code, int codeLength, int lineOffset, int sectionIdx, bool makeCopy); + asCScriptCode *FindOrAddCode(const char *name, const char *code, size_t length); + int Build(); + + int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asCScriptFunction **outFunc); + int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset); +#endif + +protected: + friend class asCModule; + friend class asCParser; + friend class asCScriptFunction; + friend class asCScriptEngine; + + void Reset(); + + void WriteInfo(const asCString &scriptname, const asCString &msg, int r, int c, bool preMessage); + void WriteInfo(const asCString &msg, asCScriptCode *file, asCScriptNode *node); + void WriteError(const asCString &scriptname, const asCString &msg, int r, int c); + void WriteError(const asCString &msg, asCScriptCode *file, asCScriptNode *node); + void WriteWarning(const asCString &scriptname, const asCString &msg, int r, int c); + void WriteWarning(const asCString &msg, asCScriptCode *file, asCScriptNode *node); + + bool DoesGlobalPropertyExist(const char *prop, asSNameSpace *ns, asCGlobalProperty **outProp = 0, sGlobalVariableDescription **outDesc = 0, bool *isAppProp = 0); + asCGlobalProperty *GetGlobalProperty(const char *prop, asSNameSpace *ns, bool *isCompiled, bool *isPureConstant, asQWORD *constantValue, bool *isAppProp); + int ValidateDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func); + asCString GetCleanExpressionString(asCScriptNode *n, asCScriptCode *file); + + asSNameSpace *GetNameSpaceFromNode(asCScriptNode *node, asCScriptCode *script, asSNameSpace *implicitNs, asCScriptNode **next, asCObjectType **objType = 0); + asSNameSpace *GetNameSpaceByString(const asCString &nsName, asSNameSpace *implicitNs, asCScriptNode *errNode, asCScriptCode *script, asCTypeInfo **scopeType = 0, bool isRequired = true); + asCString GetScopeFromNode(asCScriptNode *n, asCScriptCode *script, asCScriptNode **next = 0); + + asCTypeInfo *GetType(const char *type, asSNameSpace *ns, asCObjectType *parentType); + asCObjectType *GetObjectType(const char *type, asSNameSpace *ns); + asCFuncdefType *GetFuncDef(const char *type, asSNameSpace *ns, asCObjectType *parentType); + asCTypeInfo *GetTypeFromTypesKnownByObject(const char *type, asCObjectType *currentType); + asCDataType CreateDataTypeFromNode(asCScriptNode *node, asCScriptCode *file, asSNameSpace *implicitNamespace, bool acceptHandleForScope = false, asCObjectType *currentType = 0, bool reportError = true, bool *isValid = 0); + asCObjectType *GetTemplateInstanceFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *templateType, asSNameSpace *implicitNamespace, asCObjectType *currentType, asCScriptNode **next = 0); + asCDataType ModifyDataTypeFromNode(const asCDataType &type, asCScriptNode *node, asCScriptCode *file, asETypeModifiers *inOutFlag, bool *autoHandle); + + int numErrors; + int numWarnings; + bool silent; + + asCScriptEngine *engine; + asCModule *module; + +#ifndef AS_NO_COMPILER +protected: + friend class asCCompiler; + + int CheckForConflictsDueToDefaultArgs(asCScriptCode *script, asCScriptNode *node, asCScriptFunction *func, asCObjectType *objType); + int GetNamespaceAndNameFromNode(asCScriptNode *n, asCScriptCode *script, asSNameSpace *implicitNs, asSNameSpace *&outNs, asCString &outName); + int RegisterMixinClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + sMixinClass *GetMixinClass(const char *name, asSNameSpace *ns); + void IncludePropertiesFromMixins(sClassDeclaration *decl); + void IncludeMethodsFromMixins(sClassDeclaration *decl); + void AddInterfaceToClass(sClassDeclaration *decl, asCScriptNode *errNode, asCObjectType *intf); + void AddInterfaceFromMixinToClass(sClassDeclaration *decl, asCScriptNode *errNode, sMixinClass *mixin); + + int RegisterScriptFunctionFromNode(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false, bool isMixin = false); + int RegisterScriptFunction(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, bool isInterface, bool isGlobalFunction, asSNameSpace *ns, bool isExistingShared, bool isMixin, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits funcTraits); + int RegisterVirtualProperty(asCScriptNode *node, asCScriptCode *file, asCObjectType *object = 0, bool isInterface = false, bool isGlobalFunction = false, asSNameSpace *ns = 0, bool isExistingShared = false); + int RegisterImportedFunction(int funcID, asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterGlobalVar(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterClass(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterInterface(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterEnum(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterTypedef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns); + int RegisterFuncDef(asCScriptNode *node, asCScriptCode *file, asSNameSpace *ns, asCObjectType *parent); + asCScriptFunction *RegisterLambda(asCScriptNode *node, asCScriptCode *file, asCScriptFunction *funcDef, const asCString &name, asSNameSpace *ns); + void CompleteFuncDef(sFuncDef *funcDef); + void CompileInterfaces(); + void CompileClasses(asUINT originalNumTempl); + void DetermineTypeRelations(); + void GetParsedFunctionDetails(asCScriptNode *node, asCScriptCode *file, asCObjectType *objType, asCString &name, asCDataType &returnType, asCArray ¶meterNames, asCArray ¶meterTypes, asCArray &inOutFlags, asCArray &defaultArgs, asSFunctionTraits &traits, asSNameSpace *implicitNamespace); + bool DoesMethodExist(asCObjectType *objType, int methodId, asUINT *methodIndex = 0); + void AddDefaultConstructor(asCObjectType *objType, asCScriptCode *file); + asCObjectProperty *AddPropertyToClass(sClassDeclaration *c, const asCString &name, const asCDataType &type, bool isPrivate, bool isProtected, bool isInherited, asCScriptCode *file = 0, asCScriptNode *node = 0); + int CreateVirtualFunction(asCScriptFunction *func, int idx); + void ParseScripts(); + void RegisterTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns); + void RegisterNonTypesFromScript(asCScriptNode *node, asCScriptCode *script, asSNameSpace *ns); + void CompileFunctions(); + void CompileGlobalVariables(); + int GetEnumValueFromType(asCEnumType *type, const char *name, asCDataType &outDt, asDWORD &outValue); + int GetEnumValue(const char *name, asCDataType &outDt, asDWORD &outValue, asSNameSpace *ns); + bool DoesTypeExist(const asCString &type); + asCObjectProperty *GetObjectProperty(asCDataType &obj, const char *prop); + asCScriptFunction *GetFunctionDescription(int funcId); + void GetFunctionDescriptions(const char *name, asCArray &funcs, asSNameSpace *ns); + void GetObjectMethodDescriptions(const char *name, asCObjectType *objectType, asCArray &methods, bool objIsConst, const asCString &scope = "", asCScriptNode *errNode = 0, asCScriptCode *script = 0); + void EvaluateTemplateInstances(asUINT startIdx, bool keepSilent); + void CleanupEnumValues(); + + asCArray scripts; + asCArray functions; + asCSymbolTable globVariables; + asCArray classDeclarations; + asCArray interfaceDeclarations; + asCArray namedTypeDeclarations; + asCArray funcDefs; + asCArray mixinClasses; + + // For use with the DoesTypeExists() method + bool hasCachedKnownTypes; + asCMap knownTypes; +#endif +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_bytecode.cpp b/angelscript/source/as_bytecode.cpp new file mode 100644 index 0000000..fbad9d9 --- /dev/null +++ b/angelscript/source/as_bytecode.cpp @@ -0,0 +1,3023 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_bytecode.cpp +// +// A class for constructing the final byte code +// + +#include // fopen(), fprintf(), fclose() + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_bytecode.h" +#include "as_debug.h" // mkdir() +#include "as_array.h" +#include "as_string.h" +#include "as_scriptengine.h" +#include "as_debug.h" + +BEGIN_AS_NAMESPACE + +asCByteCode::asCByteCode(asCScriptEngine *engine) +{ + first = 0; + last = 0; + largestStackUsed = -1; + temporaryVariables = 0; + + this->engine = engine; +} + +asCByteCode::~asCByteCode() +{ + ClearAll(); +} + +void asCByteCode::Finalize(const asCArray &tempVariableOffsets) +{ + temporaryVariables = &tempVariableOffsets; + + // verify the bytecode + PostProcess(); + + // Optimize the code + Optimize(); + + // Resolve jumps + ResolveJumpAddresses(); + + // Build line numbers buffer + ExtractLineNumbers(); +} + +void asCByteCode::ClearAll() +{ + asCByteInstruction *del = first; + + while( del ) + { + first = del->next; + engine->memoryMgr.FreeByteInstruction(del); + del = first; + } + + first = 0; + last = 0; + + lineNumbers.SetLength(0); + + largestStackUsed = -1; +} + +void asCByteCode::InsertIfNotExists(asCArray &vars, int var) +{ + if( !vars.Exists(var) ) + vars.PushLast(var); +} + +void asCByteCode::GetVarsUsed(asCArray &vars) +{ + TimeIt("asCByteCode::GetVarsUsed"); + + asCByteInstruction *curr = first; + while( curr ) + { + if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ) + { + InsertIfNotExists(vars, curr->wArg[0]); + InsertIfNotExists(vars, curr->wArg[1]); + InsertIfNotExists(vars, curr->wArg[2]); + } + else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ) + { + InsertIfNotExists(vars, curr->wArg[0]); + } + else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ) + { + InsertIfNotExists(vars, curr->wArg[0]); + InsertIfNotExists(vars, curr->wArg[1]); + } + else if( curr->op == asBC_LoadThisR ) + { + InsertIfNotExists(vars, 0); + } + + curr = curr->next; + } +} + +bool asCByteCode::IsVarUsed(int offset) +{ + TimeIt("asCByteCode::IsVarUsed"); + + asCByteInstruction *curr = first; + while( curr ) + { + // Verify all ops that use variables + if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ) + { + if( curr->wArg[0] == offset || curr->wArg[1] == offset || curr->wArg[2] == offset ) + return true; + } + else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ) + { + if( curr->wArg[0] == offset ) + return true; + } + else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG ) + { + if( curr->wArg[0] == offset || curr->wArg[1] == offset ) + return true; + } + else if( curr->op == asBC_LoadThisR ) + { + if( offset == 0 ) + return true; + } + + curr = curr->next; + } + + return false; +} + +void asCByteCode::ExchangeVar(int oldOffset, int newOffset) +{ + asASSERT(oldOffset != 0); + + asCByteInstruction *curr = first; + while( curr ) + { + // Verify all ops that use variables + if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG ) + { + if( curr->wArg[0] == oldOffset ) + curr->wArg[0] = (short)newOffset; + if( curr->wArg[1] == oldOffset ) + curr->wArg[1] = (short)newOffset; + if( curr->wArg[2] == oldOffset ) + curr->wArg[2] = (short)newOffset; + } + else if( asBCInfo[curr->op].type == asBCTYPE_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG ) + { + if( curr->wArg[0] == oldOffset ) + curr->wArg[0] = (short)newOffset; + } + else if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG ) + { + if( curr->wArg[0] == oldOffset ) + curr->wArg[0] = (short)newOffset; + if( curr->wArg[1] == oldOffset ) + curr->wArg[1] = (short)newOffset; + } + + curr = curr->next; + } +} + +void asCByteCode::AddPath(asCArray &paths, asCByteInstruction *instr, int stackSize) +{ + if( instr->marked ) + { + // Verify the size of the stack + asASSERT(instr->stackSize == stackSize); + } + else + { + // Add the destination to the code paths + instr->marked = true; + instr->stackSize = stackSize; + paths.PushLast(instr); + } +} + +asCByteInstruction *asCByteCode::ChangeFirstDeleteNext(asCByteInstruction *curr, asEBCInstr bc) +{ + curr->op = bc; + + if( curr->next ) DeleteInstruction(curr->next); + + // Continue optimization with the instruction before the altered one + if( curr->prev ) + return curr->prev; + else + return curr; +} + +asCByteInstruction *asCByteCode::DeleteFirstChangeNext(asCByteInstruction *curr, asEBCInstr bc) +{ + asASSERT( curr->next ); + + asCByteInstruction *instr = curr->next; + instr->op = bc; + + DeleteInstruction(curr); + + // Continue optimization with the instruction before the altered one + if( instr->prev ) + return instr->prev; + else + return instr; +} + +void asCByteCode::InsertBefore(asCByteInstruction *before, asCByteInstruction *instr) +{ + asASSERT(instr->next == 0); + asASSERT(instr->prev == 0); + + if( before->prev ) before->prev->next = instr; + instr->prev = before->prev; + before->prev = instr; + instr->next = before; + + if( first == before ) first = instr; +} + +void asCByteCode::RemoveInstruction(asCByteInstruction *instr) +{ + if( instr == first ) first = first->next; + if( instr == last ) last = last->prev; + + if( instr->prev ) instr->prev->next = instr->next; + if( instr->next ) instr->next->prev = instr->prev; + + instr->next = 0; + instr->prev = 0; +} + +bool asCByteCode::CanBeSwapped(asCByteInstruction *curr) +{ + asASSERT( curr->op == asBC_SwapPtr ); + + if( !curr->prev || !curr->prev->prev ) return false; + + asCByteInstruction *b = curr->prev; + asCByteInstruction *a = b->prev; + + if( a->op != asBC_PshNull && + a->op != asBC_PshVPtr && + a->op != asBC_PSF ) + return false; + + if( b->op != asBC_PshNull && + b->op != asBC_PshVPtr && + b->op != asBC_PSF ) + return false; + + return true; +} + +asCByteInstruction *asCByteCode::GoBack(asCByteInstruction *curr) +{ + // Go back 2 instructions + if( !curr ) return 0; + if( curr->prev ) curr = curr->prev; + if( curr->prev ) curr = curr->prev; + return curr; +} + +asCByteInstruction *asCByteCode::GoForward(asCByteInstruction *curr) +{ + // Go forward 2 instructions + if( !curr ) return 0; + if( curr->next ) curr = curr->next; + if( curr->next ) curr = curr->next; + return curr; +} + +bool asCByteCode::PostponeInitOfTemp(asCByteInstruction *curr, asCByteInstruction **next) +{ + TimeIt("asCByteCode::PostponeInitOfTemp"); + + // This is not done for pointers + if( (curr->op != asBC_SetV4 && curr->op != asBC_SetV8) || + !IsTemporary(curr->wArg[0]) ) return false; + + // Move the initialization to just before it's use. + // Don't move it beyond any labels or jumps. + asCByteInstruction *use = curr->next; + while( use ) + { + if( IsTempVarReadByInstr(use, curr->wArg[0]) ) + break; + + if( IsTempVarOverwrittenByInstr(use, curr->wArg[0]) ) + return false; + + if( IsInstrJmpOrLabel(use) ) + return false; + + use = use->next; + } + + if( use && use->prev != curr ) + { + asCByteInstruction *orig = curr->next; + + // Move the instruction + RemoveInstruction(curr); + InsertBefore(use, curr); + + // Try a RemoveUnusedValue to see if it can be combined with the other + if( RemoveUnusedValue(curr, 0) ) + { + // Optimizations should continue from the instruction that uses the value + *next = orig; + return true; + } + + // Return the instructions to its original position as it wasn't useful + RemoveInstruction(curr); + InsertBefore(orig, curr); + } + + return false; +} + +bool asCByteCode::RemoveUnusedValue(asCByteInstruction *curr, asCByteInstruction **next) +{ + TimeIt("asCByteCode::RemoveUnusedValue"); + + asCByteInstruction *dummy; + if( next == 0 ) + next = &dummy; + + // TODO: runtime optimize: Should work for 64bit types as well + + // TODO: runtime optimize: Need a asBCTYPE_rwW_ARG to cover the instructions that read + // and write to the same variable. Currently they are considered + // as readers only, so they are not optimized away. This includes + // NOT, BNOT, IncV, DecV, NEG, iTOf (and all other type casts) + + // The value isn't used for anything + if( curr->op != asBC_FREE && // Can't remove the FREE instruction + (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr, curr->wArg[0]) ) + { + if( curr->op == asBC_LdGRdR4 && IsTempRegUsed(curr) ) + { + curr->op = asBC_LDG; + *next = GoForward(curr); + return true; + } + + *next = GoForward(DeleteInstruction(curr)); + return true; + } + + if( curr->op == asBC_SetV4 && curr->next ) + { + // The value is immediately used and then never again + if( (curr->next->op == asBC_CMPi || + curr->next->op == asBC_CMPf || + curr->next->op == asBC_CMPu) && + curr->wArg[0] == curr->next->wArg[1] && + IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + if( curr->next->op == asBC_CMPi ) curr->next->op = asBC_CMPIi; + else if( curr->next->op == asBC_CMPf ) curr->next->op = asBC_CMPIf; + else if( curr->next->op == asBC_CMPu ) curr->next->op = asBC_CMPIu; + curr->next->size = asBCTypeSize[asBCInfo[asBC_CMPIi].type]; + curr->next->arg = curr->arg; + *next = GoForward(DeleteInstruction(curr)); + return true; + } + + // The value is immediately used and then never again + if( (curr->next->op == asBC_ADDi || + curr->next->op == asBC_SUBi || + curr->next->op == asBC_MULi || + curr->next->op == asBC_ADDf || + curr->next->op == asBC_SUBf || + curr->next->op == asBC_MULf) && + curr->wArg[0] == curr->next->wArg[2] && + (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten + (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again + !IsTempVarRead(curr->next, curr->wArg[0]))) ) + { + if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi; + else if( curr->next->op == asBC_SUBi ) curr->next->op = asBC_SUBIi; + else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi; + else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf; + else if( curr->next->op == asBC_SUBf ) curr->next->op = asBC_SUBIf; + else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf; + curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type]; + curr->next->arg = curr->arg; + *next = GoForward(DeleteInstruction(curr)); + return true; + } + + if( (curr->next->op == asBC_ADDi || + curr->next->op == asBC_MULi || + curr->next->op == asBC_ADDf || + curr->next->op == asBC_MULf) && + curr->wArg[0] == curr->next->wArg[1] && + (curr->next->wArg[0] == curr->wArg[0] || // The variable is overwritten + (IsTemporary(curr->wArg[0]) && // The variable is temporary and never used again + !IsTempVarRead(curr->next, curr->wArg[0]))) ) + { + if( curr->next->op == asBC_ADDi ) curr->next->op = asBC_ADDIi; + else if( curr->next->op == asBC_MULi ) curr->next->op = asBC_MULIi; + else if( curr->next->op == asBC_ADDf ) curr->next->op = asBC_ADDIf; + else if( curr->next->op == asBC_MULf ) curr->next->op = asBC_MULIf; + curr->next->size = asBCTypeSize[asBCInfo[asBC_ADDIi].type]; + curr->next->arg = curr->arg; + + // The order of the operands are changed + curr->next->wArg[1] = curr->next->wArg[2]; + + *next = GoForward(DeleteInstruction(curr)); + return true; + } + + // The constant value is immediately moved to another variable and then not used again + if( curr->next->op == asBC_CpyVtoV4 && + curr->wArg[0] == curr->next->wArg[1] && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + curr->wArg[0] = curr->next->wArg[0]; + *next = GoForward(DeleteInstruction(curr->next)); + return true; + } + + // The constant is copied to a temp and then immediately pushed on the stack + if( curr->next->op == asBC_PshV4 && + curr->wArg[0] == curr->next->wArg[0] && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + curr->op = asBC_PshC4; + curr->stackInc = asBCInfo[asBC_PshC4].stackInc; + *next = GoForward(DeleteInstruction(curr->next)); + return true; + } + + // The constant is copied to a global variable and then never used again + if( curr->next->op == asBC_CpyVtoG4 && + curr->wArg[0] == curr->next->wArg[0] && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + curr->op = asBC_SetG4; + curr->size = asBCTypeSize[asBCInfo[asBC_SetG4].type]; + *(((asDWORD*)&curr->arg)+AS_PTR_SIZE) = *ARG_DW(curr->arg); + *ARG_PTR(curr->arg) = *ARG_PTR(curr->next->arg); + *next = GoForward(DeleteInstruction(curr->next)); + return true; + } + } + + // The value is immediately moved to another variable and then not used again + if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) && + curr->next && curr->next->op == asBC_CpyVtoV4 && + curr->wArg[0] == curr->next->wArg[1] && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + curr->wArg[0] = curr->next->wArg[0]; + *next = GoForward(DeleteInstruction(curr->next)); + return true; + } + + // The register is copied to a temp variable and then back to the register again without being used afterwards + if( curr->op == asBC_CpyRtoV4 && curr->next && curr->next->op == asBC_CpyVtoR4 && + curr->wArg[0] == curr->next->wArg[0] && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + // Delete both instructions + DeleteInstruction(curr->next); + *next = GoForward(DeleteInstruction(curr)); + return true; + } + + // The global value is copied to a temp and then immediately pushed on the stack + if( curr->op == asBC_CpyGtoV4 && curr->next && curr->next->op == asBC_PshV4 && + curr->wArg[0] == curr->next->wArg[0] && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + curr->op = asBC_PshG4; + curr->size = asBCTypeSize[asBCInfo[asBC_PshG4].type]; + curr->stackInc = asBCInfo[asBC_PshG4].stackInc; + *next = GoForward(DeleteInstruction(curr->next)); + return true; + } + + // The constant is assigned to a variable, then the value of the variable + // pushed on the stack, and then the variable is never used again + if( curr->op == asBC_SetV8 && curr->next && curr->next->op == asBC_PshV8 && + curr->wArg[0] == curr->next->wArg[0] && + IsTemporary(curr->wArg[0]) && + !IsTempVarRead(curr->next, curr->wArg[0]) ) + { + curr->op = asBC_PshC8; + curr->stackInc = asBCInfo[asBC_PshC8].stackInc; + *next = GoForward(DeleteInstruction(curr->next)); + return true; + } + + return false; +} + +bool asCByteCode::IsTemporary(int offset) +{ + TimeIt("asCByteCode::IsTemporary"); + + asASSERT(temporaryVariables); + + return temporaryVariables->Exists(offset); +} + +void asCByteCode::OptimizeLocally(const asCArray &tempVariableOffsets) +{ + // This function performs the optimizations that doesn't require global knowledge of the + // entire function, e.g. replacement of sequences of bytecodes for specialized instructions. + + if( !engine->ep.optimizeByteCode ) + return; + + temporaryVariables = &tempVariableOffsets; + + // TODO: runtime optimize: VAR + GET... should be optimized if the only instructions between them are trivial, i.e. no + // function calls that can suspend the execution. + + // TODO: runtime optimize: Remove temporary copies of handles, when the temp is just copied to yet another location + + // TODO: runtime optimize: A single bytecode for incrementing a variable, comparing, and jumping can probably improve + // loops a lot. How often do these loops really occur? + + // TODO: runtime optimize: Need a bytecode BC_AddRef so that BC_CALLSYS doesn't have to be used for this trivial call + + // TODO: optimize: Should possibly do two loops. Some of the checks are best doing by iterating from + // the end to beginning, e.g. the removal of unused values. Other checks are best + // doing by iterating from the beginning to end, e.g. replacement of sequences with + // shorter ones. By doing this, we should be able to avoid backtracking with every + // change thus avoid unnecessary duplicate checks. + + // Iterate through the bytecode instructions in the reverse order. + // An optimization in an instruction may mean that another instruction before that + // can also be optimized, e.g. if an add instruction is removed because the result is not + // used, then the instructions that created the operands may potentially also be removed. + asCByteInstruction *instr = last; + while( instr ) + { + asCByteInstruction *curr = instr; + instr = instr->prev; + + // Remove instructions when the result is not used anywhere + // This will return true if the instruction is deleted, and + // false if it is not deleted. Observe that the instruction + // can be modified. + if( RemoveUnusedValue(curr, &instr) ) continue; + + // Postpone initializations so that they may be combined in the second pass. + // If the initialization is postponed, then the optimizations should continue + // from where the value was used, so instr will be updated to point to that. + if( PostponeInitOfTemp(curr, &instr) ) continue; + + // Look for sequences that can be replaced with shorter ones + const asEBCInstr currOp = curr->op; + if( currOp == asBC_SwapPtr ) + { + // XXX x, YYY y, SwapPtr -> YYY y, XXX x + if( CanBeSwapped(curr) ) + { + // Delete the SwapPtr + DeleteInstruction(curr); + + // Swap instructions + asCByteInstruction *a = instr->prev; + RemoveInstruction(instr); + InsertBefore(a, instr); + + // Continue the optimization from the second instruction + instr = GoForward(a); + continue; + } + } + else if( currOp == asBC_ClrHi ) + { + // T??, ClrHi -> T?? + if( instr && + (instr->op == asBC_TZ || + instr->op == asBC_TNZ || + instr->op == asBC_TS || + instr->op == asBC_TNS || + instr->op == asBC_TP || + instr->op == asBC_TNP) ) + { + // Remove the ClrHi instruction since the test + // instructions always clear the top bytes anyway + instr = GoForward(DeleteInstruction(curr)); + continue; + } + + // ClrHi, JZ -> JLowZ + if( curr->next && + curr->next->op == asBC_JZ ) + { + curr->next->op = asBC_JLowZ; + instr = GoForward(DeleteInstruction(curr)); + continue; + } + + // ClrHi, JNZ -> JLowNZ + if( curr->next && + curr->next->op == asBC_JNZ ) + { + curr->next->op = asBC_JLowNZ; + instr = GoForward(DeleteInstruction(curr)); + continue; + } + } + else if( currOp == asBC_LDV && curr->next ) + { + // LDV x, INCi -> IncVi x + if( curr->next->op == asBC_INCi && !IsTempRegUsed(curr->next) ) + { + curr->op = asBC_IncVi; + DeleteInstruction(curr->next); + instr = GoForward(curr); + } + // LDV x, DECi -> DecVi x + else if( curr->next->op == asBC_DECi && !IsTempRegUsed(curr->next) ) + { + curr->op = asBC_DecVi; + DeleteInstruction(curr->next); + instr = GoForward(curr); + } + } + else if( currOp == asBC_LDG && curr->next ) + { + // LDG x, WRTV4 y -> CpyVtoG4 y, x + if( curr->next->op == asBC_WRTV4 && !IsTempRegUsed(curr->next) ) + { + curr->op = asBC_CpyVtoG4; + curr->size = asBCTypeSize[asBCInfo[asBC_CpyVtoG4].type]; + curr->wArg[0] = curr->next->wArg[0]; + DeleteInstruction(curr->next); + instr = GoForward(curr); + } + // LDG x, RDR4 y -> CpyGtoV4 y, x + else if( curr->next->op == asBC_RDR4 ) + { + if( !IsTempRegUsed(curr->next) ) + curr->op = asBC_CpyGtoV4; + else + curr->op = asBC_LdGRdR4; + curr->size = asBCTypeSize[asBCInfo[asBC_CpyGtoV4].type]; + curr->wArg[0] = curr->next->wArg[0]; + DeleteInstruction(curr->next); + instr = GoForward(curr); + } + } + else if( currOp == asBC_CHKREF ) + { + // CHKREF, ADDSi -> ADDSi + // CHKREF, RDSPtr -> RDSPtr + if( curr->next && + (curr->next->op == asBC_ADDSi || curr->next->op == asBC_RDSPtr) ) + { + // As ADDSi & RDSPtr already checks the pointer the CHKREF instruction is unnecessary + instr = GoForward(DeleteInstruction(curr)); + } + // ADDSi, CHKREF -> ADDSi + // PGA, CHKREF -> PGA + // PSF, CHKREF -> PSF + else if( instr && + (instr->op == asBC_ADDSi || + instr->op == asBC_PGA || + instr->op == asBC_PSF) ) + { + // ADDSi is guaranteed to work on valid pointers so CHKREF is not necessary. + // PGA and PSF always pushes a valid address on the stack. + instr = GoForward(DeleteInstruction(curr)); + } + // PGA, ChkRefS, CHKREF -> PGA, ChkRefS + else if( instr && instr->op == asBC_ChkRefS && + instr->prev && instr->prev->op == asBC_PGA ) + { + // Delete CHKREF since PGA always pushes a valid address on the stack + instr = GoForward(DeleteInstruction(curr)); + } + } + else if( currOp == asBC_PopPtr ) + { + // RDSPtr, PopPtr -> PopPtr + if( instr && instr->op == asBC_RDSPtr ) + { + instr = GoForward(DeleteInstruction(instr)); + } + // PshNull, RefCpyV, PopPtr -> FREE + else if( instr && instr->op == asBC_RefCpyV && + instr->prev && instr->prev->op == asBC_PshNull ) + { + DeleteInstruction(curr); + DeleteInstruction(instr->prev); + instr->op = asBC_FREE; + instr = GoForward(instr); + } + // PshVPtr y, PopPtr -> nothing + // PSF y , PopPtr -> nothing + // VAR y , PopPtr -> nothing + // PshNull , PopPtr -> nothing + // PshRPtr , PopPtr -> nothing + else if( instr && + (instr->op == asBC_PshRPtr || + instr->op == asBC_PSF || + instr->op == asBC_VAR || + instr->op == asBC_PshVPtr || + instr->op == asBC_PshNull) ) + { + // A pointer is pushed on the stack then immediately removed + // Remove both instructions as they cancel each other + DeleteInstruction(curr); + instr = GoForward(DeleteInstruction(instr)); + } + // PSF, ChkRefS, PopPtr -> ChkNullV + else if( instr && instr->op == asBC_ChkRefS && + instr->prev && instr->prev->op == asBC_PSF ) + { + instr = instr->prev; + instr->op = asBC_ChkNullV; + instr->stackInc = 0; + // Delete the PopPtr instruction + DeleteInstruction(curr); + // Delete the ChkRefS instruction + DeleteInstruction(instr->next); + instr = GoForward(instr); + } + // PshVPtr, CHKREF, PopPtr -> ChkNullV + else if( instr && instr->op == asBC_CHKREF && + instr->prev && instr->prev->op == asBC_PshVPtr ) + { + instr = instr->prev; + instr->op = asBC_ChkNullV; + instr->stackInc = 0; + DeleteInstruction(curr->prev); + DeleteInstruction(curr); + instr = GoForward(instr); + } + // STOREOBJ y, PSF y, RDSPtr, PSF x, REFCPY, FREE y, PopPtr -> FREE x, STOREOBJ x + else if( instr && instr->op == asBC_FREE ) + { + asCByteInstruction *i = instr->prev; + if( !i || i->op != asBC_REFCPY ) continue; + i = i->prev; + if( !i || i->op != asBC_PSF ) continue; + short x = i->wArg[0]; + i = i->prev; + if( !i || i->op != asBC_RDSPtr ) continue; + i = i->prev; + if( !i || i->op != asBC_PSF ) continue; + short y = i->wArg[0]; + i = i->prev; + if( !i || i->op != asBC_STOREOBJ || i->wArg[0] != y ) continue; + + // Don't do the substitution if the var y is not a temporary, or if it is used after PopPtr + if( !IsTemporary(y) || IsTempVarRead(curr, y) ) continue; + + // Transform the PopPtr into STOREOBJ + curr->op = asBC_STOREOBJ; + curr->stackInc = 0; + curr->wArg[0] = x; + curr->size = i->size; + + // Change arg of the FREE to x + // TODO: runtime optimize: The FREE instruction shouldn't be necessary. STOREOBJ should free the previous value by itself + instr->wArg[0] = x; + + // Delete all other instructions + DeleteInstruction(instr->prev); // REFCPY + DeleteInstruction(instr->prev); // PSF + DeleteInstruction(instr->prev); // RDSTR + DeleteInstruction(instr->prev); // PSF + DeleteInstruction(instr->prev); // STOREOBJ + + instr = GoForward(curr); + } + } + else if( currOp == asBC_RDSPtr ) + { + // PGA, RDSPtr -> PshGPtr + if( instr && instr->op == asBC_PGA ) + { + instr->op = asBC_PshGPtr; + DeleteInstruction(curr); + instr = GoForward(instr); + } + // ChkRefS, RDSPtr -> RDSPtr, CHKREF + else if( instr && instr->op == asBC_ChkRefS ) + { + // This exchange removes one pointer dereference, and also + // makes it easier to completely remove the CHKREF instruction + curr->op = asBC_CHKREF; + instr->op = asBC_RDSPtr; + instr = GoForward(curr); + } + // PSF, RDSPtr -> PshVPtr + else if( instr && instr->op == asBC_PSF ) + { + instr->op = asBC_PshVPtr; + instr = GoForward(DeleteInstruction(curr)); + } + // PSF, ChkRefS, RDSPtr -> PshVPtr, CHKREF + else if( instr && instr->op == asBC_ChkRefS && + instr->prev && instr->prev->op == asBC_PSF ) + { + instr->prev->op = asBC_PshVPtr; + instr->op = asBC_CHKREF; + instr = GoForward(DeleteInstruction(curr)); + } + } + else if( currOp == asBC_PopRPtr ) + { + // PshVPtr 0, ADDSi, PopRPtr -> LoadThisR + if( instr && instr->op == asBC_ADDSi && + instr->prev && instr->prev->op == asBC_PshVPtr && + instr->prev->wArg[0] == 0 ) + { + DeleteInstruction(instr->prev); + ChangeFirstDeleteNext(instr, asBC_LoadThisR); + instr = GoForward(instr); + } + // TODO: runtime optimize: PshVPtr x, PopRPtr -> LoadRObjR x, 0 + // PshVPtr x, ADDSi, PopRPtr -> LoadRObjR + else if( instr && instr->op == asBC_ADDSi && + instr->prev && instr->prev->op == asBC_PshVPtr && + instr->prev->wArg[0] != 0 ) + { + instr = instr->prev; + instr->op = asBC_LoadRObjR; + instr->size = asBCTypeSize[asBCInfo[asBC_LoadRObjR].type]; + instr->stackInc = asBCInfo[asBC_LoadRObjR].stackInc; + instr->wArg[1] = instr->next->wArg[0]; + *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg; + DeleteInstruction(instr->next); + DeleteInstruction(curr); + instr = GoForward(instr); + } + // PSF x, ADDSi, PopRPtr -> LoadVObjR + else if( instr && instr->op == asBC_ADDSi && + instr->prev && instr->prev->op == asBC_PSF ) + { + instr = instr->prev; + instr->op = asBC_LoadVObjR; + instr->size = asBCTypeSize[asBCInfo[asBC_LoadVObjR].type]; + instr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc; + instr->wArg[1] = instr->next->wArg[0]; + *(asDWORD*)&instr->arg = *(asDWORD*)&instr->next->arg; + DeleteInstruction(instr->next); + DeleteInstruction(curr); + instr = GoForward(instr); + } + } + else if( currOp == asBC_REFCPY ) + { + // PSF x, REFCPY -> RefCpyV x + if( instr && instr->op == asBC_PSF ) + { + curr->op = asBC_RefCpyV; + curr->wArg[0] = instr->wArg[0]; + curr->stackInc = asBCInfo[asBC_LoadVObjR].stackInc; + DeleteInstruction(instr); + instr = GoForward(curr); + } + } + else if( ((currOp >= asBC_JZ && currOp <= asBC_JNP) || currOp == asBC_JLowZ || currOp == asBC_JLowNZ) && instr ) + { + // T**; J** +x -> J** +x + if( (instr->op == asBC_TZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || + (instr->op == asBC_TNZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) + instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNZ)); + else if( (instr->op == asBC_TNZ && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || + (instr->op == asBC_TZ && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) + instr = GoForward(DeleteFirstChangeNext(instr, asBC_JZ)); + else if( (instr->op == asBC_TS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || + (instr->op == asBC_TNS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) + instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNS)); + else if( (instr->op == asBC_TNS && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || + (instr->op == asBC_TS && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) + instr = GoForward(DeleteFirstChangeNext(instr, asBC_JS)); + else if( (instr->op == asBC_TP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || + (instr->op == asBC_TNP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) + instr = GoForward(DeleteFirstChangeNext(instr, asBC_JNP)); + else if( (instr->op == asBC_TNP && (currOp == asBC_JZ || currOp == asBC_JLowZ)) || + (instr->op == asBC_TP && (currOp == asBC_JNZ || currOp == asBC_JLowNZ)) ) + instr = GoForward(DeleteFirstChangeNext(instr, asBC_JP)); + } + else if( currOp == asBC_FREE && instr ) + { + // PSF, FREE -> FREE, PSF + if( instr->op == asBC_PSF ) + { + // This pattern usually happens when a function returns an object, or handle + // and then releases a temporary variable, possibly used in one of the arguments. + // By swapping the order of these instructions, the code can be further optimized + // to combine the PSF with the following instructions + RemoveInstruction(curr); + InsertBefore(instr, curr); + instr = GoForward(instr); + } + // VAR, FREE -> FREE, VAR + else if( instr->op == asBC_VAR ) + { + // Swap the two instructions, so that the VAR instruction + // gets closer to its corresponding GET instruction and thus + // has a greater chance of getting optimized + RemoveInstruction(curr); + InsertBefore(instr, curr); + instr = GoForward(instr); + } + } + else if( currOp == asBC_VAR ) + { + // VAR, PSF, GETOBJREF {PTR_SIZE} -> PshVPtr, PSF + if( curr->next && curr->next->op == asBC_PSF && + curr->next->next && curr->next->next->op == asBC_GETOBJREF && + curr->next->next->wArg[0] == AS_PTR_SIZE ) + { + curr->op = asBC_PshVPtr; + DeleteInstruction(curr->next->next); + instr = GoForward(curr); + } + // VAR a, GETREF 0 -> PSF a + else if( curr->next && curr->next->op == asBC_GETREF && curr->next->wArg[0] == 0 ) + { + ChangeFirstDeleteNext(curr, asBC_PSF); + instr = GoForward(curr); + } + // VAR a, GETOBJREF 0 -> PshVPtr a + else if( curr->next && curr->next->op == asBC_GETOBJREF && curr->next->wArg[0] == 0 ) + { + ChangeFirstDeleteNext(curr, asBC_PshVPtr); + instr = GoForward(curr); + } + // VAR, PSF, GETREF {PTR_SIZE} -> PSF, PSF + if( curr->next && curr->next->op == asBC_PSF && + curr->next->next && curr->next->next->op == asBC_GETREF && + curr->next->next->wArg[0] == AS_PTR_SIZE ) + { + curr->op = asBC_PSF; + DeleteInstruction(curr->next->next); + instr = GoForward(curr); + } + } + } + + // Optimize unnecessary refcpy for return handle. This scenario only happens for return statements + // and LOADOBJ can only be the last instruction before the RET, so doing this check after the rest of + // the optimizations have taken place saves us time. + if( last && last->op == asBC_LOADOBJ && IsTemporary(last->wArg[0]) ) + { + // A temporary handle is being loaded into the object register. + // Let's look for a trivial RefCpyV to that temporary variable, and a Free of the original + // variable. If this is found, then we can simply load the original value into the register + // and avoid both the RefCpy and the Free. + short tempVar = last->wArg[0]; + asCArray freedVars; + + instr = last->prev; + asASSERT( instr && instr->op == asBC_Block ); + instr = instr->prev; + while( instr && instr->op == asBC_FREE ) + { + freedVars.PushLast(instr->wArg[0]); + instr = instr->prev; + } + + // If there is any non-trivial cleanups, e.g. call to destructors, then we skip this optimizations + // TODO: runtime optimize: Do we need to skip it? Is there really a chance the local variable + // will be invalidated while the destructor, or any other function for + // that matter, is being called? + if( instr && instr->op == asBC_Block ) + { + // We expect a sequence PshVPtr, RefCpyV, PopPtr just before the clean up block + instr = instr->prev; + if( instr && instr->op == asBC_PopPtr ) instr = instr->prev; + if( instr && instr->op == asBC_RefCpyV && instr->wArg[0] == tempVar ) instr = instr->prev; + if( instr && instr->op == asBC_PshVPtr && freedVars.Exists(instr->wArg[0]) ) + { + // Update the LOADOBJ to load the local variable directly + tempVar = instr->wArg[0]; + last->wArg[0] = tempVar; + + // Remove the copy of the local variable into the temp + DeleteInstruction(instr->next); // deletes RefCpyV + DeleteInstruction(instr->next); // deletes PopPtr + DeleteInstruction(instr); // deletes PshVPtr + + // Find and remove the FREE instruction for the local variable too + instr = last->prev->prev; + while( instr ) + { + asASSERT( instr->op == asBC_FREE ); + if( instr->wArg[0] == tempVar ) + { + DeleteInstruction(instr); + break; + } + instr = instr->prev; + } + } + } + } +} + +void asCByteCode::Optimize() +{ + // This function performs the optimizations that require global knowledge of the entire function + + TimeIt("asCByteCode::Optimize"); + + if( !engine->ep.optimizeByteCode ) + return; + + // TODO: runtime optimize: The optimizer should be able to inline function calls. + // If the called function has only a few instructions, the function call should be inlined. + // This is especially useful with the factory stubs used for template types and script classes. + + asCByteInstruction *instr = first; + while( instr ) + { + asCByteInstruction *curr = instr; + instr = instr->next; + + const asEBCInstr currOp = curr->op; + + // Delete JitEntry if the JIT instructions are not supposed to be included + if( currOp == asBC_JitEntry && !engine->ep.includeJitInstructions ) + { + instr = GoBack(DeleteInstruction(curr)); + continue; + } + + if( instr ) + { + const asEBCInstr instrOp = instr->op; + + // PopPtr, RET b -> RET b + if( currOp == asBC_PopPtr && instrOp == asBC_RET ) + { + // We don't combine the PopPtr+RET because RET first restores + // the previous stack pointer and then pops the arguments + + // Delete PopPtr + instr = GoBack(DeleteInstruction(curr)); + } + else if( currOp == asBC_SUSPEND ) + { + // SUSPEND, JitEntry, SUSPEND -> SUSPEND + if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_SUSPEND ) + { + // Delete the two first instructions + DeleteInstruction(instr); + instr = GoBack(DeleteInstruction(curr)); + } + // SUSPEND, SUSPEND -> SUSPEND + else if( instrOp == asBC_SUSPEND ) + { + // Delete the first instruction + instr = GoBack(DeleteInstruction(curr)); + } + // SUSPEND, Block, SUSPEND -> Block, SUSPEND + else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_SUSPEND ) + { + // Delete the first instruction + instr = GoBack(DeleteInstruction(curr)); + } + } + else if( currOp == asBC_LINE ) + { + // LINE, JitEntry, LINE -> LINE + if( instrOp == asBC_JitEntry && instr->next && instr->next->op == asBC_LINE ) + { + // Delete the two first instructions + DeleteInstruction(instr); + instr = GoBack(DeleteInstruction(curr)); + } + // LINE, VarDecl, LINE -> VarDecl, LINE + else if (instrOp == asBC_VarDecl && instr->next && instr->next->op == asBC_LINE ) + { + // Delete the first instruction + instr = GoBack(DeleteInstruction(curr)); + } + // LINE, LINE -> LINE + else if( instrOp == asBC_LINE ) + { + // Delete the first instruction + instr = GoBack(DeleteInstruction(curr)); + } + // LINE, Block, LINE -> Block, LINE + else if( instrOp == asBC_Block && instr->next && instr->next->op == asBC_LINE ) + { + // Delete the first instruction + instr = GoBack(DeleteInstruction(curr)); + } + } + // JMP +0 -> remove + else if( currOp == asBC_JMP && instrOp == asBC_LABEL && *(int*)&curr->arg == instr->wArg[0] ) + instr = GoBack(DeleteInstruction(curr)); + } + } +} + +bool asCByteCode::IsTempVarReadByInstr(asCByteInstruction *curr, int offset) +{ + // Which instructions read from variables? + if( asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG && + (int(curr->wArg[1]) == offset || int(curr->wArg[2]) == offset) ) + return true; + else if( (asBCInfo[curr->op].type == asBCTYPE_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_QW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_W_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_rW_DW_DW_ARG || + curr->op == asBC_FREE) && // FREE both read and write to the variable + int(curr->wArg[0]) == offset ) + return true; + else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG) && + int(curr->wArg[1]) == offset ) + return true; + else if( asBCInfo[curr->op].type == asBCTYPE_rW_rW_ARG && + (int(curr->wArg[0]) == offset || int(curr->wArg[1]) == offset) ) + return true; + else if( curr->op == asBC_LoadThisR && offset == 0 ) + return true; + + return false; +} + +bool asCByteCode::IsInstrJmpOrLabel(asCByteInstruction *curr) +{ + if( curr->op == asBC_JS || + curr->op == asBC_JNS || + curr->op == asBC_JP || + curr->op == asBC_JNP || + curr->op == asBC_JMPP || + curr->op == asBC_JMP || + curr->op == asBC_JZ || + curr->op == asBC_JNZ || + curr->op == asBC_JLowZ || + curr->op == asBC_JLowNZ || + curr->op == asBC_LABEL ) + return true; + + return false; +} + +bool asCByteCode::IsTempVarOverwrittenByInstr(asCByteInstruction *curr, int offset) +{ + // Which instructions overwrite the variable or discard it? + if( curr->op == asBC_RET || + curr->op == asBC_SUSPEND ) + return true; + else if( (asBCInfo[curr->op].type == asBCTYPE_wW_rW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_rW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_W_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_DW_ARG || + asBCInfo[curr->op].type == asBCTYPE_wW_QW_ARG) && + int(curr->wArg[0]) == offset ) + return true; + + return false; +} + +bool asCByteCode::IsTempVarRead(asCByteInstruction *curr, int offset) +{ + TimeIt("asCByteCode::IsTempVarRead"); + + asCArray openPaths; + asCArray closedPaths; + + // We're not interested in the first instruction, since it is the one that sets the variable + openPaths.PushLast(curr->next); + + while( openPaths.GetLength() ) + { + curr = openPaths.PopLast(); + + // Add the instruction to the closed paths so that we don't verify it again + closedPaths.PushLast(curr); + + while( curr ) + { + if( IsTempVarReadByInstr(curr, offset) ) + return true; + + if( IsTempVarOverwrittenByInstr(curr, offset) ) break; + + // In case of jumps, we must follow the each of the paths + if( curr->op == asBC_JMP ) + { + // Find the destination. If it cannot be found it is because we're doing a localized + // optimization and the label hasn't been added to the final bytecode yet + + int label = *((int*)ARG_DW(curr->arg)); + int r = FindLabel(label, curr, &curr, 0); + if( r >= 0 && + !closedPaths.Exists(curr) && + !openPaths.Exists(curr) ) + openPaths.PushLast(curr); + + break; + } + else if( curr->op == asBC_JZ || curr->op == asBC_JNZ || + curr->op == asBC_JS || curr->op == asBC_JNS || + curr->op == asBC_JP || curr->op == asBC_JNP || + curr->op == asBC_JLowZ || curr->op == asBC_JLowNZ ) + { + // Find the destination. If it cannot be found it is because we're doing a localized + // optimization and the label hasn't been added to the final bytecode yet + + asCByteInstruction *dest = 0; + int label = *((int*)ARG_DW(curr->arg)); + int r = FindLabel(label, curr, &dest, 0); + if( r >= 0 && + !closedPaths.Exists(dest) && + !openPaths.Exists(dest) ) + openPaths.PushLast(dest); + } + else if( curr->op == asBC_JMPP ) + { + // A JMPP instruction is always followed by a series of JMP instructions + // that give the real destination (like a look-up table). We need add all + // of these as open paths. + curr = curr->next; + while( curr->op == asBC_JMP ) + { + // Find the destination. If it cannot be found it is because we're doing a localized + // optimization and the label hasn't been added to the final bytecode yet + + asCByteInstruction *dest = 0; + int label = *((int*)ARG_DW(curr->arg)); + int r = FindLabel(label, curr, &dest, 0); + if( r >= 0 && + !closedPaths.Exists(dest) && + !openPaths.Exists(dest) ) + openPaths.PushLast(dest); + + curr = curr->next; + } + + // We should now be on a label which is the destination of the + // first JMP in the sequence and is already added in the open paths + asASSERT(curr->op == asBC_LABEL); + break; + } + + curr = curr->next; + } + } + + return false; +} + +bool asCByteCode::IsTempRegUsed(asCByteInstruction *curr) +{ + TimeIt("asCByteCode::IsTempRegUsed"); + + // We're not interested in the first instruction, since it is the one that sets the register + while( curr->next ) + { + curr = curr->next; + + // Which instructions read from the register? + if( curr->op == asBC_INCi || + curr->op == asBC_INCi16 || + curr->op == asBC_INCi8 || + curr->op == asBC_INCf || + curr->op == asBC_INCd || + curr->op == asBC_DECi || + curr->op == asBC_DECi16 || + curr->op == asBC_DECi8 || + curr->op == asBC_DECf || + curr->op == asBC_DECd || + curr->op == asBC_WRTV1 || + curr->op == asBC_WRTV2 || + curr->op == asBC_WRTV4 || + curr->op == asBC_WRTV8 || + curr->op == asBC_RDR1 || + curr->op == asBC_RDR2 || + curr->op == asBC_RDR4 || + curr->op == asBC_RDR8 || + curr->op == asBC_PshRPtr || + curr->op == asBC_CpyRtoV4 || + curr->op == asBC_CpyRtoV8 || + curr->op == asBC_TZ || + curr->op == asBC_TNZ || + curr->op == asBC_TS || + curr->op == asBC_TNS || + curr->op == asBC_TP || + curr->op == asBC_TNP || + curr->op == asBC_JZ || + curr->op == asBC_JNZ || + curr->op == asBC_JLowZ || + curr->op == asBC_JLowNZ || + curr->op == asBC_JS || + curr->op == asBC_JNS || + curr->op == asBC_JP || + curr->op == asBC_JNP ) + return true; + + // Which instructions overwrite the register or discard the value? + if( curr->op == asBC_CALL || + curr->op == asBC_PopRPtr || + curr->op == asBC_CALLSYS || + curr->op == asBC_CALLBND || + curr->op == asBC_Thiscall1 || + curr->op == asBC_SUSPEND || + curr->op == asBC_ALLOC || + curr->op == asBC_CpyVtoR4 || + curr->op == asBC_LdGRdR4 || + curr->op == asBC_LDG || + curr->op == asBC_LDV || + curr->op == asBC_TZ || + curr->op == asBC_TNZ || + curr->op == asBC_TS || + curr->op == asBC_TNS || + curr->op == asBC_TP || + curr->op == asBC_TNP || + curr->op == asBC_JS || + curr->op == asBC_JNS || + curr->op == asBC_JP || + curr->op == asBC_JNP || + curr->op == asBC_JMPP || + curr->op == asBC_JMP || + curr->op == asBC_JZ || + curr->op == asBC_JNZ || + curr->op == asBC_JLowZ || + curr->op == asBC_JLowNZ || + curr->op == asBC_CMPi || + curr->op == asBC_CMPu || + curr->op == asBC_CMPf || + curr->op == asBC_CMPd || + curr->op == asBC_CMPIi || + curr->op == asBC_CMPIu || + curr->op == asBC_CMPIf || + curr->op == asBC_LABEL || + curr->op == asBC_LoadThisR || + curr->op == asBC_LoadRObjR || + curr->op == asBC_LoadVObjR ) + return false; + } + + return false; +} + +bool asCByteCode::IsSimpleExpression() +{ + // A simple expression is one that cannot be suspended at any time, i.e. + // it doesn't have any calls to other routines, and doesn't have any suspend instructions + asCByteInstruction *instr = first; + while( instr ) + { + if( instr->op == asBC_ALLOC || + instr->op == asBC_CALL || + instr->op == asBC_CALLSYS || + instr->op == asBC_SUSPEND || + instr->op == asBC_LINE || + instr->op == asBC_FREE || + instr->op == asBC_CallPtr || + instr->op == asBC_CALLINTF || + instr->op == asBC_CALLBND || + instr->op == asBC_Thiscall1 ) + return false; + + instr = instr->next; + } + + return true; +} + +void asCByteCode::ExtractLineNumbers() +{ + // This function will extract the line number and source file for each statement by looking for LINE instructions. + // The LINE instructions will be converted to SUSPEND instructions, or removed depending on the configuration. + + TimeIt("asCByteCode::ExtractLineNumbers"); + + int lastLinePos = -1; + int pos = 0; + asCByteInstruction *instr = first; + while( instr ) + { + asCByteInstruction *curr = instr; + instr = instr->next; + + if( curr->op == asBC_LINE ) + { + if( lastLinePos == pos ) + { + lineNumbers.PopLast(); // pop position + lineNumbers.PopLast(); // pop line number + sectionIdxs.PopLast(); // pop section index + } + + lastLinePos = pos; + lineNumbers.PushLast(pos); + lineNumbers.PushLast(*(int*)ARG_DW(curr->arg)); + sectionIdxs.PushLast(*((int*)ARG_DW(curr->arg)+1)); + + if( !engine->ep.buildWithoutLineCues ) + { + // Transform BC_LINE into BC_SUSPEND + curr->op = asBC_SUSPEND; + curr->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type]; + pos += curr->size; + } + else + { + // Delete the instruction + DeleteInstruction(curr); + } + } + else + pos += curr->size; + } +} + +void asCByteCode::ExtractObjectVariableInfo(asCScriptFunction *outFunc) +{ + asASSERT( outFunc->scriptData ); + + unsigned int pos = 0; + asCByteInstruction *instr = first; + int blockLevel = 0; + while( instr ) + { + if( instr->op == asBC_Block ) + { + asSObjectVariableInfo info; + info.programPos = pos; + info.variableOffset = 0; + info.option = instr->wArg[0] ? asBLOCK_BEGIN : asBLOCK_END; + if( info.option == asBLOCK_BEGIN ) + { + blockLevel++; + outFunc->scriptData->objVariableInfo.PushLast(info); + } + else + { + blockLevel--; + asASSERT( blockLevel >= 0 ); + if( outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].option == asBLOCK_BEGIN && + outFunc->scriptData->objVariableInfo[outFunc->scriptData->objVariableInfo.GetLength()-1].programPos == pos ) + outFunc->scriptData->objVariableInfo.PopLast(); + else + outFunc->scriptData->objVariableInfo.PushLast(info); + } + } + else if( instr->op == asBC_ObjInfo ) + { + asSObjectVariableInfo info; + info.programPos = pos; + info.variableOffset = (short)instr->wArg[0]; + info.option = (asEObjVarInfoOption)*(int*)ARG_DW(instr->arg); + outFunc->scriptData->objVariableInfo.PushLast(info); + } + else if( instr->op == asBC_VarDecl ) + { + // Record the position for debug info + outFunc->scriptData->variables[instr->wArg[0]]->declaredAtProgramPos = pos; + + // Record declaration of object variables for try/catch handling + // This is used for identifying if handles and objects on the heap should be cleared upon catching an exception + // Only extract this info if there is a try/catch block in the function, so we don't use up unnecessary space + if( outFunc->scriptData->tryCatchInfo.GetLength() && outFunc->scriptData->variables[instr->wArg[0]]->type.GetTypeInfo() ) + { + asSObjectVariableInfo info; + info.programPos = pos; + info.variableOffset = outFunc->scriptData->variables[instr->wArg[0]]->stackOffset; + info.option = asOBJ_VARDECL; + outFunc->scriptData->objVariableInfo.PushLast(info); + } + } + else + pos += instr->size; + + instr = instr->next; + } + asASSERT( blockLevel == 0 ); +} + +void asCByteCode::ExtractTryCatchInfo(asCScriptFunction *outFunc) +{ + asASSERT(outFunc->scriptData); + + unsigned int pos = 0; + asCByteInstruction *instr = first; + while (instr) + { + if (instr->op == asBC_TryBlock) + { + asSTryCatchInfo info; + info.tryPos = pos; + info.catchPos = *ARG_DW(instr->arg); + outFunc->scriptData->tryCatchInfo.PushLast(info); + } + + pos += instr->size; + instr = instr->next; + } +} + +int asCByteCode::GetSize() +{ + int size = 0; + asCByteInstruction *instr = first; + while( instr ) + { + size += instr->GetSize(); + + instr = instr->next; + } + + return size; +} + +void asCByteCode::AddCode(asCByteCode *bc) +{ + if( bc == this ) return; + if( bc->first ) + { + if( first == 0 ) + { + first = bc->first; + last = bc->last; + bc->first = 0; + bc->last = 0; + } + else + { + last->next = bc->first; + bc->first->prev = last; + last = bc->last; + bc->first = 0; + bc->last = 0; + } + } +} + +int asCByteCode::AddInstruction() +{ + void *ptr = engine->memoryMgr.AllocByteInstruction(); + if( ptr == 0 ) + { + // Out of memory + return 0; + } + + asCByteInstruction *instr = new(ptr) asCByteInstruction(); + if( first == 0 ) + { + first = last = instr; + } + else + { + last->AddAfter(instr); + last = instr; + } + + return 0; +} + +int asCByteCode::AddInstructionFirst() +{ + void *ptr = engine->memoryMgr.AllocByteInstruction(); + if( ptr == 0 ) + { + // Out of memory + return 0; + } + + asCByteInstruction *instr = new(ptr) asCByteInstruction(); + if( first == 0 ) + { + first = last = instr; + } + else + { + first->AddBefore(instr); + first = instr; + } + + return 0; +} + +void asCByteCode::Call(asEBCInstr instr, int funcID, int pop) +{ + if( AddInstruction() < 0 ) + return; + + asASSERT(asBCInfo[instr].type == asBCTYPE_DW_ARG); + + last->op = instr; + last->size = asBCTypeSize[asBCInfo[instr].type]; + last->stackInc = -pop; // BC_CALL and BC_CALLBND doesn't pop the argument but when the callee returns the arguments are already popped + *((int*)ARG_DW(last->arg)) = funcID; + + // Add a JitEntry instruction after function calls so that JIT's can resume execution + InstrPTR(asBC_JitEntry, 0); +} + +void asCByteCode::CallPtr(asEBCInstr instr, int funcPtrVar, int pop) +{ + if( AddInstruction() < 0 ) + return; + + asASSERT(asBCInfo[instr].type == asBCTYPE_rW_ARG); + + last->op = instr; + last->size = asBCTypeSize[asBCInfo[instr].type]; + last->stackInc = -pop; + last->wArg[0] = (short)funcPtrVar; + + // Add a JitEntry instruction after function calls so that JIT's can resume execution + InstrPTR(asBC_JitEntry, 0); +} + +void asCByteCode::Alloc(asEBCInstr instr, void *objID, int funcID, int pop) +{ + if( AddInstruction() < 0 ) + return; + + last->op = instr; + last->size = asBCTypeSize[asBCInfo[instr].type]; + last->stackInc = -pop; // BC_ALLOC + + asASSERT(asBCInfo[instr].type == asBCTYPE_PTR_DW_ARG); + *ARG_PTR(last->arg) = (asPWORD)objID; + *((int*)(ARG_DW(last->arg)+AS_PTR_SIZE)) = funcID; + + // Add a JitEntry instruction after function calls so that JIT's can resume execution + InstrPTR(asBC_JitEntry, 0); +} + +void asCByteCode::Ret(int pop) +{ + if( AddInstruction() < 0 ) + return; + + asASSERT(asBCInfo[asBC_RET].type == asBCTYPE_W_ARG); + + last->op = asBC_RET; + last->size = asBCTypeSize[asBCInfo[asBC_RET].type]; + last->stackInc = 0; // The instruction pops the argument, but it doesn't affect current function + last->wArg[0] = (short)pop; +} + +void asCByteCode::JmpP(int var, asDWORD max) +{ + if( AddInstruction() < 0 ) + return; + + asASSERT(asBCInfo[asBC_JMPP].type == asBCTYPE_rW_ARG); + + last->op = asBC_JMPP; + last->size = asBCTypeSize[asBCInfo[asBC_JMPP].type]; + last->stackInc = asBCInfo[asBC_JMPP].stackInc; + last->wArg[0] = (short)var; + + // Store the largest jump that is made for PostProcess() + *ARG_DW(last->arg) = max; +} + +void asCByteCode::Label(short label) +{ + if( AddInstruction() < 0 ) + return; + + last->op = asBC_LABEL; + last->size = 0; + last->stackInc = 0; + last->wArg[0] = label; +} + +void asCByteCode::Line(int line, int column, int scriptIdx) +{ + if( AddInstruction() < 0 ) + return; + + last->op = asBC_LINE; + // If the build is without line cues these instructions will be removed + // otherwise they will be transformed into SUSPEND instructions. + if( engine->ep.buildWithoutLineCues ) + last->size = 0; + else + last->size = asBCTypeSize[asBCInfo[asBC_SUSPEND].type]; + last->stackInc = 0; + *((int*)ARG_DW(last->arg)) = (line & 0xFFFFF)|((column & 0xFFF)<<20); + *((int*)ARG_DW(last->arg)+1) = scriptIdx; + + // Add a JitEntry after the line instruction to allow the JIT function to resume after a suspend + InstrPTR(asBC_JitEntry, 0); +} + +void asCByteCode::ObjInfo(int offset, int info) +{ + if( AddInstruction() < 0 ) + return; + + // Add the special instruction that will be used to tell the exception + // handler when an object is initialized and deinitialized. + last->op = asBC_ObjInfo; + last->size = 0; + last->stackInc = 0; + last->wArg[0] = (short)offset; + *((int*)ARG_DW(last->arg)) = info; +} + +void asCByteCode::Block(bool start) +{ + if( AddInstruction() < 0 ) + return; + + last->op = asBC_Block; + last->size = 0; + last->stackInc = 0; + last->wArg[0] = start ? 1 : 0; +} + +void asCByteCode::TryBlock(short catchLabel) +{ + if (AddInstruction() < 0) + return; + + last->op = asBC_TryBlock; + last->size = 0; + last->stackInc = 0; + *ARG_DW(last->arg) = catchLabel; +} + +void asCByteCode::VarDecl(int varDeclIdx) +{ + if( AddInstruction() < 0 ) + return; + + last->op = asBC_VarDecl; + last->size = 0; + last->stackInc = 0; + last->wArg[0] = asWORD(varDeclIdx); +} + +int asCByteCode::FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta) +{ + TimeIt("asCByteCode::FindLabel"); + + // Search forward + int labelPos = -from->GetSize(); + + asCByteInstruction *labelInstr = from; + while( labelInstr ) + { + labelPos += labelInstr->GetSize(); + labelInstr = labelInstr->next; + + if( labelInstr && labelInstr->op == asBC_LABEL ) + { + if( labelInstr->wArg[0] == label ) + break; + } + } + + if( labelInstr == 0 ) + { + // Search backwards + labelPos = -from->GetSize(); + + labelInstr = from; + while( labelInstr ) + { + labelInstr = labelInstr->prev; + if( labelInstr ) + { + labelPos -= labelInstr->GetSize(); + + if( labelInstr->op == asBC_LABEL ) + { + if( labelInstr->wArg[0] == label ) + break; + } + } + } + } + + if( labelInstr != 0 ) + { + if( dest ) *dest = labelInstr; + if( positionDelta ) *positionDelta = labelPos; + return 0; + } + + return -1; +} + +int asCByteCode::ResolveJumpAddresses() +{ + TimeIt("asCByteCode::ResolveJumpAddresses"); + + asUINT currPos = 0; + + asCByteInstruction *instr = first; + while( instr ) + { + if( instr->op == asBC_JMP || + instr->op == asBC_JZ || instr->op == asBC_JNZ || + instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ || + instr->op == asBC_JS || instr->op == asBC_JNS || + instr->op == asBC_JP || instr->op == asBC_JNP ) + { + int label = *((int*) ARG_DW(instr->arg)); + int labelPosOffset; + int r = FindLabel(label, instr, 0, &labelPosOffset); + if( r == 0 ) + *((int*) ARG_DW(instr->arg)) = labelPosOffset; + else + return -1; + } + else if (instr->op == asBC_TryBlock) + { + int label = *((int*)ARG_DW(instr->arg)); + int labelPosOffset; + int r = FindLabel(label, instr, 0, &labelPosOffset); + if (r == 0) + { + // Should store the absolute address so the exception handler doesn't need to figure it out + *((int*)ARG_DW(instr->arg)) = currPos + labelPosOffset; + } + else + return -1; + } + + currPos += instr->GetSize(); + instr = instr->next; + } + + return 0; +} + + +asCByteInstruction *asCByteCode::DeleteInstruction(asCByteInstruction *instr) +{ + if( instr == 0 ) return 0; + + asCByteInstruction *ret = instr->prev ? instr->prev : instr->next; + + RemoveInstruction(instr); + + engine->memoryMgr.FreeByteInstruction(instr); + + return ret; +} + +void asCByteCode::Output(asDWORD *array) +{ + TimeIt("asCByteCode::Output"); + + // TODO: Receive a script function pointer instead of the bytecode array + + asDWORD *ap = array; + + asCByteInstruction *instr = first; + while( instr ) + { + if( instr->GetSize() > 0 ) + { + *(asBYTE*)ap = asBYTE(instr->op); + *(((asBYTE*)ap)+1) = 0; // Second byte is always zero + switch( asBCInfo[instr->op].type ) + { + case asBCTYPE_NO_ARG: + *(((asWORD*)ap)+1) = 0; // Clear upper bytes + break; + case asBCTYPE_wW_rW_rW_ARG: + *(((asWORD*)ap)+1) = instr->wArg[0]; + *(((asWORD*)ap)+2) = instr->wArg[1]; + *(((asWORD*)ap)+3) = instr->wArg[2]; + break; + case asBCTYPE_wW_DW_ARG: + case asBCTYPE_rW_DW_ARG: + case asBCTYPE_W_DW_ARG: + *(((asWORD*)ap)+1) = instr->wArg[0]; + *(ap+1) = *(asDWORD*)&instr->arg; + break; + case asBCTYPE_wW_rW_DW_ARG: + case asBCTYPE_rW_W_DW_ARG: + *(((asWORD*)ap)+1) = instr->wArg[0]; + *(((asWORD*)ap)+2) = instr->wArg[1]; + *(ap+2) = *(asDWORD*)&instr->arg; + break; + case asBCTYPE_wW_QW_ARG: + case asBCTYPE_rW_QW_ARG: + *(((asWORD*)ap)+1) = instr->wArg[0]; + *(asQWORD*)(ap+1) = asQWORD(instr->arg); + break; + case asBCTYPE_W_ARG: + case asBCTYPE_rW_ARG: + case asBCTYPE_wW_ARG: + *(((asWORD*)ap)+1) = instr->wArg[0]; + break; + case asBCTYPE_wW_rW_ARG: + case asBCTYPE_rW_rW_ARG: + case asBCTYPE_wW_W_ARG: + *(((asWORD *)ap)+1) = instr->wArg[0]; + *(((asWORD *)ap)+2) = instr->wArg[1]; + break; + case asBCTYPE_QW_DW_ARG: + case asBCTYPE_DW_DW_ARG: + case asBCTYPE_QW_ARG: + case asBCTYPE_DW_ARG: + *(((asWORD*)ap)+1) = 0; // Clear upper bytes + memcpy(ap+1, &instr->arg, instr->GetSize()*4-4); + break; + case asBCTYPE_rW_DW_DW_ARG: + *(((asWORD*)ap)+1) = instr->wArg[0]; + memcpy(ap+1, &instr->arg, instr->GetSize()*4-4); + break; + default: + // How did we get here? + asASSERT(false); + break; + } + } + + ap += instr->GetSize(); + instr = instr->next; + } +} + +void asCByteCode::PostProcess() +{ + TimeIt("asCByteCode::PostProcess"); + + if( first == 0 ) return; + + // This function will do the following + // - Verify if there is any code that never gets executed and remove it + // - Calculate the stack size at the position of each byte code + // - Calculate the largest stack needed + + largestStackUsed = 0; + + asCByteInstruction *instr = first; + while( instr ) + { + instr->marked = false; + instr->stackSize = -1; + instr = instr->next; + } + + // Add the first instruction to the list of unchecked code paths + asCArray paths; + AddPath(paths, first, 0); + + // Go through each of the code paths + for( asUINT p = 0; p < paths.GetLength(); ++p ) + { + instr = paths[p]; + int stackSize = instr->stackSize; + + while( instr ) + { + instr->marked = true; + instr->stackSize = stackSize; + stackSize += instr->stackInc; + if( stackSize > largestStackUsed ) + largestStackUsed = stackSize; + + if( instr->op == asBC_JMP ) + { + // Find the label that we should jump to + int label = *((int*) ARG_DW(instr->arg)); + asCByteInstruction *dest = 0; + int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r); + + AddPath(paths, dest, stackSize); + break; + } + else if( instr->op == asBC_JZ || instr->op == asBC_JNZ || + instr->op == asBC_JLowZ || instr->op == asBC_JLowNZ || + instr->op == asBC_JS || instr->op == asBC_JNS || + instr->op == asBC_JP || instr->op == asBC_JNP || + instr->op == asBC_TryBlock ) + { + // Find the label that is being jumped to + int label = *((int*) ARG_DW(instr->arg)); + asCByteInstruction *dest = 0; + int r = FindLabel(label, instr, &dest, 0); asASSERT( r == 0 ); UNUSED_VAR(r); + + AddPath(paths, dest, stackSize); + + // Add both paths to the code paths + AddPath(paths, instr->next, stackSize); + + break; + } + else if( instr->op == asBC_JMPP ) + { + // I need to know the largest value possible + asDWORD max = *ARG_DW(instr->arg); + + // Add all destinations to the code paths + asCByteInstruction *dest = instr->next; + for( asDWORD n = 0; n <= max && dest != 0; ++n ) + { + AddPath(paths, dest, stackSize); + dest = dest->next; + } + + break; + } + else + { + instr = instr->next; + if( instr == 0 || instr->marked ) + break; + } + } + } + + // Are there any instructions that didn't get visited? + instr = first; + while( instr ) + { + // Don't remove asBC_Block instructions as then the start and end of blocks may become mismatched + if( instr->marked == false && instr->op != asBC_Block ) + { + // Remove it + asCByteInstruction *curr = instr; + instr = instr->next; + DeleteInstruction(curr); + } + else + { +#ifndef AS_DEBUG + // If the stackSize is negative, then there is a problem with the bytecode. + // If AS_DEBUG is turned on, this same check is done in DebugOutput. + asASSERT( instr->stackSize >= 0 || asBCInfo[instr->op].type == asBCTYPE_INFO ); +#endif + instr = instr->next; + } + } +} + +#ifdef AS_DEBUG +void asCByteCode::DebugOutput(const char *name, asCScriptFunction *func) +{ +#ifndef __MINGW32__ + // _mkdir is broken on mingw + _mkdir("AS_DEBUG"); +#endif + + asCString path = "AS_DEBUG/"; + path += name; + + // Anonymous functions created from within class methods will contain :: as part of the name + // Replace :: with __ to avoid error when creating the file for debug output + for (asUINT n = 0; n < path.GetLength(); n++) + if (path[n] == ':') path[n] = '_'; + +#if _MSC_VER >= 1500 && !defined(AS_MARMALADE) + FILE *file; + fopen_s(&file, path.AddressOf(), "w"); +#else + FILE *file = fopen(path.AddressOf(), "w"); +#endif + +#if !defined(AS_XENON) && !defined(__MINGW32__) + // XBox 360: When running in DVD Emu, no write is allowed + // MinGW: As _mkdir is broken, don't assert on file not created if the AS_DEBUG directory doesn't exist + asASSERT( file ); +#endif + + if( file == 0 ) + return; + + asUINT n; + + fprintf(file, "%s\n\n", func->GetDeclaration()); + + fprintf(file, "Temps: "); + for( n = 0; n < temporaryVariables->GetLength(); n++ ) + { + fprintf(file, "%d", (*temporaryVariables)[n]); + if( n < temporaryVariables->GetLength()-1 ) + fprintf(file, ", "); + } + fprintf(file, "\n\n"); + + fprintf(file, "Variables: \n"); + for( n = 0; n < func->scriptData->variables.GetLength(); n++ ) + { + int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->variables[n]->stackOffset); + bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false; + fprintf(file, " %.3d: %s%s %s\n", func->scriptData->variables[n]->stackOffset, isOnHeap ? "(heap) " : "", func->scriptData->variables[n]->type.Format(func->nameSpace, true).AddressOf(), func->scriptData->variables[n]->name.AddressOf()); + } + asUINT offset = 0; + if( func->objectType ) + { + fprintf(file, " %.3d: %s this\n", 0, func->objectType->name.AddressOf()); + offset -= AS_PTR_SIZE; + } + for( n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + bool found = false; + for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ ) + { + if( func->scriptData->variables[v]->stackOffset == (int)offset ) + { + found = true; + break; + } + } + if( !found ) + { + int idx = func->scriptData->objVariablePos.IndexOf(offset); + bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false; + fprintf(file, " %.3d: %s%s {noname param}\n", offset, isOnHeap ? "(heap) " : "", func->parameterTypes[n].Format(func->nameSpace, true).AddressOf()); + } + + offset -= func->parameterTypes[n].GetSizeOnStackDWords(); + } + for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) + { + bool found = false; + for( asUINT v = 0; v < func->scriptData->variables.GetLength(); v++ ) + { + if( func->scriptData->variables[v]->stackOffset == func->scriptData->objVariablePos[n] ) + { + found = true; + break; + } + } + if( !found ) + { + if( func->scriptData->objVariableTypes[n] ) + { + int idx = func->scriptData->objVariablePos.IndexOf(func->scriptData->objVariablePos[n]); + bool isOnHeap = asUINT(idx) < func->scriptData->objVariablesOnHeap ? true : false; + fprintf(file, " %.3d: %s%s {noname}\n", func->scriptData->objVariablePos[n], isOnHeap ? "(heap) " : "", func->scriptData->objVariableTypes[n]->name.AddressOf()); + } + else + fprintf(file, " %.3d: null handle {noname}\n", func->scriptData->objVariablePos[n]); + } + } + fprintf(file, "\n\n"); + + bool invalidStackSize = false; + int pos = 0; + asUINT lineIndex = 0; + asCByteInstruction *instr = first; + while( instr ) + { + if( lineIndex < lineNumbers.GetLength() && lineNumbers[lineIndex] == pos ) + { + asDWORD line = lineNumbers[lineIndex+1]; + fprintf(file, "- %d,%d -\n", (int)(line&0xFFFFF), (int)(line>>20)); + lineIndex += 2; + } + + if( instr->GetSize() > 0 ) + { + fprintf(file, "%5d ", pos); + pos += instr->GetSize(); + + fprintf(file, "%3d %c ", int(instr->stackSize + func->scriptData->variableSpace), instr->marked ? '*' : ' '); + if( instr->stackSize < 0 ) + invalidStackSize = true; + } + else + { + fprintf(file, " "); + } + + switch( asBCInfo[instr->op].type ) + { + case asBCTYPE_W_ARG: + fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, instr->wArg[0]); + break; + + case asBCTYPE_wW_ARG: + case asBCTYPE_rW_ARG: + fprintf(file, " %-8s v%d\n", asBCInfo[instr->op].name, instr->wArg[0]); + break; + + case asBCTYPE_wW_rW_ARG: + case asBCTYPE_rW_rW_ARG: + fprintf(file, " %-8s v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]); + break; + + case asBCTYPE_wW_W_ARG: + fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1]); + break; + + case asBCTYPE_wW_rW_DW_ARG: + case asBCTYPE_rW_W_DW_ARG: + switch( instr->op ) + { + case asBC_ADDIf: + case asBC_SUBIf: + case asBC_MULIf: + fprintf(file, " %-8s v%d, v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((float*) ARG_DW(instr->arg))); + break; + default: + fprintf(file, " %-8s v%d, v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], *((int*) ARG_DW(instr->arg))); + break; + } + break; + + case asBCTYPE_DW_ARG: + switch( instr->op ) + { + case asBC_OBJTYPE: + { + asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg); + fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), ot->GetName()); + } + break; + + case asBC_FuncPtr: + { + asCScriptFunction *f = *(asCScriptFunction**)ARG_DW(instr->arg); + fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), f->GetDeclaration()); + } + break; + + case asBC_PshC4: + case asBC_Cast: + fprintf(file, " %-8s 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg))); + break; + + case asBC_TYPEID: + fprintf(file, " %-8s 0x%x '%s'\n", asBCInfo[instr->op].name, (asUINT)*ARG_DW(instr->arg), engine->GetTypeDeclaration((int)*ARG_DW(instr->arg))); + break; + + case asBC_CALL: + case asBC_CALLSYS: + case asBC_CALLBND: + case asBC_CALLINTF: + case asBC_Thiscall1: + { + int funcID = *(int*)ARG_DW(instr->arg); + asCString decl = engine->GetFunctionDeclaration(funcID); + + fprintf(file, " %-8s %d (%s)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), decl.AddressOf()); + } + break; + + case asBC_REFCPY: + fprintf(file, " %-8s 0x%x\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg))); + break; + + case asBC_JMP: + case asBC_JZ: + case asBC_JLowZ: + case asBC_JS: + case asBC_JP: + case asBC_JNZ: + case asBC_JLowNZ: + case asBC_JNS: + case asBC_JNP: + fprintf(file, " %-8s %+d (d:%d)\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg)), pos+*((int*) ARG_DW(instr->arg))); + break; + + default: + fprintf(file, " %-8s %d\n", asBCInfo[instr->op].name, *((int*) ARG_DW(instr->arg))); + break; + } + break; + + case asBCTYPE_QW_ARG: + switch( instr->op ) + { + case asBC_OBJTYPE: + { + asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); + fprintf(file, " %-8s 0x%x (type:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), ot->GetName()); + } + break; + + case asBC_FuncPtr: + { + asCScriptFunction *f = *(asCScriptFunction**)ARG_QW(instr->arg); + fprintf(file, " %-8s 0x%x (func:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), f->GetDeclaration()); + } + break; + + case asBC_PGA: + { + void *ptr = *(void**)ARG_QW(instr->arg); + asSMapNode *cursor = 0; + if( engine->varAddressMap.MoveTo(&cursor, ptr) ) + { + fprintf(file, " %-8s 0x%x (var:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), cursor->value->name.AddressOf()); + } + else + { + asUINT length; + engine->stringFactory->GetRawStringData(ptr, 0, &length); + asCString str; + str.SetLength(length); + engine->stringFactory->GetRawStringData(ptr, str.AddressOf(), &length); + if (str.GetLength() > 20) + { + // TODO: Replace non-visible characters with space or something like it + str.SetLength(20); + str += "..."; + } + fprintf(file, " %-8s 0x%x (str:%s)\n", asBCInfo[instr->op].name, (asUINT)*ARG_QW(instr->arg), str.AddressOf()); + } + } + break; + + default: +#ifdef __GNUC__ +#ifdef _LP64 + fprintf(file, " %-8s 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); +#else + fprintf(file, " %-8s 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); +#endif +#else + fprintf(file, " %-8s 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); +#endif + } + break; + + case asBCTYPE_wW_QW_ARG: + case asBCTYPE_rW_QW_ARG: + switch( instr->op ) + { + case asBC_RefCpyV: + case asBC_FREE: + { + asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); + fprintf(file, " %-8s v%d, 0x%x (type:%s)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_QW(instr->arg), ot->GetName()); + } + break; + + default: +#ifdef __GNUC__ +#ifdef _LP64 + fprintf(file, " %-8s v%d, 0x%lx (i:%ld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); +#else + fprintf(file, " %-8s v%d, 0x%llx (i:%lld, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); +#endif +#else + fprintf(file, " %-8s v%d, 0x%I64x (i:%I64d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], *ARG_QW(instr->arg), *((asINT64*) ARG_QW(instr->arg)), *((double*) ARG_QW(instr->arg))); +#endif + } + break; + + case asBCTYPE_DW_DW_ARG: + if( instr->op == asBC_ALLOC ) + { + asCObjectType *ot = *(asCObjectType**)ARG_DW(instr->arg); + asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; + fprintf(file, " %-8s 0x%x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); + } + else + fprintf(file, " %-8s %u, %d\n", asBCInfo[instr->op].name, *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1)); + break; + + case asBCTYPE_rW_DW_DW_ARG: + fprintf(file, " %-8s v%d, %u, %u\n", asBCInfo[instr->op].name, instr->wArg[0], *(int*)ARG_DW(instr->arg), *(int*)(ARG_DW(instr->arg)+1)); + break; + + case asBCTYPE_QW_DW_ARG: + if( instr->op == asBC_ALLOC ) + { + asCObjectType *ot = *(asCObjectType**)ARG_QW(instr->arg); + asCScriptFunction *f = engine->scriptFunctions[instr->wArg[0]]; +#if defined(__GNUC__) && !defined(_MSC_VER) +#ifdef AS_64BIT_PTR + fprintf(file, " %-8s 0x%lx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); +#else + fprintf(file, " %-8s 0x%llx, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); +#endif +#else + fprintf(file, " %-8s 0x%I64x, %d (type:%s, %s)\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2), ot->GetName(), f ? f->GetDeclaration() : "{no func}"); +#endif + } + else +#if defined(__GNUC__) && !defined(_MSC_VER) +#ifdef AS_64BIT_PTR + fprintf(file, " %-8s %lu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2)); +#else + fprintf(file, " %-8s %llu, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2)); +#endif +#else + fprintf(file, " %-8s %I64u, %d\n", asBCInfo[instr->op].name, *(asINT64*)ARG_QW(instr->arg), *(int*)(ARG_DW(instr->arg)+2)); +#endif + break; + + case asBCTYPE_INFO: + if( instr->op == asBC_LABEL ) + fprintf(file, "%d:\n", instr->wArg[0]); + else if( instr->op == asBC_LINE ) + fprintf(file, " %s\n", asBCInfo[instr->op].name); + else if( instr->op == asBC_Block ) + fprintf(file, "%c\n", instr->wArg[0] ? '{' : '}'); + break; + + case asBCTYPE_rW_DW_ARG: + case asBCTYPE_wW_DW_ARG: + case asBCTYPE_W_DW_ARG: + if( instr->op == asBC_SetV1 ) + fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asBYTE*)ARG_DW(instr->arg)); + else if( instr->op == asBC_SetV2 ) + fprintf(file, " %-8s v%d, 0x%x\n", asBCInfo[instr->op].name, instr->wArg[0], *(asWORD*)ARG_DW(instr->arg)); + else if( instr->op == asBC_SetV4 ) + fprintf(file, " %-8s v%d, 0x%x (i:%d, f:%g)\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_DW(instr->arg), *((int*) ARG_DW(instr->arg)), *((float*) ARG_DW(instr->arg))); + else if( instr->op == asBC_CMPIf ) + fprintf(file, " %-8s v%d, %f\n", asBCInfo[instr->op].name, instr->wArg[0], *(float*)ARG_DW(instr->arg)); + else + fprintf(file, " %-8s v%d, %d\n", asBCInfo[instr->op].name, instr->wArg[0], (asUINT)*ARG_DW(instr->arg)); + break; + + case asBCTYPE_wW_rW_rW_ARG: + fprintf(file, " %-8s v%d, v%d, v%d\n", asBCInfo[instr->op].name, instr->wArg[0], instr->wArg[1], instr->wArg[2]); + break; + + case asBCTYPE_NO_ARG: + fprintf(file, " %s\n", asBCInfo[instr->op].name); + break; + + default: + asASSERT(false); + } + + instr = instr->next; + } + + fclose(file); + + // If the stackSize is negative then there is something wrong with the + // bytecode, i.e. there is a bug in the compiler or in the optimizer. We + // only check this here to have the bytecode available on file for verification + asASSERT( !invalidStackSize ); +} +#endif + +//============================================================================= + +int asCByteCode::InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstructionFirst() < 0 ) + return 0; + + first->op = bc; + *ARG_DW(first->arg) = param; + first->size = asBCTypeSize[asBCInfo[bc].type]; + first->stackInc = asBCInfo[bc].stackInc; + + return first->stackInc; +} + +int asCByteCode::InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstructionFirst() < 0 ) + return 0; + + first->op = bc; + *ARG_QW(first->arg) = param; + first->size = asBCTypeSize[asBCInfo[bc].type]; + first->stackInc = asBCInfo[bc].stackInc; + + return first->stackInc; +} + +int asCByteCode::Instr(asEBCInstr bc) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_NO_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrW_W_W(asEBCInstr bc, int a, int b, int c) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_rW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = (short)a; + last->wArg[1] = (short)b; + last->wArg[2] = (short)c; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrW_W(asEBCInstr bc, int a, int b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_rW_ARG || + asBCInfo[bc].type == asBCTYPE_rW_rW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = (short)a; + last->wArg[1] = (short)b; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrW_PTR(asEBCInstr bc, short a, void *param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_PTR_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + *ARG_PTR(last->arg) = (asPWORD)param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_W_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + *((int*) ARG_DW(last->arg)) = b; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_rW_DW_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + *(int*)ARG_DW(last->arg) = b; + *(int*)(ARG_DW(last->arg)+1) = c; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrSHORT_B(asEBCInstr bc, short a, asBYTE b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_W_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + + // We'll have to be careful to store the byte correctly, independent of endianess. + // Some optimizing compilers may change the order of operations, so we make sure + // the value is not overwritten even if that happens. + asBYTE *argPtr = (asBYTE*)ARG_DW(last->arg); + argPtr[0] = b; // The value is always stored in the lower byte + argPtr[1] = 0; // and clear the rest of the DWORD + argPtr[2] = 0; + argPtr[3] = 0; + + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrSHORT_W(asEBCInstr bc, short a, asWORD b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_W_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + + // We'll have to be careful to store the word correctly, independent of endianess. + // Some optimizing compilers may change the order of operations, so we make sure + // the value is not overwritten even if that happens. + asWORD *argPtr = (asWORD*)ARG_DW(last->arg); + argPtr[0] = b; // The value is always stored in the lower word + argPtr[1] = 0; // and clear the rest of the DWORD + + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrSHORT_DW(asEBCInstr bc, short a, asDWORD b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_rW_DW_ARG || + asBCInfo[bc].type == asBCTYPE_W_DW_ARG); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + *((int*) ARG_DW(last->arg)) = b; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrW_QW(asEBCInstr bc, asWORD a, asQWORD b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + *ARG_QW(last->arg) = b; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrSHORT_QW(asEBCInstr bc, short a, asQWORD b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_QW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + *ARG_QW(last->arg) = b; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrW_FLOAT(asEBCInstr bc, asWORD a, float b) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_wW_DW_ARG); + asASSERT(asBCInfo[bc].stackInc == 0); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = a; + *((float*) ARG_DW(last->arg)) = b; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrSHORT(asEBCInstr bc, short param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_rW_ARG || + asBCInfo[bc].type == asBCTYPE_wW_ARG || + asBCInfo[bc].type == asBCTYPE_W_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrINT(asEBCInstr bc, int param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + *((int*) ARG_DW(last->arg)) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrDWORD(asEBCInstr bc, asDWORD param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + *ARG_DW(last->arg) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrPTR(asEBCInstr bc, void *param) +{ + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + asASSERT(asBCInfo[bc].type == asBCTYPE_PTR_ARG); + *ARG_PTR(last->arg) = (asPWORD)param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrQWORD(asEBCInstr bc, asQWORD param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + *ARG_QW(last->arg) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrWORD(asEBCInstr bc, asWORD param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_W_ARG || + asBCInfo[bc].type == asBCTYPE_rW_ARG || + asBCInfo[bc].type == asBCTYPE_wW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + last->wArg[0] = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrFLOAT(asEBCInstr bc, float param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_DW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + *((float*) ARG_DW(last->arg)) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::InstrDOUBLE(asEBCInstr bc, double param) +{ + asASSERT(asBCInfo[bc].type == asBCTYPE_QW_ARG); + asASSERT(asBCInfo[bc].stackInc != 0xFFFF); + + if( AddInstruction() < 0 ) + return 0; + + last->op = bc; + *((double*) ARG_QW(last->arg)) = param; + last->size = asBCTypeSize[asBCInfo[bc].type]; + last->stackInc = asBCInfo[bc].stackInc; + + return last->stackInc; +} + +int asCByteCode::GetLastInstr() +{ + if( last == 0 ) return -1; + + return last->op; +} + +int asCByteCode::RemoveLastInstr() +{ + if( last == 0 ) return -1; + + if( first == last ) + { + engine->memoryMgr.FreeByteInstruction(last); + first = 0; + last = 0; + } + else + { + asCByteInstruction *bc = last; + last = bc->prev; + + bc->Remove(); + engine->memoryMgr.FreeByteInstruction(bc); + } + + return 0; +} + +asDWORD asCByteCode::GetLastInstrValueDW() +{ + if( last == 0 ) return 0; + + return *ARG_DW(last->arg); +} + +//=================================================================== + +asCByteInstruction::asCByteInstruction() +{ + next = 0; + prev = 0; + + op = asBC_LABEL; + + arg = 0; + wArg[0] = 0; + wArg[1] = 0; + wArg[2] = 0; + size = 0; + stackInc = 0; + marked = false; + stackSize = 0; +} + +void asCByteInstruction::AddAfter(asCByteInstruction *nextCode) +{ + if( next ) + next->prev = nextCode; + + nextCode->next = next; + nextCode->prev = this; + next = nextCode; +} + +void asCByteInstruction::AddBefore(asCByteInstruction *prevCode) +{ + if( prev ) + prev->next = prevCode; + + prevCode->prev = prev; + prevCode->next = this; + prev = prevCode; +} + +int asCByteInstruction::GetSize() +{ + return size; +} + +int asCByteInstruction::GetStackIncrease() +{ + return stackInc; +} + +void asCByteInstruction::Remove() +{ + if( prev ) prev->next = next; + if( next ) next->prev = prev; + prev = 0; + next = 0; +} + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + diff --git a/angelscript/source/as_bytecode.h b/angelscript/source/as_bytecode.h new file mode 100644 index 0000000..f69f35b --- /dev/null +++ b/angelscript/source/as_bytecode.h @@ -0,0 +1,205 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2018 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_bytecode.h +// +// A class for constructing the final byte code +// + + + +#ifndef AS_BYTECODE_H +#define AS_BYTECODE_H + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_array.h" + +BEGIN_AS_NAMESPACE + +#define BYTECODE_SIZE 4 +#define MAX_DATA_SIZE 8 +#define MAX_INSTR_SIZE (BYTECODE_SIZE+MAX_DATA_SIZE) + +class asCScriptEngine; +class asCScriptFunction; +class asCByteInstruction; + +class asCByteCode +{ +public: + asCByteCode(asCScriptEngine *engine); + ~asCByteCode(); + + void ClearAll(); + + int GetSize(); + + void Finalize(const asCArray &tempVariableOffsets); + + void Optimize(); + void OptimizeLocally(const asCArray &tempVariableOffsets); + void ExtractLineNumbers(); + void ExtractObjectVariableInfo(asCScriptFunction *outFunc); + void ExtractTryCatchInfo(asCScriptFunction *outFunc); + int ResolveJumpAddresses(); + int FindLabel(int label, asCByteInstruction *from, asCByteInstruction **dest, int *positionDelta); + + void AddPath(asCArray &paths, asCByteInstruction *instr, int stackSize); + + void Output(asDWORD *array); + void AddCode(asCByteCode *bc); + + void PostProcess(); + +#ifdef AS_DEBUG + void DebugOutput(const char *name, asCScriptFunction *func); +#endif + + int GetLastInstr(); + int RemoveLastInstr(); + asDWORD GetLastInstrValueDW(); + + void InsertIfNotExists(asCArray &vars, int var); + void GetVarsUsed(asCArray &vars); + bool IsVarUsed(int offset); + void ExchangeVar(int oldOffset, int newOffset); + bool IsSimpleExpression(); + + void Label(short label); + void Line(int line, int column, int scriptIdx); + void ObjInfo(int offset, int info); + void Block(bool start); + void TryBlock(short catchLabel); + + void VarDecl(int varDeclIdx); + void Call(asEBCInstr bc, int funcID, int pop); + void CallPtr(asEBCInstr bc, int funcPtrVar, int pop); + void Alloc(asEBCInstr bc, void *objID, int funcID, int pop); + void Ret(int pop); + void JmpP(int var, asDWORD max); + + int InsertFirstInstrDWORD(asEBCInstr bc, asDWORD param); + int InsertFirstInstrQWORD(asEBCInstr bc, asQWORD param); + int Instr(asEBCInstr bc); + int InstrQWORD(asEBCInstr bc, asQWORD param); + int InstrDOUBLE(asEBCInstr bc, double param); + int InstrPTR(asEBCInstr bc, void *param); + int InstrDWORD(asEBCInstr bc, asDWORD param); + int InstrWORD(asEBCInstr bc, asWORD param); + int InstrSHORT(asEBCInstr bc, short param); + int InstrFLOAT(asEBCInstr bc, float param); + int InstrINT(asEBCInstr bc, int param); + int InstrW_W_W(asEBCInstr bc, int a, int b, int c); + int InstrSHORT_B(asEBCInstr bc, short a, asBYTE b); + int InstrSHORT_W(asEBCInstr bc, short a, asWORD b); + int InstrSHORT_DW(asEBCInstr bc, short a, asDWORD b); + int InstrSHORT_QW(asEBCInstr bc, short a, asQWORD b); + int InstrW_DW(asEBCInstr bc, asWORD a, asDWORD b); + int InstrW_QW(asEBCInstr bc, asWORD a, asQWORD b); + int InstrW_PTR(asEBCInstr bc, short a, void *param); + int InstrW_FLOAT(asEBCInstr bc, asWORD a, float b); + int InstrW_W(asEBCInstr bc, int w, int b); + int InstrSHORT_DW_DW(asEBCInstr bc, short a, asDWORD b, asDWORD c); + + asCScriptEngine *GetEngine() const { return engine; }; + + asCArray lineNumbers; + asCArray sectionIdxs; + int largestStackUsed; + +protected: + // Assignments are not allowed + void operator=(const asCByteCode &) {} + + // Helpers for Optimize + bool CanBeSwapped(asCByteInstruction *curr); + asCByteInstruction *ChangeFirstDeleteNext(asCByteInstruction *curr, asEBCInstr bc); + asCByteInstruction *DeleteFirstChangeNext(asCByteInstruction *curr, asEBCInstr bc); + asCByteInstruction *DeleteInstruction(asCByteInstruction *instr); + void RemoveInstruction(asCByteInstruction *instr); + asCByteInstruction *GoBack(asCByteInstruction *curr); + asCByteInstruction *GoForward(asCByteInstruction *curr); + void InsertBefore(asCByteInstruction *before, asCByteInstruction *instr); + bool RemoveUnusedValue(asCByteInstruction *curr, asCByteInstruction **next); + bool IsTemporary(int offset); + bool IsTempRegUsed(asCByteInstruction *curr); + bool IsTempVarRead(asCByteInstruction *curr, int offset); + bool PostponeInitOfTemp(asCByteInstruction *curr, asCByteInstruction **next); + bool IsTempVarReadByInstr(asCByteInstruction *curr, int var); + bool IsTempVarOverwrittenByInstr(asCByteInstruction *curr, int var); + bool IsInstrJmpOrLabel(asCByteInstruction *curr); + + int AddInstruction(); + int AddInstructionFirst(); + + asCByteInstruction *first; + asCByteInstruction *last; + + const asCArray *temporaryVariables; + + asCScriptEngine *engine; +}; + +class asCByteInstruction +{ +public: + asCByteInstruction(); + + void AddAfter(asCByteInstruction *nextCode); + void AddBefore(asCByteInstruction *nextCode); + void Remove(); + + int GetSize(); + int GetStackIncrease(); + + asCByteInstruction *next; + asCByteInstruction *prev; + + asEBCInstr op; + asQWORD arg; + short wArg[3]; + int size; + int stackInc; + + // Testing + bool marked; + int stackSize; +}; + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + +#endif diff --git a/angelscript/source/as_callfunc.cpp b/angelscript/source/as_callfunc.cpp new file mode 100644 index 0000000..58dfaaa --- /dev/null +++ b/angelscript/source/as_callfunc.cpp @@ -0,0 +1,921 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc.cpp +// +// These functions handle the actual calling of system functions +// + + + +#include "as_config.h" +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_context.h" + +BEGIN_AS_NAMESPACE + +// ref: Member Function Pointers and the Fastest Possible C++ Delegates +// describes the structure of class method pointers for most compilers +// http://www.codeproject.com/Articles/7150/Member-Function-Pointers-and-the-Fastest-Possible + +// ref: The code comments for ItaniumCXXABI::EmitLoadOfMemberFunctionPointer in the LLVM compiler +// describes the structure for class method pointers on Itanium and arm64 ABI +// http://clang.llvm.org/doxygen/CodeGen_2ItaniumCXXABI_8cpp_source.html#l00937 + +int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal) +{ + memset(internal, 0, sizeof(asSSystemFunctionInterface)); + + internal->func = ptr.ptr.f.func; + internal->auxiliary = 0; + + // Was a compatible calling convention specified? + if( internal->func ) + { + if( ptr.flag == 1 && callConv != asCALL_GENERIC ) + return asWRONG_CALLING_CONV; + else if( ptr.flag == 2 && (callConv == asCALL_GENERIC || callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) ) + return asWRONG_CALLING_CONV; + else if( ptr.flag == 3 && !(callConv == asCALL_THISCALL || callConv == asCALL_THISCALL_ASGLOBAL || callConv == asCALL_THISCALL_OBJFIRST || callConv == asCALL_THISCALL_OBJLAST) ) + return asWRONG_CALLING_CONV; + } + + asDWORD base = callConv; + if( !isMethod ) + { + if( base == asCALL_CDECL ) + internal->callConv = ICC_CDECL; + else if( base == asCALL_STDCALL ) + internal->callConv = ICC_STDCALL; + else if( base == asCALL_THISCALL_ASGLOBAL ) + { + if(auxiliary == 0) + return asINVALID_ARG; + internal->auxiliary = auxiliary; + internal->callConv = ICC_THISCALL; + + // This is really a thiscall, so it is necessary to check for virtual method pointers + base = asCALL_THISCALL; + isMethod = true; + } + else if (base == asCALL_GENERIC) + { + internal->callConv = ICC_GENERIC_FUNC; + + // The auxiliary object is optional for generic calling convention + internal->auxiliary = auxiliary; + } + else + return asNOT_SUPPORTED; + } + + if( isMethod ) + { +#ifndef AS_NO_CLASS_METHODS + if( base == asCALL_THISCALL || base == asCALL_THISCALL_OBJFIRST || base == asCALL_THISCALL_OBJLAST ) + { + internalCallConv thisCallConv; + if( base == asCALL_THISCALL ) + { + if(callConv != asCALL_THISCALL_ASGLOBAL && auxiliary) + return asINVALID_ARG; + + thisCallConv = ICC_THISCALL; + } + else + { +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + return asNOT_SUPPORTED; +#else + if(auxiliary == 0) + return asINVALID_ARG; + + internal->auxiliary = auxiliary; + if( base == asCALL_THISCALL_OBJFIRST ) + thisCallConv = ICC_THISCALL_OBJFIRST; + else //if( base == asCALL_THISCALL_OBJLAST ) + thisCallConv = ICC_THISCALL_OBJLAST; +#endif + } + + internal->callConv = thisCallConv; +#ifdef GNU_STYLE_VIRTUAL_METHOD + if( (size_t(ptr.ptr.f.func) & 1) ) + internal->callConv = (internalCallConv)(thisCallConv + 2); +#endif + internal->baseOffset = ( int )MULTI_BASE_OFFSET(ptr); +#if (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS)) && (defined(__GNUC__) || defined(AS_PSVITA)) + // As the least significant bit in func is used to switch to THUMB mode + // on ARM processors, the LSB in the __delta variable is used instead of + // the one in __pfn on ARM processors. + // MIPS also appear to use the base offset to indicate virtual method. + if( (size_t(internal->baseOffset) & 1) ) + internal->callConv = (internalCallConv)(thisCallConv + 2); +#endif + +#ifdef HAVE_VIRTUAL_BASE_OFFSET + // We don't support virtual inheritance + if( VIRTUAL_BASE_OFFSET(ptr) != 0 ) + return asNOT_SUPPORTED; +#endif + } + else +#endif + if( base == asCALL_CDECL_OBJLAST ) + internal->callConv = ICC_CDECL_OBJLAST; + else if( base == asCALL_CDECL_OBJFIRST ) + internal->callConv = ICC_CDECL_OBJFIRST; + else if (base == asCALL_GENERIC) + { + internal->callConv = ICC_GENERIC_METHOD; + internal->auxiliary = auxiliary; + } + else + return asNOT_SUPPORTED; + } + + return 0; +} + +// This function should prepare system functions so that it will be faster to call them +int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine) +{ + asASSERT(internal->callConv == ICC_GENERIC_METHOD || internal->callConv == ICC_GENERIC_FUNC); + + // Calculate the size needed for the parameters + internal->paramSize = func->GetSpaceNeededForArguments(); + + // Prepare the clean up instructions for the function arguments + internal->cleanArgs.SetLength(0); + int offset = 0; + for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + asCDataType &dt = func->parameterTypes[n]; + + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() ) + { + if (dt.IsFuncdef()) + { + // If the generic call mode is set to old behaviour then always release handles + // else only release the handle if the function is declared with auto handles + if (engine->ep.genericCallMode == 0 || (internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n])) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 0; // call release + clean.ot = &engine->functionBehaviours; + clean.off = short(offset); + internal->cleanArgs.PushLast(clean); + } + } + else if( dt.GetTypeInfo()->flags & asOBJ_REF ) + { + // If the generic call mode is set to old behaviour then always release handles + // else only release the handle if the function is declared with auto handles + if (!dt.IsObjectHandle() || + engine->ep.genericCallMode == 0 || + (internal->paramAutoHandles.GetLength() > n && internal->paramAutoHandles[n]) ) + { + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; + asASSERT((dt.GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release); + if (beh->release) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 0; // call release + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); + internal->cleanArgs.PushLast(clean); + } + } + } + else + { + asSSystemFunctionInterface::SClean clean; + clean.op = 1; // call free + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); + + // Call the destructor then free the memory + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; + if( beh->destruct ) + clean.op = 2; // call destruct, then free + + internal->cleanArgs.PushLast(clean); + } + } + + if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) + offset += AS_PTR_SIZE; + else + offset += dt.GetSizeOnStackDWords(); + } + + return 0; +} + +// This function should prepare system functions so that it will be faster to call them +int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine) +{ +#ifdef AS_MAX_PORTABILITY + UNUSED_VAR(func); + UNUSED_VAR(internal); + UNUSED_VAR(engine); + + // This should never happen, as when AS_MAX_PORTABILITY is on, all functions + // are asCALL_GENERIC, which are prepared by PrepareSystemFunctionGeneric + asASSERT(false); +#else + // References are always returned as primitive data + if( func->returnType.IsReference() || func->returnType.IsObjectHandle() ) + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = sizeof(void*)/4; + internal->hostReturnFloat = false; + } + // Registered types have special flags that determine how they are returned + else if( func->returnType.IsObject() ) + { + asDWORD objType = func->returnType.GetTypeInfo()->flags; + + // Only value types can be returned by value + asASSERT( objType & asOBJ_VALUE ); + + if( !(objType & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) ) + { + // If the return is by value then we need to know the true type + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); + + asCString str; + str.Format(TXT_CANNOT_RET_TYPE_s_BY_VAL, func->returnType.GetTypeInfo()->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); + } + else if( objType & asOBJ_APP_ARRAY ) + { + // Array types are always returned in memory + internal->hostReturnInMemory = true; + internal->hostReturnSize = sizeof(void*)/4; + internal->hostReturnFloat = false; + } + else if( objType & asOBJ_APP_CLASS ) + { + internal->hostReturnFloat = false; + if( objType & COMPLEX_RETURN_MASK ) + { + internal->hostReturnInMemory = true; + internal->hostReturnSize = sizeof(void*)/4; + } + else + { +#ifdef HAS_128_BIT_PRIMITIVES + if( func->returnType.GetSizeInMemoryDWords() > 4 ) +#else + if( func->returnType.GetSizeInMemoryDWords() > 2 ) +#endif + { + internal->hostReturnInMemory = true; + internal->hostReturnSize = sizeof(void*)/4; + } + else + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); +#ifdef SPLIT_OBJS_BY_MEMBER_TYPES + if( func->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) + internal->hostReturnFloat = true; +#endif + } + +#ifdef THISCALL_RETURN_SIMPLE_IN_MEMORY + if((internal->callConv == ICC_THISCALL || +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + internal->callConv == ICC_VIRTUAL_THISCALL) && +#else + internal->callConv == ICC_VIRTUAL_THISCALL || + internal->callConv == ICC_THISCALL_OBJFIRST || + internal->callConv == ICC_THISCALL_OBJLAST) && +#endif + func->returnType.GetSizeInMemoryDWords() >= THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE) + { + internal->hostReturnInMemory = true; + internal->hostReturnSize = sizeof(void*)/4; + } +#endif +#ifdef CDECL_RETURN_SIMPLE_IN_MEMORY + if((internal->callConv == ICC_CDECL || + internal->callConv == ICC_CDECL_OBJLAST || + internal->callConv == ICC_CDECL_OBJFIRST) && + func->returnType.GetSizeInMemoryDWords() >= CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE) + { + internal->hostReturnInMemory = true; + internal->hostReturnSize = sizeof(void*)/4; + } +#endif +#ifdef STDCALL_RETURN_SIMPLE_IN_MEMORY + if( internal->callConv == ICC_STDCALL && + func->returnType.GetSizeInMemoryDWords() >= STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE) + { + internal->hostReturnInMemory = true; + internal->hostReturnSize = sizeof(void*)/4; + } +#endif + } + +#ifdef SPLIT_OBJS_BY_MEMBER_TYPES + // It's not safe to return objects by value because different registers + // will be used depending on the memory layout of the object. + // Ref: http://www.x86-64.org/documentation/abi.pdf + // Ref: http://www.agner.org/optimize/calling_conventions.pdf + // If the application informs that the class should be treated as all integers, then we allow it + if( !internal->hostReturnInMemory && + !(func->returnType.GetTypeInfo()->flags & (asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) + { + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); + + asCString str; + str.Format(TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL, func->returnType.Format(func->nameSpace).AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); + } +#endif + } + else if( objType & asOBJ_APP_PRIMITIVE ) + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); + internal->hostReturnFloat = false; + } + else if( objType & asOBJ_APP_FLOAT ) + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = func->returnType.GetSizeInMemoryDWords(); + internal->hostReturnFloat = true; + } + } + // Primitive types can easily be determined +#ifdef HAS_128_BIT_PRIMITIVES + else if( func->returnType.GetSizeInMemoryDWords() > 4 ) + { + // Shouldn't be possible to get here + asASSERT(false); + } + else if( func->returnType.GetSizeInMemoryDWords() == 4 ) + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = 4; + internal->hostReturnFloat = false; + } +#else + else if( func->returnType.GetSizeInMemoryDWords() > 2 ) + { + // Shouldn't be possible to get here + asASSERT(false); + } +#endif + else if( func->returnType.GetSizeInMemoryDWords() == 2 ) + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = 2; + internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttDouble, true)); + } + else if( func->returnType.GetSizeInMemoryDWords() == 1 ) + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = 1; + internal->hostReturnFloat = func->returnType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttFloat, true)); + } + else + { + internal->hostReturnInMemory = false; + internal->hostReturnSize = 0; + internal->hostReturnFloat = false; + } + + // Calculate the size needed for the parameters + internal->paramSize = func->GetSpaceNeededForArguments(); + + // Verify if the function takes any objects by value + asUINT n; + internal->takesObjByVal = false; + for( n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + if( func->parameterTypes[n].IsObject() && !func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference() ) + { + internal->takesObjByVal = true; + + // Can't pass objects by value unless the application type is informed + if( !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_CLASS | asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY)) ) + { + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); + + asCString str; + str.Format(TXT_CANNOT_PASS_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); + } + + +#ifdef SPLIT_OBJS_BY_MEMBER_TYPES + // It's not safe to pass objects by value because different registers + // will be used depending on the memory layout of the object + // Ref: http://www.x86-64.org/documentation/abi.pdf + // Ref: http://www.agner.org/optimize/calling_conventions.pdf + if( +#ifdef COMPLEX_OBJS_PASSED_BY_REF + !(func->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) && +#endif +#ifdef LARGE_OBJS_PASS_BY_REF + func->parameterTypes[n].GetSizeInMemoryDWords() < AS_LARGE_OBJ_MIN_SIZE && +#endif + !(func->parameterTypes[n].GetTypeInfo()->flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_CLASS_ALLINTS | asOBJ_APP_CLASS_ALLFLOATS)) ) + { + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, func->GetDeclarationStr().AddressOf()); + + asCString str; + str.Format(TXT_DONT_SUPPORT_TYPE_s_BY_VAL, func->parameterTypes[n].GetTypeInfo()->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + engine->ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); + } +#endif + break; + } + } + + // Prepare the clean up instructions for the function arguments + internal->cleanArgs.SetLength(0); + int offset = 0; + for( n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + asCDataType &dt = func->parameterTypes[n]; + +#if defined(COMPLEX_OBJS_PASSED_BY_REF) || defined(AS_LARGE_OBJS_PASSED_BY_REF) + bool needFree = false; +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & COMPLEX_MASK ) needFree = true; +#endif +#ifdef AS_LARGE_OBJS_PASSED_BY_REF + if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE ) needFree = true; +#endif + if( needFree && + dt.IsObject() && + !dt.IsObjectHandle() && + !dt.IsReference() ) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 1; // call free + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); + +#ifndef AS_CALLEE_DESTROY_OBJ_BY_VAL + // If the called function doesn't destroy objects passed by value we must do so here + asSTypeBehaviour *beh = &CastToObjectType(dt.GetTypeInfo())->beh; + if( beh->destruct ) + clean.op = 2; // call destruct, then free +#endif + + internal->cleanArgs.PushLast(clean); + } +#endif + + if( n < internal->paramAutoHandles.GetLength() && internal->paramAutoHandles[n] ) + { + asSSystemFunctionInterface::SClean clean; + clean.op = 0; // call release + if (dt.IsFuncdef()) + clean.ot = &engine->functionBehaviours; + else + clean.ot = CastToObjectType(dt.GetTypeInfo()); + clean.off = short(offset); + internal->cleanArgs.PushLast(clean); + } + + if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) + offset += AS_PTR_SIZE; + else + offset += dt.GetSizeOnStackDWords(); + } +#endif // !defined(AS_MAX_PORTABILITY) + return 0; +} + +#ifdef AS_MAX_PORTABILITY + +int CallSystemFunction(int id, asCContext *context) +{ + asCScriptEngine *engine = context->m_engine; + asCScriptFunction *func = engine->scriptFunctions[id]; + asSSystemFunctionInterface *sysFunc = func->sysFuncIntf; + int callConv = sysFunc->callConv; + if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD ) + return context->CallGeneric(func); + + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + + return 0; +} + +#else + +// +// CallSystemFunctionNative +// +// This function is implemented for each platform where the native calling conventions is supported. +// See the various as_callfunc_xxx.cpp files for their implementation. It is responsible for preparing +// the arguments for the function call, calling the function, and then retrieving the return value. +// +// Parameters: +// +// context - This is the context that can be used to retrieve specific information from the engine +// descr - This is the script function object that holds the information on how to call the function +// obj - This is the object pointer, if the call is for a class method, otherwise it is null +// args - This is the function arguments, which are packed as in AngelScript +// retPointer - This points to a the memory buffer where the return object is to be placed, if the function returns the value in memory rather than in registers +// retQW2 - This output parameter should be used if the function returns a value larger than 64bits in registers +// secondObj - This is the object pointer that the proxy method should invoke its method on when the call convention is THISCALL_OBJFIRST/LAST +// +// Return value: +// +// The function should return the value that is returned in registers. +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObj); + + +int CallSystemFunction(int id, asCContext *context) +{ + asCScriptEngine *engine = context->m_engine; + asCScriptFunction *descr = engine->scriptFunctions[id]; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + + int callConv = sysFunc->callConv; + if( callConv == ICC_GENERIC_FUNC || callConv == ICC_GENERIC_METHOD ) + return context->CallGeneric(descr); + + asQWORD retQW = 0; + asQWORD retQW2 = 0; + asDWORD *args = context->m_regs.stackPointer; + void *retPointer = 0; + int popSize = sysFunc->paramSize; + + // TODO: clean-up: CallSystemFunctionNative should have two arguments for object pointers + // objForThiscall is the object pointer that should be used for the thiscall + // objForArg is the object pointer that should be passed as argument when using OBJFIRST or OBJLAST + + // Used to save two object pointers with THISCALL_OBJLAST or THISCALL_OBJFIRST + void *obj = 0; + void *secondObj = 0; + +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + if( callConv >= ICC_THISCALL ) + { + if(sysFunc->auxiliary) + { + // This class method is being called as if it is a global function + obj = sysFunc->auxiliary; + } + else + { + // The object pointer should be popped from the context stack + popSize += AS_PTR_SIZE; + + // Check for null pointer + obj = (void*)*(asPWORD*)(args); + if( obj == 0 ) + { + context->SetInternalException(TXT_NULL_POINTER_ACCESS); + return 0; + } + + // Skip the object pointer + args += AS_PTR_SIZE; + } + + // Add the base offset for multiple inheritance +#if (defined(__GNUC__) && (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA) + // On GNUC + ARM the lsb of the offset is used to indicate a virtual function + // and the whole offset is thus shifted one bit left to keep the original + // offset resolution + // MIPS also work like ARM in this regard + obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1)); +#else + obj = (void*)(asPWORD(obj) + sysFunc->baseOffset); +#endif + } +#else // !defined(AS_NO_THISCALL_FUNCTOR_METHOD) + + if( callConv >= ICC_THISCALL ) + { + bool continueCheck = true; // True if need check objectPointer or context stack for object + int continueCheckIndex = 0; // Index into objectsPtrs to save the object if continueCheck + + if( callConv >= ICC_THISCALL_OBJLAST ) + { + asASSERT( sysFunc->auxiliary != 0 ); + // This class method is being called as object method (sysFunc->auxiliary must be set). + obj = sysFunc->auxiliary; + continueCheckIndex = 1; + } + else if(sysFunc->auxiliary) + { + // This class method is being called as if it is a global function + obj = sysFunc->auxiliary; + continueCheck = false; + } + + if( obj ) + { + // Add the base offset for multiple inheritance +#if (defined(__GNUC__) && (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA) + // On GNUC + ARM the lsb of the offset is used to indicate a virtual function + // and the whole offset is thus shifted one bit left to keep the original + // offset resolution + // MIPS also work like ARM in this regard + obj = (void*)(asPWORD(obj) + (sysFunc->baseOffset>>1)); +#else + obj = (void*)(asPWORD(obj) + sysFunc->baseOffset); +#endif + } + + if( continueCheck ) + { + void *tempPtr = 0; + + // The object pointer should be popped from the context stack + popSize += AS_PTR_SIZE; + + // Check for null pointer + tempPtr = (void*)*(asPWORD*)(args); + if( tempPtr == 0 ) + { + context->SetInternalException(TXT_NULL_POINTER_ACCESS); + return 0; + } + + // Add the base offset for multiple inheritance +#if (defined(__GNUC__) && (defined(AS_ARM64) || defined(AS_ARM) || defined(AS_MIPS))) || defined(AS_PSVITA) + // On GNUC + ARM the lsb of the offset is used to indicate a virtual function + // and the whole offset is thus shifted one bit left to keep the original + // offset resolution + // MIPS also work like ARM in this regard + tempPtr = (void*)(asPWORD(tempPtr) + (sysFunc->baseOffset>>1)); +#else + tempPtr = (void*)(asPWORD(tempPtr) + sysFunc->baseOffset); +#endif + + // Skip the object pointer + args += AS_PTR_SIZE; + + if( continueCheckIndex ) + secondObj = tempPtr; + else + { + asASSERT( obj == 0 ); + obj = tempPtr; + } + } + } +#endif // AS_NO_THISCALL_FUNCTOR_METHOD + + if( descr->DoesReturnOnStack() ) + { + // Get the address of the location for the return value from the stack + retPointer = (void*)*(asPWORD*)(args); + popSize += AS_PTR_SIZE; + args += AS_PTR_SIZE; + + // When returning the value on the location allocated by the called + // we shouldn't set the object type in the register + context->m_regs.objectType = 0; + } + else + { + // Set the object type of the reference held in the register + context->m_regs.objectType = descr->returnType.GetTypeInfo(); + } + + // For composition we need to add the offset and/or dereference the pointer + if(obj) + { + obj = (void*) ((char*) obj + sysFunc->compositeOffset); + if(sysFunc->isCompositeIndirect) obj = *((void**)obj); + } + + context->m_callingSystemFunction = descr; + bool cppException = false; +#ifdef AS_NO_EXCEPTIONS + retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj); +#else + // This try/catch block is to catch potential exception that may + // be thrown by the registered function. The implementation of the + // CallSystemFunctionNative() must make sure not to have any manual + // clean-up after the call to the real function, or that won't be + // executed in case of an exception. + try + { + retQW = CallSystemFunctionNative(context, descr, obj, args, sysFunc->hostReturnInMemory ? retPointer : 0, retQW2, secondObj); + } + catch(...) + { + cppException = true; + + // Convert the exception to a script exception so the VM can + // properly report the error to the application and then clean up + context->HandleAppException(); + } +#endif + context->m_callingSystemFunction = 0; + + // Store the returned value in our stack + if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() ) + { + if( descr->returnType.IsObjectHandle() ) + { +#if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1 + // Since we're treating the system function as if it is returning a QWORD we are + // actually receiving the value in the high DWORD of retQW. + retQW >>= 32; +#endif + + context->m_regs.objectRegister = (void*)(asPWORD)retQW; + + if( sysFunc->returnAutoHandle && context->m_regs.objectRegister ) + { + asASSERT( !(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT) ); + engine->CallObjectMethod(context->m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref); + } + } + else + { + asASSERT( retPointer ); + + if( !sysFunc->hostReturnInMemory ) + { + // Copy the returned value to the pointer sent by the script engine + if( sysFunc->hostReturnSize == 1 ) + { +#if defined(AS_BIG_ENDIAN) && AS_PTR_SIZE == 1 + // Since we're treating the system function as if it is returning a QWORD we are + // actually receiving the value in the high DWORD of retQW. + retQW >>= 32; +#endif + + *(asDWORD*)retPointer = (asDWORD)retQW; + } + else if( sysFunc->hostReturnSize == 2 ) + *(asQWORD*)retPointer = retQW; + else if( sysFunc->hostReturnSize == 3 ) + { + *(asQWORD*)retPointer = retQW; + *(((asDWORD*)retPointer) + 2) = (asDWORD)retQW2; + } + else // if( sysFunc->hostReturnSize == 4 ) + { + *(asQWORD*)retPointer = retQW; + *(((asQWORD*)retPointer) + 1) = retQW2; + } + } + + if( context->m_status == asEXECUTION_EXCEPTION && !cppException ) + { + // If the function raised a script exception it really shouldn't have + // initialized the object. However, as it is a soft exception there is + // no way for the application to not return a value, so instead we simply + // destroy it here, to pretend it was never created. + if(CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct ) + engine->CallObjectMethod(retPointer, CastToObjectType(descr->returnType.GetTypeInfo())->beh.destruct); + } + } + } + else + { + // Store value in value register + if( sysFunc->hostReturnSize == 1 ) + { +#if defined(AS_BIG_ENDIAN) + // Since we're treating the system function as if it is returning a QWORD we are + // actually receiving the value in the high DWORD of retQW. + retQW >>= 32; + + // Due to endian issues we need to handle return values that are + // less than a DWORD (32 bits) in size specially + int numBytes = descr->returnType.GetSizeInMemoryBytes(); + if( descr->returnType.IsReference() ) numBytes = 4; + switch( numBytes ) + { + case 1: + { + // 8 bits + asBYTE *val = (asBYTE*)&context->m_regs.valueRegister; + val[0] = (asBYTE)retQW; + val[1] = 0; + val[2] = 0; + val[3] = 0; + val[4] = 0; + val[5] = 0; + val[6] = 0; + val[7] = 0; + } + break; + case 2: + { + // 16 bits + asWORD *val = (asWORD*)&context->m_regs.valueRegister; + val[0] = (asWORD)retQW; + val[1] = 0; + val[2] = 0; + val[3] = 0; + } + break; + default: + { + // 32 bits + asDWORD *val = (asDWORD*)&context->m_regs.valueRegister; + val[0] = (asDWORD)retQW; + val[1] = 0; + } + break; + } +#else + *(asDWORD*)&context->m_regs.valueRegister = (asDWORD)retQW; +#endif + } + else + context->m_regs.valueRegister = retQW; + } + + // Clean up arguments + const asUINT cleanCount = sysFunc->cleanArgs.GetLength(); + if( cleanCount ) + { + args = context->m_regs.stackPointer; + + // Skip the hidden argument for the return pointer + // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction + if( descr->DoesReturnOnStack() ) + args += AS_PTR_SIZE; + + // Skip the object pointer on the stack + // TODO: runtime optimize: This check and increment should have been done in PrepareSystemFunction + if( callConv >= ICC_THISCALL && sysFunc->auxiliary == 0 ) + args += AS_PTR_SIZE; + + asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf(); + for( asUINT n = 0; n < cleanCount; n++, clean++ ) + { + void **addr = (void**)&args[clean->off]; + if( clean->op == 0 ) + { + if( *addr != 0 ) + { + engine->CallObjectMethod(*addr, clean->ot->beh.release); + *addr = 0; + } + } + else + { + asASSERT( clean->op == 1 || clean->op == 2 ); + asASSERT( *addr ); + + if( clean->op == 2 ) + engine->CallObjectMethod(*addr, clean->ot->beh.destruct); + + engine->CallFree(*addr); + } + } + } + + return popSize; +} + +#endif // AS_MAX_PORTABILITY + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_callfunc.h b/angelscript/source/as_callfunc.h new file mode 100644 index 0000000..c9bdfc6 --- /dev/null +++ b/angelscript/source/as_callfunc.h @@ -0,0 +1,152 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc.h +// +// These functions handle the actual calling of system functions +// + + +#ifndef AS_CALLFUNC_H +#define AS_CALLFUNC_H + +#include "as_array.h" + +BEGIN_AS_NAMESPACE + +class asCContext; +class asCScriptEngine; +class asCScriptFunction; +class asCObjectType; +struct asSSystemFunctionInterface; + +int DetectCallingConvention(bool isMethod, const asSFuncPtr &ptr, int callConv, void *auxiliary, asSSystemFunctionInterface *internal); + +int PrepareSystemFunctionGeneric(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); + +int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); + +int CallSystemFunction(int id, asCContext *context); + +inline asPWORD FuncPtrToUInt(asFUNCTION_t func) +{ + // A little trickery as the C++ standard doesn't allow direct + // conversion between function pointer and data pointer + union { asFUNCTION_t func; asPWORD idx; } u; + u.func = func; + + return u.idx; +} + +enum internalCallConv +{ + ICC_GENERIC_FUNC, + ICC_GENERIC_FUNC_RETURNINMEM, // never used + ICC_CDECL, + ICC_CDECL_RETURNINMEM, + ICC_STDCALL, + ICC_STDCALL_RETURNINMEM, + ICC_THISCALL, + ICC_THISCALL_RETURNINMEM, + ICC_VIRTUAL_THISCALL, + ICC_VIRTUAL_THISCALL_RETURNINMEM, + ICC_CDECL_OBJLAST, + ICC_CDECL_OBJLAST_RETURNINMEM, + ICC_CDECL_OBJFIRST, + ICC_CDECL_OBJFIRST_RETURNINMEM, + ICC_GENERIC_METHOD, + ICC_GENERIC_METHOD_RETURNINMEM, // never used + ICC_THISCALL_OBJLAST, + ICC_THISCALL_OBJLAST_RETURNINMEM, + ICC_VIRTUAL_THISCALL_OBJLAST, + ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM, + ICC_THISCALL_OBJFIRST, + ICC_THISCALL_OBJFIRST_RETURNINMEM, + ICC_VIRTUAL_THISCALL_OBJFIRST, + ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM +}; + +struct asSSystemFunctionInterface +{ + asFUNCTION_t func; + int baseOffset; + internalCallConv callConv; + bool hostReturnInMemory; + bool hostReturnFloat; + int hostReturnSize; + int paramSize; + bool takesObjByVal; + asCArray paramAutoHandles; // TODO: Should be able to remove this array. Perhaps the flags can be stored together with the inOutFlags in asCScriptFunction? + bool returnAutoHandle; + int compositeOffset; + bool isCompositeIndirect; + void *auxiliary; // can be used for functors, e.g. by asCALL_THISCALL_ASGLOBAL or asCALL_THISCALL_OBJFIRST + + struct SClean + { + asCObjectType *ot; // argument type for clean up + short op; // clean up operation: 0 = release, 1 = free, 2 = destruct then free + short off; // argument offset on the stack + }; + asCArray cleanArgs; + + asSSystemFunctionInterface() : func(0), baseOffset(0), callConv(ICC_GENERIC_FUNC), hostReturnInMemory(false), hostReturnFloat(false), hostReturnSize(0), paramSize(0), takesObjByVal(false), returnAutoHandle(false), compositeOffset(0), isCompositeIndirect(false), auxiliary(0) {} + + asSSystemFunctionInterface(const asSSystemFunctionInterface &in) + { + *this = in; + } + + asSSystemFunctionInterface &operator=(const asSSystemFunctionInterface &in) + { + func = in.func; + baseOffset = in.baseOffset; + callConv = in.callConv; + hostReturnInMemory = in.hostReturnInMemory; + hostReturnFloat = in.hostReturnFloat; + hostReturnSize = in.hostReturnSize; + paramSize = in.paramSize; + takesObjByVal = in.takesObjByVal; + paramAutoHandles = in.paramAutoHandles; + returnAutoHandle = in.returnAutoHandle; + compositeOffset = in.compositeOffset; + isCompositeIndirect = in.isCompositeIndirect; + auxiliary = in.auxiliary; + cleanArgs = in.cleanArgs; + return *this; + } +}; + +END_AS_NAMESPACE + +#endif + diff --git a/angelscript/source/as_callfunc_arm.cpp b/angelscript/source/as_callfunc_arm.cpp new file mode 100644 index 0000000..6d82070 --- /dev/null +++ b/angelscript/source/as_callfunc_arm.cpp @@ -0,0 +1,665 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_arm.cpp +// +// These functions handle the actual calling of system functions on the arm platform +// +// Written by Fredrik Ehnbom in June 2009, based on as_callfunc_x86.cpp +// +// The code was complemented to support Linux with ARM by Carlos Luna in December, 2012. +// +// Added support for functor methods by Jordi Oliveras Rovira in April, 2014. + + +// This code has to conform to both AAPCS and the modified ABI for iOS +// +// Reference: +// +// AAPCS: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042d/IHI0042D_aapcs.pdf +// iOS: http://developer.apple.com/library/ios/documentation/Xcode/Conceptual/iPhoneOSABIReference/iPhoneOSABIReference.pdf + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_ARM + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +#if defined(AS_SOFTFP) + +// This code supports the soft-float ABI, i.e. g++ -mfloat-abi=softfp +// +// The code for iOS, Android, Marmalade and Windows Phone goes here + +BEGIN_AS_NAMESPACE + +extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t); +extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0); +extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1); +extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj); +extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj); + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + + asQWORD retQW = 0; + asFUNCTION_t func = sysFunc->func; + int paramSize = sysFunc->paramSize; + asFUNCTION_t *vftable; + + if( sysFunc->hostReturnInMemory ) + { + // The return is made in memory + callConv++; + } + bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; + + + asDWORD paramBuffer[64+2]; + // Android & Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone + // TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this + // doesn't have to be done for functions that don't have any 64bit types +#if !defined(AS_ANDROID) && !defined(AS_LINUX) + // In cases of thiscall methods, the callstack is configured as a standard thiscall + // adding the secondObject as first or last element in callstack + if( sysFunc->takesObjByVal || isThisCallMethod ) +#endif + { +#if defined(AS_ANDROID) || defined(AS_LINUX) + // mask is used as a toggler to skip uneven registers. + int mask = 1; + + if( isThisCallMethod ) + { + mask = 0; + } + else + { + // Check for object pointer as first argument + switch( callConv ) + { + case ICC_THISCALL: + case ICC_CDECL_OBJFIRST: + case ICC_VIRTUAL_THISCALL: + case ICC_THISCALL_RETURNINMEM: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + mask = 0; + break; + default: + break; + } + } + + // Check for hidden address in case of return by value + if( sysFunc->hostReturnInMemory ) + mask = !mask; +#endif + paramSize = 0; + int spos = 0; + int dpos = 2; + + if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST && + callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) + { + // Add the object pointer as the first parameter + paramBuffer[dpos++] = (asDWORD)secondObject; + paramSize++; + } + + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + // TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else +#endif + { +#if defined(AS_ANDROID) || defined(AS_LINUX) + if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && + ((dpos & 1) == mask) ) + { + // 64 bit value align + dpos++; + paramSize++; + } +#endif + // Copy the object's memory to the buffer + memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos++; + dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); + } + } + else + { +#if defined(AS_ANDROID) || defined(AS_LINUX) + // Should an alignment be performed? + if( !descr->parameterTypes[n].IsObjectHandle() && + !descr->parameterTypes[n].IsReference() && + descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && + ((dpos & 1) == mask) ) + { + // 64 bit value align + dpos++; + paramSize++; + } +#endif + + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + paramBuffer[dpos++] = args[spos++]; + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + } + + if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST && + callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) + { + // Add the object pointer as the last parameter + paramBuffer[dpos++] = (asDWORD)secondObject; + paramSize++; + } + + // Keep a free location at the beginning + args = ¶mBuffer[2]; + } + + switch( callConv ) + { + case ICC_CDECL_RETURNINMEM: // fall through + case ICC_STDCALL_RETURNINMEM: + retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer); + break; + case ICC_CDECL: // fall through + case ICC_STDCALL: + retQW = armFunc(args, paramSize<<2, func); + break; + case ICC_THISCALL: // fall through + case ICC_CDECL_OBJFIRST: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJLAST: + retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); + break; + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST_RETURNINMEM: +#ifdef __GNUC__ + // On GNUC the address where the return value will be placed should be put in R0 + retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); +#else + // On Windows the R0 should always hold the object pointer, and the address for the return value comes after + retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)obj, (asDWORD)retPointer); +#endif + break; + case ICC_CDECL_OBJFIRST_RETURNINMEM: + retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); + break; + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJLAST: + // Get virtual function table from the object pointer + vftable = *(asFUNCTION_t**)obj; + retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj); + break; + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(asFUNCTION_t**)obj; +#ifdef __GNUC__ + // On GNUC the address where the return value will be placed should be put in R0 + retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj); +#else + // On Windows the R0 should always hold the object pointer, and the address for the return value comes after + retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj, (asDWORD)retPointer); +#endif + break; + case ICC_CDECL_OBJLAST: + retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj); + break; + case ICC_CDECL_OBJLAST_RETURNINMEM: + retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); + break; + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + return retQW; +} + +END_AS_NAMESPACE + +#elif !defined(AS_SOFTFP) + +// This code supports the hard-float ABI, i.e. g++ -mfloat-abi=hard +// The main difference is that the floating point values are passed in the fpu registers + +#define VFP_OFFSET 70 +#define STACK_OFFSET 6 +#define PARAM_BUFFER_SIZE 104 + +BEGIN_AS_NAMESPACE + +extern "C" asQWORD armFunc (const asDWORD *, int, asFUNCTION_t); +extern "C" asQWORD armFuncR0 (const asDWORD *, int, asFUNCTION_t, asDWORD r0); +extern "C" asQWORD armFuncR0R1 (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD r1); +extern "C" asQWORD armFuncObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD obj); +extern "C" asQWORD armFuncR0ObjLast (const asDWORD *, int, asFUNCTION_t, asDWORD r0, asDWORD obj); + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + + asQWORD retQW = 0; + asFUNCTION_t func = sysFunc->func; + int paramSize = sysFunc->paramSize; + asFUNCTION_t *vftable; + + //---------------------------------------------------------------------------- RPi + int freeFloatSlot = VFP_OFFSET; + int freeDoubleSlot = VFP_OFFSET; + int stackPos = STACK_OFFSET; + int stackSize = 0; + //---------------------------------------------------------------------------- + + //---------------------------------------------------------------------------- RPi + // We´ll divide paramBuffer into several segments: + // + // 0-1 Unused + // 2-5 (+8 / +0 asm) values that should be placed in R0 - R3 + // 6-67 (+24 / +16 asm) values that should be placed on the stack + // 68 (+272 / +264 asm) number of values stored in r registers (R0 - R3) + // 69 (+276 / +268 asm) number of args stored on the stack + // 70-85 (+280 / +272 asm) values that should be placed in VFP registers (16) + // 86-87 (+344 / +336 asm) sp original value - sp final value - for debugging + // 88-103 (+352 / +344 asm) Check area for free-used VFP registers + // + // Total number of elements: 104 + // + // When passing the paramBuffer to the asm routines via the args pointer we are + // offsetting the start of the array to being at element # 2. That´s why in asm + // all addresses must have an offset of -2 words (-8 bytes). + //---------------------------------------------------------------------------- RPi + + asDWORD paramBuffer[PARAM_BUFFER_SIZE]; + memset(paramBuffer, 0, sizeof(asDWORD) * PARAM_BUFFER_SIZE); + + if( sysFunc->hostReturnInMemory ) + { + // TODO: runtime optimize: This check should be done in PrepareSystemFunction + if ( !( descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK ) && + ( descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS ) && + descr->returnType.GetSizeInMemoryBytes() <= 8 ) + callConv--; + + // The return is made in memory + callConv++; + } + + bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; + + // Linux needs to align 64bit types on even registers, but this isn't done on iOS or Windows Phone + // TODO: optimize runtime: There should be a check for this in PrepareSystemFunction() so this + // doesn't have to be done for functions that don't have any 64bit types + { + // mask is used as a toggler to skip uneven registers. + int mask = 1; + + if( isThisCallMethod ) + { + mask = 0; + } + else + { + // Check for object pointer as first argument + switch( callConv ) + { + case ICC_THISCALL: + case ICC_CDECL_OBJFIRST: + case ICC_VIRTUAL_THISCALL: + case ICC_THISCALL_RETURNINMEM: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + mask = 0; + break; + default: + break; + } + } + // Check for hidden address in case of return by value + if( sysFunc->hostReturnInMemory ) + mask = !mask; + + paramSize = 0; + int spos = 0; + int dpos = 2; + + if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJFIRST && + callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) + { + // Add the object pointer as the first parameter + paramBuffer[dpos++] = (asDWORD)secondObject; + paramSize++; + } + + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + // TODO: runtime optimize: Declare a reference to descr->parameterTypes[n] so the array doesn't have to be access all the time + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && + !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else +#endif + { + if( (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) ) + { + if ( (dpos & 1) == mask ) + { + // 64 bit value align + dpos++; + paramSize++; + } + + if ( (stackPos & 1) == mask ) + { + // 64 bit value align + stackPos++; + stackSize++; + } + } + + // Copy the object's memory to the buffer + if (descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) + { + int target = (freeFloatSlot > freeDoubleSlot) ? freeFloatSlot : freeDoubleSlot; + + if ( descr->parameterTypes[n].GetSizeInMemoryDWords() <= ( (VFP_OFFSET + 16) - target) ) + { + memcpy(¶mBuffer[target], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + memset(¶mBuffer[target + 18], (asDWORD)1, descr->parameterTypes[n].GetSizeInMemoryDWords()); + target += descr->parameterTypes[n].GetSizeInMemoryDWords(); + freeFloatSlot = freeDoubleSlot = target; + } + else + { + memcpy(¶mBuffer[stackPos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + stackPos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + stackSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + } + else + { + memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); + } + + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos++; + } + + continue; + } + else if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() ) + { + // Are there any "s" registers available? + if ( freeFloatSlot < (VFP_OFFSET + 16) ) + { + if (freeFloatSlot == freeDoubleSlot) + freeDoubleSlot += 2; + + paramBuffer[freeFloatSlot + 18] = (asDWORD)1; + paramBuffer[freeFloatSlot++] = args[spos++]; + + while(freeFloatSlot < (VFP_OFFSET + 16) && paramBuffer[freeFloatSlot + 18] != 0) + freeFloatSlot++; + } + // If not, then store the float arg in the stack area + else + { + paramBuffer[stackPos++] = args[spos++]; + stackSize++; + } + + continue; + } + else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() ) + { + // Are there any "d" registers available? + if ( freeDoubleSlot < (VFP_OFFSET + 15) ) + { + if (freeFloatSlot == freeDoubleSlot) + freeFloatSlot += 2; + + // Copy two dwords for the double + paramBuffer[freeDoubleSlot + 18] = (asDWORD)1; + paramBuffer[freeDoubleSlot + 19] = (asDWORD)1; + paramBuffer[freeDoubleSlot++] = args[spos++]; + paramBuffer[freeDoubleSlot++] = args[spos++]; + + while(freeDoubleSlot < (VFP_OFFSET + 15) && paramBuffer[freeDoubleSlot + 18] != 0) + freeDoubleSlot += 2; + } + // If not, then store the double arg in the stack area + else + { + if ( (stackPos & 1) == mask ) + { + // 64 bit value align + stackPos++; + stackSize++; + } + + paramBuffer[stackPos++] = args[spos++]; + paramBuffer[stackPos++] = args[spos++]; + stackSize += 2; + } + + continue; + } + else + { + // Copy the value directly to "r" registers or the stack, checking for alignment + if (paramSize < 4) + { + // Should an alignment be performed? + if( (dpos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && + !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && + !descr->parameterTypes[n].IsAnyType() ) + { + // 64 bit value align + dpos++; + paramSize++; + } + + paramBuffer[dpos++] = args[spos++]; + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + else + { + // Should an alignment be performed? + if( (stackPos & 1) == mask && descr->parameterTypes[n].GetSizeOnStackDWords() == 2 && + !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && + !descr->parameterTypes[n].IsAnyType() ) + { + // 64 bit value align + stackPos++; + stackSize++; + } + + paramBuffer[stackPos++] = args[spos++]; + stackSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + { + if (paramSize < 5) + paramBuffer[dpos++] = args[spos++]; + else + paramBuffer[stackPos++] = args[spos++]; + } + }// else... + }// Loop + + if( isThisCallMethod && (callConv >= ICC_THISCALL_OBJLAST && + callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) + { + if (paramSize < 4) + { + paramBuffer[dpos++] = (asDWORD)secondObject; + paramSize++; + } + else + { + paramBuffer[stackPos++] = (asDWORD)secondObject; + stackSize++; + } + } + + // Keep a free location at the beginning + args = ¶mBuffer[2]; + } + + paramBuffer[69] = static_cast(stackSize<<2); + + switch( callConv ) + { + case ICC_CDECL_RETURNINMEM: // fall through + case ICC_STDCALL_RETURNINMEM: + retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)retPointer); + break; + case ICC_CDECL: // fall through + case ICC_STDCALL: + retQW = armFunc(args, paramSize<<2, func); + break; + case ICC_THISCALL: // fall through + case ICC_CDECL_OBJFIRST: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJLAST: + retQW = armFuncR0(args, paramSize<<2, func, (asDWORD)obj); + break; + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST_RETURNINMEM: + // On GNUC the address where the return value will be placed should be put in R0 + retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); + break; + case ICC_CDECL_OBJFIRST_RETURNINMEM: + retQW = armFuncR0R1(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); + break; + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJLAST: + // Get virtual function table from the object pointer + vftable = *(asFUNCTION_t**)obj; + retQW = armFuncR0(args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)obj); + break; + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(asFUNCTION_t**)obj; + // On GNUC the address where the return value will be placed should be put in R0 + retQW = armFuncR0R1(args, (paramSize+1)<<2, vftable[FuncPtrToUInt(func)>>2], (asDWORD)retPointer, (asDWORD)obj); + break; + case ICC_CDECL_OBJLAST: + retQW = armFuncObjLast(args, paramSize<<2, func, (asDWORD)obj); + break; + case ICC_CDECL_OBJLAST_RETURNINMEM: + retQW = armFuncR0ObjLast(args, paramSize<<2, func, (asDWORD)retPointer, (asDWORD)obj); + break; + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + // On Linux with arm the float and double values are returns in the + // floating point registers, s0 and s1. Objects that contain only + // float types and are not considered complex are also returned in the + // floating point registers. + if( sysFunc->hostReturnFloat ) + { + retQW = paramBuffer[VFP_OFFSET]; + + if ( sysFunc->hostReturnSize > 1 ) + retQW = *( (asQWORD*)¶mBuffer[VFP_OFFSET] ); + } + else if ( descr->returnType.IsObject() ) + { + // TODO: runtime optimize: This should be identified with a flag determined in PrepareSystemFunction + if ( !descr->returnType.IsObjectHandle() && + !descr->returnType.IsReference() && + !(descr->returnType.GetTypeInfo()->flags & COMPLEX_RETURN_MASK) && + (descr->returnType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) ) + memcpy( retPointer, ¶mBuffer[VFP_OFFSET], descr->returnType.GetSizeInMemoryBytes() ); + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_LINUX + +#endif // AS_ARM +#endif // AS_MAX_PORTABILITY + + + + diff --git a/angelscript/source/as_callfunc_arm64.cpp b/angelscript/source/as_callfunc_arm64.cpp new file mode 100644 index 0000000..3e0944d --- /dev/null +++ b/angelscript/source/as_callfunc_arm64.cpp @@ -0,0 +1,329 @@ +/* + AngelCode Scripting Library + Copyright (c) 2020-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_arm64.cpp +// +// These functions handle the actual calling of system functions on the arm64 platform +// +// Written by Max Waine in July 2020, based on as_callfunc_arm.cpp +// + + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_ARM64 + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +// ARM64 targets use has no software floating-point ABI, it's all hardware (or totally disabled) + +#define HFA_RET_REGISTERS 4 // s0-s3/d0-d3 +#define GP_ARG_REGISTERS 8 // x0-x7 +#define FLOAT_ARG_REGISTERS 8 // v0-v7 + +BEGIN_AS_NAMESPACE + +// x0-7: Argument registers (pass params or return results. OK as volatile local variables) +// x8: Indirect result register (e.g. address of large returned struct) +// x9-15: Volatile local variable registers +// x16-17: Intra-procedure-call temporary registers +// x18: Platform register (reserved for use of platform ABIs) +// x19-29: Non-volatile variable registers (must be saved and restored if modified) +// x29: Frame pointer register +// x30: Link register (where to return to) + +extern "C" void GetHFAReturnDouble(asQWORD *out1, asQWORD *out2, asQWORD returnSize); +extern "C" void GetHFAReturnFloat(asQWORD *out1, asQWORD *out2, asQWORD returnSize); + +extern "C" asQWORD CallARM64RetInMemory( + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + void *retPointer, asFUNCTION_t func +); +extern "C" double CallARM64Double( + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asFUNCTION_t func +); +extern "C" float CallARM64Float( + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asFUNCTION_t func +); +extern "C" asQWORD CallARM64( + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asFUNCTION_t func +); +extern "C" asQWORD CallARM64Ret128( + const asQWORD *gpRegArgs, asQWORD numGPRegArgs, + const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, + const asQWORD *stackArgs, asQWORD numStackArgs, + asQWORD *higherQWORD, asFUNCTION_t func +); + +// +// If it's possible to fit in registers, +// there may not be enough float register space even if true is returned +// +static inline bool IsRegisterHFA(const asCDataType &type) +{ + const asCTypeInfo *const typeInfo = type.GetTypeInfo(); + + if( typeInfo == nullptr || + (typeInfo->flags & asOBJ_APP_CLASS_ALLFLOATS) == 0 || + type.IsObjectHandle() && type.IsReference() ) + return false; + + const bool doubles = (typeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0; + const int maxAllowedSize = doubles ? sizeof(double) * HFA_RET_REGISTERS : sizeof(float) * HFA_RET_REGISTERS; + + return type.GetSizeInMemoryBytes() <= maxAllowedSize; +} + +// +// If it's possible to fit it in registers, +// if true is returned there is enough space to fit +// +static inline bool IsRegisterHFAParameter(const asCDataType &type, const asQWORD numFloatRegArgs) +{ + if( !IsRegisterHFA(type) ) + return false; + + const bool doubles = (type.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) != 0; + const int registersUsed = type.GetSizeInMemoryDWords() / (doubles ? sizeof(double) : sizeof(float)); + + return numFloatRegArgs + registersUsed <= FLOAT_ARG_REGISTERS; +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + const asSSystemFunctionInterface *const sysFunc = descr->sysFuncIntf; + const asCDataType &retType = descr->returnType; + const asCTypeInfo *const retTypeInfo = retType.GetTypeInfo(); + asFUNCTION_t func = sysFunc->func; + int callConv = sysFunc->callConv; + asQWORD retQW = 0; + + asQWORD gpRegArgs[GP_ARG_REGISTERS]; + asQWORD floatRegArgs[FLOAT_ARG_REGISTERS]; + asQWORD stackArgs[64]; // It's how many x64 users can have + asQWORD numGPRegArgs = 0; + asQWORD numFloatRegArgs = 0; + asQWORD numStackArgs = 0; + + asFUNCTION_t *vftable; + + // Optimization to avoid check 12 values (all ICC_ that contains THISCALL) + if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) || + (callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) + { + // Add the object pointer as the first parameter + gpRegArgs[numGPRegArgs++] = (asQWORD)obj; + } + + if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ) + { + // Add the object pointer as the first parameter + gpRegArgs[numGPRegArgs++] = (asQWORD)obj; + } + else if( callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) + { + // Add the object pointer as the first parameter + gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject; + } + + if( callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Get virtual function table from the object pointer + vftable = *(asFUNCTION_t**)obj; + func = vftable[FuncPtrToUInt(func)/sizeof(void*)]; + } + + asUINT argsPos = 0; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + const asCDataType &parmType = descr->parameterTypes[n]; + const asCTypeInfo *const parmTypeInfo = parmType.GetTypeInfo(); + + if( parmType.IsObject() && !parmType.IsObjectHandle() && !parmType.IsReference() ) + { + const asUINT parmDWords = parmType.GetSizeInMemoryDWords(); + const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1); + + const bool passedAsPointer = parmQWords <= 2; + const bool fitsInRegisters = passedAsPointer ? (numGPRegArgs < GP_ARG_REGISTERS) : (numGPRegArgs + parmQWords <= GP_ARG_REGISTERS); + asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs; + asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs; + + if( (parmTypeInfo->flags & COMPLEX_MASK) ) + { + argsArray[numArgs++] = *(asQWORD*)&args[argsPos]; + argsPos += AS_PTR_SIZE; + } + else if( IsRegisterHFAParameter(parmType, numFloatRegArgs) ) + { + if( (parmTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 ) + { + const asQWORD *const contents = *(asQWORD**)&args[argsPos]; + for( asUINT i = 0; i < parmQWords; i++ ) + floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i]; + } + else + { + const asDWORD *const contents = *(asDWORD**)&args[argsPos]; + for( asUINT i = 0; i < parmDWords; i++ ) + floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&contents[i]; + } + engine->CallFree(*(char**)(args+argsPos)); + argsPos += AS_PTR_SIZE; + } + else + { + // Copy the object's memory to the buffer + memcpy(&argsArray[numArgs], *(void**)(args+argsPos), parmType.GetSizeInMemoryBytes()); + + // Delete the original memory + engine->CallFree(*(char**)(args+argsPos)); + argsPos += AS_PTR_SIZE; + numArgs += parmQWords; + } + } + else if( parmType.IsFloatType() && !parmType.IsReference() ) + { + if( numFloatRegArgs >= FLOAT_ARG_REGISTERS ) + stackArgs[numStackArgs++] = args[argsPos]; + else + floatRegArgs[numFloatRegArgs++] = args[argsPos]; + argsPos++; + } + else if( parmType.IsDoubleType() && !parmType.IsReference() ) + { + if( numFloatRegArgs >= FLOAT_ARG_REGISTERS ) + stackArgs[numStackArgs++] = *(asQWORD*)&args[argsPos]; + else + floatRegArgs[numFloatRegArgs++] = *(asQWORD*)&args[argsPos]; + argsPos += 2; + } + else + { + // Copy the value directly + const asUINT parmDWords = parmType.GetSizeOnStackDWords(); + const asUINT parmQWords = (parmDWords >> 1) + (parmDWords & 1); + + const bool fitsInRegisters = numGPRegArgs + parmQWords <= GP_ARG_REGISTERS; + asQWORD *const argsArray = fitsInRegisters ? gpRegArgs : stackArgs; + asQWORD &numArgs = fitsInRegisters ? numGPRegArgs : numStackArgs; + + memcpy(&argsArray[numArgs], (void*)(args+argsPos), parmDWords * 4); + argsPos += parmDWords; + numArgs += parmQWords; + } + } + + if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last parameter + if( numGPRegArgs < GP_ARG_REGISTERS ) + gpRegArgs[numGPRegArgs++] = (asQWORD)obj; + else + stackArgs[numStackArgs++] = (asQWORD)obj; + } + else if( callConv == ICC_THISCALL_OBJLAST || callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last parameter + if( numGPRegArgs < GP_ARG_REGISTERS ) + gpRegArgs[numGPRegArgs++] = (asQWORD)secondObject; + else + stackArgs[numStackArgs++] = (asQWORD)secondObject; + } + + if( IsRegisterHFA(retType) && !(retTypeInfo->flags & COMPLEX_MASK) ) + { + // This is to deal with HFAs (Homogeneous Floating-point Aggregates): + // ARM64 will place all-float composite types (of equal precision) + // with <= 4 members in the float return registers + + const int structSize = retType.GetSizeInMemoryBytes(); + + CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + if( (retTypeInfo->flags & asOBJ_APP_CLASS_ALIGN8) != 0 ) + { + if( structSize <= sizeof(double) * 2 ) + GetHFAReturnDouble(&retQW, &retQW2, structSize); + else + GetHFAReturnDouble((asQWORD*)retPointer, ((asQWORD*)retPointer) + 1, structSize); + } + else + GetHFAReturnFloat(&retQW, &retQW2, structSize); + } + else if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(float*)&retQW = CallARM64Float(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + else + *(double*)&retQW = CallARM64Double(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + } + else if( sysFunc->hostReturnInMemory ) + retQW = CallARM64RetInMemory(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, retPointer, func); + else + { + if( retType.GetSizeInMemoryBytes() > sizeof(asQWORD) ) + retQW = CallARM64Ret128(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, &retQW2, func); + else + retQW = CallARM64(gpRegArgs, numGPRegArgs, floatRegArgs, numFloatRegArgs, stackArgs, numStackArgs, func); + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_ARM64 +#endif // AS_MAX_PORTABILITY + + + + diff --git a/angelscript/source/as_callfunc_arm64_gcc.S b/angelscript/source/as_callfunc_arm64_gcc.S new file mode 100644 index 0000000..b5d5a5d --- /dev/null +++ b/angelscript/source/as_callfunc_arm64_gcc.S @@ -0,0 +1,219 @@ +// +// AngelCode Scripting Library +// Copyright (c) 2020-2020 Andreas Jonsson +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any +// damages arising from the use of this software. +// +// Permission is granted to anyone to use this software for any +// purpose, including commercial applications, and to alter it and +// redistribute it freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented// you +// must not claim that you wrote the original software. If you use +// this software in a product, an acknowledgment in the product +// documentation would be appreciated but is not required. +// +// 2. Altered source versions must be plainly marked as such, and +// must not be misrepresented as being the original software. +// +// 3. This notice may not be removed or altered from any source +// distribution. +// +// The original version of this library can be located at: +// http://www.angelcode.com/angelscript/ +// +// Andreas Jonsson +// andreas@angelcode.com +// + + +// Assembly routines for the ARM64/AArch64 call convention used for Linux +// Written by Max Waine in July 2020, based on as_callfunc_arm_msvc.asm, +// with assistance & guidance provided by Sir Kane + +// Compile with GCC/GAS + +.arch armv8-a +.text + +.global GetHFAReturnDouble +.global GetHFAReturnFloat +.global CallARM64Ret128 +.global CallARM64RetInMemory +.global CallARM64Double +.global CallARM64Float +.global CallARM64 + +.type GetHFAReturnDouble, %function +.type GetHFAReturnFloat, %function +.type CallARM64Ret128, %function +.type CallARM64RetInMemory, %function +.type CallARM64Double, %function +.type CallARM64Float, %function +.type CallARM64, %function + +.align 2 +GetHFAReturnDouble: + adr x9, populateDoubles + sub x9, x9, x1, lsr 1 // x9 -= returnSize >> 1; (/2 because double is 2x instruction size) + br x9 + + str d3, [x0, #0x18] + str d2, [x0, #0x10] + str d1, [x1] + str d0, [x0] +populateDoubles: + + ret + +.align 2 +GetHFAReturnFloat: + adr x9, populateFloats + sub x9, x9, x2 // x9 -= returnSize; (already 4 bytes per return) + br x9 + + str s3, [x1, #0x4] + str s2, [x1] + str s1, [x0, #0x4] + str s0, [x0] +populateFloats: + + ret + + +//[returnType] CallARM64[type]( +// const asQWORD *gpRegArgs, asQWORD numGPRegArgs, +// const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, +// const asQWORD *stackArgs, asQWORD numStackArgs, +// asFUNCTION_t func +//) +.align 2 +CallARM64Double: +CallARM64Float: +CallARM64: + .cfi_startproc + stp fp, lr, [sp,#-0x20]! + str x20, [sp,#0x10] + .cfi_def_cfa_offset 0x20 + .cfi_offset 20, 0x10 + .cfi_offset fp, -0x20 + .cfi_offset lr, -0x18 + mov fp, sp + + mov x20, #0 + + cbz x5, stackArgsLoopEnd + + // Align count to 2, then multiply by 8, resulting in a size aligned to 16 + add x20, x5, #1 + lsl x20, x20, #3 + and x20, x20, #-0x10 + // Multiply count by 8 + lsl x10, x5, #3 + sub sp, sp, x20 +stackArgsLoopStart: + ldp x9,x11, [x4],#16 + stp x9,x11, [sp],#16 + subs x10, x10, #16 + bgt stackArgsLoopStart +stackArgsLoopEnd: + + // Calculate amount to jump forward, avoiding pointless instructions + adr x9, populateFloatRegisterArgsEnd + sub x9, x9, x3, lsl 2 // x9 -= numFloatRegArgs * 4 + br x9 + + ldr d7, [x2, #0x38] + ldr d6, [x2, #0x30] + ldr d5, [x2, #0x28] + ldr d4, [x2, #0x20] + ldr d3, [x2, #0x18] + ldr d2, [x2, #0x10] + ldr d1, [x2, #0x08] + ldr d0, [x2] +populateFloatRegisterArgsEnd: + + mov x15, x6 + // Calculate amount to jump forward, avoiding pointless instructions + adr x9, populateGPRegisterArgsEnd + sub x9, x9, x1, lsl 2 // x9 -= numGPRegArgs * 4 + br x9 + + ldr x7, [x0, #0x38] + ldr x6, [x0, #0x30] + ldr x5, [x0, #0x28] + ldr x4, [x0, #0x20] + ldr x3, [x0, #0x18] + ldr x2, [x0, #0x10] + ldr x1, [x0, #0x08] + ldr x0, [x0] +populateGPRegisterArgsEnd: + + // Actually call function + sub sp, sp, x20 + blr x15 + add sp, sp, x20 + + ldr x20, [sp,#0x10] + ldp fp, lr, [sp],#0x20 + + .cfi_restore lr + .cfi_restore fp + .cfi_restore 20 + .cfi_def_cfa_offset 0 + ret + .cfi_endproc + +.align 2 +CallARM64Ret128: + .cfi_startproc + stp fp, lr, [sp,#-0x20]! + str x20, [sp,#0x10] + .cfi_def_cfa_offset 0x20 + .cfi_offset 20, 0x10 + .cfi_offset fp, -0x20 + .cfi_offset lr, -0x18 + mov fp, sp + + mov x20, x6 + mov x6, x7 + mov x7, #0 + bl CallARM64 + + str x1, [x20] + + ldr x20, [sp,#0x10] + ldp fp, lr, [sp],#0x20 + + .cfi_restore lr + .cfi_restore fp + .cfi_restore 20 + .cfi_def_cfa_offset 0 + ret + .cfi_endproc + +.align 2 +CallARM64RetInMemory: + .cfi_startproc + stp fp, lr, [sp,#-0x10]! + mov fp, sp + .cfi_def_cfa_offset 0x10 + .cfi_offset fp, -0x10 + .cfi_offset lr, -0x08 + + mov x8, x6 + mov x6, x7 + mov x7, #0 + bl CallARM64 + + mov x0, x8 + + ldp fp, lr, [sp],#0x10 + + .cfi_restore lr + .cfi_restore fp + .cfi_def_cfa_offset 0 + ret + .cfi_endproc diff --git a/angelscript/source/as_callfunc_arm64_msvc.asm b/angelscript/source/as_callfunc_arm64_msvc.asm new file mode 100644 index 0000000..ce43c75 --- /dev/null +++ b/angelscript/source/as_callfunc_arm64_msvc.asm @@ -0,0 +1,205 @@ +; +; AngelCode Scripting Library +; Copyright (c) 2020-2020 Andreas Jonsson +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any +; purpose, including commercial applications, and to alter it and +; redistribute it freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you +; must not claim that you wrote the original software. If you use +; this software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; +; 2. Altered source versions must be plainly marked as such, and +; must not be misrepresented as being the original software. +; +; 3. This notice may not be removed or altered from any source +; distribution. +; +; The original version of this library can be located at: +; http://www.angelcode.com/angelscript/ +; +; Andreas Jonsson +; andreas@angelcode.com +; + + +; Assembly routines for the ARM64/AArch64 call convention used for Windows 10 on ARM +; Written by Max Waine in July 2020, based on as_callfunc_arm_msvc.asm + +; MSVC currently doesn't support inline assembly for the ARM64 platform, +; and if they're treating it like x64 /won't/ ever support inline assembly, +; so this separate file is needed. + +; Compile with Microsoft ARM64 assembler (armasm64) +; http://msdn.microsoft.com/en-us/library/hh873190.aspx + + AREA |.rdata|, DATA, READONLY + EXPORT GetHFAReturnDouble + EXPORT GetHFAReturnFloat + EXPORT CallARM64Ret128 + EXPORT CallARM64RetInMemory + EXPORT CallARM64Double + EXPORT CallARM64Float + EXPORT CallARM64 + + AREA |.text|, CODE, ALIGN=2 + + ALIGN 4 +GetHFAReturnDouble PROC + adr x9, |populateDoubles| + sub x9, x9, x1, lsr 1 ; x9 -= returnSize >> 1; (/2 because double is 2x instruction size) + br x9 + + str d3, [x0, #0x18] + str d2, [x0, #0x10] + str d1, [x1] + str d0, [x0] +|populateDoubles| + + ret + ENDP ; GetHFAReturnDouble + + ALIGN 4 +GetHFAReturnFloat PROC + adr x9, |populateFloats| + sub x9, x9, x2 // x9 -= returnSize; (already 4 bytes per return) + br x9 + + str s3, [x1, #0x4] + str s2, [x1] + str s1, [x0, #0x4] + str s0, [x0] +|populateFloats| + + ret + ENDP ; GetHFAReturnFloat + + +;[returnType] CallARM64[type]( +; const asQWORD *gpRegArgs, asQWORD numGPRegArgs, +; const asQWORD *floatRegArgs, asQWORD numFloatRegArgs, +; const asQWORD *stackArgs, asQWORD numStackArgs, +; asFUNCTION_t func +;) + ALIGN 4 +CallARM64Double PROC + stp fp, lr, [sp,#-0x10]! + bl CallARM64 + ldp fp, lr, [sp,#-0x10]! + ret + ENDP ; CallARM64Double + + ALIGN 4 +CallARM64Float PROC + stp fp, lr, [sp,#-0x10]! + bl CallARM64 + ldp fp, lr, [sp,#-0x10]! + ret + ENDP ; CallARM64Float + + ALIGN 4 +CallARM64 PROC + stp fp, lr, [sp,#-0x20]! + str x20, [sp,#0x10] + + mov x20, #0; + + cbz x5, |stackArgsLoopEnd| + + ; Align count to 2, then multiply by 8, resulting in a size aligned to 16 + add x20, x5, #1 + lsl x20, x20, #3 + and x20, x20, #-0x10 + ; Multiply count by 8 + lsl x10, x5, #3 + sub sp, sp, x20 +|stackArgsLoopStart| + ldp x9,x11, [x4],#16 + stp x9,x11, [sp],#16 + subs x10, x10, #16 + bgt |stackArgsLoopStart| +|stackArgsLoopEnd| + + ; Calculate amount to jump forward, avoiding pointless instructions + adr x9, |populateFloatRegisterArgsEnd| + sub x9, x9, x3, lsl 2 ; x9 -= numFloatRegArgs * 4 + br x9 + + ldr d7, [x2, #0x38] + ldr d6, [x2, #0x30] + ldr d5, [x2, #0x28] + ldr d4, [x2, #0x20] + ldr d3, [x2, #0x18] + ldr d2, [x2, #0x10] + ldr d1, [x2, #0x08] + ldr d0, [x2] +|populateFloatRegisterArgsEnd| + + mov x15, x6 + ; Calculate amount to jump forward, avoiding pointless instructions + adr x9, |populateGPRegisterArgsEnd| + sub x9, x9, x1, lsl 2 ; x9 -= numGPRegArgs * 4 + br x9 + + ldr x7, [x0, #0x38] + ldr x6, [x0, #0x30] + ldr x5, [x0, #0x28] + ldr x4, [x0, #0x20] + ldr x3, [x0, #0x18] + ldr x2, [x0, #0x10] + ldr x1, [x0, #0x08] + ldr x0, [x0] +|populateGPRegisterArgsEnd| + + ; Actually call function + sub sp, sp, x20 + blr x15 + add sp, sp, x20 + + ldr x20, [sp,#0x10] + ldp fp, lr, [sp],#0x20 + + ret + ENDP ; CallARM64 + + ALIGN 4 +CallARM64Ret128 PROC + stp fp, lr, [sp,#-0x20]! + str x20, [sp,#0x10] + mov fp, sp + + mov x20, x6 + mov x6, x7 + mov x7, #0 + bl CallARM64 + + str x1, [x20] + + ldr x20, [sp,#0x10] + ldp fp, lr, [sp],#0x20 + + ret ; CallARM64Ret128 + + ALIGN 4 +CallARM64RetInMemory PROC + stp fp, lr, [sp,#-0x10]! + mov fp, sp + + mov x8, x6 + mov x6, x7 + mov x7, #0 + bl CallARM64 + + mov x0, x8 + + ldp fp, lr, [sp],#0x10 + + ret ; CallARM64RetInMemory + + END diff --git a/angelscript/source/as_callfunc_arm_gcc.S b/angelscript/source/as_callfunc_arm_gcc.S new file mode 100644 index 0000000..994fcb0 --- /dev/null +++ b/angelscript/source/as_callfunc_arm_gcc.S @@ -0,0 +1,730 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +/* + Assembly routines for the ARM call convention + Written by Fredrik Ehnbom in June 2009 + + Adapted to GNUC by darktemplar216 in September 2009 + + Modified by Lasse Oorni for 8-byte stack alignment in May 2012 + + The assembler routines for Linux were written by Carlos Luna in December 2012 +*/ + +#if !defined(AS_MAX_PORTABILITY) + +#if defined(__arm__) || defined(__ARM__) || defined(I3D_ARCH_ARM) + +#if !defined(__linux__) || defined(__ANDROID__) || defined(ANDROID) || defined(__SOFTFP__) || defined(__ARM_PCS) + +/* iOS, Android, Marmalade, and Linux with soft-float ABI goes here */ + +.global armFunc +.global armFuncR0 +.global armFuncR0R1 +.global armFuncObjLast +.global armFuncR0ObjLast + +/* --------------------------------------------------------------------------------------------*/ +armFunc: + stmdb sp!, {r4-r8, lr} + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r8, #0 + + beq nomoreargs + + /* Load the first 4 arguments into r0-r3 */ + cmp r7, #4 + ldrge r0, [r6],#4 + cmp r7, #2*4 + ldrge r1, [r6],#4 + cmp r7, #3*4 + ldrge r2, [r6],#4 + cmp r7, #4*4 + ldrge r3, [r6],#4 + ble nomoreargs + + /* Load the rest of the arguments onto the stack */ + sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */ + add r8, r7, #4 /* ensure 8-byte stack alignment */ + bic r8, r8, #4 + sub sp, sp, r8 + mov r12, sp /* copy size != frame size, so store frame start sp */ +stackargsloop: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargsloop + mov sp, r12 +nomoreargs: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + +/* --------------------------------------------------------------------------------------------*/ +armFuncObjLast: + stmdb sp!, {r4-r8, lr} + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r8, #0 + + mov r0, r3 /* objlast. might get overwritten */ + mov r5, r3 /* objlast to temp reg */ + + beq nomoreargsarmFuncObjLast + + /* Load the first 4 arguments into r0-r3 */ + cmp r7, #4 + ldrge r0, [r6],#4 + cmp r7, #2*4 + ldrge r1, [r6],#4 + movlt r1, r5 + cmp r7, #3*4 + ldrge r2, [r6],#4 + movlt r2, r5 + cmp r7, #4*4 + ldrge r3, [r6],#4 + movlt r3, r5 + blt nomoreargsarmFuncObjLast + + /* Load the rest of the arguments onto the stack */ + sub r7, r7, #4*4 /* skip the 4 registers already loaded into r0-r3 */ + add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */ + bic r8, r8, #4 + str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */ + str r5, [sp,#-8] + sub sp, sp, r8 /* adjust frame */ + cmp r7, #0 /* we may also have come here with no extra params */ + beq nomoreargsarmFuncObjLast + mov r12, sp /* copy size != frame size, so store frame start sp */ +stackargslooparmFuncObjLast: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncObjLast + mov sp, r12 +nomoreargsarmFuncObjLast: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + +/* --------------------------------------------------------------------------------------------*/ +armFuncR0ObjLast: + stmdb sp!, {r4-r8, lr} + ldr r5, [sp,#6*4] /* objlast to temp reg */ + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r8, #0 + + mov r0, r3 /* r0 explicitly set */ + mov r1, r5 /* objlast. might get overwritten */ + + beq nomoreargsarmFuncR0ObjLast + + /* Load the first 3 arguments into r1-r3 */ + cmp r7, #1*4 + ldrge r1, [r6],#4 + cmp r7, #2*4 + ldrge r2, [r6],#4 + movlt r2, r5 + cmp r7, #3*4 + ldrge r3, [r6],#4 + movlt r3, r5 + blt nomoreargsarmFuncR0ObjLast + + /* Load the rest of the arguments onto the stack */ + sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */ + add r8, r7, #8 /* account for the objlast pointer, ensure 8-byte stack alignment */ + bic r8, r8, #4 + str r5, [sp,#-4] /* store the objlast on stack, twice in case we adjusted alignment */ + str r5, [sp,#-8] + sub sp, sp, r8 /* adjust frame */ + cmp r7, #0 /* we may also have come here with no extra params */ + beq nomoreargsarmFuncR0ObjLast + mov r12, sp /* copy size != frame size, so store frame start sp */ +stackargslooparmFuncR0ObjLast: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncR0ObjLast + mov sp, r12 +nomoreargsarmFuncR0ObjLast: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + +/* --------------------------------------------------------------------------------------------*/ +armFuncR0: + stmdb sp!, {r4-r8, lr} + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r8, #0 + + mov r0, r3 /* r0 explicitly set */ + + beq nomoreargsarmFuncR0 + + /* Load the first 3 arguments into r1-r3 */ + cmp r7, #1*4 + ldrge r1, [r6],#4 + cmp r7, #2*4 + ldrge r2, [r6],#4 + cmp r7, #3*4 + ldrge r3, [r6],#4 + ble nomoreargsarmFuncR0 + + /* Load the rest of the arguments onto the stack */ + sub r7, r7, #3*4 /* skip the 3 registers already loaded into r1-r3 */ + add r8, r7, #4 /* ensure 8-byte stack alignment */ + bic r8, r8, #4 + sub sp, sp, r8 + mov r12, sp /* copy size != frame size, so store frame start sp */ +stackargslooparmFuncR0: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncR0 + mov sp, r12 +nomoreargsarmFuncR0: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + +/* --------------------------------------------------------------------------------------------*/ +armFuncR0R1: + stmdb sp!, {r4-r8, lr} + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r8, #0 + + mov r0, r3 /* r0 explicitly set */ + ldr r1, [sp, #6*4] /* r1 explicitly set too */ + + beq nomoreargsarmFuncR0R1 + + /* Load the first 2 arguments into r2-r3 */ + cmp r7, #1*4 + ldrge r2, [r6],#4 + cmp r7, #2*4 + ldrge r3, [r6],#4 + ble nomoreargsarmFuncR0R1 + + /* Load the rest of the arguments onto the stack */ + sub r7, r7, #2*4 /* skip the 2 registers already loaded into r2-r3 */ + add r8, r7, #4 /* ensure 8-byte stack alignment */ + bic r8, r8, #4 + sub sp, sp, r8 + mov r12, sp /* copy size != frame size, so store frame start sp */ +stackargslooparmFuncR0R1: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncR0R1 + mov sp, r12 +nomoreargsarmFuncR0R1: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + +/* --------------------------------------------------------------------------------------------*/ +#elif defined(__linux__) && !defined(__SOFTFP__) && !defined(__ARM_PCS) + +/* The Linux with hard-float ABI code goes here */ + + +/* These codes are suitable for armeabi + vfp / armeabihf */ +/* when using armeabi + vfp, please set C_FLAGS -mfloat-abi=softfp -mfpu=vfp */ +/* using armeabihf, please set C_FLAGS -mfloat-abi=hard -mfpu=vfpv3-d16 */ + +/* if you prefer to run in ARM mode, please add -marm to C_FLAGS */ +/* while using thumb mode, please add -mthumb -Wa,-mimplicit-it=thumb */ + + +/* SP is a multiple of 8 when control first enters a program.*/ +/* This places an obligation on authors of low level OS, RTOS, and runtime library code to align SP at all points */ +/* at which control first enters a body of (AAPCS-conforming) code. (please read "ARM IHI 0046B" document)*/ + + +.section .text + + .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ +#if defined(__thumb__) || defined(__thumb2__) + .thumb + .syntax unified +#else + .arm /* Use ARM instructions instead of Thumb.*/ +#endif + .globl armFunc /* Make the function globally accessible.*/ +armFunc: + push {r4-r8, r10, r11, lr} /* sp must be 8-byte alignment for ABI compliance, so the pushed registers must be even */ + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + + /* Load float and double args into d0-d7 and s0-s15 */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargs + + /* Load the first 4 arguments into r0-r3 */ + cmp r7, #4 + ldrge r0, [r6] + cmp r7, #8 + ldrge r1, [r6, #4] + cmp r7, #12 + ldrge r2, [r6, #8] + cmp r7, #16 + ldrge r3, [r6, #12] + +stackargs: + ldr r5, [r6, #268] /* Load stack size into r5 */ + movs r7, r5 /* Load stack size into r7, checking for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargs + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargsloop: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargsloop + mov sp, r12 + +nomoreargs: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d7 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + +/* --------------------------------------------------------------------------------------------*/ + .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ +#if defined(__thumb__) || defined(__thumb2__) + .thumb + .syntax unified +#else + .arm /* Use ARM instructions instead of Thumb.*/ +#endif + .globl armFuncObjLast /* Make the function globally accessible.*/ +armFuncObjLast: + push {r4-r8, r10, r11, lr} /* We´re storing r11 just to keep the stack aligned to an 8 byte boundary */ + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + + mov r0, r3 /* objlast. might get overwritten */ + mov r5, #0 /* This will hold an offset of #4 only if objlast couldn´t be placed into an "r" register */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsFuncObjLast + + mov r5, r3 /* store objlast in r5 temporarily */ + + /* Load the first 4 arguments into r0-r3 */ + cmp r7, #4 + ldrge r0, [r6] + cmp r7, #8 + ldrge r1, [r6,#4] + movlt r1, r5 + cmp r7, #12 + ldrge r2, [r6,#8] + movlt r2, r5 + cmp r7, #16 + ldrge r3, [r6,#12] + movlt r3, r5 + movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */ + blt stackargsFuncObjLast /* If objlast got placed into a register, go to stackargsFuncObjLast */ + + str r5, [r6, #12] /* Put objlast in r6 + 12 */ + mov r5, #4 /* Set r5 with an offset of #4, so objlast can be loaded into the stack */ + +stackargsFuncObjLast: + ldr r7, [r6, #268] /* Load stack size into r7 */ + add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */ + cmp r7, #0 /* Check for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncObjLast + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncObjLast: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncObjLast + mov sp, r12 + +nomoreargsarmFuncObjLast: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10,r11, pc} + +/* ------------------------------------------------------------------------------------------- */ + .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ +#if defined(__thumb__) || defined(__thumb2__) + .thumb + .syntax unified +#else + .arm /* Use ARM instructions instead of Thumb.*/ +#endif + .globl armFuncR0ObjLast /* Make the function globally accessible.*/ +armFuncR0ObjLast: + push {r4-r8, r10, r11, lr} + + ldr r5, [sp,#32] /* objlast to temp reg */ + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + + mov r0, r3 /* r0 explicitly set */ + mov r1, r5 /* objlast. might get overwritten */ + mov r5, #0 /* This will hold an offset of #4 or #8 if objlast or one arg couldn´t be placed into an "r" register */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsFuncR0ObjLast + + mov r5, r1 /* store objlast in r5 temporarily */ + + /* Load the first 3 arguments into r1-r3 */ + cmp r7, #4 + ldrge r1, [r6] + cmp r7, #8 + ldrge r2, [r6,#4] + movlt r2, r5 + cmp r7, #12 + ldrge r3, [r6,#8] + movlt r3, r5 + movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */ + blt stackargsFuncR0ObjLast /* If objlast got placed into a register, go to stackargsFuncR0ObjLast */ + + cmp r7, #16 /* Else if we have one last arg set the offset accordingly and store the arg in the array */ + ldrge r7, [r6, #12] + strge r7, [r6, #8] + + str r5, [r6, #12] /* Put objlast in r6 + 12 */ + mov r5, #0 + + movge r5, #4 /* Set r5 with an offset of #4 if there´s one last arg that couldn´t be placed in r registers */ + add r5, r5, #4 /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */ + +stackargsFuncR0ObjLast: + ldr r7, [r6, #268] /* Load stack size into r7 */ + add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */ + cmp r7, #0 /* Check for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncR0ObjLast + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncR0ObjLast: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncR0ObjLast + mov sp, r12 + +nomoreargsarmFuncR0ObjLast: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + +/* ------------------------------------------------------------------------------------------- */ + .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ +#if defined(__thumb__) || defined(__thumb2__) + .thumb + .syntax unified +#else + .arm /* Use ARM instructions instead of Thumb.*/ +#endif + .globl armFuncR0 /* Make the function globally accessible.*/ +armFuncR0: + push {r4-r8, r10, r11, lr} + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r11, #0 /* This will hold an offset of #4 only if the last arg that should have been placed into an "r" reg needs to go to the stack */ + mov r0, r3 /* r0 explicitly set */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsarmFuncR0 + + /* Load the first 3 arguments into r1-r3 */ + cmp r7, #4 + ldrge r1, [r6] + cmp r7, #8 + ldrge r2, [r6, #4] + cmp r7, #12 + ldrge r3, [r6, #8] + cmp r7, #16 + movge r11, #4 /* If there is still one arg to be placed, set the offset in r11 to #4 */ + +stackargsarmFuncR0: + ldr r5, [r6, #268] /* Load stack size into r5 */ + add r5, r11 /* Add the offset placed in r11 (could be #0 or #4) */ + movs r7, r5 /* Load stack size into r7, checking for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncR0 + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncR0: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncR0 + mov sp, r12 + +nomoreargsarmFuncR0: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + +/* ------------------------------------------------------------------------------------------- */ + .align 2 /* Align the function code to a 4-byte (2^n) word boundary. */ +#if defined(__thumb__) || defined(__thumb2__) + .thumb + .syntax unified +#else + .arm /* Use ARM instructions instead of Thumb.*/ +#endif + .globl armFuncR0R1 /* Make the function globally accessible.*/ +armFuncR0R1: + push {r4-r8, r10, r11, lr} + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r11, #0 /* This will hold an offset of #4 or #8 only if the last arg (or last 2 args) that should have been placed into "r" regs need to go to the stack */ + + mov r0, r3 /* r0 explicitly set */ + ldr r1, [sp, #32] /* r1 explicitly set too */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r2-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsarmFuncR0R1 + + /* Load the first 2 arguments into r2-r3 */ + cmp r7, #4 + ldrge r2, [r6] + cmp r7, #8 + ldrge r3, [r6, #4] + cmp r7, #12 + movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */ + cmp r7, #16 + movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */ + ldrlt r7, [r6, #8] /* Else copy the third arg to the correct place in the array */ + strlt r7, [r6, #12] + +stackargsarmFuncR0R1: + ldr r5, [r6, #268] /* Load stack size into r5 */ + add r5, r11 /* Add the offset placed in r11 (could be #0 or #4 or #8) */ + movs r7, r5 /* Load stack size into r7, checking for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncR0R1 + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4 or #8) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncR0R1: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncR0R1 + mov sp, r12 + +nomoreargsarmFuncR0R1: +#if defined (__ARM_ARCH_4T__) || defined (__ARM_ARCH_4__) + mov lr, pc /* older ARM didn't support blx */ + mov pc, r4 +#else + blx r4 +#endif + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + +#endif /* hard float abi */ + +#endif /* arm */ + +#if defined(__linux__) && defined(__ELF__) +/* ref: http://hardened.gentoo.org/gnu-stack.xml + ref: https://wiki.gentoo.org/wiki/Hardened/GNU_stack_quickstart */ +.section .note.GNU-stack,"",%progbits +#endif + +#endif /* !AS_MAX_PORTABILITY */ + + diff --git a/angelscript/source/as_callfunc_arm_msvc.asm b/angelscript/source/as_callfunc_arm_msvc.asm new file mode 100644 index 0000000..7ddf997 --- /dev/null +++ b/angelscript/source/as_callfunc_arm_msvc.asm @@ -0,0 +1,249 @@ +; +; AngelCode Scripting Library +; Copyright (c) 2003-2014 Andreas Jonsson +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any +; purpose, including commercial applications, and to alter it and +; redistribute it freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you +; must not claim that you wrote the original software. If you use +; this software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; +; 2. Altered source versions must be plainly marked as such, and +; must not be misrepresented as being the original software. +; +; 3. This notice may not be removed or altered from any source +; distribution. +; +; The original version of this library can be located at: +; http://www.angelcode.com/angelscript/ +; +; Andreas Jonsson +; andreas@angelcode.com +; + + +; Assembly routines for the ARM call convention used for Windows CE +; Written by Fredrik Ehnbom in June 2009 + +; MSVC currently doesn't support inline assembly for the ARM platform +; so this separate file is needed. + +; Compile with Microsoft ARM assembler (armasm) +; http://msdn.microsoft.com/en-us/library/hh873190.aspx + + + AREA |.rdata|, DATA, READONLY + EXPORT armFunc + EXPORT armFuncR0 + EXPORT armFuncR0R1 + EXPORT armFuncObjLast + EXPORT armFuncR0ObjLast + + AREA |.text|, CODE, ARM, ALIGN=3 + + ALIGN 8 +armFunc PROC + stmdb sp!, {r4-r8, lr} + mov r6, r0 ; arg table + movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 ; function address + mov r8, #0 + + beq |nomoreargs| + + ; Load the first 4 arguments into r0-r3 + cmp r7, #4 + ldrge r0, [r6],#4 + cmp r7, #2*4 + ldrge r1, [r6],#4 + cmp r7, #3*4 + ldrge r2, [r6],#4 + cmp r7, #4*4 + ldrge r3, [r6],#4 + ble |nomoreargs| + + ; Load the rest of the arguments onto the stack + sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3 + sub sp, sp, r7 + mov r8, r7 +|stackargsloop| + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne |stackargsloop| +|nomoreargs| + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + ENDP + + ALIGN 8 +armFuncObjLast PROC + stmdb sp!, {r4-r8, lr} + mov r6, r0 ; arg table + movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 ; function address + mov r8, #0 + + mov r0, r3 ; objlast. might get overwritten + str r3, [sp, #-4]! ; objlast again. + + beq |nomoreargs@armFuncObjLast| + + ; Load the first 4 arguments into r0-r3 + cmp r7, #4 + ldrge r0, [r6],#4 + cmp r7, #2*4 + ldrge r1, [r6],#4 + ldrlt r1, [sp] + cmp r7, #3*4 + ldrge r2, [r6],#4 + ldrlt r2, [sp] + cmp r7, #4*4 + ldrge r3, [r6],#4 + ldrlt r3, [sp] + ble |nomoreargs@armFuncObjLast| + + ; Load the rest of the arguments onto the stack + sub r7, r7, #4*4 ; skip the 4 registers already loaded into r0-r3 + sub sp, sp, r7 + mov r8, r7 +|stackargsloop@armFuncObjLast| + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne |stackargsloop@armFuncObjLast| +|nomoreargs@armFuncObjLast| + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + add sp, sp, #4 + ldmia sp!, {r4-r8, pc} + ENDP + + ALIGN 8 +armFuncR0ObjLast PROC + stmdb sp!, {r4-r8, lr} + ldr r7, [sp,#6*4] + str r7, [sp,#-4]! + + mov r6, r0 ; arg table + movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 ; function address + mov r8, #0 + + mov r0, r3 ; r0 explicitly set + ldr r1, [sp] ; objlast. might get overwritten + + beq |nomoreargs@armFuncR0ObjLast| + + ; Load the first 3 arguments into r1-r3 + cmp r7, #1*4 + ldrge r1, [r6],#4 + cmp r7, #2*4 + ldrge r2, [r6],#4 + ldrlt r2, [sp] + cmp r7, #3*4 + ldrge r3, [r6],#4 + ldrlt r3, [sp] + ble |nomoreargs@armFuncR0ObjLast| + + ; Load the rest of the arguments onto the stack + sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3 + sub sp, sp, r7 + mov r8, r7 +|stackargsloop@armFuncR0ObjLast| + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne |stackargsloop@armFuncR0ObjLast| +|nomoreargs@armFuncR0ObjLast| + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + add sp, sp, #4 + ldmia sp!, {r4-r8, pc} + ENDP + + ALIGN 8 +armFuncR0 PROC + stmdb sp!, {r4-r8, lr} + mov r6, r0 ; arg table + movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 ; function address + mov r8, #0 + + mov r0, r3 ; r0 explicitly set + + beq |nomoreargs@armFuncR0| + + ; Load the first 3 arguments into r1-r3 + cmp r7, #1*4 + ldrge r1, [r6],#4 + cmp r7, #2*4 + ldrge r2, [r6],#4 + cmp r7, #3*4 + ldrge r3, [r6],#4 + ble |nomoreargs@armFuncR0| + + ; Load the rest of the arguments onto the stack + sub r7, r7, #3*4 ; skip the 3 registers already loaded into r1-r3 + sub sp, sp, r7 + mov r8, r7 +|stackargsloop@armFuncR0| + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne |stackargsloop@armFuncR0| +|nomoreargs@armFuncR0| + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + ENDP + + ALIGN 8 +armFuncR0R1 PROC + stmdb sp!, {r4-r8, lr} + mov r6, r0 ; arg table + movs r7, r1 ; arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 ; function address + mov r8, #0 + + mov r0, r3 ; r0 explicitly set + ldr r1, [sp, #6*4] ; r1 explicitly set too + + beq |nomoreargs@armFuncR0R1| + + ; Load the first 2 arguments into r2-r3 + cmp r7, #1*4 + ldrge r2, [r6],#4 + cmp r7, #2*4 + ldrge r3, [r6],#4 + ble |nomoreargs@armFuncR0R1| + + ; Load the rest of the arguments onto the stack + sub r7, r7, #2*4 ; skip the 2 registers already loaded into r2-r3 + sub sp, sp, r7 + mov r8, r7 +|stackargsloop@armFuncR0R1| + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne |stackargsloop@armFuncR0R1| +|nomoreargs@armFuncR0R1| + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + ENDP + + END diff --git a/angelscript/source/as_callfunc_arm_vita.S b/angelscript/source/as_callfunc_arm_vita.S new file mode 100644 index 0000000..406db03 --- /dev/null +++ b/angelscript/source/as_callfunc_arm_vita.S @@ -0,0 +1,485 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +/* + Assembly routines for the Playstation Vita SNC call convention. + + This code was adapted from as_callfunc_arm_gcc (ARM, Linux hard float) by Brandon Bare on October 2014. +*/ + +#if !defined(AS_MAX_PORTABILITY) + +#ifdef __psp2__ + +.syntax unified +.cpu cortex-a9 +.fpu neon + +.section .text.armCallFunc +.balign 2 +.thumb +.thumb_func + +.align 2 + +.global armFunc +.global armFuncR0 +.global armFuncR0R1 +.global armFuncObjLast +.global armFuncR0ObjLast + +.type armFunc, %function +.type armFuncR0, %function +.type armFuncR0R1, %function +.type armFuncObjLast, %function +.type armFuncR0ObjLast, %function + +/* --------------------------------------------------------------------------------------------*/ +armFunc: + .fnstart + + push {r4-r8, r10, r11, lr} /* sp must be 8-byte alignment for ABI compliance, so the pushed registers must be even */ + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + + /* Load float and double args into d0-d7 and s0-s15 */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargs + + /* Load the first 4 arguments into r0-r3 */ + cmp r7, #4 + + it ge + ldrge r0, [r6] + cmp r7, #8 + + it ge + ldrge r1, [r6, #4] + cmp r7, #12 + + it ge + ldrge r2, [r6, #8] + cmp r7, #16 + + it ge + ldrge r3, [r6, #12] + +stackargs: + ldr r5, [r6, #268] /* Load stack size into r5 */ + movs r7, r5 /* Load stack size into r7, checking for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargs + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargsloop: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargsloop + mov sp, r12 + +nomoreargs: + blx r4 + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d7 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + + .fnend + +/* --------------------------------------------------------------------------------------------*/ +armFuncObjLast: + .fnstart + + push {r4-r8, r10, r11, lr} /* We´re storing r11 just to keep the stack aligned to an 8 byte boundary */ + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + + mov r0, r3 /* objlast. might get overwritten */ + mov r5, #0 /* This will hold an offset of #4 only if objlast couldn´t be placed into an "r" register */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsFuncObjLast + + mov r5, r3 /* store objlast in r5 temporarily */ + + /* Load the first 4 arguments into r0-r3 */ + cmp r7, #4 + + it ge + ldrge r0, [r6] + cmp r7, #8 + + it ge + ldrge r1, [r6,#4] + + it lt + movlt r1, r5 + cmp r7, #12 + + it ge + ldrge r2, [r6,#8] + + it lt + movlt r2, r5 + cmp r7, #16 + + it ge + ldrge r3, [r6,#12] + + ittt lt + movlt r3, r5 + movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */ + blt stackargsFuncObjLast /* If objlast got placed into a register, go to stackargsFuncObjLast */ + + str r5, [r6, #12] /* Put objlast in r6 + 12 */ + mov r5, #4 /* Set r5 with an offset of #4, so objlast can be loaded into the stack */ + +stackargsFuncObjLast: + ldr r7, [r6, #268] /* Load stack size into r7 */ + add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */ + cmp r7, #0 /* Check for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncObjLast + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncObjLast: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncObjLast + mov sp, r12 + +nomoreargsarmFuncObjLast: + blx r4 + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10,r11, pc} + + .fnend + +/* --------------------------------------------------------------------------------------------*/ +armFuncR0ObjLast: + .fnstart + + push {r4-r8, r10, r11, lr} + + ldr r5, [sp,#32] /* objlast to temp reg */ + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + + mov r0, r3 /* r0 explicitly set */ + mov r1, r5 /* objlast. might get overwritten */ + mov r5, #0 /* This will hold an offset of #4 or #8 if objlast or one arg couldn´t be placed into an "r" register */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsFuncR0ObjLast + + mov r5, r1 /* store objlast in r5 temporarily */ + + /* Load the first 3 arguments into r1-r3 */ + cmp r7, #4 + + it ge + ldrge r1, [r6] + cmp r7, #8 + + it ge + ldrge r2, [r6,#4] + + it lt + movlt r2, r5 + cmp r7, #12 + + it ge + ldrge r3, [r6,#8] + + ittt lt + movlt r3, r5 + movlt r5, #0 /* If objlast got placed into a register, r5 = 0 */ + blt stackargsFuncR0ObjLast /* If objlast got placed into a register, go to stackargsFuncR0ObjLast */ + + cmp r7, #16 /* Else if we have one last arg set the offset accordingly and store the arg in the array */ + + itt ge + ldrge r7, [r6, #12] + strge r7, [r6, #8] + + str r5, [r6, #12] /* Put objlast in r6 + 12 */ + mov r5, #0 + + it ge + movge r5, #4 /* Set r5 with an offset of #4 if there´s one last arg that couldn´t be placed in r registers */ + add r5, r5, #4 /* Set r5 with an offset of + #4, so objlast can be loaded into the stack */ + +stackargsFuncR0ObjLast: + ldr r7, [r6, #268] /* Load stack size into r7 */ + add r7, r7, r5 /* Add the offset placed in r5 (could be #0 or #4) */ + cmp r7, #0 /* Check for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncR0ObjLast + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r5 /* r6 = r6 - r5 (r5 can be #0 or #4) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncR0ObjLast: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncR0ObjLast + mov sp, r12 + +nomoreargsarmFuncR0ObjLast: + blx r4 + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + + .fnend + +/* --------------------------------------------------------------------------------------------*/ +armFuncR0: + .fnstart + + push {r4-r8, r10, r11, lr} + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r11, #0 /* This will hold an offset of #4 only if the last arg that should have been placed into an "r" reg needs to go to the stack */ + mov r0, r3 /* r0 explicitly set */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r0-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsarmFuncR0 + + /* Load the first 3 arguments into r1-r3 */ + cmp r7, #4 + + it ge + ldrge r1, [r6] + cmp r7, #8 + + it ge + ldrge r2, [r6, #4] + cmp r7, #12 + + it ge + ldrge r3, [r6, #8] + cmp r7, #16 + + it ge + movge r11, #4 /* If there is still one arg to be placed, set the offset in r11 to #4 */ + +stackargsarmFuncR0: + ldr r5, [r6, #268] /* Load stack size into r5 */ + add r5, r11 /* Add the offset placed in r11 (could be #0 or #4) */ + movs r7, r5 /* Load stack size into r7, checking for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncR0 + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncR0: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncR0 + mov sp, r12 + +nomoreargsarmFuncR0: + blx r4 + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + + .fnend + +/* --------------------------------------------------------------------------------------------*/ +armFuncR0R1: + .fnstart + + push {r4-r8, r10, r11, lr} + + mov r6, r0 /* arg table */ + movs r7, r1 /* arg size (also set the condition code flags so that we detect if there are no arguments) */ + mov r4, r2 /* function address */ + mov r11, #0 /* This will hold an offset of #4 or #8 only if the last arg (or last 2 args) that should have been placed into "r" regs need to go to the stack */ + + mov r0, r3 /* r0 explicitly set */ + ldr r1, [sp, #32] /* r1 explicitly set too */ + + /* Load float and double args into d0-d7 and s0-s15 (r10 holds pointer to first float value) */ + add r10, r6, #272 /* r10 (r6 + 272) points to the first value for the VFP registers */ + mov r8, #0 + vldmia.64 r10, {d0-d7} /* Load contents starting at r10 into registers d0-d7 */ + + /* If there are no arguments to set into r2-r3 */ + /* go check if there are arguments for the stack */ + beq stackargsarmFuncR0R1 + + /* Load the first 2 arguments into r2-r3 */ + cmp r7, #4 + + it ge + ldrge r2, [r6] + cmp r7, #8 + + it ge + ldrge r3, [r6, #4] + cmp r7, #12 + + it ge + movge r11, #4 /* If there is a third arg to be placed, set the offset in r11 to #4 */ + + cmp r7, #16 + + it ge + movge r11, #8 /* If there is a fourth arg to be placed, set the offset in r11 to #8 */ + + itt lt + ldrlt r7, [r6, #8] /* Else copy the third arg to the correct place in the array */ + strlt r7, [r6, #12] + +stackargsarmFuncR0R1: + ldr r5, [r6, #268] /* Load stack size into r5 */ + add r5, r11 /* Add the offset placed in r11 (could be #0 or #4 or #8) */ + movs r7, r5 /* Load stack size into r7, checking for 0 args */ + + /* If there are no args for the stack, branch */ + beq nomoreargsarmFuncR0R1 + + /* Load the rest of the arguments onto the stack */ + /* Ensure 8-byte stack alignment */ + mov r8, sp + sub sp, sp, r7 + add r6, r6, #16 /* Set r6 to point to the first arg to be placed on the stack */ + + sub r12, sp, #8 + sub r6, r6, r11 /* r6 = r6 - r11 (r11 can be #0 or #4 or #8) */ + bic r12, r12, #7 /* thumb mode couldn't support "bic sp, sp, #7" instruction */ + sub r8, r8, r12 + mov sp, r12 /* copy size != frame size, so store frame start sp, r12(ip) is not callee saved register */ + +stackargslooparmFuncR0R1: + ldr r5, [r6], #4 + subs r7, r7, #4 + str r5, [sp], #4 + bne stackargslooparmFuncR0R1 + mov sp, r12 + +nomoreargsarmFuncR0R1: + blx r4 + add sp, sp, r8 + vstmia.64 r10, {d0-d7} /* Copy contents of registers d0-d10 to the address stored in r10 */ + + pop {r4-r8, r10, r11, pc} + + .fnend + +#endif + +#endif /* !AS_MAX_PORTABILITY */ + diff --git a/angelscript/source/as_callfunc_arm_xcode.S b/angelscript/source/as_callfunc_arm_xcode.S new file mode 100644 index 0000000..235e242 --- /dev/null +++ b/angelscript/source/as_callfunc_arm_xcode.S @@ -0,0 +1,242 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// Assembly routines for the ARM call convention +// Written by Fredrik Ehnbom in June 2009 + +// Adapted to GNUC by darktemplar216 in September 2009 +// Small fixed to work under XCode GCC by Gilad Novik in October 2009 + +#if !defined(AS_MAX_PORTABILITY) + +#if defined(__arm__) || defined(__ARM__) + +.align 2 +.globl _armFunc +.globl _armFuncR0 +.globl _armFuncR0R1 +.globl _armFuncObjLast +.globl _armFuncR0ObjLast + +_armFunc: + stmdb sp!, {r4-r8, lr} + mov r6, r0 // arg table + movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 // function address + mov r8, #0 + + beq nomoreargs + + // Load the first 4 arguments into r0-r3 + cmp r7, #4 + ldrge r0, [r6],#4 + cmp r7, #2*4 + ldrge r1, [r6],#4 + cmp r7, #3*4 + ldrge r2, [r6],#4 + cmp r7, #4*4 + ldrge r3, [r6],#4 + ble nomoreargs + + // Load the rest of the arguments onto the stack + sub r7, r7, #4*4 // skip the 4 registers already loaded into r0-r3 + sub sp, sp, r7 + mov r8, r7 +stackargsloop: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargsloop +nomoreargs: + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + +_armFuncObjLast: + stmdb sp!, {r4-r8, lr} + mov r6, r0 // arg table + movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 // function address + mov r8, #0 + + mov r0, r3 // objlast. might get overwritten + str r3, [sp, #-4]! // objlast again. + + beq nomoreargsarmFuncObjLast + + // Load the first 4 arguments into r0-r3 + cmp r7, #4 + ldrge r0, [r6],#4 + cmp r7, #2*4 + ldrge r1, [r6],#4 + ldrlt r1, [sp] + cmp r7, #3*4 + ldrge r2, [r6],#4 + ldrlt r2, [sp] + cmp r7, #4*4 + ldrge r3, [r6],#4 + ldrlt r3, [sp] + ble nomoreargsarmFuncObjLast + + // Load the rest of the arguments onto the stack + sub r7, r7, #4*4 // skip the 4 registers already loaded into r0-r3 + sub sp, sp, r7 + mov r8, r7 +stackargslooparmFuncObjLast: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncObjLast +nomoreargsarmFuncObjLast: + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + add sp, sp, #4 + ldmia sp!, {r4-r8, pc} + +_armFuncR0ObjLast: + stmdb sp!, {r4-r8, lr} + ldr r7, [sp,#6*4] + str r7, [sp,#-4]! + + mov r6, r0 // arg table + movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 // function address + mov r8, #0 + + mov r0, r3 // r0 explicitly set + ldr r1, [sp] // objlast. might get overwritten + + beq nomoreargsarmFuncR0ObjLast + + // Load the first 3 arguments into r1-r3 + cmp r7, #1*4 + ldrge r1, [r6],#4 + cmp r7, #2*4 + ldrge r2, [r6],#4 + ldrlt r2, [sp] + cmp r7, #3*4 + ldrge r3, [r6],#4 + ldrlt r3, [sp] + ble nomoreargsarmFuncR0ObjLast + + // Load the rest of the arguments onto the stack + sub r7, r7, #3*4 // skip the 3 registers already loaded into r1-r3 + sub sp, sp, r7 + mov r8, r7 +stackargslooparmFuncR0ObjLast: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncR0ObjLast +nomoreargsarmFuncR0ObjLast: + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + add sp, sp, #4 + ldmia sp!, {r4-r8, pc} + + +_armFuncR0: + stmdb sp!, {r4-r8, lr} + mov r6, r0 // arg table + movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 // function address + mov r8, #0 + + mov r0, r3 // r0 explicitly set + + beq nomoreargsarmFuncR0 + + // Load the first 3 arguments into r1-r3 + cmp r7, #1*4 + ldrge r1, [r6],#4 + cmp r7, #2*4 + ldrge r2, [r6],#4 + cmp r7, #3*4 + ldrge r3, [r6],#4 + ble nomoreargsarmFuncR0 + + // Load the rest of the arguments onto the stack + sub r7, r7, #3*4 // skip the 3 registers already loaded into r1-r3 + sub sp, sp, r7 + mov r8, r7 +stackargslooparmFuncR0: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncR0 +nomoreargsarmFuncR0: + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + + +_armFuncR0R1: + stmdb sp!, {r4-r8, lr} + mov r6, r0 // arg table + movs r7, r1 // arg size (also set the condition code flags so that we detect if there are no arguments) + mov r4, r2 // function address + mov r8, #0 + + mov r0, r3 // r0 explicitly set + ldr r1, [sp, #6*4] // r1 explicitly set too + + beq nomoreargsarmFuncR0R1 + + // Load the first 2 arguments into r2-r3 + cmp r7, #1*4 + ldrge r2, [r6],#4 + cmp r7, #2*4 + ldrge r3, [r6],#4 + ble nomoreargsarmFuncR0R1 + + // Load the rest of the arguments onto the stack + sub r7, r7, #2*4 // skip the 2 registers already loaded into r2-r3 + sub sp, sp, r7 + mov r8, r7 +stackargslooparmFuncR0R1: + ldr r5, [r6], #4 + str r5, [sp], #4 + subs r7, r7, #4 + bne stackargslooparmFuncR0R1 +nomoreargsarmFuncR0R1: + sub sp, sp, r8 + blx r4 + add sp, sp, r8 + ldmia sp!, {r4-r8, pc} + +#endif + +#endif /* !AS_MAX_PORTABILITY */ + diff --git a/angelscript/source/as_callfunc_mips.cpp b/angelscript/source/as_callfunc_mips.cpp new file mode 100644 index 0000000..be7d189 --- /dev/null +++ b/angelscript/source/as_callfunc_mips.cpp @@ -0,0 +1,735 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_mips.cpp +// +// These functions handle the actual calling of system functions +// +// This version is MIPS specific and was originally written +// by Manu Evans in April, 2006 for Playstation Portable (PSP) +// +// Support for Linux with MIPS was added by Andreas Jonsson in April, 2015 +// + + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_MIPS + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +#include +#include +#if !defined(AS_ANDROID) +#include +#endif + +BEGIN_AS_NAMESPACE + +#if defined(__linux__) && defined(_ABIO32) + +// The MIPS ABI used by Linux is implemented here +// (Tested on CI20 MIPS Creator with Debian Linux) +// +// ref: SYSTEM V +// APPLICATION BINARY INTERFACE +// MIPS RISC Processor +// http://math-atlas.sourceforge.net/devel/assembly/mipsabi32.pdf +// +// ref: MIPS Instruction Reference +// http://www.mrc.uidaho.edu/mrc/people/jff/digital/MIPSir.html + +union SFloatRegs +{ + union { double d0; struct { float f0; asDWORD dummy0; };}; + union { double d1; struct { float f1; asDWORD dummy1; };}; +} ; + +extern "C" asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs); +asDWORD GetReturnedFloat(); +asQWORD GetReturnedDouble(); + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + + asQWORD retQW = 0; + + void *func = (void*)sysFunc->func; + void **vftable; + + asDWORD argBuffer[128]; // Ought to be big enough + asASSERT( sysFunc->paramSize < 128 ); + + asDWORD argOffset = 0; + + SFloatRegs floatRegs; + asDWORD floatOffset = 0; + + // If the application function returns the value in memory then + // the first argument must be the pointer to that memory + if( sysFunc->hostReturnInMemory ) + { + asASSERT( retPointer ); + argBuffer[argOffset++] = (asPWORD)retPointer; + } + + if( callConv == ICC_CDECL_OBJFIRST || callConv == ICC_CDECL_OBJFIRST_RETURNINMEM || + callConv == ICC_THISCALL || callConv == ICC_THISCALL_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || + callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the first argument + argBuffer[argOffset++] = (asPWORD)obj; + } + + if( callConv == ICC_THISCALL_OBJFIRST || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) + { + // Add the second object pointer + argBuffer[argOffset++] = (asPWORD)secondObject; + } + + int spos = 0; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + asCDataType ¶mType = descr->parameterTypes[n]; + if( paramType.IsObject() && !paramType.IsObjectHandle() && !paramType.IsReference() ) + { + if( paramType.GetTypeInfo()->flags & COMPLEX_MASK ) + { + // The object is passed by reference + argBuffer[argOffset++] = args[spos++]; + } + else + { + // Ensure 8byte alignment for classes that need it + if( (paramType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALIGN8) && (argOffset & 1) ) + argOffset++; + + // Copy the object's memory to the buffer + memcpy(&argBuffer[argOffset], *(void**)(args+spos), paramType.GetSizeInMemoryBytes()); + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos++; + argOffset += paramType.GetSizeInMemoryDWords(); + } + } + else if( paramType.GetTokenType() == ttQuestion ) + { + // Copy both pointer and type id + argBuffer[argOffset++] = args[spos++]; + argBuffer[argOffset++] = args[spos++]; + } + else + { + // The first 2 floats or doubles are loaded into the float registers. + // Actually this is only done if they are the first arguments to the function, + // but it doesn't cause any harm to load them into the registers even if they + // won't be used so we don't need to check if they really are the first args. + if( floatOffset == 0 ) + { + if( paramType.GetTokenType() == ttFloat ) + floatRegs.f0 = *reinterpret_cast(&args[spos]); + else if( paramType.GetTokenType() == ttDouble ) + floatRegs.d0 = *reinterpret_cast(&args[spos]); + floatOffset++; + } + else if( floatOffset == 1 ) + { + if( paramType.GetTokenType() == ttFloat ) + floatRegs.f1 = *reinterpret_cast(&args[spos]); + else if( paramType.GetTokenType() == ttDouble ) + floatRegs.d1 = *reinterpret_cast(&args[spos]); + floatOffset++; + } + + // Copy the value directly + if( paramType.GetSizeOnStackDWords() > 1 ) + { + // Make sure the argument is 8byte aligned + if( argOffset & 1 ) + argOffset++; + *reinterpret_cast(&argBuffer[argOffset]) = *reinterpret_cast(&args[spos]); + argOffset += 2; + spos += 2; + } + else + argBuffer[argOffset++] = args[spos++]; + } + } + + if( callConv == ICC_CDECL_OBJLAST || callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last argument + argBuffer[argOffset++] = (asPWORD)obj; + } + + if( callConv == ICC_THISCALL_OBJLAST || callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Add the second object pointer + argBuffer[argOffset++] = (asPWORD)secondObject; + } + + switch( callConv ) + { + case ICC_CDECL: + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL: + case ICC_STDCALL_RETURNINMEM: + case ICC_CDECL_OBJLAST: + case ICC_CDECL_OBJLAST_RETURNINMEM: + case ICC_CDECL_OBJFIRST: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL: + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST: + case ICC_THISCALL_OBJLAST_RETURNINMEM: + retQW = mipsFunc(argOffset*4, argBuffer, func, floatRegs); + break; + + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(void***)obj; + retQW = mipsFunc(argOffset*4, argBuffer, vftable[asPWORD(func)>>2], floatRegs); + break; + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + + return retQW; +} + +asDWORD GetReturnedFloat() +{ + asDWORD f; + + asm("swc1 $f0, %0\n" : "=m"(f)); + + return f; +} + +asQWORD GetReturnedDouble() +{ + asQWORD d = 0; + + asm("sdc1 $f0, %0\n" : "=m"(d)); + + return d; +} + +// asQWORD mipsFunc(asUINT argSize, asDWORD *argBuffer, void *func, SFloatRegs &floatRegs); +// $2,$3 $4 $5 $6 $7 +asm( +" .text\n" +//" .align 2\n" +" .cfi_startproc\n" +" .global mipsFunc\n" +" .ent mipsFunc\n" +"mipsFunc:\n" +//" .frame $fp,64,$31 # vars= 0, regs= 0/0, args= 0, gp= 0\n" +//" .mask 0x00000000,0\n" +//" .fmask 0x00000000,0\n" +" .set noreorder\n" +" .set nomacro\n" + +// align the stack frame to 8 bytes +" addiu $12, $4, 7\n" // t4 ($12) = argSize ($4) + 7 +" li $13, -8\n" // t5 ($13) = 0xfffffffffffffff8 +" and $12, $12, $13\n" // t4 ($12) &= t5 ($13). t4 holds the size of the argument block +// It is required that the caller reserves space for at least 16 bytes even if there are less than 4 arguments +// and add 8 bytes for the return pointer and s0 ($16) backup +" addiu $13, $12, 24\n" // t5 = t4 + 24. t5 ($13) holds the total size of the stack frame (including return pointer) +// save the s0 register (so we can use it to remember where our return pointer is lives) +" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is) +" .cfi_offset 16, -4\n" +// store the return pointer +" sw $31, -8($sp)\n" +" .cfi_offset 31, -8\n" +// keep original stack pointer +" move $16, $sp\n" +" .cfi_def_cfa_register 16\n" +// push the stack +" subu $sp, $sp, $13\n" + +// store the argument in temporary registers +" addiu $25, $6, 0\n" // t9 ($25) holds the function pointer (must be t9 for position independent code) +" addiu $3, $4, 0\n" // v1 ($3) holds the size of the argument buffer +" move $15, $5\n" // t7 ($15) holds the pointer to the argBuffer +" move $14, $7\n" // t6 ($14) holds the values for the float registers + +// load integer registers +" lw $4, 0($15)\n" // a0 ($4) +" lw $5, 4($15)\n" // a1 ($5) +" lw $6, 8($15)\n" // a2 ($6) +" lw $7, 12($15)\n" // a3 ($7) + +// load float registers +" ldc1 $f12, 8($14)\n" +" ldc1 $f14, 0($14)\n" + +// skip stack parameters if there are 4 or less as they are moved into the registers +" addi $14, $3, -16\n" // The first 4 args were already loaded into registers +" blez $14, andCall\n" +" nop\n" + +// push stack parameters +"pushArgs:\n" +" addi $3, -4\n" +// load from $15 + stack bytes ($3) +" addu $14, $15, $3\n" +" lw $14, 0($14)\n" +// store to $sp + stack bytes ($3) +" addu $13, $sp, $3\n" +" sw $14, 0($13)\n" +// if there are more, loop... +" bne $3, $0, pushArgs\n" +" nop\n" + +// and call the function +"andCall:\n" +" jalr $25\n" +" nop\n" + +// restore original stack pointer +" move $sp, $16\n" +// restore the return pointer +" lw $31, -8($sp)\n" +// restore the original value of $16 +" lw $16, -4($sp)\n" +// and return from the function +" jr $31\n" +" nop\n" + +" .set macro\n" +" .set reorder\n" +" .end mipsFunc\n" +" .cfi_endproc\n" +" .size mipsFunc, .-mipsFunc\n" +); + +#else // !(defined(__linux__) && defined(_ABIO32)) + +// The MIPS ABI used by PSP and PS2 is implemented here + +#define AS_MIPS_MAX_ARGS 32 +#define AS_NUM_REG_FLOATS 8 +#define AS_NUM_REG_INTS 8 + +// The array used to send values to the correct places. +// first 0-8 regular values to load into the a0-a3, t0-t3 registers +// then 0-8 float values to load into the f12-f19 registers +// then (AS_MIPS_MAX_ARGS - 16) values to load onto the stack +// the +1 is for when CallThis (object methods) is used +// extra +1 when returning in memory +extern "C" { +// TODO: This array shouldn't be global. It should be a local array in CallSystemFunctionNative +asDWORD mipsArgs[AS_MIPS_MAX_ARGS + 1 + 1]; +} + +// Loads all data into the correct places and calls the function. +// intArgSize is the size in bytes for how much data to put in int registers +// floatArgSize is the size in bytes for how much data to put in float registers +// stackArgSize is the size in bytes for how much data to put on the callstack +extern "C" asQWORD mipsFunc(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func); + +// puts the arguments in the correct place in the mipsArgs-array. See comments above. +// This could be done better. +inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags) +{ + int i; + + int argBit = 1; + for (i = 0; i < argNum; i++) + { + if (hostFlags & argBit) + { + if (numRegFloatArgs < AS_NUM_REG_FLOATS) + { + // put in float register + mipsArgs[AS_NUM_REG_INTS + numRegFloatArgs] = args[i]; + numRegFloatArgs++; + } + else + { + // put in stack + mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + numRestArgs] = args[i]; + numRestArgs++; + } + } + else + { + if (numRegIntArgs < AS_NUM_REG_INTS) + { + // put in int register + mipsArgs[numRegIntArgs] = args[i]; + numRegIntArgs++; + } + else + { + // put in stack + mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + numRestArgs] = args[i]; + numRestArgs++; + } + } + argBit <<= 1; + } +} + +asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags) +{ + int argNum = argSize >> 2; + + int intArgs = 0; + int floatArgs = 0; + int restArgs = 0; + + // put the arguments in the correct places in the mipsArgs array + if(argNum > 0) + splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); + + return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func); +} + +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the first parameter is the object +asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) +{ + int argNum = argSize >> 2; + + int intArgs = 1; + int floatArgs = 0; + int restArgs = 0; + + mipsArgs[0] = (asDWORD) obj; + + // put the arguments in the correct places in the mipsArgs array + if (argNum > 0) + splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); + + return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func); +} + +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the last parameter is the object +asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) +{ + int argNum = argSize >> 2; + + int intArgs = 0; + int floatArgs = 0; + int restArgs = 0; + + // put the arguments in the correct places in the mipsArgs array + if(argNum > 0) + splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); + + if(intArgs < AS_NUM_REG_INTS) + { + mipsArgs[intArgs] = (asDWORD) obj; + intArgs++; + } + else + { + mipsArgs[AS_NUM_REG_INTS + AS_NUM_REG_FLOATS + restArgs] = (asDWORD) obj; + restArgs++; + } + + return mipsFunc(intArgs << 2, floatArgs << 2, restArgs << 2, func); +} + +asDWORD GetReturnedFloat() +{ + asDWORD f; + + asm("swc1 $f0, %0\n" : "=m"(f)); + + return f; +} + +asQWORD GetReturnedDouble() +{ + asQWORD d = 0; + + asm("sdc1 $f0, %0\n" : "=m"(d)); + + return d; +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + + // TODO: Mips does not yet support THISCALL_OBJFIRST/LAST + + asQWORD retQW = 0; + + void *func = (void*)sysFunc->func; + int paramSize = sysFunc->paramSize; + asDWORD *vftable; + + if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() ) + { + mipsArgs[AS_MIPS_MAX_ARGS+1] = (asDWORD) retPointer; + } + + asASSERT(descr->parameterTypes.GetLength() <= AS_MIPS_MAX_ARGS); + + // mark all float arguments + int argBit = 1; + int hostFlags = 0; + int intArgs = 0; + for( size_t a = 0; a < descr->parameterTypes.GetLength(); a++ ) + { + if (descr->parameterTypes[a].IsFloatType()) + hostFlags |= argBit; + else + intArgs++; + argBit <<= 1; + } + + asDWORD paramBuffer[64]; + if( sysFunc->takesObjByVal ) + { + paramSize = 0; + int spos = 0; + int dpos = 1; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else +#endif + { + // Copy the object's memory to the buffer + memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos++; + dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); + } + } + else + { + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + paramBuffer[dpos++] = args[spos++]; + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + } + // Keep a free location at the beginning + args = ¶mBuffer[1]; + } + + switch( callConv ) + { + case ICC_CDECL: + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL: + case ICC_STDCALL_RETURNINMEM: + retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags); + break; + case ICC_THISCALL: + case ICC_THISCALL_RETURNINMEM: + retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); + break; + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(asDWORD**)obj; + retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags); + break; + case ICC_CDECL_OBJLAST: + case ICC_CDECL_OBJLAST_RETURNINMEM: + retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags); + break; + case ICC_CDECL_OBJFIRST: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); + break; + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + + return retQW; +} + + +asm( +" .text\n" +//" .align 2\n" +" .global mipsFunc\n" +" .ent mipsFunc\n" +"mipsFunc:\n" +//" .frame $fp,64,$31 # vars= 0, regs= 0/0, args= 0, gp= 0\n" +//" .mask 0x00000000,0\n" +//" .fmask 0x00000000,0\n" +" .set noreorder\n" +" .set nomacro\n" +// align the stack frame to 8 bytes +" addiu $12, $6, 7\n" +" li $13, -8\n" // 0xfffffffffffffff8 +" and $12, $12, $13\n" // t4 holds the size of the argument block +// and add 8 bytes for the return pointer and s0 backup +" addiu $13, $12, 8\n" // t5 holds the total size of the stack frame (including return pointer) +// save the s0 register (so we can use it to remember where our return pointer is lives) +" sw $16, -4($sp)\n" // store the s0 register (so we can use it to remember how big our stack frame is) +// push the stack +" subu $sp, $sp, $13\n" +// find the return address, place in s0 +" addu $16, $sp, $12\n" +// store the return pointer +" sw $31, 0($16)\n" + +// backup our function params +" addiu $2, $7, 0\n" +" addiu $3, $6, 0\n" + +// get global mipsArgs[] array pointer +//" lui $15, %hi(mipsArgs)\n" +//" addiu $15, $15, %lo(mipsArgs)\n" +// we'll use the macro instead because SN Systems doesnt like %hi/%lo +".set macro\n" +" la $15, mipsArgs\n" +".set nomacro\n" +// load register params +" lw $4, 0($15)\n" +" lw $5, 4($15)\n" +" lw $6, 8($15)\n" +" lw $7, 12($15)\n" +" lw $8, 16($15)\n" +" lw $9, 20($15)\n" +" lw $10, 24($15)\n" +" lw $11, 28($15)\n" + +// load float params +" lwc1 $f12, 32($15)\n" +" lwc1 $f13, 36($15)\n" +" lwc1 $f14, 40($15)\n" +" lwc1 $f15, 44($15)\n" +" lwc1 $f16, 48($15)\n" +" lwc1 $f17, 52($15)\n" +" lwc1 $f18, 56($15)\n" +" lwc1 $f19, 60($15)\n" + +// skip stack paramaters if there are none +" beq $3, $0, andCall\n" + +// push stack paramaters +" addiu $15, $15, 64\n" +"pushArgs:\n" +" addiu $3, -4\n" +// load from $15 + stack bytes ($3) +" addu $14, $15, $3\n" +" lw $14, 0($14)\n" +// store to $sp + stack bytes ($3) +" addu $13, $sp, $3\n" +" sw $14, 0($13)\n" +// if there are more, loop... +" bne $3, $0, pushArgs\n" +" nop\n" + +// and call the function +"andCall:\n" +" jal $2\n" +" nop\n" + +// restore the return pointer +" lw $31, 0($16)\n" +// pop the stack pointer (remembering the return pointer was 8 bytes below the top) +" addiu $sp, $16, 8\n" +// and return from the function +" jr $31\n" +// restore the s0 register (in the branch delay slot) +" lw $16, -4($sp)\n" +" .set macro\n" +" .set reorder\n" +" .end mipsFunc\n" +" .size mipsFunc, .-mipsFunc\n" +); + +#endif // PSP and PS2 MIPS ABI + +END_AS_NAMESPACE + +#endif // AS_MIPS +#endif // AS_MAX_PORTABILITY + + + + diff --git a/angelscript/source/as_callfunc_ppc.cpp b/angelscript/source/as_callfunc_ppc.cpp new file mode 100644 index 0000000..053221f --- /dev/null +++ b/angelscript/source/as_callfunc_ppc.cpp @@ -0,0 +1,674 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_ppc.cpp +// +// These functions handle the actual calling of system functions +// +// This version is PPC specific +// + +#include + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_PPC + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +#include + +BEGIN_AS_NAMESPACE + +// This part was originally written by Pecan Heber, June 2006, for +// use on MacOS X with 32bit PPC processor. He based the code on the +// code in as_callfunc_sh4.cpp + +#define AS_PPC_MAX_ARGS 32 + +// The array used to send values to the correct places. +// Contains a byte of argTypes to indicate the register tYpe to load +// or zero if end of arguments +// The +1 is for when CallThis (object methods) is used +// Extra +1 when returning in memory +// Extra +1 in ppcArgsType to ensure zero end-of-args marker + +// TODO: multithread: We need to remove these global variables for thread-safety + +enum argTypes { ppcENDARG, ppcINTARG, ppcFLOATARG, ppcDOUBLEARG }; +static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1]; + +// Using extern "C" because we use this symbol name in the assembly code +extern "C" +{ + static asBYTE ppcArgsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1]; +} + +// NOTE: these values are for PowerPC 32 bit. +#define PPC_LINKAGE_SIZE (24) // how big the PPC linkage area is in a stack frame +#define PPC_NUM_REGSTORE (9) // how many registers of the PPC we need to store/restore for ppcFunc() +#define PPC_REGSTORE_SIZE (4*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore +#define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame +#define PPC_STACK_SIZE(numParams) (-( ( ((((numParams)<8)?8:(numParams))<<2) + EXTRA_STACK_SIZE + 15 ) & ~15 )) // calculates the total stack size needed for ppcFunc64, must pad to 16bytes + +// Loads all data into the correct places and calls the function. +// ppcArgsType is an array containing a byte type (enum argTypes) for each argument. +// stackArgSize is the size in bytes for how much data to put on the stack frame +extern "C" asQWORD ppcFunc(const asDWORD* argsPtr, int StackArgSize, asDWORD func); + +asm(" .text\n" + " .align 2\n" // align the code to 1 << 2 = 4 bytes + " .globl _ppcFunc\n" + "_ppcFunc:\n" + + // We're receiving the following parameters + + // r3 : argsPtr + // r4 : StackArgSize + // r5 : func + + // The following registers are used through out the function + + // r31 : the address of the label address, as reference for all other labels + // r30 : temporary variable + // r29 : arg list pointer + // r28 : number of FPR registers used by the parameters + // r27 : the function pointer that will be called + // r26 : the location of the parameters for the call + // r25 : arg type list pointer + // r24 : temporary variable + // r23 : number of GPR registers used by the parameters + // r1 : this is stack pointer + // r0 : temporary variable + // f0 : temporary variable + + // We need to store some of the registers for restoral before returning to caller + + // lr - always stored in 8(r1) - this is the return address + // cr - not required to be stored, but if it is, its place is in 4(r1) - this is the condition register + // r1 - always stored in 0(r1) - this is the stack pointer + // r11 + // r13 to r31 + // f14 to f31 + + // Store register values and setup our stack frame + " mflr r0 \n" // move the return address into r0 + " stw r0, 8(r1) \n" // Store the return address on the stack + " stmw r23, -36(r1) \n" // Store registers r23 to r31 on the stack + " stwux r1, r1, r4 \n" // Increase the stack with the needed space and store the original value in the destination + + // Obtain an address that we'll use as our position of reference when obtaining addresses of other labels + " bl address \n" + "address: \n" + " mflr r31 \n" + + // initial registers for the function + " mr r29, r3 \n" // (r29) args list + " mr r27, r5 \n" // load the function pointer to call. func actually holds the pointer to our function + " addi r26, r1, 24 \n" // setup the pointer to the parameter area to the function we're going to call + " sub r0, r0, r0 \n" // zero out r0 + " mr r23, r0 \n" // zero out r23, which holds the number of used GPR registers + " mr r28, r0 \n" // zero our r22, which holds the number of used float registers + + // load the global ppcArgsType which holds the types of arguments for each argument + " addis r25, r31, ha16(_ppcArgsType - address) \n" // load the upper 16 bits of the address to r25 + " la r25, lo16(_ppcArgsType - address)(r25) \n" // load the lower 16 bits of the address to r25 + " subi r25, r25, 1 \n" // since we increment r25 on its use, we'll pre-decrement it + + // loop through the arguments + "ppcNextArg: \n" + " addi r25, r25, 1 \n" // increment r25, our arg type pointer + // switch based on the current argument type (0:end, 1:int, 2:float 3:double) + " lbz r24, 0(r25) \n" // load the current argument type (it's a byte) + " mulli r24, r24, 4 \n" // our jump table has 4 bytes per case (1 instruction) + " addis r30, r31, ha16(ppcTypeSwitch - address) \n" // load the address of the jump table for the switch + " la r30, lo16(ppcTypeSwitch - address)(r30) \n" + + " add r0, r30, r24 \n" // offset by our argument type + " mtctr r0 \n" // load the jump address into CTR + " bctr \n" // jump into the jump table/switch + " nop \n" + + // the jump table/switch based on the current argument type + "ppcTypeSwitch: \n" + " b ppcArgsEnd \n" + " b ppcArgIsInteger \n" + " b ppcArgIsFloat \n" + " b ppcArgIsDouble \n" + + // when we get here we have finished processing all the arguments + // everything is ready to go to call the function + "ppcArgsEnd: \n" + " mtctr r27 \n" // the function pointer is stored in r27, load that into CTR + " bctrl \n" // call the function. We have to do it this way so that the LR gets the proper + " nop \n" // return value (the next instruction below). So we have to branch from CTR instead of LR. + + // Restore registers and caller's stack frame, then return to caller + " lwz r1, 0(r1) \n" // restore the caller's stack pointer + " lwz r0, 8(r1) \n" // load in the caller's LR + " mtlr r0 \n" // restore the caller's LR + " lmw r23, -36(r1) \n" // restore registers r23 to r31 from the stack + " blr \n" // return back to the caller + " nop \n" + + // Integer argument (GPR register) + "ppcArgIsInteger: \n" + " addis r30, r31, ha16(ppcLoadIntReg - address) \n" // load the address to the jump table for integer registers + " la r30, lo16(ppcLoadIntReg - address)(r30) \n" + " mulli r0, r23, 8 \n" // each item in the jump table is 2 instructions (8 bytes) + " add r0, r0, r30 \n" // calculate ppcLoadIntReg[numUsedGPRRegs] + " lwz r30, 0(r29) \n" // load the next argument from the argument list into r30 + " cmpwi r23, 8 \n" // we can only load GPR3 through GPR10 (8 registers) + " bgt ppcLoadIntRegUpd \n" // if we're beyond 8 GPR registers, we're in the stack, go there + " mtctr r0 \n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers) + " bctr \n" // load the argument into a GPR register + " nop \n" + // jump table for GPR registers, for the first 8 GPR arguments + "ppcLoadIntReg: \n" + " mr r3, r30 \n" // arg0 (to r3) + " b ppcLoadIntRegUpd \n" + " mr r4, r30 \n" // arg1 (to r4) + " b ppcLoadIntRegUpd \n" + " mr r5, r30 \n" // arg2 (to r5) + " b ppcLoadIntRegUpd \n" + " mr r6, r30 \n" // arg3 (to r6) + " b ppcLoadIntRegUpd \n" + " mr r7, r30 \n" // arg4 (to r7) + " b ppcLoadIntRegUpd \n" + " mr r8, r30 \n" // arg5 (to r8) + " b ppcLoadIntRegUpd \n" + " mr r9, r30 \n" // arg6 (to r9) + " b ppcLoadIntRegUpd \n" + " mr r10, r30 \n" // arg7 (to r10) + " b ppcLoadIntRegUpd \n" + // all GPR arguments still go on the stack + "ppcLoadIntRegUpd: \n" + " stw r30, 0(r26) \n" // store the argument into the next slot on the stack's argument list + " addi r23, r23, 1 \n" // count a used GPR register + " addi r29, r29, 4 \n" // move to the next argument on the list + " addi r26, r26, 4 \n" // adjust our argument stack pointer for the next + " b ppcNextArg \n" // next argument + + // single Float argument + "ppcArgIsFloat:\n" + " addis r30, r31, ha16(ppcLoadFloatReg - address) \n" // get the base address of the float register jump table + " la r30, lo16(ppcLoadFloatReg - address)(r30) \n" + " mulli r0, r28, 8 \n" // each jump table entry is 8 bytes + " add r0, r0, r30 \n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg] + " lfs f0, 0(r29) \n" // load the next argument as a float into f0 + " cmpwi r28, 13 \n" // can't load more than 13 float/double registers + " bgt ppcLoadFloatRegUpd \n" // if we're beyond 13 registers, just fall to inserting into the stack + " mtctr r0 \n" // jump into the float jump table + " bctr \n" + " nop \n" + // jump table for float registers, for the first 13 float arguments + "ppcLoadFloatReg: \n" + " fmr f1, f0 \n" // arg0 (f1) + " b ppcLoadFloatRegUpd \n" + " fmr f2, f0 \n" // arg1 (f2) + " b ppcLoadFloatRegUpd \n" + " fmr f3, f0 \n" // arg2 (f3) + " b ppcLoadFloatRegUpd \n" + " fmr f4, f0 \n" // arg3 (f4) + " b ppcLoadFloatRegUpd \n" + " fmr f5, f0 \n" // arg4 (f5) + " b ppcLoadFloatRegUpd \n" + " fmr f6, f0 \n" // arg5 (f6) + " b ppcLoadFloatRegUpd \n" + " fmr f7, f0 \n" // arg6 (f7) + " b ppcLoadFloatRegUpd \n" + " fmr f8, f0 \n" // arg7 (f8) + " b ppcLoadFloatRegUpd \n" + " fmr f9, f0 \n" // arg8 (f9) + " b ppcLoadFloatRegUpd \n" + " fmr f10, f0 \n" // arg9 (f10) + " b ppcLoadFloatRegUpd \n" + " fmr f11, f0 \n" // arg10 (f11) + " b ppcLoadFloatRegUpd \n" + " fmr f12, f0 \n" // arg11 (f12) + " b ppcLoadFloatRegUpd \n" + " fmr f13, f0 \n" // arg12 (f13) + " b ppcLoadFloatRegUpd \n" + " nop \n" + // all float arguments still go on the stack + "ppcLoadFloatRegUpd: \n" + " stfs f0, 0(r26) \n" // store, as a single float, f0 (current argument) on to the stack argument list + " addi r23, r23, 1 \n" // a float register eats up a GPR register + " addi r28, r28, 1 \n" // ...and, of course, a float register + " addi r29, r29, 4 \n" // move to the next argument in the list + " addi r26, r26, 4 \n" // move to the next stack slot + " b ppcNextArg \n" // on to the next argument + " nop \n" + + // double Float argument + "ppcArgIsDouble: \n" + " addis r30, r31, ha16(ppcLoadDoubleReg - address) \n" // load the base address of the jump table for double registers + " la r30, lo16(ppcLoadDoubleReg - address)(r30) \n" + " mulli r0, r28, 8 \n" // each slot of the jump table is 8 bytes + " add r0, r0, r30 \n" // calculate ppcLoadDoubleReg[numUsedFloatReg] + " lfd f0, 0(r29) \n" // load the next argument, as a double float, into f0 + " cmpwi r28, 13 \n" // the first 13 floats must go into float registers also + " bgt ppcLoadDoubleRegUpd \n" // if we're beyond 13, then just put on to the stack + " mtctr r0 \n" // we're under 13, first load our register + " bctr \n" // jump into the jump table + " nop \n" + // jump table for float registers, for the first 13 float arguments + "ppcLoadDoubleReg: \n" + " fmr f1, f0 \n" // arg0 (f1) + " b ppcLoadDoubleRegUpd \n" + " fmr f2, f0 \n" // arg1 (f2) + " b ppcLoadDoubleRegUpd \n" + " fmr f3, f0 \n" // arg2 (f3) + " b ppcLoadDoubleRegUpd \n" + " fmr f4, f0 \n" // arg3 (f4) + " b ppcLoadDoubleRegUpd \n" + " fmr f5, f0 \n" // arg4 (f5) + " b ppcLoadDoubleRegUpd \n" + " fmr f6, f0 \n" // arg5 (f6) + " b ppcLoadDoubleRegUpd \n" + " fmr f7, f0 \n" // arg6 (f7) + " b ppcLoadDoubleRegUpd \n" + " fmr f8, f0 \n" // arg7 (f8) + " b ppcLoadDoubleRegUpd \n" + " fmr f9, f0 \n" // arg8 (f9) + " b ppcLoadDoubleRegUpd \n" + " fmr f10, f0 \n" // arg9 (f10) + " b ppcLoadDoubleRegUpd \n" + " fmr f11, f0 \n" // arg10 (f11) + " b ppcLoadDoubleRegUpd \n" + " fmr f12, f0 \n" // arg11 (f12) + " b ppcLoadDoubleRegUpd \n" + " fmr f13, f0 \n" // arg12 (f13) + " b ppcLoadDoubleRegUpd \n" + " nop \n" + // all float arguments still go on the stack + "ppcLoadDoubleRegUpd: \n" + " stfd f0, 0(r26) \n" // store f0, as a double, into the argument list on the stack + " addi r23, r23, 2 \n" // a double float eats up two GPRs + " addi r28, r28, 1 \n" // ...and, of course, a float + " addi r29, r29, 8 \n" // increment to our next argument we need to process (8 bytes for the 64bit float) + " addi r26, r26, 8 \n" // increment to the next slot on the argument list on the stack (8 bytes) + " b ppcNextArg \n" // on to the next argument + " nop \n" +); + +asDWORD GetReturnedFloat() +{ + asDWORD f; + asm(" stfs f1, %0\n" : "=m"(f)); + return f; +} + +asQWORD GetReturnedDouble() +{ + asQWORD f; + asm(" stfd f1, %0\n" : "=m"(f)); + return f; +} + +// puts the arguments in the correct place in the stack array. See comments above. +void stackArgs(const asDWORD *args, const asBYTE *argsType, int& numIntArgs, int& numFloatArgs, int& numDoubleArgs) +{ + int i; + int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2); + int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs; + + int typeIndex; + for( i = 0, typeIndex = 0; ; i++, typeIndex++ ) + { + // store the type + ppcArgsType[typeOffset++] = argsType[typeIndex]; + if( argsType[typeIndex] == ppcENDARG ) + break; + + switch( argsType[typeIndex] ) + { + case ppcFLOATARG: + // stow float + ppcArgs[argWordPos] = args[i]; // it's just a bit copy + numFloatArgs++; + argWordPos++; //add one word + break; + + case ppcDOUBLEARG: + // stow double + memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment + numDoubleArgs++; + argWordPos+=2; //add two words + i++;//doubles take up 2 argument slots + break; + + case ppcINTARG: + // stow register + ppcArgs[argWordPos] = args[i]; + numIntArgs++; + argWordPos++; + break; + } + } + + // close off the argument list (if we have max args we won't close it off until here) + ppcArgsType[typeOffset] = ppcENDARG; +} + +static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) +{ + int baseArgCount = 0; + if( retInMemory ) + { + // the first argument is the 'return in memory' pointer + ppcArgs[0] = (asDWORD)retInMemory; + ppcArgsType[0] = ppcINTARG; + ppcArgsType[1] = ppcENDARG; + baseArgCount = 1; + } + + // put the arguments in the correct places in the ppcArgs array + int numTotalArgs = baseArgCount; + if( argSize > 0 ) + { + int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0; + stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs ); + numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots + } + else + { + // no arguments, cap the type list + ppcArgsType[baseArgCount] = ppcENDARG; + } + + // call the function with the arguments + return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); +} + +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the first parameter is the object (unless we are returning in memory) +static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory ) +{ + int baseArgCount = 0; + if( retInMemory ) + { + // the first argument is the 'return in memory' pointer + ppcArgs[0] = (asDWORD)retInMemory; + ppcArgsType[0] = ppcINTARG; + ppcArgsType[1] = ppcENDARG; + baseArgCount = 1; + } + + // the first argument is the 'this' of the object + ppcArgs[baseArgCount] = (asDWORD)obj; + ppcArgsType[baseArgCount++] = ppcINTARG; + ppcArgsType[baseArgCount] = ppcENDARG; + + // put the arguments in the correct places in the ppcArgs array + int numTotalArgs = baseArgCount; + if( argSize > 0 ) + { + int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0; + stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs ); + numTotalArgs = intArgs + floatArgs + 2*doubleArgs; // doubles occupy two slots + } + + // call the function with the arguments + return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func); +} + +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the last parameter is the object +// NOTE: on PPC the order for the args is reversed +static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) +{ + UNUSED_VAR(argSize); + int baseArgCount = 0; + if( retInMemory ) + { + // the first argument is the 'return in memory' pointer + ppcArgs[0] = (asDWORD)retInMemory; + ppcArgsType[0] = ppcINTARG; + ppcArgsType[1] = ppcENDARG; + baseArgCount = 1; + } + + // stack any of the arguments + int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0; + stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs ); + int numTotalArgs = intArgs + floatArgs + doubleArgs; + + // can we fit the object in at the end? + if( numTotalArgs < AS_PPC_MAX_ARGS ) + { + // put the object pointer at the end + int argPos = intArgs + floatArgs + (doubleArgs * 2); + ppcArgs[argPos] = (asDWORD)obj; + ppcArgsType[numTotalArgs++] = ppcINTARG; + ppcArgsType[numTotalArgs] = ppcENDARG; + } + + // call the function with the arguments + return ppcFunc( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) +{ + // TODO: PPC does not yet support THISCALL_OBJFIRST/LAST + + // use a working array of types, we'll configure the final one in stackArgs + asBYTE argsType[2*AS_PPC_MAX_ARGS + 1 + 1 + 1]; + memset( argsType, 0, sizeof(argsType)); + + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + + asQWORD retQW = 0; + void *func = (void*)sysFunc->func; + int paramSize = sysFunc->paramSize; + asDWORD *vftable = NULL; + int a, s; + + // convert the parameters that are < 4 bytes from little endian to big endian + int argDwordOffset = 0; + for( a = 0; a < (int)descr->parameterTypes.GetLength(); a++ ) + { + int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes(); + if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() ) + { + argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords(); + continue; + } + + // flip + asASSERT( numBytes == 1 || numBytes == 2 ); + switch( numBytes ) + { + case 1: + { + volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]); + asBYTE t = bPtr[0]; + bPtr[0] = bPtr[3]; + bPtr[3] = t; + t = bPtr[1]; + bPtr[1] = bPtr[2]; + bPtr[2] = t; + } + break; + case 2: + { + volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]); + asWORD t = wPtr[0]; + wPtr[0] = wPtr[1]; + wPtr[1] = t; + } + break; + } + argDwordOffset++; + } + + // mark all float/double/int arguments + if( !sysFunc->takesObjByVal ) + { + for( s = 0, a = 0; s < (int)descr->parameterTypes.GetLength(); s++, a++ ) + { + if( descr->parameterTypes[s].IsFloatType() && !descr->parameterTypes[s].IsReference() ) + { + argsType[a] = ppcFLOATARG; + } + else if( descr->parameterTypes[s].IsDoubleType() && !descr->parameterTypes[s].IsReference() ) + { + argsType[a] = ppcDOUBLEARG; + } + else + { + argsType[a] = ppcINTARG; + if( descr->parameterTypes[s].GetSizeOnStackDWords() == 2 ) + { + // Add an extra integer argument for the extra size + a++; + argsType[a] = ppcINTARG; + } + } + } + } + + asDWORD paramBuffer[64]; + if( sysFunc->takesObjByVal ) + { + paramSize = 0; + int spos = 0; + int dpos = 1; + + int a = 0; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + argsType[a++] = ppcINTARG; + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else +#endif + { + // TODO: Probably have to handle asOBJ_APP_FLOAT as a primitive + + // Copy the object's memory to the buffer + memcpy( ¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() ); + + // Delete the original memory + engine->CallFree(*(char**)(args+spos) ); + spos++; + asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords(); + dpos += dwords; + paramSize += dwords; + for( asUINT i = 0; i < dwords; i++ ) + argsType[a++] = ppcINTARG; + } + } + else + { + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference() ) + argsType[a++] = ppcFLOATARG; + else if( descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference() ) + argsType[a++] = ppcDOUBLEARG; + else + argsType[a++] = ppcINTARG; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + { + paramBuffer[dpos++] = args[spos++]; + if( !descr->parameterTypes[n].IsDoubleType() ) // Double already knows it is 2 dwords + argsType[a++] = ppcINTARG; + } + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + } + + // Keep a free location at the beginning + args = ¶mBuffer[1]; + } + + int callConv = sysFunc->callConv; + switch( callConv ) + { + case ICC_CDECL: + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL: + case ICC_STDCALL_RETURNINMEM: + retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + case ICC_THISCALL: + case ICC_THISCALL_RETURNINMEM: + retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(asDWORD**)obj; + retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retPointer ); + break; + case ICC_CDECL_OBJLAST: + case ICC_CDECL_OBJLAST_RETURNINMEM: + retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + case ICC_CDECL_OBJFIRST: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_PPC +#endif // AS_MAX_PORTABILITY + diff --git a/angelscript/source/as_callfunc_ppc_64.cpp b/angelscript/source/as_callfunc_ppc_64.cpp new file mode 100644 index 0000000..275f615 --- /dev/null +++ b/angelscript/source/as_callfunc_ppc_64.cpp @@ -0,0 +1,773 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2016 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_ppc_64.cpp +// +// These functions handle the actual calling of system functions +// +// This version is 64 bit PPC specific +// + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_PPC_64 +#if AS_PTR_SIZE == 2 +// TODO: Add support for PPC 64bit platforms with 64bit pointers, for example Linux PPC64 (big endian) and PPC64 (little endian) +#error This code has not been prepared for PPC with 64bit pointers. Most likely the ABI is different +#else + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +#include +#include + +#ifdef __SNC__ +#include "ppu_asm_intrinsics.h" +#endif + + +BEGIN_AS_NAMESPACE + +// This part was written and tested by Jeff Slutter +// from Reactor Zero, Abril, 2007, for PlayStation 3, which +// is a PowerPC 64bit based architecture. Even though it is +// 64bit it seems the pointer size is still 32bit. + +// It still remains to be seen how well this code works +// on other PPC platforms, such as XBox 360, GameCube. + +#define AS_PPC_MAX_ARGS 32 + +// The array used to send values to the correct places. +// Contains a byte of argTypes to indicate the register type to load +// or zero if end of arguments +// The +1 is for when CallThis (object methods) is used +// Extra +1 when returning in memory +// Extra +1 in ppcArgsType to ensure zero end-of-args marker + +// TODO: multithread: The global variables must be removed to make the code thread safe + +extern "C" +{ + enum argTypes { ppcENDARG = 0, ppcINTARG = 1, ppcFLOATARG = 2, ppcDOUBLEARG = 3, ppcLONGARG = 4 }; + static asBYTE ppcArgsType[AS_PPC_MAX_ARGS + 1 + 1 + 1]; + static asDWORD ppcArgs[2*AS_PPC_MAX_ARGS + 1 + 1]; +} + +// NOTE: these values are for PowerPC 64 bit. I'm sure things are different for PowerPC 32bit, but I don't have one. +// I'm pretty sure that PPC 32bit sets up a stack frame slightly different (only 24 bytes for linkage area for instance) +#define PPC_LINKAGE_SIZE (0x30) // how big the PPC linkage area is in a stack frame +#define PPC_NUM_REGSTORE (10) // how many registers of the PPC we need to store/restore for ppcFunc64() +#define PPC_REGSTORE_SIZE (8*PPC_NUM_REGSTORE) // how many bytes are required for register store/restore +#define EXTRA_STACK_SIZE (PPC_LINKAGE_SIZE + PPC_REGSTORE_SIZE) // memory required, not including parameters, for the stack frame +#define PPC_STACK_SIZE(numParams) ( -(( ( (((numParams)<8)?8:(numParams))<<3) + EXTRA_STACK_SIZE + 15 ) & ~15) ) // calculates the total stack size needed for ppcFunc64, must pad to 16bytes + +// This is PowerPC 64 bit specific +// Loads all data into the correct places and calls the function. +// ppcArgsType is an array containing a byte type (enum argTypes) for each argument. +// StackArgSizeInBytes is the size in bytes of the stack frame (takes into account linkage area, etc. must be multiple of 16) +extern "C" asQWORD ppcFunc64(const asDWORD* argsPtr, int StackArgSizeInBytes, asDWORD func); +asm("" + ".text\n" + ".align 4\n" + ".p2align 4,,15\n" + ".globl .ppcFunc64\n" + ".ppcFunc64:\n" + + // function prolog + "std %r22, -0x08(%r1)\n" // we need a register other than r0, to store the old stack pointer + "mr %r22, %r1\n" // store the old stack pointer, for now (to make storing registers easier) + "stdux %r1, %r1, %r4\n" // atomically store and update the stack pointer for the new stack frame (in case of a signal/interrupt) + "mflr %r0\n" // get the caller's LR register + "std %r0, 0x10(%r22)\n" // store the caller's LR register + "std %r23, -0x10(%r22)\n" // + "std %r24, -0x18(%r22)\n" // + "std %r25, -0x20(%r22)\n" // + "std %r26, -0x28(%r22)\n" // + "std %r27, -0x30(%r22)\n" // + "std %r28, -0x38(%r22)\n" // + "std %r29, -0x40(%r22)\n" // + "std %r30, -0x48(%r22)\n" // + "std %r31, -0x50(%r22)\n" // + "std %r3, 0x30(%r22)\n" // save our parameters + "std %r4, 0x38(%r22)\n" // + "std %r5, 0x40(%r22)\n" // + "mr %r31, %r1\n" // functions tend to store the stack pointer here too + + // initial registers for the function + "mr %r29, %r3\n" // (r29) args list + "lwz %r27, 0(%r5)\n" // load the function pointer to call. func actually holds the pointer to our function + "addi %r26, %r1, 0x30\n" // setup the pointer to the parameter area to the function we're going to call + "sub %r0,%r0,%r0\n" // zero out r0 + "mr %r23,%r0\n" // zero out r23, which holds the number of used GPR registers + "mr %r22,%r0\n" // zero our r22, which holds the number of used float registers + + // load the global ppcArgsType which holds the types of arguments for each argument + "lis %r25, ppcArgsType@ha\n" // load the upper 16 bits of the address to r25 + "addi %r25, %r25, ppcArgsType@l\n" // load the lower 16 bits of the address to r25 + "subi %r25, %r25, 1\n" // since we increment r25 on its use, we'll pre-decrement it + + // loop through the arguments + "ppcNextArg:\n" + "addi %r25, %r25, 1\n" // increment r25, our arg type pointer + // switch based on the current argument type (0:end, 1:int, 2:float 3:double) + "lbz %r24, 0(%r25)\n" // load the current argument type (it's a byte) + "mulli %r24, %r24, 4\n" // our jump table has 4 bytes per case (1 instruction) + "lis %r30, ppcTypeSwitch@ha\n" // load the address of the jump table for the switch + "addi %r30, %r30, ppcTypeSwitch@l\n" + "add %r0, %r30, %r24\n" // offset by our argument type + "mtctr %r0\n" // load the jump address into CTR + "bctr\n" // jump into the jump table/switch + "nop\n" + // the jump table/switch based on the current argument type + "ppcTypeSwitch:\n" + "b ppcArgsEnd\n" + "b ppcArgIsInteger\n" + "b ppcArgIsFloat\n" + "b ppcArgIsDouble\n" + "b ppcArgIsLong\n" + + // when we get here we have finished processing all the arguments + // everything is ready to go to call the function + "ppcArgsEnd:\n" + "mtctr %r27\n" // the function pointer is stored in r27, load that into CTR + "bctrl\n" // call the function. We have to do it this way so that the LR gets the proper + "nop\n" // return value (the next instruction below). So we have to branch from CTR instead of LR. + // when we get here, the function has returned, this is the function epilog + "ld %r11,0x00(%r1)\n" // load in the caller's stack pointer + "ld %r0,0x10(%r11)\n" // load in the caller's LR + "mtlr %r0\n" // restore the caller's LR + "ld %r22, -0x08(%r11)\n" // load registers + "ld %r23, -0x10(%r11)\n" // + "ld %r24, -0x18(%r11)\n" // + "ld %r25, -0x20(%r11)\n" // + "ld %r26, -0x28(%r11)\n" // + "ld %r27, -0x30(%r11)\n" // + "ld %r28, -0x38(%r11)\n" // + "ld %r29, -0x40(%r11)\n" // + "ld %r30, -0x48(%r11)\n" // + "ld %r31, -0x50(%r11)\n" // + "mr %r1, %r11\n" // restore the caller's SP + "blr\n" // return back to the caller + "nop\n" + // Integer argument (GPR register) + "ppcArgIsInteger:\n" + "lis %r30,ppcLoadIntReg@ha\n" // load the address to the jump table for integer registers + "addi %r30, %r30, ppcLoadIntReg@l\n" + "mulli %r0, %r23, 8\n" // each item in the jump table is 2 instructions (8 bytes) + "add %r0, %r0, %r30\n" // calculate ppcLoadIntReg[numUsedGPRRegs] + "lwz %r30,0(%r29)\n" // load the next argument from the argument list into r30 + "cmpwi %r23, 8\n" // we can only load GPR3 through GPR10 (8 registers) + "bgt ppcLoadIntRegUpd\n" // if we're beyond 8 GPR registers, we're in the stack, go there + "mtctr %r0\n" // load the address of our ppcLoadIntReg jump table (we're below 8 GPR registers) + "bctr\n" // load the argument into a GPR register + "nop\n" + // jump table for GPR registers, for the first 8 GPR arguments + "ppcLoadIntReg:\n" + "mr %r3,%r30\n" // arg0 (to r3) + "b ppcLoadIntRegUpd\n" + "mr %r4,%r30\n" // arg1 (to r4) + "b ppcLoadIntRegUpd\n" + "mr %r5,%r30\n" // arg2 (to r5) + "b ppcLoadIntRegUpd\n" + "mr %r6,%r30\n" // arg3 (to r6) + "b ppcLoadIntRegUpd\n" + "mr %r7,%r30\n" // arg4 (to r7) + "b ppcLoadIntRegUpd\n" + "mr %r8,%r30\n" // arg5 (to r8) + "b ppcLoadIntRegUpd\n" + "mr %r9,%r30\n" // arg6 (to r9) + "b ppcLoadIntRegUpd\n" + "mr %r10,%r30\n" // arg7 (to r10) + "b ppcLoadIntRegUpd\n" + + // all GPR arguments still go on the stack + "ppcLoadIntRegUpd:\n" + "std %r30,0(%r26)\n" // store the argument into the next slot on the stack's argument list + "addi %r23, %r23, 1\n" // count a used GPR register + "addi %r29, %r29, 4\n" // move to the next argument on the list + "addi %r26, %r26, 8\n" // adjust our argument stack pointer for the next + "b ppcNextArg\n" // next argument + + // single Float argument + "ppcArgIsFloat:\n" + "lis %r30,ppcLoadFloatReg@ha\n" // get the base address of the float register jump table + "addi %r30, %r30, ppcLoadFloatReg@l\n" + "mulli %r0, %r22 ,8\n" // each jump table entry is 8 bytes + "add %r0, %r0, %r30\n" // calculate the offset to ppcLoadFloatReg[numUsedFloatReg] + "lfs 0, 0(%r29)\n" // load the next argument as a float into f0 + "cmpwi %r22, 13\n" // can't load more than 13 float/double registers + "bgt ppcLoadFloatRegUpd\n" // if we're beyond 13 registers, just fall to inserting into the stack + "mtctr %r0\n" // jump into the float jump table + "bctr\n" + "nop\n" + // jump table for float registers, for the first 13 float arguments + "ppcLoadFloatReg:\n" + "fmr 1,0\n" // arg0 (f1) + "b ppcLoadFloatRegUpd\n" + "fmr 2,0\n" // arg1 (f2) + "b ppcLoadFloatRegUpd\n" + "fmr 3,0\n" // arg2 (f3) + "b ppcLoadFloatRegUpd\n" + "fmr 4,0\n" // arg3 (f4) + "b ppcLoadFloatRegUpd\n" + "fmr 5,0\n" // arg4 (f5) + "b ppcLoadFloatRegUpd\n" + "fmr 6,0\n" // arg5 (f6) + "b ppcLoadFloatRegUpd\n" + "fmr 7,0\n" // arg6 (f7) + "b ppcLoadFloatRegUpd\n" + "fmr 8,0\n" // arg7 (f8) + "b ppcLoadFloatRegUpd\n" + "fmr 9,0\n" // arg8 (f9) + "b ppcLoadFloatRegUpd\n" + "fmr 10,0\n" // arg9 (f10) + "b ppcLoadFloatRegUpd\n" + "fmr 11,0\n" // arg10 (f11) + "b ppcLoadFloatRegUpd\n" + "fmr 12,0\n" // arg11 (f12) + "b ppcLoadFloatRegUpd\n" + "fmr 13,0\n" // arg12 (f13) + "b ppcLoadFloatRegUpd\n" + "nop\n" + // all float arguments still go on the stack + "ppcLoadFloatRegUpd:\n" + "stfs 0, 0x04(%r26)\n" // store, as a single float, f0 (current argument) on to the stack argument list + "addi %r23, %r23, 1\n" // a float register eats up a GPR register + "addi %r22, %r22, 1\n" // ...and, of course, a float register + "addi %r29, %r29, 4\n" // move to the next argument in the list + "addi %r26, %r26, 8\n" // move to the next stack slot + "b ppcNextArg\n" // on to the next argument + "nop\n" + // double Float argument + "ppcArgIsDouble:\n" + "lis %r30, ppcLoadDoubleReg@ha\n" // load the base address of the jump table for double registers + "addi %r30, %r30, ppcLoadDoubleReg@l\n" + "mulli %r0, %r22, 8\n" // each slot of the jump table is 8 bytes + "add %r0, %r0, %r30\n" // calculate ppcLoadDoubleReg[numUsedFloatReg] + "lfd 0, 0(%r29)\n" // load the next argument, as a double float, into f0 + "cmpwi %r22,13\n" // the first 13 floats must go into float registers also + "bgt ppcLoadDoubleRegUpd\n" // if we're beyond 13, then just put on to the stack + "mtctr %r0\n" // we're under 13, first load our register + "bctr\n" // jump into the jump table + "nop\n" + // jump table for float registers, for the first 13 float arguments + "ppcLoadDoubleReg:\n" + "fmr 1,0\n" // arg0 (f1) + "b ppcLoadDoubleRegUpd\n" + "fmr 2,0\n" // arg1 (f2) + "b ppcLoadDoubleRegUpd\n" + "fmr 3,0\n" // arg2 (f3) + "b ppcLoadDoubleRegUpd\n" + "fmr 4,0\n" // arg3 (f4) + "b ppcLoadDoubleRegUpd\n" + "fmr 5,0\n" // arg4 (f5) + "b ppcLoadDoubleRegUpd\n" + "fmr 6,0\n" // arg5 (f6) + "b ppcLoadDoubleRegUpd\n" + "fmr 7,0\n" // arg6 (f7) + "b ppcLoadDoubleRegUpd\n" + "fmr 8,0\n" // arg7 (f8) + "b ppcLoadDoubleRegUpd\n" + "fmr 9,0\n" // arg8 (f9) + "b ppcLoadDoubleRegUpd\n" + "fmr 10,0\n" // arg9 (f10) + "b ppcLoadDoubleRegUpd\n" + "fmr 11,0\n" // arg10 (f11) + "b ppcLoadDoubleRegUpd\n" + "fmr 12,0\n" // arg11 (f12) + "b ppcLoadDoubleRegUpd\n" + "fmr 13,0\n" // arg12 (f13) + "b ppcLoadDoubleRegUpd\n" + "nop\n" + // all float arguments still go on the stack + "ppcLoadDoubleRegUpd:\n" + "stfd 0,0(%r26)\n" // store f0, as a double, into the argument list on the stack + "addi %r23, %r23, 1\n" // a double float eats up one GPR + "addi %r22, %r22, 1\n" // ...and, of course, a float + "addi %r29, %r29, 8\n" // increment to our next argument we need to process (8 bytes for the 64bit float) + "addi %r26, %r26, 8\n" // increment to the next slot on the argument list on the stack (8 bytes) + "b ppcNextArg\n" // on to the next argument + "nop\n" + + // Long (64 bit int) argument + "ppcArgIsLong:\n" + "lis %r30,ppcLoadLongReg@ha\n" // load the address to the jump table for integer64 + "addi %r30, %r30, ppcLoadLongReg@l\n" + "mulli %r0, %r23, 8\n" // each item in the jump table is 2 instructions (8 bytes) + "add %r0, %r0, %r30\n" // calculate ppcLoadLongReg[numUsedGPRRegs] + "ld %r30,0(%r29)\n" // load the next argument from the argument list into r30 + "cmpwi %r23, 8\n" // we can only load GPR3 through GPR10 (8 registers) + "bgt ppcLoadLongRegUpd\n" // if we're beyond 8 GPR registers, we're in the stack, go there + "mtctr %r0\n" // load the address of our ppcLoadLongReg jump table (we're below 8 GPR registers) + "bctr\n" // load the argument into a GPR register + "nop\n" + // jump table for GPR registers, for the first 8 GPR arguments + "ppcLoadLongReg:\n" + "mr %r3,%r30\n" // arg0 (to r3) + "b ppcLoadLongRegUpd\n" + "mr %r4,%r30\n" // arg1 (to r4) + "b ppcLoadLongRegUpd\n" + "mr %r5,%r30\n" // arg2 (to r5) + "b ppcLoadLongRegUpd\n" + "mr %r6,%r30\n" // arg3 (to r6) + "b ppcLoadLongRegUpd\n" + "mr %r7,%r30\n" // arg4 (to r7) + "b ppcLoadLongRegUpd\n" + "mr %r8,%r30\n" // arg5 (to r8) + "b ppcLoadLongRegUpd\n" + "mr %r9,%r30\n" // arg6 (to r9) + "b ppcLoadLongRegUpd\n" + "mr %r10,%r30\n" // arg7 (to r10) + "b ppcLoadLongRegUpd\n" + + // all GPR arguments still go on the stack + "ppcLoadLongRegUpd:\n" + "std %r30,0(%r26)\n" // store the argument into the next slot on the stack's argument list + "addi %r23, %r23, 1\n" // count a used GPR register + "addi %r29, %r29, 8\n" // move to the next argument on the list + "addi %r26, %r26, 8\n" // adjust our argument stack pointer for the next + "b ppcNextArg\n" // next argument +); + +static asDWORD GetReturnedFloat(void) +{ + asDWORD f; +#ifdef __SNC__ + __stfs( __freg(1), 0, (void*)&f); +#else + asm(" stfs 1, %0\n" : "=m"(f)); +#endif + return f; +} + +static asQWORD GetReturnedDouble(void) +{ + asQWORD f; +#ifdef __SNC__ + __stfd( __freg(1), 0, (void*)&f); +#else + asm(" stfd 1, %0\n" : "=m"(f)); +#endif + return f; +} + +// puts the arguments in the correct place in the stack array. See comments above. +static void stackArgs( const asDWORD *args, const asBYTE *argsType, int &numIntArgs, int &numFloatArgs, int &numDoubleArgs, int &numLongArgs ) +{ + // initialize our offset based on any already placed arguments + int i; + int argWordPos = numIntArgs + numFloatArgs + (numDoubleArgs*2) + (numLongArgs*2); + int typeOffset = numIntArgs + numFloatArgs + numDoubleArgs + numLongArgs; + + int typeIndex; + for( i = 0, typeIndex = 0; ; i++, typeIndex++ ) + { + // store the type + ppcArgsType[typeOffset++] = argsType[typeIndex]; + if( argsType[typeIndex] == ppcENDARG ) + break; + + switch( argsType[typeIndex] ) + { + case ppcFLOATARG: + { + // stow float + ppcArgs[argWordPos] = args[i]; // it's just a bit copy + numFloatArgs++; + argWordPos++; //add one word + } + break; + + case ppcDOUBLEARG: + { + // stow double + memcpy( &ppcArgs[argWordPos], &args[i], sizeof(double) ); // we have to do this because of alignment + numDoubleArgs++; + argWordPos+=2; //add two words + i++;//doubles take up 2 argument slots + } + break; + + case ppcINTARG: + { + // stow register + ppcArgs[argWordPos] = args[i]; + numIntArgs++; + argWordPos++; + } + break; + + case ppcLONGARG: + { + // stow long + memcpy( &ppcArgs[argWordPos], &args[i], 8 ); // for alignment purposes, we use memcpy + numLongArgs++; + argWordPos += 2; // add two words + i++; // longs take up 2 argument slots + } + break; + } + } + + // close off the argument list (if we have max args we won't close it off until here) + ppcArgsType[typeOffset] = ppcENDARG; +} + +static asQWORD CallCDeclFunction(const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) +{ + int baseArgCount = 0; + if( retInMemory ) + { + // the first argument is the 'return in memory' pointer + ppcArgs[0] = (asDWORD)retInMemory; + ppcArgsType[0] = ppcINTARG; + ppcArgsType[1] = ppcENDARG; + baseArgCount = 1; + } + + // put the arguments in the correct places in the ppcArgs array + int numTotalArgs = baseArgCount; + if( argSize > 0 ) + { + int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0; + stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs ); + numTotalArgs = intArgs + floatArgs + doubleArgs + longArgs; + } + else + { + // no arguments, cap the type list + ppcArgsType[baseArgCount] = ppcENDARG; + } + + // call the function with the arguments + return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); +} + +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the first parameter is the object (unless we are returning in memory) +static asQWORD CallThisCallFunction(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory ) +{ + int baseArgCount = 0; + if( retInMemory ) + { + // the first argument is the 'return in memory' pointer + ppcArgs[0] = (asDWORD)retInMemory; + ppcArgsType[0] = ppcINTARG; + ppcArgsType[1] = ppcENDARG; + baseArgCount = 1; + } + + // the first argument is the 'this' of the object + ppcArgs[baseArgCount] = (asDWORD)obj; + ppcArgsType[baseArgCount++] = ppcINTARG; + ppcArgsType[baseArgCount] = ppcENDARG; + + // put the arguments in the correct places in the ppcArgs array + int numTotalArgs = baseArgCount; + if( argSize > 0 ) + { + int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0; + stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs ); + numTotalArgs = intArgs + floatArgs + doubleArgs + longArgs; + } + + // call the function with the arguments + return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func); +} + +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the last parameter is the object +// NOTE: on PPC the order for the args is reversed +static asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD* pArgs, const asBYTE *pArgsType, int argSize, asDWORD func, void *retInMemory) +{ + UNUSED_VAR(argSize); + int baseArgCount = 0; + if( retInMemory ) + { + // the first argument is the 'return in memory' pointer + ppcArgs[0] = (asDWORD)retInMemory; + ppcArgsType[0] = ppcINTARG; + ppcArgsType[1] = ppcENDARG; + baseArgCount = 1; + } + + // stack any of the arguments + int intArgs = baseArgCount, floatArgs = 0, doubleArgs = 0, longArgs = 0; + stackArgs( pArgs, pArgsType, intArgs, floatArgs, doubleArgs, longArgs ); + int numTotalArgs = intArgs + floatArgs + doubleArgs; + + // can we fit the object in at the end? + if( numTotalArgs < AS_PPC_MAX_ARGS ) + { + // put the object pointer at the end + int argPos = intArgs + floatArgs + (doubleArgs * 2) + (longArgs *2); + ppcArgs[argPos] = (asDWORD)obj; + ppcArgsType[numTotalArgs++] = ppcINTARG; + ppcArgsType[numTotalArgs] = ppcENDARG; + } + + // call the function with the arguments + return ppcFunc64( ppcArgs, PPC_STACK_SIZE(numTotalArgs), func ); +} + +// returns true if the given parameter is a 'variable argument' +inline bool IsVariableArgument( asCDataType type ) +{ + return (type.GetTokenType() == ttQuestion) ? true : false; +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) +{ + // TODO: PPC 64 does not yet support THISCALL_OBJFIRST/LAST + + // use a working array of types, we'll configure the final one in stackArgs + asBYTE argsType[AS_PPC_MAX_ARGS + 1 + 1 + 1]; + memset( argsType, 0, sizeof(argsType)); + + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + + int callConv = sysFunc->callConv; + + asQWORD retQW = 0; + void *func = (void*)sysFunc->func; + int paramSize = sysFunc->paramSize; + asDWORD *vftable = NULL; + int a; + + // convert the parameters that are < 4 bytes from little endian to big endian + int argDwordOffset = 0; + int totalArgumentCount = 0; + + for( a = 0; a < (int)descr->parameterTypes.GetLength(); ++a ) + { + // get the size for the parameter + int numBytes = descr->parameterTypes[a].GetSizeInMemoryBytes(); + ++totalArgumentCount; + + // is this a variable argument? + // for variable arguments, the typeID will always follow...but we know it is 4 bytes + // so we can skip that parameter automatically. + bool isVarArg = IsVariableArgument( descr->parameterTypes[a] ); + if( isVarArg ) + { + ++totalArgumentCount; + } + + if( numBytes >= 4 || descr->parameterTypes[a].IsReference() || descr->parameterTypes[a].IsObjectHandle() ) + { + // DWORD or larger parameter --- no flipping needed + argDwordOffset += descr->parameterTypes[a].GetSizeOnStackDWords(); + } + else + { + // flip + asASSERT( numBytes == 1 || numBytes == 2 ); + switch( numBytes ) + { + case 1: + { + volatile asBYTE *bPtr = (asBYTE*)ARG_DW(args[argDwordOffset]); + asBYTE t = bPtr[0]; + bPtr[0] = bPtr[3]; + bPtr[3] = t; + t = bPtr[1]; + bPtr[1] = bPtr[2]; + bPtr[2] = t; + } + break; + case 2: + { + volatile asWORD *wPtr = (asWORD*)ARG_DW(args[argDwordOffset]); + asWORD t = wPtr[0]; + wPtr[0] = wPtr[1]; + wPtr[1] = t; + } + break; + } + ++argDwordOffset; + } + + if( isVarArg ) + { + // skip the implicit typeID + ++argDwordOffset; + } + } + + asASSERT( totalArgumentCount <= AS_PPC_MAX_ARGS ); + + // mark all float/double/int arguments + int argIndex = 0; + for( a = 0; a < (int)descr->parameterTypes.GetLength(); ++a, ++argIndex ) + { + // get the base type + argsType[argIndex] = ppcINTARG; + if( descr->parameterTypes[a].IsFloatType() && !descr->parameterTypes[a].IsReference() ) + { + argsType[argIndex] = ppcFLOATARG; + } + if( descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() ) + { + argsType[argIndex] = ppcDOUBLEARG; + } + if( descr->parameterTypes[a].GetSizeOnStackDWords() == 2 && !descr->parameterTypes[a].IsDoubleType() && !descr->parameterTypes[a].IsReference() ) + { + argsType[argIndex] = ppcLONGARG; + } + + // if it is a variable argument, account for the typeID + if( IsVariableArgument(descr->parameterTypes[a]) ) + { + // implicitly add another parameter (AFTER the parameter above), for the TypeID + argsType[++argIndex] = ppcINTARG; + } + } + asASSERT( argIndex == totalArgumentCount ); + + asDWORD paramBuffer[64]; + if( sysFunc->takesObjByVal ) + { + paramSize = 0; + int spos = 0; + int dpos = 1; + + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() && + !(descr->parameterTypes[n].GetTypeInfo()->flags & asOBJ_APP_ARRAY) ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + ++paramSize; + } + else +#endif + { + // NOTE: we may have to do endian flipping here + + // Copy the object's memory to the buffer + memcpy( ¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes() ); + + // Delete the original memory + engine->CallFree( *(char**)(args+spos) ); + spos++; + dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); + } + } + else + { + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + { + paramBuffer[dpos++] = args[spos++]; + } + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + + // if this was a variable argument parameter, then account for the implicit typeID + if( IsVariableArgument( descr->parameterTypes[n] ) ) + { + // the TypeID is just a DWORD + paramBuffer[dpos++] = args[spos++]; + ++paramSize; + } + } + + // Keep a free location at the beginning + args = ¶mBuffer[1]; + } + + // one last verification to make sure things are how we expect + switch( callConv ) + { + case ICC_CDECL: + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL: + case ICC_STDCALL_RETURNINMEM: + retQW = CallCDeclFunction( args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + case ICC_THISCALL: + case ICC_THISCALL_RETURNINMEM: + retQW = CallThisCallFunction(obj, args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(asDWORD**)obj; + retQW = CallThisCallFunction( obj, args, argsType, paramSize, vftable[asDWORD(func)>>2], retPointer ); + break; + case ICC_CDECL_OBJLAST: + case ICC_CDECL_OBJLAST_RETURNINMEM: + retQW = CallThisCallFunction_objLast( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + case ICC_CDECL_OBJFIRST: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + retQW = CallThisCallFunction( obj, args, argsType, paramSize, (asDWORD)func, retPointer ); + break; + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + if( sysFunc->hostReturnFloat ) + { + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + else if( sysFunc->hostReturnSize == 1 ) + { + // Move the bits to the higher value to compensate for the adjustment that the caller does + retQW <<= 32; + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_PTR_SIZE == 2 +#endif // AS_PPC_64 +#endif // AS_MAX_PORTABILITY + diff --git a/angelscript/source/as_callfunc_sh4.cpp b/angelscript/source/as_callfunc_sh4.cpp new file mode 100644 index 0000000..b24be9a --- /dev/null +++ b/angelscript/source/as_callfunc_sh4.cpp @@ -0,0 +1,393 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_sh4.cpp +// +// These functions handle the actual calling of system functions +// +// This version is SH4 specific and was originally written +// by Fredrik Ehnbom in May, 2004 +// Later updated for angelscript 2.0.0 by Fredrik Ehnbom in Jan, 2005 + +// References: +// * http://www.renesas.com/avs/resource/japan/eng/pdf/mpumcu/e602156_sh4.pdf +// * http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wcechp40/html/_callsh4_SH_4_Calling_Standard.asp + + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_SH4 + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +#include +#include + +BEGIN_AS_NAMESPACE + +#define AS_SH4_MAX_ARGS 32 +// The array used to send values to the correct places. +// first 0-4 regular values to load into the r4-r7 registers +// then 0-8 float values to load into the fr4-fr11 registers +// then (AS_SH4_MAX_ARGS - 12) values to load onto the stack +// the +1 is for when CallThis (object methods) is used +// extra +1 when returning in memory +extern "C" { +static asDWORD sh4Args[AS_SH4_MAX_ARGS + 1 + 1]; +} + +// Loads all data into the correct places and calls the function. +// intArgSize is the size in bytes for how much data to put in int registers +// floatArgSize is the size in bytes for how much data to put in float registers +// stackArgSize is the size in bytes for how much data to put on the callstack +extern "C" asQWORD sh4Func(int intArgSize, int floatArgSize, int stackArgSize, asDWORD func); + +asm("" +" .align 4\n" +" .global _sh4Func\n" +"_sh4Func:\n" +" mov.l r14,@-r15\n" +" mov.l r13,@-r15\n" +" mov.l r12,@-r15\n" +" sts.l pr,@-r15\n" // must be saved since we call a subroutine +" mov r7, r14\n" // func +" mov r6, r13\n" // stackArgSize +" mov.l r5,@-r15\n" // floatArgSize +" mov.l sh4Args,r0\n" +" pref @r0\n" +" mov r4, r1\n" // intArgsize +" mov #33*4,r2\n" +" extu.b r2,r2\n" // make unsigned (33*4 = 132 => 128) +" mov.l @(r0,r2), r2\n" // r2 has adress for when returning in memory +"_sh4f_intarguments:\n" // copy all the int arguments to the respective registers +" mov #4*2*2,r3\n" // calculate how many bytes to skip +" sub r1,r3\n" +" braf r3\n" +" add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot) +" mov.l @(r0,r1),r7\n" // 4 arguments +" add #-4,r1\n" +" mov.l @(r0,r1),r6\n" // 3 arguments +" add #-4,r1\n" +" mov.l @(r0,r1),r5\n" // 2 arguments +" add #-4,r1\n" +" mov.l @(r0,r1),r4\n" // 1 argument +" nop\n" +"_sh4f_floatarguments:\n" // copy all the float arguments to the respective registers +" add #4*4, r0\n" +" mov.l @r15+,r1\n" // floatArgSize +" mov #8*2*2,r3\n" // calculate how many bytes to skip +" sub r1,r3\n" +" braf r3\n" +" add #-4,r1\n" // we are indexing the array backwards, so subtract one (delayed slot) +" fmov.s @(r0,r1),fr11\n" // 8 arguments +" add #-4,r1\n" +" fmov.s @(r0,r1),fr10\n" // 7 arguments +" add #-4,r1\n" +" fmov.s @(r0,r1),fr9\n" // 6 arguments +" add #-4,r1\n" +" fmov.s @(r0,r1),fr8\n" // 5 arguments +" add #-4,r1\n" +" fmov.s @(r0,r1),fr7\n" // 4 arguments +" add #-4,r1\n" +" fmov.s @(r0,r1),fr6\n" // 3 arguments +" add #-4,r1\n" +" fmov.s @(r0,r1),fr5\n" // 2 arguments +" add #-4,r1\n" +" fmov.s @(r0,r1),fr4\n" // 1 argument +" nop\n" +"_sh4f_stackarguments:\n" // copy all the stack argument onto the stack +" add #8*4, r0\n" +" mov r0, r1\n" +" mov #0, r0\n" // init position counter (also used as a 0-check on the line after) +" cmp/eq r0, r13\n" +" bt _sh4f_functioncall\n" // no arguments to push onto the stack +" mov r13, r3\n" // stackArgSize +" sub r3,r15\n" // "allocate" space on the stack +" shlr2 r3\n" // make into a counter +"_sh4f_stackloop:\n" +" mov.l @r1+, r12\n" +" mov.l r12, @(r0, r15)\n" +" add #4, r0\n" +" dt r3\n" +" bf _sh4f_stackloop\n" +"_sh4f_functioncall:\n" +" jsr @r14\n" // no arguments +" nop\n" +" add r13, r15\n" // restore stack position +" lds.l @r15+,pr\n" +" mov.l @r15+, r12\n" +" mov.l @r15+, r13\n" +" rts\n" +" mov.l @r15+, r14\n" // delayed slot +"\n" +" .align 4\n" +"sh4Args:\n" +" .long _sh4Args\n" +); + +// puts the arguments in the correct place in the sh4Args-array. See comments above. +// This could be done better. +inline void splitArgs(const asDWORD *args, int argNum, int &numRegIntArgs, int &numRegFloatArgs, int &numRestArgs, int hostFlags) { + int i; + + int argBit = 1; + for (i = 0; i < argNum; i++) { + if (hostFlags & argBit) { + if (numRegFloatArgs < 12 - 4) { + // put in float register + sh4Args[4 + numRegFloatArgs] = args[i]; + numRegFloatArgs++; + } else { + // put in stack + sh4Args[4 + 8 + numRestArgs] = args[i]; + numRestArgs++; + } + } else { + if (numRegIntArgs < 8 - 4) { + // put in int register + sh4Args[numRegIntArgs] = args[i]; + numRegIntArgs++; + } else { + // put in stack + sh4Args[4 + 8 + numRestArgs] = args[i]; + numRestArgs++; + } + } + argBit <<= 1; + } +} +asQWORD CallCDeclFunction(const asDWORD *args, int argSize, asDWORD func, int flags) +{ + int argNum = argSize >> 2; + + int intArgs = 0; + int floatArgs = 0; + int restArgs = 0; + + // put the arguments in the correct places in the sh4Args array + if (argNum > 0) + splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); + + return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); +} + +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the first parameter is the object +asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) +{ + int argNum = argSize >> 2; + + int intArgs = 1; + int floatArgs = 0; + int restArgs = 0; + + sh4Args[0] = (asDWORD) obj; + + // put the arguments in the correct places in the sh4Args array + if (argNum >= 1) + splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); + + return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); +} +// This function is identical to CallCDeclFunction, with the only difference that +// the value in the last parameter is the object +asQWORD CallThisCallFunction_objLast(const void *obj, const asDWORD *args, int argSize, asDWORD func, int flags) +{ + int argNum = argSize >> 2; + + int intArgs = 0; + int floatArgs = 0; + int restArgs = 0; + + + // put the arguments in the correct places in the sh4Args array + if (argNum >= 1) + splitArgs(args, argNum, intArgs, floatArgs, restArgs, flags); + + if (intArgs < 4) { + sh4Args[intArgs] = (asDWORD) obj; + intArgs++; + } else { + sh4Args[4 + 8 + restArgs] = (asDWORD) obj; + restArgs++; + } + + + return sh4Func(intArgs << 2, floatArgs << 2, restArgs << 2, func); +} + +asDWORD GetReturnedFloat() +{ + asDWORD f; + + asm("fmov.s fr0, %0\n" : "=m"(f)); + + return f; +} + +// sizeof(double) == 4 with sh-elf-gcc (3.4.0) -m4 +// so this isn't really used... +asQWORD GetReturnedDouble() +{ + asQWORD d; + + asm("fmov dr0, %0\n" : "=m"(d)); + + return d; +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) +{ + // TODO: SH4 does not yet support THISCALL_OBJFIRST/LAST + + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + + asQWORD retQW = 0; + + void *func = (void*)sysFunc->func; + int paramSize = sysFunc->paramSize; + asDWORD *vftable; + + if( descr->returnType.IsObject() && !descr->returnType.IsReference() && !descr->returnType.IsObjectHandle() ) + { + sh4Args[AS_SH4_MAX_ARGS+1] = (asDWORD) retPointer; + } + + asASSERT(descr->parameterTypes.GetLength() <= 32); + + // mark all float arguments + int argBit = 1; + int hostFlags = 0; + int intArgs = 0; + for( asUINT a = 0; a < descr->parameterTypes.GetLength(); a++ ) { + if (descr->parameterTypes[a].IsFloatType()) { + hostFlags |= argBit; + } else intArgs++; + argBit <<= 1; + } + + asDWORD paramBuffer[64]; + if( sysFunc->takesObjByVal ) + { + paramSize = 0; + int spos = 0; + int dpos = 1; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else +#endif + { + // Copy the object's memory to the buffer + memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos++; + dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); + } + } + else + { + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + paramBuffer[dpos++] = args[spos++]; + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + } + // Keep a free location at the beginning + args = ¶mBuffer[1]; + } + + switch( callConv ) + { + case ICC_CDECL: + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL: + case ICC_STDCALL_RETURNINMEM: + retQW = CallCDeclFunction(args, paramSize<<2, (asDWORD)func, hostFlags); + break; + case ICC_THISCALL: + case ICC_THISCALL_RETURNINMEM: + retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); + break; + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + // Get virtual function table from the object pointer + vftable = *(asDWORD**)obj; + retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[asDWORD(func)>>2], hostFlags); + break; + case ICC_CDECL_OBJLAST: + case ICC_CDECL_OBJLAST_RETURNINMEM: + retQW = CallThisCallFunction_objLast(obj, args, paramSize<<2, (asDWORD)func, hostFlags); + break; + case ICC_CDECL_OBJFIRST: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + retQW = CallThisCallFunction(obj, args, paramSize<<2, (asDWORD)func, hostFlags); + break; + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_SH4 +#endif // AS_MAX_PORTABILITY + + diff --git a/angelscript/source/as_callfunc_x64_gcc.cpp b/angelscript/source/as_callfunc_x64_gcc.cpp new file mode 100644 index 0000000..ad6c27f --- /dev/null +++ b/angelscript/source/as_callfunc_x64_gcc.cpp @@ -0,0 +1,477 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +/* + * Implements the AMD64 calling convention for gcc-based 64bit Unices + * + * Author: Ionut "gargltk" Leonte + * + * Initial author: niteice + * + * Added support for functor methods by Jordi Oliveras Rovira in April, 2014. + */ + +// Useful references for the System V AMD64 ABI: +// http://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64/ +// http://math-atlas.sourceforge.net/devel/assembly/abi_sysV_amd64.pdf + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_X64_GCC + +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_context.h" + +BEGIN_AS_NAMESPACE + +enum argTypes { x64INTARG = 0, x64FLOATARG = 1 }; +typedef asQWORD ( *funcptr_t )( void ); + +#define X64_MAX_ARGS 32 +#define MAX_CALL_INT_REGISTERS 6 +#define MAX_CALL_SSE_REGISTERS 8 +#define X64_CALLSTACK_SIZE ( X64_MAX_ARGS + MAX_CALL_SSE_REGISTERS + 3 ) + +// Note to self: Always remember to inform the used registers on the clobber line, +// so that the gcc optimizer doesn't try to use them for other things + +static asQWORD __attribute__((noinline)) X64_CallFunction(const asQWORD *args, int cnt, funcptr_t func, asQWORD &retQW2, bool returnFloat) +{ + // Need to flag the variable as volatile so the compiler doesn't optimize out the variable + volatile asQWORD retQW1 = 0; + + // Reference: http://www.x86-64.org/documentation/abi.pdf + + __asm__ __volatile__ ( + + " movq %0, %%rcx \n" // rcx = cnt + " movq %1, %%r10 \n" // r10 = args + " movq %2, %%r11 \n" // r11 = func + + // Backup stack pointer in R15 that is guaranteed to maintain its value over function calls + " movq %%rsp, %%r15 \n" +#ifdef __OPTIMIZE__ + // Make sure the stack unwind logic knows we've backed up the stack pointer in register r15 + // This should only be done if any optimization is done. If no optimization (-O0) is used, + // then the compiler already backups the rsp before entering the inline assembler code + " .cfi_def_cfa_register r15 \n" +#endif + + // Skip the first 128 bytes on the stack frame, called "red zone", + // that might be used by the compiler to store temporary values + " sub $128, %%rsp \n" + + // Make sure the stack pointer will be aligned to 16 bytes when the function is called + " movq %%rcx, %%rdx \n" + " salq $3, %%rdx \n" + " movq %%rsp, %%rax \n" + " sub %%rdx, %%rax \n" + " and $15, %%rax \n" + " sub %%rax, %%rsp \n" + + // Push the stack parameters, i.e. the arguments that won't be loaded into registers + " movq %%rcx, %%rsi \n" + " testl %%esi, %%esi \n" + " jle endstack \n" + " subl $1, %%esi \n" + " xorl %%edx, %%edx \n" + " leaq 8(, %%rsi, 8), %%rcx \n" + "loopstack: \n" + " movq 112(%%r10, %%rdx), %%rax \n" + " pushq %%rax \n" + " addq $8, %%rdx \n" + " cmpq %%rcx, %%rdx \n" + " jne loopstack \n" + "endstack: \n" + + // Populate integer and floating point parameters + " movq %%r10, %%rax \n" + " mov (%%rax), %%rdi \n" + " mov 8(%%rax), %%rsi \n" + " mov 16(%%rax), %%rdx \n" + " mov 24(%%rax), %%rcx \n" + " mov 32(%%rax), %%r8 \n" + " mov 40(%%rax), %%r9 \n" + " add $48, %%rax \n" + " movsd (%%rax), %%xmm0 \n" + " movsd 8(%%rax), %%xmm1 \n" + " movsd 16(%%rax), %%xmm2 \n" + " movsd 24(%%rax), %%xmm3 \n" + " movsd 32(%%rax), %%xmm4 \n" + " movsd 40(%%rax), %%xmm5 \n" + " movsd 48(%%rax), %%xmm6 \n" + " movsd 56(%%rax), %%xmm7 \n" + + // Call the function + " call *%%r11 \n" + + // Restore stack pointer + " mov %%r15, %%rsp \n" +#ifdef __OPTIMIZE__ + // Inform the stack unwind logic that the stack pointer has been restored + // This should only be done if any optimization is done. If no optimization (-O0) is used, + // then the compiler already backups the rsp before entering the inline assembler code + " .cfi_def_cfa_register rsp \n" +#endif + + // Put return value in retQW1 and retQW2, using either RAX:RDX or XMM0:XMM1 depending on type of return value + " movl %5, %%ecx \n" + " testb %%cl, %%cl \n" + " je intret \n" + " lea %3, %%rax \n" + " movq %%xmm0, (%%rax) \n" + " lea %4, %%rdx \n" + " movq %%xmm1, (%%rdx) \n" + " jmp endcall \n" + "intret: \n" + " movq %%rax, %3 \n" + " movq %%rdx, %4 \n" + "endcall: \n" + + : : "g" ((asQWORD)cnt), "g" (args), "g" (func), "m" (retQW1), "m" (retQW2), "m" (returnFloat) + : "%xmm0", "%xmm1", "%xmm2", "%xmm3", "%xmm4", "%xmm5", "%xmm6", "%xmm7", + "%rdi", "%rsi", "%rax", "%rdx", "%rcx", "%r8", "%r9", "%r10", "%r11", "%r15"); + + return retQW1; +} + +// returns true if the given parameter is a 'variable argument' +static inline bool IsVariableArgument( asCDataType type ) +{ + return ( type.GetTokenType() == ttQuestion ) ? true : false; +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &retQW2, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + asQWORD retQW = 0; + asDWORD *stack_pointer = args; + funcptr_t *vftable = NULL; + int totalArgumentCount = 0; + int n = 0; + int param_post = 0; + int argIndex = 0; + funcptr_t func = (funcptr_t)sysFunc->func; + + if( sysFunc->hostReturnInMemory ) + { + // The return is made in memory + callConv++; + } + +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + // Determine the real function pointer in case of virtual method + if ( obj && ( callConv == ICC_VIRTUAL_THISCALL || callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) ) +#else + if ( obj && ( callConv == ICC_VIRTUAL_THISCALL || + callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) +#endif + { + vftable = *((funcptr_t**)obj); + func = vftable[FuncPtrToUInt(asFUNCTION_t(func)) >> 3]; + } + + // Determine the type of the arguments, and prepare the input array for the X64_CallFunction + asQWORD paramBuffer[X64_CALLSTACK_SIZE] = { 0 }; + asBYTE argsType[X64_CALLSTACK_SIZE] = { 0 }; + + switch ( callConv ) + { + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL_RETURNINMEM: + { + paramBuffer[0] = (asPWORD)retPointer; + argsType[0] = x64INTARG; + + argIndex = 1; + + break; + } +#ifndef AS_NO_THISCALL_FUNCTOR_METHOD + case ICC_THISCALL_OBJLAST: + case ICC_VIRTUAL_THISCALL_OBJLAST: + param_post = 2; +#endif + case ICC_THISCALL: + case ICC_VIRTUAL_THISCALL: + case ICC_CDECL_OBJFIRST: + { + paramBuffer[0] = (asPWORD)obj; + argsType[0] = x64INTARG; + + argIndex = 1; + + break; + } +#ifndef AS_NO_THISCALL_FUNCTOR_METHOD + case ICC_THISCALL_OBJLAST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + param_post = 2; +#endif + case ICC_THISCALL_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + { + paramBuffer[0] = (asPWORD)retPointer; + paramBuffer[1] = (asPWORD)obj; + argsType[0] = x64INTARG; + argsType[1] = x64INTARG; + + argIndex = 2; + + break; + } +#ifndef AS_NO_THISCALL_FUNCTOR_METHOD + case ICC_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + { + paramBuffer[0] = (asPWORD)obj; + paramBuffer[1] = (asPWORD)secondObject; + argsType[0] = x64INTARG; + argsType[1] = x64INTARG; + + argIndex = 2; + break; + } + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + { + paramBuffer[0] = (asPWORD)retPointer; + paramBuffer[1] = (asPWORD)obj; + paramBuffer[2] = (asPWORD)secondObject; + argsType[0] = x64INTARG; + argsType[1] = x64INTARG; + argsType[2] = x64INTARG; + + argIndex = 3; + break; + } +#endif + case ICC_CDECL_OBJLAST: + param_post = 1; + break; + case ICC_CDECL_OBJLAST_RETURNINMEM: + { + paramBuffer[0] = (asPWORD)retPointer; + argsType[0] = x64INTARG; + + argIndex = 1; + param_post = 1; + + break; + } + } + + int argumentCount = ( int )descr->parameterTypes.GetLength(); + for( int a = 0; a < argumentCount; ++a ) + { + const asCDataType &parmType = descr->parameterTypes[a]; + if( parmType.IsFloatType() && !parmType.IsReference() ) + { + argsType[argIndex] = x64FLOATARG; + memcpy(paramBuffer + argIndex, stack_pointer, sizeof(float)); + argIndex++; + stack_pointer++; + } + else if( parmType.IsDoubleType() && !parmType.IsReference() ) + { + argsType[argIndex] = x64FLOATARG; + memcpy(paramBuffer + argIndex, stack_pointer, sizeof(double)); + argIndex++; + stack_pointer += 2; + } + else if( IsVariableArgument( parmType ) ) + { + // The variable args are really two, one pointer and one type id + argsType[argIndex] = x64INTARG; + argsType[argIndex+1] = x64INTARG; + memcpy(paramBuffer + argIndex, stack_pointer, sizeof(void*)); + memcpy(paramBuffer + argIndex + 1, stack_pointer + 2, sizeof(asDWORD)); + argIndex += 2; + stack_pointer += 3; + } + else if( parmType.IsPrimitive() || + parmType.IsReference() || + parmType.IsObjectHandle() ) + { + argsType[argIndex] = x64INTARG; + if( parmType.GetSizeOnStackDWords() == 1 ) + { + memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asDWORD)); + stack_pointer++; + } + else + { + memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD)); + stack_pointer += 2; + } + argIndex++; + } + else + { + // An object is being passed by value + if( (parmType.GetTypeInfo()->flags & COMPLEX_MASK) || + parmType.GetSizeInMemoryDWords() > 4 ) + { + // Copy the address of the object + argsType[argIndex] = x64INTARG; + memcpy(paramBuffer + argIndex, stack_pointer, sizeof(asQWORD)); + argIndex++; + } + else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLINTS) || + (parmType.GetTypeInfo()->flags & asOBJ_APP_PRIMITIVE) ) + { + // Copy the value of the object + if( parmType.GetSizeInMemoryDWords() > 2 ) + { + argsType[argIndex] = x64INTARG; + argsType[argIndex+1] = x64INTARG; + memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); + argIndex += 2; + } + else + { + argsType[argIndex] = x64INTARG; + memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); + argIndex++; + } + // Delete the original memory + engine->CallFree(*(void**)stack_pointer); + } + else if( (parmType.GetTypeInfo()->flags & asOBJ_APP_CLASS_ALLFLOATS) || + (parmType.GetTypeInfo()->flags & asOBJ_APP_FLOAT) ) + { + // Copy the value of the object + if( parmType.GetSizeInMemoryDWords() > 2 ) + { + argsType[argIndex] = x64FLOATARG; + argsType[argIndex+1] = x64FLOATARG; + memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); + argIndex += 2; + } + else + { + argsType[argIndex] = x64FLOATARG; + memcpy(paramBuffer + argIndex, *(asDWORD**)stack_pointer, parmType.GetSizeInMemoryBytes()); + argIndex++; + } + // Delete the original memory + engine->CallFree(*(void**)stack_pointer); + } + stack_pointer += 2; + } + } + + // For the CDECL_OBJ_LAST calling convention we need to add the object pointer as the last argument + if( param_post ) + { +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + paramBuffer[argIndex] = (asPWORD)obj; +#else + paramBuffer[argIndex] = (asPWORD)(param_post > 1 ? secondObject : obj); +#endif + argsType[argIndex] = x64INTARG; + argIndex++; + } + + totalArgumentCount = argIndex; + + /* + * Q: WTF is going on here !? + * + * A: The idea is to pre-arange the parameters so that X64_CallFunction() can do + * it's little magic which must work regardless of how the compiler decides to + * allocate registers. Basically: + * - the first MAX_CALL_INT_REGISTERS entries in tempBuff will + * contain the values/types of the x64INTARG parameters - that is the ones who + * go into the registers. If the function has less then MAX_CALL_INT_REGISTERS + * integer parameters then the last entries will be set to 0 + * - the next MAX_CALL_SSE_REGISTERS entries will contain the float/double arguments + * that go into the floating point registers. If the function has less than + * MAX_CALL_SSE_REGISTERS floating point parameters then the last entries will + * be set to 0 + * - index MAX_CALL_INT_REGISTERS + MAX_CALL_SSE_REGISTERS marks the start of the + * parameters which will get passed on the stack. These are added to the array + * in reverse order so that X64_CallFunction() can simply push them to the stack + * without the need to perform further tests + */ + asQWORD tempBuff[X64_CALLSTACK_SIZE] = { 0 }; + asBYTE argsSet[X64_CALLSTACK_SIZE] = { 0 }; + int used_int_regs = 0; + int used_sse_regs = 0; + int used_stack_args = 0; + int idx = 0; + for ( n = 0; ( n < totalArgumentCount ) && ( used_int_regs < MAX_CALL_INT_REGISTERS ); n++ ) + { + if ( argsType[n] == x64INTARG ) + { + argsSet[n] = 1; + tempBuff[idx++] = paramBuffer[n]; + used_int_regs++; + } + } + idx = MAX_CALL_INT_REGISTERS; + for ( n = 0; ( n < totalArgumentCount ) && ( used_sse_regs < MAX_CALL_SSE_REGISTERS ); n++ ) + { + if ( argsType[n] == x64FLOATARG ) + { + argsSet[n] = 1; + tempBuff[idx++] = paramBuffer[n]; + used_sse_regs++; + } + } + idx = MAX_CALL_INT_REGISTERS + MAX_CALL_SSE_REGISTERS; + for ( n = totalArgumentCount - 1; n >= 0; n-- ) + { + if ( !argsSet[n] ) + { + tempBuff[idx++] = paramBuffer[n]; + used_stack_args++; + } + } + + retQW = X64_CallFunction( tempBuff, used_stack_args, func, retQW2, sysFunc->hostReturnFloat ); + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_X64_GCC +#endif // AS_MAX_PORTABILITY + diff --git a/angelscript/source/as_callfunc_x64_mingw.cpp b/angelscript/source/as_callfunc_x64_mingw.cpp new file mode 100644 index 0000000..1c5bdb5 --- /dev/null +++ b/angelscript/source/as_callfunc_x64_mingw.cpp @@ -0,0 +1,348 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +// +// This code was adapted from as_callfunc_x64_msvc by _Vicious_ on August 20th, 2011. +// +// Added support for functor methods by Jordi Oliveras Rovira in April, 2014. +// + +#include + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_X64_MINGW + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_context.h" + +BEGIN_AS_NAMESPACE + +static asQWORD __attribute__((noinline)) CallX64(const asQWORD *args, const asQWORD *floatArgs, const int paramSize, asQWORD func) +{ + volatile asQWORD ret = 0; + + __asm__ __volatile__ ( + "# Move the parameters into registers before the rsp is modified\n" + "mov %1, %%r10\n" // r10 = args + "mov %2, %%r11\n" // r11 = floatArgs + "xor %%r12, %%r12\n" + "mov %3, %%r12d\n" + "mov %4, %%r14\n" // r14 = func + + "# Store the stack pointer in r15 since it is guaranteed not to change over a function call\n" + "mov %%rsp, %%r15\n" + + "# Allocate space on the stack for the arguments\n" + "# Make room for at least 4 arguments even if there are less. When\n" + "# the compiler does optimizations for speed it may use these for \n" + "# temporary storage.\n" + "mov %%r12, %%rdi\n" + "add $32,%%edi\n" + + "# Make sure the stack pointer is 16byte aligned so the\n" + "# whole program optimizations will work properly\n" + "# TODO: runtime optimize: Can this be optimized with fewer instructions?\n" + "mov %%rsp,%%rsi\n" + "sub %%rdi,%%rsi\n" + "and $0x8,%%rsi\n" + "add %%rsi,%%rdi\n" + "sub %%rdi,%%rsp\n" + + "# Jump straight to calling the function if no parameters\n" + "cmp $0,%%r12 # Compare paramSize with 0\n" + "je callfunc # Jump to call funtion if (paramSize == 0)\n" + + "# Copy arguments from script stack to application stack\n" + "# Order is (first to last):\n" + "# rcx, rdx, r8, r9 & everything else goes on stack\n" + "movq (%%r10),%%rcx\n" + "movq 8(%%r10),%%rdx\n" + "movq 16(%%r10),%%r8\n" + "movq 24(%%r10),%%r9\n" + + "# Negate the 4 params from the size to be copied\n" + "sub $32,%%r12d\n" + "js copyfloat # Jump if negative result\n" + "jz copyfloat # Jump if zero result\n" + + "# Now copy all remaining params onto stack allowing space for first four\n" + "# params to be flushed back to the stack if required by the callee.\n" + "add $32,%%r10 # Position input pointer 4 args ahead\n" + "mov %%rsp,%%r13 # Put the stack pointer into r13\n" + "add $32,%%r13 # Leave space for first 4 args on stack\n" + + "copyoverflow:\n" + "movq (%%r10),%%rdi # Read param from source stack into rdi\n" + "movq %%rdi,(%%r13) # Copy param to real stack\n" + "add $8,%%r13 # Move virtual stack pointer\n" + "add $8,%%r10 # Move source stack pointer\n" + "sub $8,%%r12d # Decrement remaining count\n" + "jnz copyoverflow # Continue if more params\n" + + "copyfloat:\n" + "# Any floating point params?\n" + "cmp $0,%%r11\n" + "je callfunc\n" + + "movlpd (%%r11),%%xmm0\n" + "movlpd 8(%%r11),%%xmm1\n" + "movlpd 16(%%r11),%%xmm2\n" + "movlpd 24(%%r11),%%xmm3\n" + + "callfunc:\n" + "call *%%r14\n" + + "# restore stack pointer\n" + "mov %%r15, %%rsp\n" + + "lea %0, %%rbx\n" // Load the address of the ret variable into rbx + "movq %%rax,(%%rbx)\n" // Copy the returned value into the ret variable + + : // no output + : "m" (ret), "r" (args), "r" (floatArgs), "r" (paramSize), "r" (func) + : "rdi", "rsi", "rsp", "rbx", "r10", "r11", "%r12", "r13", "r14", "r15" + ); + + return ret; +} + +static asDWORD GetReturnedFloat() +{ + volatile asDWORD ret = 0; + + __asm__ __volatile__ ( + "lea %0, %%rax\n" + "movss %%xmm0, (%%rax)" + : /* no output */ + : "m" (ret) + : "%rax" + ); + + return ret; +} + +static asQWORD GetReturnedDouble() +{ + volatile asQWORD ret = 0; + + __asm__ __volatile__ ( + "lea %0, %%rax\n" + "movlpd %%xmm0, (%%rax)" + : /* no optput */ + : "m" (ret) + : "%rax" + ); + + return ret; +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + + asQWORD retQW = 0; + void *func = (void*)sysFunc->func; + asUINT paramSize = 0; // QWords + void **vftable; + + asQWORD allArgBuffer[64]; + asQWORD floatArgBuffer[4]; + + int callConv = sysFunc->callConv; + + if( sysFunc->hostReturnInMemory ) + { + // The return is made in memory + callConv++; + + // Set the return pointer as the first argument + allArgBuffer[paramSize++] = (asQWORD)retPointer; + } + +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + if( callConv == ICC_THISCALL || + callConv == ICC_THISCALL_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL || + callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) +#else + // Optimization to avoid check 12 values (all ICC_ that contains THISCALL) + if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) || + (callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) +#endif + { + // Add the object pointer as the first parameter + allArgBuffer[paramSize++] = (asQWORD)obj; + } + + if( callConv == ICC_CDECL_OBJFIRST || + callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ) + { + // Add the object pointer as the first parameter + allArgBuffer[paramSize++] = (asQWORD)obj; + } +#ifndef AS_NO_THISCALL_FUNCTOR_METHOD + else if( callConv == ICC_THISCALL_OBJFIRST || + callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) + { + // Add the object pointer as the first parameter + allArgBuffer[paramSize++] = (asQWORD)secondObject; + } +#endif + +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + if( callConv == ICC_VIRTUAL_THISCALL || + callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM ) +#else + if( callConv == ICC_VIRTUAL_THISCALL || + callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) +#endif + { + // Get the true function pointer from the virtual function table + vftable = *(void***)obj; + func = vftable[asPWORD(func)>>3]; + } + + // Move the arguments to the buffer + asUINT dpos = paramSize; + asUINT spos = 0; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) + { + if( descr->parameterTypes[n].GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE || + (descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK) ) + { + allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; + spos += AS_PTR_SIZE; + paramSize++; + } + else + { + // Copy the object's memory to the buffer + memcpy(&allArgBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos += AS_PTR_SIZE; + asUINT dwords = descr->parameterTypes[n].GetSizeInMemoryDWords(); + asUINT qwords = (dwords >> 1) + (dwords & 1); + dpos += qwords; + paramSize += qwords; + } + } + else if( descr->parameterTypes[n].GetTokenType() == ttQuestion ) + { + // Copy the reference and the type id + allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; + spos += 2; + allArgBuffer[dpos++] = args[spos++]; + paramSize += 2; + } + else + { + // Copy the value directly + asUINT dwords = descr->parameterTypes[n].GetSizeOnStackDWords(); + if( dwords > 1 ) + { + allArgBuffer[dpos] = *(asQWORD*)&args[spos]; + + // Double arguments are moved to a separate buffer in order to be placed in the XMM registers, + // though this is only done for first 4 arguments, the rest are placed on the stack + if( paramSize < 4 && descr->parameterTypes[n].IsDoubleType() ) + floatArgBuffer[dpos] = *(asQWORD*)&args[spos]; + + dpos++; + spos += 2; + } + else + { + allArgBuffer[dpos] = args[spos]; + + // Float arguments are moved to a separate buffer in order to be placed in the XMM registers, + // though this is only done for first 4 arguments, the rest are placed on the stack + if( paramSize < 4 && descr->parameterTypes[n].IsFloatType() ) + floatArgBuffer[dpos] = args[spos]; + + dpos++; + spos++; + } + + paramSize++; + } + } + + if( callConv == ICC_CDECL_OBJLAST || + callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last parameter + allArgBuffer[paramSize++] = (asQWORD)obj; + } +#ifndef AS_NO_THISCALL_FUNCTOR_METHOD + else if( callConv == ICC_THISCALL_OBJLAST || + callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last parameter + allArgBuffer[paramSize++] = (asQWORD)secondObject; + } +#endif + + retQW = CallX64(allArgBuffer, floatArgBuffer, paramSize*8, (asPWORD)func); + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_X64_MSVC +#endif // AS_MAX_PORTABILITY + + diff --git a/angelscript/source/as_callfunc_x64_msvc.cpp b/angelscript/source/as_callfunc_x64_msvc.cpp new file mode 100644 index 0000000..8af5adc --- /dev/null +++ b/angelscript/source/as_callfunc_x64_msvc.cpp @@ -0,0 +1,217 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +// +// Added support for thiscall methods by Jordi Oliveras Rovira in April, 2014. +// + +#include + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_X64_MSVC + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_context.h" + +BEGIN_AS_NAMESPACE + +// These functions are implemented in as_callfunc_x64_msvc.asm +extern "C" asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int paramSize, asQWORD func); +extern "C" asDWORD GetReturnedFloat(); +extern "C" asQWORD GetReturnedDouble(); + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + + asQWORD retQW = 0; + void *func = (void*)sysFunc->func; + asUINT paramSize = 0; // QWords + void **vftable; + + asQWORD allArgBuffer[64]; + asQWORD floatArgBuffer[4]; + + int callConv = sysFunc->callConv; + + // Optimization to avoid check 12 values (all ICC_ that contains THISCALL) + if( (callConv >= ICC_THISCALL && callConv <= ICC_VIRTUAL_THISCALL_RETURNINMEM) || + (callConv >= ICC_THISCALL_OBJLAST && callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) + { + // Add the object pointer as the first parameter + allArgBuffer[paramSize++] = (asQWORD)obj; + } + + if( sysFunc->hostReturnInMemory ) + { + // The return is made in memory + callConv++; + + // Set the return pointer as the first argument + allArgBuffer[paramSize++] = (asQWORD)retPointer; + } + + if( callConv == ICC_CDECL_OBJFIRST || + callConv == ICC_CDECL_OBJFIRST_RETURNINMEM ) + { + // Add the object pointer as the first parameter + allArgBuffer[paramSize++] = (asQWORD)obj; + } + else if( callConv == ICC_THISCALL_OBJFIRST || + callConv == ICC_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM ) + { + // Add the object pointer as the first parameter + allArgBuffer[paramSize++] = (asQWORD)secondObject; + } + + if( callConv == ICC_VIRTUAL_THISCALL || + callConv == ICC_VIRTUAL_THISCALL_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST || + callConv == ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Get the true function pointer from the virtual function table + vftable = *(void***)obj; + func = vftable[asPWORD(func)>>2]; + } + + // Move the arguments to the buffer + asUINT dpos = paramSize; + asUINT spos = 0; + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + asCDataType &dt = descr->parameterTypes[n]; + if( dt.IsObject() && !dt.IsObjectHandle() && !dt.IsReference() ) + { + if( dt.GetSizeInMemoryDWords() >= AS_LARGE_OBJ_MIN_SIZE || + (dt.GetTypeInfo()->flags & COMPLEX_MASK) ) + { + allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; + spos += AS_PTR_SIZE; + paramSize++; + } + else + { + // Copy the object's memory to the buffer + memcpy(&allArgBuffer[dpos], *(void**)(args+spos), dt.GetSizeInMemoryBytes()); + + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos += AS_PTR_SIZE; + asUINT dwords = dt.GetSizeInMemoryDWords(); + asUINT qwords = (dwords >> 1) + (dwords & 1); + dpos += qwords; + paramSize += qwords; + } + } + else if( dt.GetTokenType() == ttQuestion ) + { + // Copy the reference and the type id + allArgBuffer[dpos++] = *(asQWORD*)&args[spos]; + spos += 2; + allArgBuffer[dpos++] = args[spos++]; + paramSize += 2; + } + else + { + // Copy the value directly + asUINT dwords = dt.GetSizeOnStackDWords(); + if( dwords > 1 ) + { + allArgBuffer[dpos] = *(asQWORD*)&args[spos]; + + // Double arguments are moved to a separate buffer in order to be placed in the XMM registers, + // though this is only done for first 4 arguments, the rest are placed on the stack + if( paramSize < 4 && dt.IsDoubleType() ) + floatArgBuffer[dpos] = *(asQWORD*)&args[spos]; + + dpos++; + spos += 2; + } + else + { + allArgBuffer[dpos] = args[spos]; + + // Float arguments are moved to a separate buffer in order to be placed in the XMM registers, + // though this is only done for first 4 arguments, the rest are placed on the stack + if( paramSize < 4 && dt.IsFloatType() ) + floatArgBuffer[dpos] = args[spos]; + + dpos++; + spos++; + } + + paramSize++; + } + } + + if( callConv == ICC_CDECL_OBJLAST || + callConv == ICC_CDECL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last parameter + allArgBuffer[paramSize++] = (asQWORD)obj; + } + else if( callConv == ICC_THISCALL_OBJLAST || + callConv == ICC_THISCALL_OBJLAST_RETURNINMEM || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST || + callConv == ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM ) + { + // Add the object pointer as the last parameter + allArgBuffer[paramSize++] = (asQWORD)secondObject; + } + + retQW = CallX64(allArgBuffer, floatArgBuffer, paramSize*8, (asPWORD)func); + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_X64_MSVC +#endif // AS_MAX_PORTABILITY + + diff --git a/angelscript/source/as_callfunc_x64_msvc_asm.asm b/angelscript/source/as_callfunc_x64_msvc_asm.asm new file mode 100644 index 0000000..f4cd1ac --- /dev/null +++ b/angelscript/source/as_callfunc_x64_msvc_asm.asm @@ -0,0 +1,208 @@ +; +; AngelCode Scripting Library +; Copyright (c) 2003-2011 Andreas Jonsson +; +; This software is provided 'as-is', without any express or implied +; warranty. In no event will the authors be held liable for any +; damages arising from the use of this software. +; +; Permission is granted to anyone to use this software for any +; purpose, including commercial applications, and to alter it and +; redistribute it freely, subject to the following restrictions: +; +; 1. The origin of this software must not be misrepresented; you +; must not claim that you wrote the original software. If you use +; this software in a product, an acknowledgment in the product +; documentation would be appreciated but is not required. +; +; 2. Altered source versions must be plainly marked as such, and +; must not be misrepresented as being the original software. +; +; 3. This notice may not be removed or altered from any source +; distribution. +; +; The original version of this library can be located at: +; http://www.angelcode.com/angelscript/ +; +; Andreas Jonsson +; andreas@angelcode.com +; + +.code +PUBLIC CallX64 + +; asQWORD CallX64(const asQWORD *args, const asQWORD *floatArgs, int paramSize, asQWORD func) + +CallX64 PROC FRAME + + ; PROLOG + + ; We must save preserved registers that are used + ; TODO: No need to save unused registers + + push rbp +.pushreg rbp + push rsi +.pushreg rsi + push r11 +.pushreg r11 + push rdi +.pushreg rdi + push r12 +.pushreg r12 + push r13 +.pushreg r13 + push r14 +.pushreg r14 + push r15 +.pushreg r15 + push rbx +.pushreg rbx + sub rsp, 050h +.allocstack 050h + mov rbp, rsp +.setframe rbp, 0 +.endprolog + + ; Move function param to non-scratch register + mov r14, r9 ; r14 = function + + ; Allocate space on the stack for the arguments + ; Make room for at least 4 arguments even if there are less. When + ; the compiler does optimizations for speed it may use these for + ; temporary storage. + mov rdi, r8 + add rdi, 32 + + ; Make sure the stack pointer is 16byte aligned so the + ; whole program optimizations will work properly + ; TODO: optimize: Can this be optimized with fewer instructions? + mov rsi, rsp + sub rsi, rdi + and rsi, 8h + add rdi, rsi + sub rsp, rdi + + ; Jump straight to calling the function if no parameters + cmp r8d, 0 ; Compare paramSize with 0 + je callfunc ; Jump to call funtion if (paramSize == 0) + + ; Move params to non-scratch registers + mov rsi, rcx ; rsi = pArgs + mov r11, rdx ; r11 = pFloatArgs (can be NULL) + mov r12d, r8d ; r12 = paramSize + + ; Copy arguments from script stack to application stack + ; Order is (first to last): + ; rcx, rdx, r8, r9 & everything else goes on stack + mov rcx, qword ptr [rsi] + mov rdx, qword ptr [rsi + 8] + mov r8, qword ptr [rsi + 16] + mov r9, qword ptr [rsi + 24] + + ; Negate the 4 params from the size to be copied + sub r12d, 32 + js copyfloat ; Jump if negative result + jz copyfloat ; Jump if zero result + + ; Now copy all remaining params onto stack allowing space for first four + ; params to be flushed back to the stack if required by the callee. + + add rsi, 32 ; Position input pointer 4 args ahead + mov r13, rsp ; Put the stack pointer into r13 + add r13, 32 ; Leave space for first 4 args on stack + +copyoverflow: + mov r15, qword ptr [rsi] ; Read param from source stack into r15 + mov qword ptr [r13], r15 ; Copy param to real stack + add r13, 8 ; Move virtual stack pointer + add rsi, 8 ; Move source stack pointer + sub r12d, 8 ; Decrement remaining count + jnz copyoverflow ; Continue if more params + +copyfloat: + ; Any floating point params? + cmp r11, 0 + je callfunc + + movlpd xmm0, qword ptr [r11] + movlpd xmm1, qword ptr [r11 + 8] + movlpd xmm2, qword ptr [r11 + 16] + movlpd xmm3, qword ptr [r11 + 24] + +callfunc: + + ; Call function + call r14 + + ; Restore the stack + mov rsp, rbp + + ; EPILOG: Restore stack & preserved registers + add rsp, 050h + pop rbx + pop r15 + pop r14 + pop r13 + pop r12 + pop rdi + pop r11 + pop rsi + pop rbp + + ; return value in RAX + ret + +CallX64 ENDP + + +PUBLIC GetReturnedFloat + +; asDWORD GetReturnedFloat() + +GetReturnedFloat PROC FRAME + + ; PROLOG: Store registers and allocate stack space + + sub rsp, 8 ; We'll need 4 bytes for temporary storage (8 bytes with alignment) +.allocstack 8 +.endprolog + + ; Move the float value from the XMM0 register to RAX register + movss dword ptr [rsp], xmm0 + mov eax, dword ptr [rsp] + + ; EPILOG: Clean up + + add rsp, 8 + + ret + +GetReturnedFloat ENDP + + +PUBLIC GetReturnedDouble + +; asDWORD GetReturnedDouble() + +GetReturnedDouble PROC FRAME + + ; PROLOG: Store registers and allocate stack space + + sub rsp, 8 ; We'll need 8 bytes for temporary storage +.allocstack 8 +.endprolog + + ; Move the double value from the XMM0 register to the RAX register + movlpd qword ptr [rsp], xmm0 + mov rax, qword ptr [rsp] + + ; EPILOG: Clean up + + add rsp, 8 + + ret + +GetReturnedDouble ENDP + +END \ No newline at end of file diff --git a/angelscript/source/as_callfunc_x86.cpp b/angelscript/source/as_callfunc_x86.cpp new file mode 100644 index 0000000..551f41a --- /dev/null +++ b/angelscript/source/as_callfunc_x86.cpp @@ -0,0 +1,1514 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2018 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_x86.cpp +// +// These functions handle the actual calling of system functions +// +// Added support for functor methods by Jordi Oliveras Rovira in April, 2014. +// + + + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#ifdef AS_X86 + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +BEGIN_AS_NAMESPACE + +// +// With some compile level optimizations the functions don't clear the FPU +// stack themselves. So we have to do it as part of calling the native functions, +// as the compiler will not be able to predict when it is supposed to do it by +// itself due to the dynamic nature of scripts +// +// - fninit clears the FPU stack and the FPU control word +// - emms only clears the FPU stack, while preserving the FPU control word +// +// By default I use fninit as it seems to be what works for most people, +// but some may find it necessary to define this as emms instead. +// +// TODO: Figure out when one or the other must be used, and a way to +// configure this automatically in as_config.h +// +#ifndef CLEAR_FPU_STACK +#define CLEAR_FPU_STACK fninit +#endif + +// These macros are just to allow me to use the above macro in the GNUC style inline assembly +#define _S(x) _TOSTRING(x) +#define _TOSTRING(x) #x + +// Prototypes +asQWORD CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func); +asQWORD CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func); +asQWORD CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func); +asQWORD CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr); +asQWORD CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr); +asQWORD CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr); +asQWORD CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func); +asQWORD CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func); +asQWORD CallThisCallFunctionRetByRef(const void *, const asDWORD *, int, asFUNCTION_t, void *retPtr); + +asDWORD GetReturnedFloat(); +asQWORD GetReturnedDouble(); + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void *secondObject) +{ + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + + asQWORD retQW = 0; + + // Prepare the parameters + asDWORD paramBuffer[64]; + int callConv = sysFunc->callConv; + + // Changed because need check for ICC_THISCALL_OBJFIRST or + // ICC_THISCALL_OBJLAST if sysFunc->takesObjByVal (avoid copy code) + // Check if is THISCALL_OBJ* calling convention (in this case needs to add secondObject pointer into stack). + bool isThisCallMethod = callConv >= ICC_THISCALL_OBJLAST; + int paramSize = isThisCallMethod || sysFunc->takesObjByVal ? 0 : sysFunc->paramSize; + + int dpos = 1; + + if( isThisCallMethod && + (callConv >= ICC_THISCALL_OBJFIRST && + callConv <= ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM) ) + { + // Add the object pointer as the first parameter + paramBuffer[dpos++] = (asDWORD)secondObject; + paramSize++; + } + + if( sysFunc->takesObjByVal || isThisCallMethod ) + { + int spos = 0; + + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + if( descr->parameterTypes[n].IsObject() && !descr->parameterTypes[n].IsObjectHandle() && !descr->parameterTypes[n].IsReference() ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else +#endif + { + // Copy the object's memory to the buffer + // TODO: bug: Must call the object's copy constructor instead of doing a memcpy, + // as the object may hold a pointer to itself. It's not enough to + // change only this memcpy as the assembler routine also makes a copy + // of paramBuffer to the final stack location. To avoid the second + // copy the C++ routine should point paramBuffer to the final stack + // position and copy the values directly to that location. The assembler + // routines then don't need to copy anything, and will just be + // responsible for setting up the registers and the stack frame appropriately. + memcpy(¶mBuffer[dpos], *(void**)(args+spos), descr->parameterTypes[n].GetSizeInMemoryBytes()); + + // Delete the original memory + engine->CallFree(*(char**)(args+spos)); + spos++; + dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); + } + } + else + { + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + paramBuffer[dpos++] = args[spos++]; + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + } + // Keep a free location at the beginning + args = ¶mBuffer[1]; + } + + if( isThisCallMethod && + (callConv >= ICC_THISCALL_OBJLAST && + callConv <= ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM) ) + { + // Add the object pointer as the last parameter + paramBuffer[dpos++] = (asDWORD)secondObject; + paramSize++; + } + + // Make the actual call + asFUNCTION_t func = sysFunc->func; + if( sysFunc->hostReturnInMemory ) + callConv++; + + switch( callConv ) + { + case ICC_CDECL: + retQW = CallCDeclFunction(args, paramSize<<2, func); + break; + + case ICC_CDECL_RETURNINMEM: + retQW = CallCDeclFunctionRetByRef(args, paramSize<<2, func, retPointer); + break; + + case ICC_STDCALL: + retQW = CallSTDCallFunction(args, paramSize<<2, func); + break; + + case ICC_STDCALL_RETURNINMEM: + // Push the return pointer on the stack + paramSize++; + args--; + *(asPWORD*)args = (size_t)retPointer; + + retQW = CallSTDCallFunction(args, paramSize<<2, func); + break; + + case ICC_THISCALL: + case ICC_THISCALL_OBJFIRST: + case ICC_THISCALL_OBJLAST: + retQW = CallThisCallFunction(obj, args, paramSize<<2, func); + break; + + case ICC_THISCALL_RETURNINMEM: + case ICC_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_THISCALL_OBJLAST_RETURNINMEM: + retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, func, retPointer); + break; + + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_OBJFIRST: + case ICC_VIRTUAL_THISCALL_OBJLAST: + { + // Get virtual function table from the object pointer + asFUNCTION_t *vftable = *(asFUNCTION_t**)obj; + retQW = CallThisCallFunction(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2]); + } + break; + + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJFIRST_RETURNINMEM: + case ICC_VIRTUAL_THISCALL_OBJLAST_RETURNINMEM: + { + // Get virtual function table from the object pointer + asFUNCTION_t *vftable = *(asFUNCTION_t**)obj; + retQW = CallThisCallFunctionRetByRef(obj, args, paramSize<<2, vftable[FuncPtrToUInt(func)>>2], retPointer); + } + break; + + case ICC_CDECL_OBJLAST: + retQW = CallCDeclFunctionObjLast(obj, args, paramSize<<2, func); + break; + + case ICC_CDECL_OBJLAST_RETURNINMEM: + // Call the system object method as a cdecl with the obj ref as the last parameter + retQW = CallCDeclFunctionRetByRefObjLast(obj, args, paramSize<<2, func, retPointer); + break; + + case ICC_CDECL_OBJFIRST: + // Call the system object method as a cdecl with the obj ref as the first parameter + retQW = CallCDeclFunctionObjFirst(obj, args, paramSize<<2, func); + break; + + case ICC_CDECL_OBJFIRST_RETURNINMEM: + // Call the system object method as a cdecl with the obj ref as the first parameter + retQW = CallCDeclFunctionRetByRefObjFirst(obj, args, paramSize<<2, func, retPointer); + break; + + default: + context->SetInternalException(TXT_INVALID_CALLING_CONVENTION); + } + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + + return retQW; +} + +// On GCC we need to prevent the compiler from inlining these assembler routines when +// optimizing for speed (-O3), as the loop labels get duplicated which cause compile errors. + +#ifdef __GNUC__ + #define NOINLINE __attribute ((__noinline__)) +#else + #define NOINLINE +#endif + + +asQWORD NOINLINE CallCDeclFunction(const asDWORD *args, int paramSize, asFUNCTION_t func) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + + // Call function + call [func] + + // Pop arguments from stack + add esp, paramSize + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + // It is not possible to rely on ESP or BSP to refer to variables or arguments on the stack + // depending on compiler settings BSP may not even be used, and the ESP is not always on the + // same offset from the local variables. Because the code adjusts the ESP register it is not + // possible to inform the arguments through symbolic names below. + + // It's not also not possible to rely on the memory layout of the function arguments, because + // on some compiler versions and settings the arguments may be copied to local variables with a + // different ordering before they are accessed by the rest of the code. + + // I'm copying the arguments into this array where I know the exact memory layout. The address + // of this array will then be passed to the inline asm in the EDX register. + volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + + asm __volatile__( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 4(%%ebx), %%eax \n" // paramSize + "addl $4, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + // Copy all arguments to the stack and call the function + "movl 4(%%ebx), %%ecx \n" // paramSize + "movl 0(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy \n" + "copyloop: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop \n" + "endcopy: \n" + "call *8(%%ebx) \n" + "addl 4(%%ebx), %%esp \n" // pop arguments + + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + +asQWORD NOINLINE CallCDeclFunctionObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Push the object pointer as the last argument to the function + push obj + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + + // Call function + call [func] + + // Pop arguments from stack + add esp, paramSize + add esp, 4 + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 8(%%ebx), %%eax \n" // paramSize + "addl $8, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "pushl 0(%%ebx) \n" // obj + "movl 8(%%ebx), %%ecx \n" // paramSize + "movl 4(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy8 \n" + "copyloop8: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop8 \n" + "endcopy8: \n" + "call *12(%%ebx) \n" + "addl 8(%%ebx), %%esp \n" // pop arguments + "addl $4, %%esp \n" // pop obj + + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + +asQWORD NOINLINE CallCDeclFunctionObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + + // push object as first parameter + push obj + + // Call function + call [func] + + // Pop arguments from stack + add esp, paramSize + add esp, 4 + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 8(%%ebx), %%eax \n" // paramSize + "addl $8, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "movl 8(%%ebx), %%ecx \n" // paramSize + "movl 4(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy6 \n" + "copyloop6: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop6 \n" + "endcopy6: \n" + "pushl 0(%%ebx) \n" // push obj + "call *12(%%ebx) \n" + "addl 8(%%ebx), %%esp \n" // pop arguments + "addl $4, %%esp \n" // pop obj + + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + +asQWORD NOINLINE CallCDeclFunctionRetByRefObjFirst(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + + // Push the object pointer + push obj + + // Push the return pointer + push retPtr; + + // Call function + call [func] + + // Pop arguments from stack + add esp, paramSize + +#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER + // Pop the return pointer + add esp, 8 +#else + add esp, 4 +#endif + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 8(%%ebx), %%eax \n" // paramSize + "addl $12, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "movl 8(%%ebx), %%ecx \n" // paramSize + "movl 4(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy5 \n" + "copyloop5: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop5 \n" + "endcopy5: \n" + "pushl 0(%%ebx) \n" // push object first + "pushl 16(%%ebx) \n" // retPtr + "call *12(%%ebx) \n" // func + "addl 8(%%ebx), %%esp \n" // pop arguments +#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER + "addl $8, %%esp \n" // Pop the return pointer and object pointer +#else + "addl $4, %%esp \n" // Pop the object pointer +#endif + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); +#endif + + return retQW; +} + +asQWORD NOINLINE CallCDeclFunctionRetByRef(const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + + // Push the return pointer + push retPtr; + + // Call function + call [func] + + // Pop arguments from stack + add esp, paramSize + +#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER + // Pop the return pointer + add esp, 4 +#endif + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + + // return value in EAX or EAX:EDX + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 4(%%ebx), %%eax \n" // paramSize + "addl $8, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "movl 4(%%ebx), %%ecx \n" // paramSize + "movl 0(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy7 \n" + "copyloop7: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop7 \n" + "endcopy7: \n" + "pushl 12(%%ebx) \n" // retPtr + "call *8(%%ebx) \n" // func + "addl 4(%%ebx), %%esp \n" // pop arguments +#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER + "addl $4, %%esp \n" // Pop the return pointer +#endif + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + +asQWORD NOINLINE CallCDeclFunctionRetByRefObjLast(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + push obj + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + + // Push the return pointer + push retPtr; + + // Call function + call [func] + + // Pop arguments from stack + add esp, paramSize + add esp, 4 + +#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER + // Pop the return pointer + add esp, 4 +#endif + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 8(%%ebx), %%eax \n" // paramSize + "addl $12, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "pushl 0(%%ebx) \n" // obj + "movl 8(%%ebx), %%ecx \n" // paramSize + "movl 4(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy4 \n" + "copyloop4: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop4 \n" + "endcopy4: \n" + "pushl 16(%%ebx) \n" // retPtr + "call *12(%%ebx) \n" // func + "addl 8(%%ebx), %%esp \n" // pop arguments +#ifndef CALLEE_POPS_HIDDEN_RETURN_POINTER + "addl $8, %%esp \n" // Pop the return pointer and object pointer +#else + "addl $4, %%esp \n" // Pop the object pointer +#endif + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + +asQWORD NOINLINE CallSTDCallFunction(const asDWORD *args, int paramSize, asFUNCTION_t func) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + + // Call function + call [func] + + // The callee already removed parameters from the stack + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 4(%%ebx), %%eax \n" // paramSize + "addl $4, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "movl 4(%%ebx), %%ecx \n" // paramSize + "movl 0(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy2 \n" + "copyloop2: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop2 \n" + "endcopy2: \n" + "call *8(%%ebx) \n" // callee pops the arguments + + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + + +asQWORD NOINLINE CallThisCallFunction(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + // Push the object pointer on the stack + push obj +#else + // Move object pointer to ECX + mov ecx, obj +#endif + + // Call function + call [func] + +#ifndef THISCALL_CALLEE_POPS_ARGUMENTS + // Pop arguments + add esp, paramSize +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + // Pop object pointer + add esp, 4 +#endif +#endif + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 8(%%ebx), %%eax \n" // paramSize + "addl $8, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "movl 8(%%ebx), %%ecx \n" // paramSize + "movl 4(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push all arguments on the stack + "cmp $0, %%ecx \n" + "je endcopy1 \n" + "copyloop1: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop1 \n" + "endcopy1: \n" + "movl 0(%%ebx), %%ecx \n" // move obj into ECX +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + "pushl %%ecx \n" // push obj on the stack +#endif + "call *12(%%ebx) \n" +#ifndef THISCALL_CALLEE_POPS_ARGUMENTS + "addl 8(%%ebx), %%esp \n" // pop arguments +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + "addl $4, %%esp \n" // pop obj +#endif +#endif + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + +asQWORD NOINLINE CallThisCallFunctionRetByRef(const void *obj, const asDWORD *args, int paramSize, asFUNCTION_t func, void *retPtr) +{ + volatile asQWORD retQW = 0; + +#if defined ASM_INTEL + + // Copy the data to the real stack. If we fail to do + // this we may run into trouble in case of exceptions. + __asm + { + // We must save registers that are used + push ecx + + // Clear the FPU stack, in case the called function doesn't do it by itself + CLEAR_FPU_STACK + + // Copy arguments from script + // stack to application stack + mov ecx, paramSize + mov eax, args + add eax, ecx + cmp ecx, 0 + je endcopy +copyloop: + sub eax, 4 + push dword ptr [eax] + sub ecx, 4 + jne copyloop +endcopy: + +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + // Push the object pointer on the stack + push obj +#else + // Move object pointer to ECX + mov ecx, obj +#endif + + // Push the return pointer + push retPtr + + // Call function + call [func] + +#ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER + // Pop the return pointer + add esp, 4 +#endif + +#ifndef THISCALL_CALLEE_POPS_ARGUMENTS + // Pop arguments + add esp, paramSize +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + // Pop object pointer + add esp, 4 +#endif +#endif + + // Copy return value from EAX:EDX + lea ecx, retQW + mov [ecx], eax + mov 4[ecx], edx + + // Restore registers + pop ecx + } + +#elif defined ASM_AT_N_T + + volatile asPWORD a[] = {asPWORD(obj), asPWORD(args), asPWORD(paramSize), asPWORD(func), asPWORD(retPtr)}; + + asm __volatile__ ( +#ifdef __OPTIMIZE__ + // When compiled with optimizations the stack unwind doesn't work properly, + // causing exceptions to crash the application. By adding this prologue + // and the epilogue below, the stack unwind works as it should. + // TODO: runtime optimize: The prologue/epilogue shouldn't be needed if the correct cfi directives are used below + "pushl %%ebp \n" + ".cfi_adjust_cfa_offset 4 \n" + ".cfi_rel_offset ebp, 0 \n" + "movl %%esp, %%ebp \n" + ".cfi_def_cfa_register ebp \n" +#endif + _S(CLEAR_FPU_STACK) "\n" + "pushl %%ebx \n" + "movl %%edx, %%ebx \n" + + // Need to align the stack pointer so that it is aligned to 16 bytes when making the function call. + // It is assumed that when entering this function, the stack pointer is already aligned, so we need + // to calculate how much we will put on the stack during this call. + "movl 8(%%ebx), %%eax \n" // paramSize + "addl $12, %%eax \n" // counting esp that we will push on the stack + "movl %%esp, %%ecx \n" + "subl %%eax, %%ecx \n" + "andl $15, %%ecx \n" + "movl %%esp, %%eax \n" + "subl %%ecx, %%esp \n" + "pushl %%eax \n" // Store the original stack pointer + + "movl 8(%%ebx), %%ecx \n" // paramSize + "movl 4(%%ebx), %%eax \n" // args + "addl %%ecx, %%eax \n" // push all arguments to the stack + "cmp $0, %%ecx \n" + "je endcopy3 \n" + "copyloop3: \n" + "subl $4, %%eax \n" + "pushl (%%eax) \n" + "subl $4, %%ecx \n" + "jne copyloop3 \n" + "endcopy3: \n" +#ifdef AS_MINGW47 + // MinGW made some strange choices with 4.7 and the thiscall calling convention, + // returning an object in memory is completely different from when not returning + // in memory + "pushl 0(%%ebx) \n" // push obj on the stack + "movl 16(%%ebx), %%ecx \n" // move the return pointer into ECX + "call *12(%%ebx) \n" // call the function +#else + "movl 0(%%ebx), %%ecx \n" // move obj into ECX +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + "pushl %%ecx \n" // push obj on the stack +#endif + "pushl 16(%%ebx) \n" // push retPtr on the stack + "call *12(%%ebx) \n" +#ifndef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER + "addl $4, %%esp \n" // pop return pointer +#endif +#ifndef THISCALL_CALLEE_POPS_ARGUMENTS + "addl 8(%%ebx), %%esp \n" // pop arguments +#ifdef THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + "addl $4, %%esp \n" // pop the object pointer +#endif +#endif +#endif // AS_MINGW47 + // Pop the alignment bytes + "popl %%esp \n" + "popl %%ebx \n" +#ifdef __OPTIMIZE__ + // Epilogue + "movl %%ebp, %%esp \n" + ".cfi_def_cfa_register esp \n" + "popl %%ebp \n" + ".cfi_adjust_cfa_offset -4 \n" + ".cfi_restore ebp \n" +#endif + // Copy EAX:EDX to retQW. As the stack pointer has been + // restored it is now safe to access the local variable + "leal %1, %%ecx \n" + "movl %%eax, 0(%%ecx) \n" + "movl %%edx, 4(%%ecx) \n" + : // output + : "d"(a), "m"(retQW) // input - pass pointer of args in edx, pass pointer of retQW in memory argument + : "%eax", "%ecx" // clobber + ); + +#endif + + return retQW; +} + +asDWORD GetReturnedFloat() +{ + asDWORD f; + +#if defined ASM_INTEL + + // Get the float value from ST0 + __asm fstp dword ptr [f] + +#elif defined ASM_AT_N_T + + asm("fstps %0 \n" : "=m" (f)); + +#endif + + return f; +} + +asQWORD GetReturnedDouble() +{ + asQWORD d; + +#if defined ASM_INTEL + + // Get the double value from ST0 + __asm fstp qword ptr [d] + +#elif defined ASM_AT_N_T + + asm("fstpl %0 \n" : "=m" (d)); + +#endif + + return d; +} + +END_AS_NAMESPACE + +#endif // AS_X86 +#endif // AS_MAX_PORTABILITY + + + + diff --git a/angelscript/source/as_callfunc_xenon.cpp b/angelscript/source/as_callfunc_xenon.cpp new file mode 100644 index 0000000..c52055e --- /dev/null +++ b/angelscript/source/as_callfunc_xenon.cpp @@ -0,0 +1,737 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_callfunc_xenon.cpp +// +// These functions handle the actual calling of system functions +// +// This version is Xenon specific +// Modified from as_callfunc_ppc.cpp by Laszlo Perneky February 2007 +// +// Modified by Cyril Tissier March 2010: +// various fixes in 'float' args passing / function return +// properly handling 'double' type +// various fixes in asm ppcFunc +// fix for variable arguments +// +// Modified by Anthony Clark May 2015 +// Fixed the issue where int64 and uint64 could not be passed nativly +// few minor fixes within asm ppcFunc to handle int64 and uint64 + + +// XBox 360 calling convention +// =========================== +// I've yet to find an official document with the ABI for XBox 360, +// but I'll describe what I've gathered from the code and tests +// performed by the AngelScript community. +// +// Arguments are passed in the following registers: +// r3 - r10 : integer/pointer arguments (each register is 64bit) +// fr1 - fr13 : float/double arguments (each register is 64bit) +// +// Arguments that don't fit in the registers will be pushed on the stack. +// +// When a float or double is passed as argument, its value will be placed +// in the next available float register, but it will also reserve general +// purpose register. +// +// Example: void foo(float a, int b). a will be passed in fr1 and b in r4. +// +// For each argument passed to a function an 8byte slot is reserved on the +// stack, so that the function can offload the value there if needed. The +// first slot is at r1+20, the next at r1+28, etc. +// +// If the function is a class method, the this pointer is passed as hidden +// first argument. If the function returns an object in memory, the address +// for that memory is passed as hidden first argument. +// +// Return value are placed in the following registers: +// r3 : integer/pointer values +// fr1 : float/double values +// +// Rules for registers +// r1 : stack pointer +// r14-r31 : nonvolatile, i.e. their values must be preserved +// fr14-fr31 : nonvolatile, i.e. their values must be preserved +// r0, r2, r13 : dedicated. I'm not sure what it means, but it is probably best not to use them +// +// The stack pointer must always be aligned at 8 bytes. +// +// References: +// https://www-01.ibm.com/chips/techlib/techlib.nsf/techdocs/852569B20050FF77852569970071B0D6/$file/eabi_app.pdf +// +// TODO: The code doesn't handle objects passed by value (unless they are max 4 bytes in size) + + + +#include "as_config.h" + +#ifndef AS_MAX_PORTABILITY +#if defined(AS_XENON) + +#include "as_callfunc.h" +#include "as_scriptengine.h" +#include "as_texts.h" +#include "as_tokendef.h" +#include "as_context.h" + +#include +#include +#include + +BEGIN_AS_NAMESPACE + +#define AS_PPC_MAX_ARGS 32 +#define AS_PPC_THISCALL_REG 1 +#define AS_PPC_RETURNINMEM_REG 1 +#define AS_PPC_ENDOFARGS 1 + +// The array used to send values to the correct places. +// Contains a byte of argTypes to indicate the register type to load, or zero if end of arguments +enum argTypes +{ + ppcENDARG = 0, + ppcINTARG = 1, + ppcFLOATARG = 2, + ppcDOUBLEARG = 3 +}; + +// Loads all data into the correct places and calls the function. +// pArgs is the array of the argument values +// pArgTypes is an array containing a byte indicating the type (enum argTypes) for each argument. +// dwFunc is the address of the function that will be called +asQWORD __declspec( naked ) ppcFunc(const asQWORD* pArgs, asDWORD dwFunc, const asBYTE* pArgTypes) +{ + __asm + { +_ppcFunc: + // Prologue + // Read and stack the link register (return address) + mflr r12 + stw r12,-8(r1) + + // Backup all non-volatile registers we use in this function + std r31,-10h(r1) // stack pointer for pushing arguments + std r27,-18h(r1) // dwFunc + std r26,-20h(r1) // pArgs + std r25,-28h(r1) // pArgTypes + std r24,-30h(r1) // current arg type + std r23,-38h(r1) // counter for used GPRs + std r22,-40h(r1) // counter for used float registers + + // Setup the stack frame to make room for the backup of registers + // and the arguments that will be passed to the application function. + // 512 bytes is enough for about 50 arguments plus backup of 8 + // TODO: Should perhaps make this dynamic based on number of arguments + stwu r1,-200h(r1) + +////////////////////////////////////////////////////////////////////////// +// Initialize local variables +////////////////////////////////////////////////////////////////////////// + + // r31 is our pointer into the stack where the arguments will be place + // The MSVC optimizer seems to rely on nobody copying the r1 register directly + // so we can't just do a simple 'addi r31, r1, 14h' as the optimizer may + // end up moving this instruction to before the update of r1 above. + // Instead we'll read the previous stack pointer from the stack, and then + // subtract to get the correct offset. + lwz r31, 0(r1) + subi r31, r31, 1ECh // prev r1 - 512 + 20 = curr r1 + 20 + + mr r26, r3 // pArgs + mr r27, r4 // dwFunc + mr r25, r5 // pArgTypes + + // Counting of used/assigned GPR's + sub r23, r23, r23 + // Counting of used/assigned Float Registers + sub r22, r22, r22 + + // Begin loading and stacking registers + subi r25, r25, 1 + +////////////////////////////////////////////////////////////////////////// +// Fetch the next argument +////////////////////////////////////////////////////////////////////////// +ppcNextArg: + // Increment rArgTypePtr + addi r25, r25, 1 + // Get data type + lbz r24, 0(r25) + + // r24 holds the data type + cmplwi cr6, r24, 0 + beq cr6, ppcArgsEnd + cmplwi cr6, r24, 1 + beq cr6, ppcArgIsInteger + cmplwi cr6, r24, 2 + beq cr6, ppcArgIsFloat + cmplwi cr6, r24, 3 + beq cr6, ppcArgIsDouble + +////////////////////////////////////////////////////////////////////////// +// Load and stack integer arguments +////////////////////////////////////////////////////////////////////////// +ppcArgIsInteger: + // Get the arg from the stack + ld r12, 0(r26) + + // r23 holds the integer arg count so far + cmplwi cr6, r23, 0 + beq cr6, ppcLoadIntReg0 + cmplwi cr6, r23, 1 + beq cr6, ppcLoadIntReg1 + cmplwi cr6, r23, 2 + beq cr6, ppcLoadIntReg2 + cmplwi cr6, r23, 3 + beq cr6, ppcLoadIntReg3 + cmplwi cr6, r23, 4 + beq cr6, ppcLoadIntReg4 + cmplwi cr6, r23, 5 + beq cr6, ppcLoadIntReg5 + cmplwi cr6, r23, 6 + beq cr6, ppcLoadIntReg6 + cmplwi cr6, r23, 7 + beq cr6, ppcLoadIntReg7 + + // no more than 8 parameters + b ppcLoadIntRegUpd + + ppcLoadIntReg0: + mr r3, r12 + b ppcLoadIntRegUpd + ppcLoadIntReg1: + mr r4, r12 + b ppcLoadIntRegUpd + ppcLoadIntReg2: + mr r5, r12 + b ppcLoadIntRegUpd + ppcLoadIntReg3: + mr r6, r12 + b ppcLoadIntRegUpd + ppcLoadIntReg4: + mr r7, r12 + b ppcLoadIntRegUpd + ppcLoadIntReg5: + mr r8, r12 + b ppcLoadIntRegUpd + ppcLoadIntReg6: + mr r9, r12 + b ppcLoadIntRegUpd + ppcLoadIntReg7: + mr r10, r12 + b ppcLoadIntRegUpd + + ppcLoadIntRegUpd: + std r12, 0(r31) // push on the stack + addi r31, r31, 8 // inc stack by 1 reg + + addi r23, r23, 1 // Increment used int register count + addi r26, r26, 8 // Increment pArgs + b ppcNextArg // Call next arg + +////////////////////////////////////////////////////////////////////////// +// Load and stack float arguments +////////////////////////////////////////////////////////////////////////// +ppcArgIsFloat: + // Get the arg from the stack + lfs fr0, 0(r26) + + // r22 holds the float arg count so far + cmplwi cr6, r22, 0 + beq cr6, ppcLoadFloatReg0 + cmplwi cr6, r22, 1 + beq cr6, ppcLoadFloatReg1 + cmplwi cr6, r22, 2 + beq cr6, ppcLoadFloatReg2 + cmplwi cr6, r22, 3 + beq cr6, ppcLoadFloatReg3 + cmplwi cr6, r22, 4 + beq cr6, ppcLoadFloatReg4 + cmplwi cr6, r22, 5 + beq cr6, ppcLoadFloatReg5 + cmplwi cr6, r22, 6 + beq cr6, ppcLoadFloatReg6 + cmplwi cr6, r22, 7 + beq cr6, ppcLoadFloatReg7 + cmplwi cr6, r22, 8 + beq cr6, ppcLoadFloatReg8 + cmplwi cr6, r22, 9 + beq cr6, ppcLoadFloatReg9 + cmplwi cr6, r22, 10 + beq cr6, ppcLoadFloatReg10 + cmplwi cr6, r22, 11 + beq cr6, ppcLoadFloatReg11 + cmplwi cr6, r22, 12 + beq cr6, ppcLoadFloatReg12 + + // no more than 12 parameters + b ppcLoadFloatRegUpd + + ppcLoadFloatReg0: + fmr fr1, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg1: + fmr fr2, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg2: + fmr fr3, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg3: + fmr fr4, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg4: + fmr fr5, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg5: + fmr fr6, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg6: + fmr fr7, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg7: + fmr fr8, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg8: + fmr fr9, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg9: + fmr fr10, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg10: + fmr fr11, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg11: + fmr fr12, fr0 + b ppcLoadFloatRegUpd + ppcLoadFloatReg12: + fmr fr13, fr0 + b ppcLoadFloatRegUpd + + ppcLoadFloatRegUpd: + stfs fr0, 0(r31) // push on the stack + addi r31, r31, 8 // inc stack by 1 reg + + addi r22, r22, 1 // Increment used float register count + addi r23, r23, 1 // Increment used int register count - a float reg eats up a GPR + addi r26, r26, 4 // Increment pArgs + b ppcNextArg // Call next arg + +////////////////////////////////////////////////////////////////////////// +// Load and stack double float arguments +////////////////////////////////////////////////////////////////////////// +ppcArgIsDouble: + // Get the arg from the stack + lfd fr0, 0(r26) + + // r22 holds the float arg count so far + cmplwi cr6, r22, 0 + beq cr6, ppcLoadDoubleReg0 + cmplwi cr6, r22, 1 + beq cr6, ppcLoadDoubleReg1 + cmplwi cr6, r22, 2 + beq cr6, ppcLoadDoubleReg2 + cmplwi cr6, r22, 3 + beq cr6, ppcLoadDoubleReg3 + cmplwi cr6, r22, 4 + beq cr6, ppcLoadDoubleReg4 + cmplwi cr6, r22, 5 + beq cr6, ppcLoadDoubleReg5 + cmplwi cr6, r22, 6 + beq cr6, ppcLoadDoubleReg6 + cmplwi cr6, r22, 7 + beq cr6, ppcLoadDoubleReg7 + cmplwi cr6, r22, 8 + beq cr6, ppcLoadDoubleReg8 + cmplwi cr6, r22, 9 + beq cr6, ppcLoadDoubleReg9 + cmplwi cr6, r22, 10 + beq cr6, ppcLoadDoubleReg10 + cmplwi cr6, r22, 11 + beq cr6, ppcLoadDoubleReg11 + cmplwi cr6, r22, 12 + beq cr6, ppcLoadDoubleReg12 + + // no more than 12 parameters + b ppcLoadDoubleRegUpd + + ppcLoadDoubleReg0: + fmr fr1, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg1: + fmr fr2, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg2: + fmr fr3, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg3: + fmr fr4, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg4: + fmr fr5, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg5: + fmr fr6, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg6: + fmr fr7, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg7: + fmr fr8, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg8: + fmr fr9, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg9: + fmr fr10, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg10: + fmr fr11, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg11: + fmr fr12, fr0 + b ppcLoadDoubleRegUpd + ppcLoadDoubleReg12: + fmr fr13, fr0 + b ppcLoadDoubleRegUpd + + ppcLoadDoubleRegUpd: + stfd fr0, 0(r31) // push on the stack + addi r31, r31, 8 // inc stack by 1 reg + + addi r22, r22, 1 // Increment used float register count + addi r23, r23, 1 // Increment used int register count + addi r26, r26, 8 // Increment pArgs + b ppcNextArg + +////////////////////////////////////////////////////////////////////////// +// Finished +////////////////////////////////////////////////////////////////////////// +ppcArgsEnd: + // Call the function + mtctr r27 + bctrl + + // Epilogue + // Restore callers stack + addi r1, r1, 200h + + // restore all registers we used in this fct + ld r22,-40h(r1) + ld r23,-38h(r1) + ld r24,-30h(r1) + ld r25,-28h(r1) + ld r26,-20h(r1) + ld r27,-18h(r1) + ld r31,-10h(r1) + + // Fetch return link to caller + lwz r12,-8(r1) + mtlr r12 + blr + } +} + +asDWORD GetReturnedFloat() +{ + // This variable must be declared volatile so that the + // compiler optimizations do not remove its initialization + // with the fr1 register due to believing the fr1 register + // isn't initialized. + volatile asDWORD f; + + __asm + { + stfs fr1, f + } + + return f; +} + +asQWORD GetReturnedDouble() +{ + // This variable must be declared volatile so that the + // compiler optimizations do not remove its initialization + // with the fr1 register due to believing the fr1 register + // isn't initialized. + volatile asQWORD f; + + __asm + { + stfd fr1, f + } + + return f; +} + +// returns true if the given parameter is a 'variable argument' +inline bool IsVariableArgument( asCDataType type ) +{ + return (type.GetTokenType() == ttQuestion) ? true : false; +} + +asQWORD CallSystemFunctionNative(asCContext *context, asCScriptFunction *descr, void *obj, asDWORD *args, void *retPointer, asQWORD &/*retQW2*/, void */*secondObject*/) +{ + // TODO: Xenon does not yet support THISCALL_OBJFIRST/LAST + + asCScriptEngine *engine = context->m_engine; + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + int callConv = sysFunc->callConv; + asQWORD retQW = 0; + void *func = (void*)sysFunc->func; + asDWORD *vftable; + + // Pack the arguments into an array that ppcFunc() can use to load each CPU register properly + asBYTE ppcArgsType[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG + AS_PPC_ENDOFARGS]; + asQWORD ppcArgs[AS_PPC_MAX_ARGS + AS_PPC_RETURNINMEM_REG + AS_PPC_THISCALL_REG]; + int argsCnt = 0; + + // If the function returns an object in memory, we allocate the memory and put the ptr to the front (will go to r3) + if( sysFunc->hostReturnInMemory ) + { + ppcArgs[argsCnt] = (asDWORD)retPointer; + ppcArgsType[argsCnt] = ppcINTARG; + argsCnt++; + } + + // If we have an object and it's not objectlast, then we put it as the first arg + if ( obj && + callConv != ICC_CDECL_OBJLAST && + callConv != ICC_CDECL_OBJLAST_RETURNINMEM ) + { + ppcArgs[argsCnt] = (asDWORD)obj; + ppcArgsType[argsCnt] = ppcINTARG; + argsCnt++; + } + + // If the function takes any objects by value, they must be copied + // to the stack, shifting the other arguments as necessary. paramBuffer + // will then replace the args pointer that was received from the VM. + // TODO: Is this really how XBox 360 passes objects by value? + asDWORD paramBuffer[AS_PPC_MAX_ARGS]; + if( sysFunc->takesObjByVal ) + { + int paramSize = 0; + int spos = 0; + int dpos = 1; + + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + // Parameter object by value + if( descr->parameterTypes[n].IsObject() && + !descr->parameterTypes[n].IsObjectHandle() && + !descr->parameterTypes[n].IsReference() ) + { +#ifdef COMPLEX_OBJS_PASSED_BY_REF + if( descr->parameterTypes[n].GetTypeInfo()->flags & COMPLEX_MASK ) + { + paramBuffer[dpos++] = args[spos++]; + paramSize++; + } + else +#endif + { + // Copy the object's memory to the buffer + memcpy( ¶mBuffer[dpos], *(void**)(args + spos), descr->parameterTypes[n].GetSizeInMemoryBytes() ); + + // Delete the original memory + engine->CallFree(*(char**)(args + spos)); + + spos++; + dpos += descr->parameterTypes[n].GetSizeInMemoryDWords(); + paramSize += descr->parameterTypes[n].GetSizeInMemoryDWords(); + } + } + else + { + // Copy the value directly + paramBuffer[dpos++] = args[spos++]; + if( descr->parameterTypes[n].GetSizeOnStackDWords() > 1 ) + paramBuffer[dpos++] = args[spos++]; + paramSize += descr->parameterTypes[n].GetSizeOnStackDWords(); + } + + // If this was a variable argument parameter, then account for the implicit typeId + if( IsVariableArgument( descr->parameterTypes[n] ) ) + { + // the TypeId is just a DWORD + paramBuffer[dpos++] = args[spos++]; + ++paramSize; + } + } + + // Keep a free location at the beginning + args = ¶mBuffer[1]; + + asASSERT( paramSize <= AS_PPC_MAX_ARGS ); + } + + + const asUINT paramCount = (asUINT)descr->parameterTypes.GetLength(); + + asBYTE * pCurArgType = (asBYTE*)&ppcArgsType[argsCnt]; + asBYTE * pCurFixedArgValue = (asBYTE*)&ppcArgs[argsCnt]; + asBYTE * pCurStackArgValue = (asBYTE*)args; + + for( asUINT n = 0; n < paramCount; n++ ) + { + argsCnt++; + + if (descr->parameterTypes[n].IsFloatType() && !descr->parameterTypes[n].IsReference()) + { + *pCurArgType++ = ppcFLOATARG; + + *((float*) pCurFixedArgValue) = *((float*) pCurStackArgValue); + + pCurFixedArgValue += 4; + pCurStackArgValue += 4; + } + else if (descr->parameterTypes[n].IsDoubleType() && !descr->parameterTypes[n].IsReference()) + { + *pCurArgType++ = ppcDOUBLEARG; + + *((double*) pCurFixedArgValue) = *((double*) pCurStackArgValue); + + pCurFixedArgValue += 8; + pCurStackArgValue += 8; + } + else + { + // TODO: The code also ignore the fact that large objects + // passed by value has been copied to the stack + // in the above loop. + + *pCurArgType++ = ppcINTARG; + + *((asQWORD*) pCurFixedArgValue) = *((asUINT*) pCurStackArgValue); + + if( !descr->parameterTypes[n].IsReference() ) + { + // If the arg is not 4 bytes which we coppied, lets do it again the right way + asUINT numBytes = descr->parameterTypes[n].GetSizeInMemoryBytes(); + if( numBytes == 1 ) + { + *((asQWORD*) pCurFixedArgValue) = *((asBYTE*) pCurStackArgValue); + } + else if( numBytes == 2 ) + { + *((asQWORD*) pCurFixedArgValue) = *((asWORD*) pCurStackArgValue); + } + else if( numBytes == 8 ) + { + *((asQWORD*) pCurFixedArgValue) = *((asQWORD*) pCurStackArgValue); + pCurStackArgValue += 4; // Increase our cur stack arg value by 4 bytes to = 8 total later + } + } + + pCurFixedArgValue += 8; + pCurStackArgValue += 4; + + // if it is a variable argument, account for the typeId + // implicitly add another parameter (AFTER the parameter above) for the typeId + if( IsVariableArgument(descr->parameterTypes[n]) ) + { + argsCnt++; + + *pCurArgType++ = ppcINTARG; + + *((int*) pCurFixedArgValue) = *((int*) pCurStackArgValue); + + pCurFixedArgValue += 4; + pCurStackArgValue += 4; + } + } + } + + // Add the arg list end indicator + ppcArgsType[argsCnt] = ppcENDARG; + + switch( callConv ) + { + case ICC_CDECL: + case ICC_CDECL_RETURNINMEM: + case ICC_STDCALL: + case ICC_STDCALL_RETURNINMEM: + case ICC_THISCALL: + case ICC_THISCALL_RETURNINMEM: + case ICC_CDECL_OBJFIRST: + case ICC_CDECL_OBJFIRST_RETURNINMEM: + { + retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType ); + break; + } + case ICC_VIRTUAL_THISCALL: + case ICC_VIRTUAL_THISCALL_RETURNINMEM: + { + // Get virtual function table from the object pointer + vftable = *(asDWORD**)obj; + retQW = ppcFunc( ppcArgs, vftable[asDWORD(func)>>2], ppcArgsType ); + break; + } + case ICC_CDECL_OBJLAST: + case ICC_CDECL_OBJLAST_RETURNINMEM: + { + // Add the object pointer as the last argument + ppcArgsType[argsCnt++] = ppcINTARG; + ppcArgsType[argsCnt] = ppcENDARG; + *((asQWORD*)pCurFixedArgValue) = (asPWORD)obj; + retQW = ppcFunc( ppcArgs, (asDWORD)func, ppcArgsType ); + break; + } + default: + context->SetInternalException( TXT_INVALID_CALLING_CONVENTION ); + } + + // If the return is a float value we need to get the value from the FP register + if( sysFunc->hostReturnFloat ) + { + if( sysFunc->hostReturnSize == 1 ) + *(asDWORD*)&retQW = GetReturnedFloat(); + else + retQW = GetReturnedDouble(); + } + else if( sysFunc->hostReturnSize == 1 ) + { + // Move the bits to the higher value to compensate for the adjustment that the caller does + retQW <<= 32; + } + + return retQW; +} + +END_AS_NAMESPACE + +#endif // AS_XENON +#endif // AS_MAX_PORTABILITY + + + diff --git a/angelscript/source/as_compiler.cpp b/angelscript/source/as_compiler.cpp new file mode 100644 index 0000000..12700c6 --- /dev/null +++ b/angelscript/source/as_compiler.cpp @@ -0,0 +1,16443 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_compiler.cpp +// +// The class that does the actual compilation of the functions +// + +#include // fmodf() pow() + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_compiler.h" +#include "as_tokendef.h" +#include "as_tokenizer.h" +#include "as_string_util.h" +#include "as_texts.h" +#include "as_parser.h" +#include "as_debug.h" +#include "as_context.h" // as_powi() + +BEGIN_AS_NAMESPACE + +// +// The calling convention rules for script functions: +// - If a class method returns a reference, the caller must guarantee the object pointer stays alive until the function returns, and the reference is no longer going to be used +// - If a class method doesn't return a reference, it must guarantee by itself that the this pointer stays alive during the function call. If no outside access is made, then the function is guaranteed to stay alive and nothing needs to be done +// - The object pointer is always passed as the first argument, position 0 +// - If the function returns a value type the caller must reserve the memory for this and pass the pointer as the first argument after the object pointer +// + + + + + +// TODO: I must correct the interpretation of a reference to objects in the compiler. +// A reference should mean that a pointer to the object is on the stack. +// No expression should end up as non-references to objects, as the actual object is +// never put on the stack. +// Local variables are declared as non-references, but the expression should be a reference to the variable. +// Function parameters of called functions can also be non-references, but in that case it means the +// object will be passed by value (currently on the heap, which will be moved to the application stack). +// +// The compiler shouldn't use the asCDataType::IsReference. The datatype should always be stored as non-references. +// Instead the compiler should keep track of references in TypeInfo, where it should also state how the reference +// is currently stored, i.e. in variable, in register, on stack, etc. + +asCCompiler::asCCompiler(asCScriptEngine *engine) : byteCode(engine) +{ + builder = 0; + script = 0; + + variables = 0; + isProcessingDeferredParams = false; + isCompilingDefaultArg = false; + noCodeOutput = 0; +} + +asCCompiler::~asCCompiler() +{ + while( variables ) + { + asCVariableScope *var = variables; + variables = variables->parent; + + asDELETE(var,asCVariableScope); + } + + // Clean up all the string constants that were allocated. By now the script + // functions that were compiled successfully already holds their own references + for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) + engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); + usedStringConstants.SetLength(0); + + // Clean up the temporary script nodes that were allocated during compilation + for (asUINT n = 0; n < nodesToFreeUponComplete.GetLength(); n++) + nodesToFreeUponComplete[n]->Destroy(engine); +} + +void asCCompiler::Reset(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc) +{ + this->builder = in_builder; + this->engine = in_builder->engine; + this->script = in_script; + this->outFunc = in_outFunc; + + hasCompileErrors = false; + + m_isConstructor = false; + m_isConstructorCalled = false; + m_classDecl = 0; + m_globalVar = 0; + + nextLabel = 0; + breakLabels.SetLength(0); + continueLabels.SetLength(0); + + numLambdas = 0; + + byteCode.ClearAll(); +} + +int asCCompiler::CompileDefaultConstructor(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl) +{ + Reset(in_builder, in_script, in_outFunc); + + m_classDecl = in_classDecl; + + // Insert a JitEntry at the start of the function for JIT compilers + byteCode.InstrPTR(asBC_JitEntry, 0); + + // Add a variable scope that might be needed to declare dummy variables + // in case the member initialization refers to undefined symbols. + AddVariableScope(); + + // Initialize the class members that have no explicit expression first. This will allow the + // base class' constructor to access these members without worry they will be uninitialized. + // This can happen if the base class' constructor calls a method that is overridden by the derived class + CompileMemberInitialization(&byteCode, true); + + // If the class is derived from another, then the base class' default constructor must be called + if( outFunc->objectType->derivedFrom ) + { + // Make sure the base class really has a default constructor + if( outFunc->objectType->derivedFrom->beh.construct == 0 ) + Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, in_node); + + // Call the base class' default constructor + byteCode.InstrSHORT(asBC_PSF, 0); + byteCode.Instr(asBC_RDSPtr); + byteCode.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE); + } + + // Initialize the class members that explicit expressions afterwards. This allow the expressions + // to access the base class members without worry they will be uninitialized + CompileMemberInitialization(&byteCode, false); + byteCode.OptimizeLocally(tempVariableOffsets); + + // If there are compile errors, there is no reason to build the final code + if( hasCompileErrors ) + return -1; + + // Pop the object pointer from the stack + byteCode.Ret(AS_PTR_SIZE); + + // Count total variable size + int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1; + outFunc->scriptData->variableSpace = varSize; + + FinalizeFunction(); + +#ifdef AS_DEBUG + // DEBUG: output byte code + byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + "__defconstr.txt").AddressOf(), in_outFunc); +#endif + + return 0; +} + +int asCCompiler::CompileFactory(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptFunction *in_outFunc) +{ + Reset(in_builder, in_script, in_outFunc); + + // Insert a JitEntry at the start of the function for JIT compilers + byteCode.InstrPTR(asBC_JitEntry, 0); + + // Find the corresponding constructor + asCDataType dt = asCDataType::CreateType(outFunc->returnType.GetTypeInfo(), false); + int constructor = 0; + for( unsigned int n = 0; n < dt.GetBehaviour()->factories.GetLength(); n++ ) + { + if( dt.GetBehaviour()->factories[n] == outFunc->id ) + { + constructor = dt.GetBehaviour()->constructors[n]; + break; + } + } + + // Allocate the class and instantiate it with the constructor + int varOffset = AllocateVariable(dt, true); + + outFunc->scriptData->variableSpace = AS_PTR_SIZE; + byteCode.InstrSHORT(asBC_PSF, (short)varOffset); + + // Copy all arguments to the top of the stack + // TODO: runtime optimize: Might be interesting to have a specific instruction for copying all arguments + int offset = (int)outFunc->GetSpaceNeededForArguments(); + for( int a = int(outFunc->parameterTypes.GetLength()) - 1; a >= 0; a-- ) + { + if( !outFunc->parameterTypes[a].IsPrimitive() || + outFunc->parameterTypes[a].IsReference() ) + { + offset -= AS_PTR_SIZE; + byteCode.InstrSHORT(asBC_PshVPtr, short(-offset)); + } + else + { + if( outFunc->parameterTypes[a].GetSizeOnStackDWords() == 2 ) + { + offset -= 2; + byteCode.InstrSHORT(asBC_PshV8, short(-offset)); + } + else + { + offset -= 1; + byteCode.InstrSHORT(asBC_PshV4, short(-offset)); + } + } + } + + int argDwords = (int)outFunc->GetSpaceNeededForArguments(); + byteCode.Alloc(asBC_ALLOC, dt.GetTypeInfo(), constructor, argDwords + AS_PTR_SIZE); + + // Return a handle to the newly created object + byteCode.InstrSHORT(asBC_LOADOBJ, (short)varOffset); + + byteCode.Ret(argDwords); + + FinalizeFunction(); + + // Tell the virtual machine not to clean up parameters on exception + outFunc->dontCleanUpOnException = true; + +/* +#ifdef AS_DEBUG + // DEBUG: output byte code + asCString args; + args.Format("%d", outFunc->parameterTypes.GetLength()); + byteCode.DebugOutput(("__" + outFunc->name + "__factory" + args + ".txt").AddressOf(), engine); +#endif +*/ + return 0; +} + +void asCCompiler::FinalizeFunction() +{ + TimeIt("asCCompiler::FinalizeFunction"); + + asASSERT( outFunc->scriptData ); + asUINT n; + + // Finalize the bytecode + byteCode.Finalize(tempVariableOffsets); + + // extract the try/catch info before object variable info, as + // some variable info is not needed if there are no try/catch blocks + byteCode.ExtractTryCatchInfo(outFunc); + + byteCode.ExtractObjectVariableInfo(outFunc); + + // Compile the list of object variables for the exception handler + // Start with the variables allocated on the heap, and then the ones allocated on the stack + for( n = 0; n < variableAllocations.GetLength(); n++ ) + { + if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() ) + { + if( variableIsOnHeap[n] ) + { + outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); + outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n)); + } + } + } + outFunc->scriptData->objVariablesOnHeap = asUINT(outFunc->scriptData->objVariablePos.GetLength()); + for( n = 0; n < variableAllocations.GetLength(); n++ ) + { + if( (variableAllocations[n].IsObject() || variableAllocations[n].IsFuncdef()) && !variableAllocations[n].IsReference() ) + { + if( !variableIsOnHeap[n] ) + { + outFunc->scriptData->objVariableTypes.PushLast(variableAllocations[n].GetTypeInfo()); + outFunc->scriptData->objVariablePos.PushLast(GetVariableOffset(n)); + } + } + } + + // Copy byte code to the function + asASSERT( outFunc->scriptData->byteCode.GetLength() == 0 ); + outFunc->scriptData->byteCode.SetLength(byteCode.GetSize()); + byteCode.Output(outFunc->scriptData->byteCode.AddressOf()); + outFunc->AddReferences(); + outFunc->scriptData->stackNeeded = byteCode.largestStackUsed + outFunc->scriptData->variableSpace; + outFunc->scriptData->lineNumbers = byteCode.lineNumbers; + + // Extract the script section indexes too if there are any entries that are different from the function's script section + int lastIdx = outFunc->scriptData->scriptSectionIdx; + for( n = 0; n < byteCode.sectionIdxs.GetLength(); n++ ) + { + if( byteCode.sectionIdxs[n] != lastIdx ) + { + lastIdx = byteCode.sectionIdxs[n]; + outFunc->scriptData->sectionIdxs.PushLast(byteCode.lineNumbers[n*2]); + outFunc->scriptData->sectionIdxs.PushLast(lastIdx); + } + } +} + +// internal +int asCCompiler::SetupParametersAndReturnVariable(asCArray ¶meterNames, asCScriptNode *func) +{ + int stackPos = 0; + + if( outFunc->objectType ) + stackPos = -AS_PTR_SIZE; // The first parameter is the pointer to the object + + // Add the first variable scope, which the parameters and + // variables declared in the outermost statement block is + // part of. + AddVariableScope(); + + bool isDestructor = false; + asCDataType returnType; + + // Examine return type + returnType = outFunc->returnType; + + // Check if this is a constructor or destructor + if( returnType.GetTokenType() == ttVoid && outFunc->objectType ) + { + if( outFunc->name[0] == '~' ) + isDestructor = true; + else if( outFunc->objectType->name == outFunc->name ) + m_isConstructor = true; + } + + // Is the return type allowed? + if( returnType != asCDataType::CreatePrimitive(ttVoid, false) && + !returnType.CanBeInstantiated() && + !returnType.IsReference() && + !returnType.IsObjectHandle() ) + { + // TODO: Hasn't this been validated by the builder already? + asCString str; + str.Format(TXT_RETURN_CANT_BE_s, returnType.Format(outFunc->nameSpace).AddressOf()); + Error(str, func); + } + + // If the return type is a value type returned by value the address of the + // location where the value will be stored is pushed on the stack before + // the arguments + if( !(isDestructor || m_isConstructor) && outFunc->DoesReturnOnStack() ) + stackPos -= AS_PTR_SIZE; + + asCVariableScope vs(0); + + // Declare parameters + asUINT n; + for( n = 0; n < parameterNames.GetLength(); n++ ) + { + // Get the parameter type + asCDataType &type = outFunc->parameterTypes[n]; + asETypeModifiers inoutFlag = n < outFunc->inOutFlags.GetLength() ? outFunc->inOutFlags[n] : asTM_NONE; + + // Is the data type allowed? + // TODO: Hasn't this been validated by the builder already? + if( (type.IsReference() && inoutFlag != asTM_INOUTREF && !type.CanBeInstantiated()) || + (!type.IsReference() && !type.CanBeInstantiated()) ) + { + asCString parm = type.Format(outFunc->nameSpace); + if( inoutFlag == asTM_INREF ) + parm += "in"; + else if( inoutFlag == asTM_OUTREF ) + parm += "out"; + + asCString str; + str.Format(TXT_PARAMETER_CANT_BE_s, parm.AddressOf()); + Error(str, func); + } + + // If the parameter has a name then declare it as variable + if( parameterNames[n] != "" ) + { + asCString &name = parameterNames[n]; + if( vs.DeclareVariable(name.AddressOf(), type, stackPos, true) < 0 ) + { + // TODO: It might be an out-of-memory too + Error(TXT_PARAMETER_ALREADY_DECLARED, func); + } + + // Add marker for variable declaration + byteCode.VarDecl((int)outFunc->scriptData->variables.GetLength()); + outFunc->AddVariable(name, type, stackPos); + } + else + vs.DeclareVariable("", type, stackPos, true); + + // Move to next parameter + stackPos -= type.GetSizeOnStackDWords(); + } + + for( n = asUINT(vs.variables.GetLength()); n-- > 0; ) + variables->DeclareVariable(vs.variables[n]->name.AddressOf(), vs.variables[n]->type, vs.variables[n]->stackOffset, vs.variables[n]->onHeap); + + variables->DeclareVariable("return", returnType, stackPos, true); + + return stackPos; +} + +void asCCompiler::CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults) +{ + asASSERT( m_classDecl ); + + // Initialize each member in the order they were declared + for( asUINT n = 0; n < outFunc->objectType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = outFunc->objectType->properties[n]; + + // Check if the property has an initialization expression + asCParser parser(builder); + asCScriptNode *declNode = 0; + asCScriptNode *initNode = 0; + asCScriptCode *initScript = 0; + for( asUINT m = 0; m < m_classDecl->propInits.GetLength(); m++ ) + { + if( m_classDecl->propInits[m].name == prop->name ) + { + declNode = m_classDecl->propInits[m].declNode; + initNode = m_classDecl->propInits[m].initNode; + initScript = m_classDecl->propInits[m].file; + break; + } + } + + // If declNode is null, the property was inherited in which case + // it was already initialized by the base class' constructor + if( declNode ) + { + if( initNode ) + { + if( onlyDefaults ) + continue; + +#ifdef AS_NO_MEMBER_INIT + // Give an error as the initialization in the declaration has been disabled + asCScriptCode *origScript = script; + script = initScript; + Error("Initialization of members in declaration is not supported", initNode); + script = origScript; + + // Clear the initialization node + initNode = 0; + initScript = script; +#else + // Re-parse the initialization expression as the parser now knows the types, which it didn't earlier + int r = parser.ParseVarInit(initScript, initNode); + if( r < 0 ) + continue; + + initNode = parser.GetScriptNode(); +#endif + } + else + { + if( !onlyDefaults ) + continue; + } + +#ifdef AS_NO_MEMBER_INIT + // The initialization will be done in the asCScriptObject constructor, so + // here we should just validate that the member has a default constructor + if( prop->type.IsObject() && + !prop->type.IsObjectHandle() && + (((prop->type.GetTypeInfo()->flags & asOBJ_REF) && + prop->type.GetBehaviour()->factory == 0) || + ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && + prop->type.GetBehaviour()->construct == 0 && + !(prop->type.GetTypeInfo()->flags & asOBJ_POD))) ) + { + // Class has no default factory/constructor. + asCString str; + // TODO: funcdef: asCDataType should have a GetTypeName() + if( prop->type.GetFuncDef() ) + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetFuncDef()->GetName()); + else + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, prop->type.GetTypeInfo()->GetName()); + Error(str, declNode); + } +#else + // Temporarily set the script that is being compiled to where the member initialization is declared. + // The script can be different when including mixin classes from a different script section + asCScriptCode *origScript = script; + script = initScript; + + // Add a line instruction with the position of the declaration + LineInstr(bc, declNode->tokenPos); + + // Compile the initialization + asQWORD constantValue; + asCByteCode bcInit(engine); + CompileInitialization(initNode, &bcInit, prop->type, declNode, prop->byteOffset, &constantValue, 2); + bcInit.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&bcInit); + + script = origScript; +#endif + } + } +} + +// Entry +int asCCompiler::CompileFunction(asCBuilder *in_builder, asCScriptCode *in_script, asCArray &in_parameterNames, asCScriptNode *in_func, asCScriptFunction *in_outFunc, sClassDeclaration *in_classDecl) +{ + TimeIt("asCCompiler::CompileFunction"); + + Reset(in_builder, in_script, in_outFunc); + int buildErrors = builder->numErrors; + + int stackPos = SetupParametersAndReturnVariable(in_parameterNames, in_func); + + //-------------------------------------------- + // Compile the statement block + + if( m_isConstructor ) + m_classDecl = in_classDecl; + + // We need to parse the statement block now + asCScriptNode *blockBegin; + + // If the function signature was implicit, e.g. virtual property accessor or + // lambda function, then the received node already is the statement block + if( in_func->nodeType != snStatementBlock ) + blockBegin = in_func->lastChild; + else + blockBegin = in_func; + + // TODO: memory: We can parse the statement block one statement at a time, thus save even more memory + // TODO: optimize: For large functions, the parsing of the statement block can take a long time. Presumably because a lot of memory needs to be allocated + asCParser parser(builder); + int r = parser.ParseStatementBlock(script, blockBegin); + if( r < 0 ) return -1; + asCScriptNode *block = parser.GetScriptNode(); + + // Reserve a label for the cleanup code + nextLabel++; + + bool hasReturn; + asCByteCode bc(engine); + LineInstr(&bc, blockBegin->tokenPos); + CompileStatementBlock(block, false, &hasReturn, &bc); + LineInstr(&bc, blockBegin->tokenPos + blockBegin->tokenLength); + + // Make sure there is a return in all paths (if not return type is void) + // Don't bother with this check if there are compiler errors, e.g. Unreachable code + if( !hasCompileErrors && outFunc->returnType != asCDataType::CreatePrimitive(ttVoid, false) ) + { + if( hasReturn == false ) + Error(TXT_NOT_ALL_PATHS_RETURN, blockBegin); + } + + //------------------------------------------------ + // Concatenate the bytecode + + // Insert a JitEntry at the start of the function for JIT compilers + byteCode.InstrPTR(asBC_JitEntry, 0); + + if( outFunc->objectType ) + { + if( m_isConstructor ) + { + if( outFunc->objectType->derivedFrom ) + { + // Call the base class' default constructor unless called manually in the code + if( !m_isConstructorCalled ) + { + if( outFunc->objectType->derivedFrom->beh.construct ) + { + // Initialize members without explicit expression first + CompileMemberInitialization(&byteCode, true); + + // Call base class' constructor + asCByteCode tmpBC(engine); + tmpBC.InstrSHORT(asBC_PSF, 0); + tmpBC.Instr(asBC_RDSPtr); + tmpBC.Call(asBC_CALL, outFunc->objectType->derivedFrom->beh.construct, AS_PTR_SIZE); + tmpBC.OptimizeLocally(tempVariableOffsets); + byteCode.AddCode(&tmpBC); + + // Add the initialization of the members with explicit expressions + CompileMemberInitialization(&byteCode, false); + } + else + Error(TEXT_BASE_DOESNT_HAVE_DEF_CONSTR, blockBegin); + } + else + { + // Only initialize members that don't have an explicit expression + // The members that are explicitly initialized will be initialized after the call to base class' constructor + CompileMemberInitialization(&byteCode, true); + } + } + else + { + // Add the initialization of the members + CompileMemberInitialization(&byteCode, true); + CompileMemberInitialization(&byteCode, false); + } + } + } + + // Add the code for the statement block + byteCode.AddCode(&bc); + + // Count total variable size + int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1; + outFunc->scriptData->variableSpace = varSize; + + // Deallocate all local variables + int n; + for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) + { + sVariable *v = variables->variables[n]; + if( v->stackOffset > 0 ) + { + // Call variables destructors + if( v->name != "return" && v->name != "return address" ) + CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode); + + DeallocateVariable(v->stackOffset); + } + } + + // This is the label that return statements jump to + // in order to exit the function + byteCode.Label(0); + + // Call destructors for function parameters + for( n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) + { + sVariable *v = variables->variables[n]; + if( v->stackOffset <= 0 ) + { + // Call variable destructors here, for variables not yet destroyed + if( v->name != "return" && v->name != "return address" ) + CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode); + } + + // Do not deallocate parameters + } + + // Check if the number of labels in the functions isn't too many to be handled + if( nextLabel >= (1<<15) ) + Error(TXT_TOO_MANY_JUMP_LABELS, in_func); + + // If there are compile errors, there is no reason to build the final code + if( hasCompileErrors || builder->numErrors != buildErrors ) + return -1; + + // At this point there should be no variables allocated + asASSERT(variableAllocations.GetLength() == freeVariables.GetLength()); + + // Remove the variable scope + RemoveVariableScope(); + + byteCode.Ret(-stackPos); + + FinalizeFunction(); + +#ifdef AS_DEBUG + // DEBUG: output byte code + if( outFunc->objectType ) + byteCode.DebugOutput(("__" + outFunc->objectType->name + "_" + outFunc->name + ".txt").AddressOf(), in_outFunc); + else + byteCode.DebugOutput(("__" + outFunc->name + ".txt").AddressOf(), in_outFunc); +#endif + + return 0; +} + +int asCCompiler::CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar, bool derefDest) +{ + if( !type.IsObject() ) + return 0; + + // CallCopyConstructor should not be called for object handles. + asASSERT( !type.IsObjectHandle() ); + + asCArray args; + args.PushLast(arg); + + // The reference parameter must be pushed on the stack + asASSERT( arg->type.dataType.GetTypeInfo() == type.GetTypeInfo() ); + + // Since we're calling the copy constructor, we have to trust the function to not do + // anything stupid otherwise we will just enter a loop, as we try to make temporary + // copies of the argument in order to guarantee safety. + + + if( type.GetTypeInfo()->flags & asOBJ_REF ) + { + asCExprContext ctx(engine); + + int func = 0; + asSTypeBehaviour *beh = type.GetBehaviour(); + if( beh ) func = beh->copyfactory; + + if( func > 0 ) + { + if( !isGlobalVar ) + { + // Call factory and store the handle in the given variable + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset); + + // Pop the reference left by the function call + ctx.bc.Instr(asBC_PopPtr); + } + else + { + // Call factory + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); + + // Store the returned handle in the global variable + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + ctx.bc.Instr(asBC_PopPtr); + ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); + } + + bc->AddCode(&ctx.bc); + + return 0; + } + } + else + { + asSTypeBehaviour *beh = type.GetBehaviour(); + int func = beh ? beh->copyconstruct : 0; + if( func > 0 ) + { + // Push the address where the object will be stored on the stack, before the argument + // TODO: When the context is serializable this probably has to be changed, since this + // pointer can remain on the stack while the context is suspended. There is no + // risk the pointer becomes invalid though, there is just no easy way to serialize it. + asCByteCode tmp(engine); + if( isGlobalVar ) + tmp.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + else if( isObjectOnHeap ) + tmp.InstrSHORT(asBC_PSF, (short)offset); + tmp.AddCode(bc); + bc->AddCode(&tmp); + + // When the object is allocated on the stack the object pointer + // must be pushed on the stack after the arguments + if( !isObjectOnHeap ) + { + asASSERT( !isGlobalVar ); + bc->InstrSHORT(asBC_PSF, (short)offset); + if( derefDest ) + { + // The variable is a reference to the real location, so we need to dereference it + bc->Instr(asBC_RDSPtr); + } + } + + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, isObjectOnHeap, &args, CastToObjectType(type.GetTypeInfo())); + + bc->AddCode(&ctx.bc); + + // TODO: value on stack: This probably needs to be done in PerformFunctionCall + // Mark the object as initialized + if( !isObjectOnHeap ) + bc->ObjInfo(offset, asOBJ_INIT); + + + return 0; + } + } + + // Class has no copy constructor/factory. + asCString str; + str.Format(TXT_NO_COPY_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName()); + Error(str, node); + + return -1; +} + +int asCCompiler::CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem, bool derefDest) +{ + if( !type.IsObject() || type.IsObjectHandle() ) + return 0; + + if( type.GetTypeInfo()->flags & asOBJ_REF ) + { + asCExprContext ctx(engine); + ctx.exprNode = node; + + int func = 0; + asSTypeBehaviour *beh = type.GetBehaviour(); + if( beh ) + { + func = beh->factory; + + // If no trivial default factory is found, look for a factory where all params have default args + if( func == 0 ) + { + for( asUINT n = 0; n < beh->factories.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[beh->factories[n]]; + if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() && + f->defaultArgs[0] != 0 ) + { + func = beh->factories[n]; + break; + } + } + } + } + + if( func > 0 ) + { + asCArray args; + asCScriptFunction *f = engine->scriptFunctions[func]; + if( f->parameterTypes.GetLength() ) + { + // Add the default values for arguments not explicitly supplied + CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo())); + + PrepareFunctionCall(func, &ctx.bc, args); + + MoveArgsToStack(func, &ctx.bc, args, false); + } + + if( isVarGlobOrMem == 0 ) + { + // Call factory and store the handle in the given variable + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo()), true, offset); + + // Pop the reference left by the function call + ctx.bc.Instr(asBC_PopPtr); + } + else + { + // Call factory + PerformFunctionCall(func, &ctx, false, &args, CastToObjectType(type.GetTypeInfo())); + + // TODO: runtime optimize: Should have a way of storing the object pointer directly to the destination + // instead of first storing it in a local variable and then copying it to the + // destination. + + if( !(type.GetTypeInfo()->flags & asOBJ_SCOPED) ) + { + // Only dereference the variable if not a scoped type + ctx.bc.Instr(asBC_RDSPtr); + } + + if( isVarGlobOrMem == 1 ) + { + // Store the returned handle in the global variable + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + } + else + { + // Store the returned handle in the class member + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + + if( type.GetTypeInfo()->flags & asOBJ_SCOPED ) + { + // For scoped typed we must move the reference from the local + // variable rather than copy it as there is no AddRef behaviour + ctx.bc.InstrSHORT_DW(asBC_COPY, AS_PTR_SIZE, asTYPEID_OBJHANDLE | engine->GetTypeIdFromDataType(type)); + + // Clear the local variable so the reference isn't released + ctx.bc.InstrSHORT(asBC_ClrVPtr, ctx.type.stackOffset); + } + else + { + if( type.IsFuncdef() ) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + } + ctx.bc.Instr(asBC_PopPtr); + ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); + } + + bc->AddCode(&ctx.bc); + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + + return 0; + } + } + else + { + asCExprContext ctx(engine); + ctx.exprNode = node; + + asSTypeBehaviour *beh = type.GetBehaviour(); + + int func = 0; + if( beh ) + { + func = beh->construct; + + // If no trivial default constructor is found, look for a constructor where all params have default args + if( func == 0 ) + { + for( asUINT n = 0; n < beh->constructors.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[beh->constructors[n]]; + if( f->defaultArgs.GetLength() == f->parameterTypes.GetLength() && + f->defaultArgs[0] != 0 ) + { + func = beh->constructors[n]; + break; + } + } + } + } + + // Allocate and initialize with the default constructor + if( func != 0 || (type.GetTypeInfo()->flags & asOBJ_POD) ) + { + asCArray args; + asCScriptFunction *f = engine->scriptFunctions[func]; + if( f && f->parameterTypes.GetLength() ) + { + // Add the default values for arguments not explicitly supplied + CompileDefaultAndNamedArgs(node, args, func, CastToObjectType(type.GetTypeInfo())); + + PrepareFunctionCall(func, &ctx.bc, args); + + MoveArgsToStack(func, &ctx.bc, args, false); + } + + if( !isObjectOnHeap ) + { + if( isVarGlobOrMem == 0 ) + { + // There is nothing to do if there is no function, + // as the memory is already allocated on the stack + if( func ) + { + // Call the constructor as a normal function + bc->InstrSHORT(asBC_PSF, (short)offset); + if( derefDest ) + bc->Instr(asBC_RDSPtr); + + asCExprContext ctxCall(engine); + PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); + bc->AddCode(&ctxCall.bc); + + // TODO: value on stack: This probably needs to be done in PerformFunctionCall + // Mark the object as initialized + bc->ObjInfo(offset, asOBJ_INIT); + } + } + else if( isVarGlobOrMem == 2 ) + { + // Only POD types can be allocated inline in script classes + asASSERT( type.GetTypeInfo()->flags & asOBJ_POD ); + + if( func ) + { + // Call the constructor as a normal function + bc->InstrSHORT(asBC_PSF, 0); + bc->Instr(asBC_RDSPtr); + bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + + asCExprContext ctxCall(engine); + PerformFunctionCall(func, &ctxCall, false, 0, CastToObjectType(type.GetTypeInfo())); + bc->AddCode(&ctxCall.bc); + } + } + else + { + asASSERT( false ); + } + } + else + { + if( isVarGlobOrMem == 0 ) + bc->InstrSHORT(asBC_PSF, (short)offset); + else if( isVarGlobOrMem == 1 ) + bc->InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + else + { + bc->InstrSHORT(asBC_PSF, 0); + bc->Instr(asBC_RDSPtr); + bc->InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + + if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) + { + asCScriptFunction *descr = engine->scriptFunctions[func]; + asASSERT( descr->funcType == asFUNC_SCRIPT ); + + // Find the id of the real constructor and not the generated stub + asUINT id = 0; + asDWORD *funcBc = descr->scriptData->byteCode.AddressOf(); + while( funcBc ) + { + if( (*(asBYTE*)funcBc) == asBC_CALLSYS ) + { + id = asBC_INTARG(funcBc); + break; + } + funcBc += asBCTypeSize[asBCInfo[*(asBYTE*)funcBc].type]; + } + + asASSERT( id ); + + bc->InstrPTR(asBC_OBJTYPE, type.GetTypeInfo()); + bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), id, AS_PTR_SIZE + AS_PTR_SIZE); + } + else + bc->Alloc(asBC_ALLOC, type.GetTypeInfo(), func, AS_PTR_SIZE); + } + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + + return 0; + } + } + + // Class has no default factory/constructor. + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, type.GetTypeInfo()->GetName()); + Error(str, node); + + return -1; +} + +void asCCompiler::CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc) +{ + if( !type.IsReference() ) + { + // Call destructor for the data type + if( type.IsObject() || type.IsFuncdef() ) + { + // The null pointer doesn't need to be destroyed + if( type.IsNullHandle() ) + return; + + // Nothing is done for list pattern types, as this is taken care of by the CompileInitList method + if( type.GetTypeInfo()->flags & asOBJ_LIST_PATTERN ) + return; + + if( isObjectOnHeap || type.IsObjectHandle() ) + { + // Free the memory + if (type.IsFuncdef()) + bc->InstrW_PTR(asBC_FREE, (short)offset, &engine->functionBehaviours); + else + bc->InstrW_PTR(asBC_FREE, (short)offset, type.GetTypeInfo()); + } + else + { + asASSERT( type.GetTypeInfo()->GetFlags() & asOBJ_VALUE ); + + if( type.GetBehaviour()->destruct ) + { + // Call the destructor as a regular function + asCExprContext ctx(engine); + ctx.bc.InstrSHORT(asBC_PSF, (short)offset); + PerformFunctionCall(type.GetBehaviour()->destruct, &ctx); + ctx.bc.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&ctx.bc); + } + + // TODO: Value on stack: This probably needs to be done in PerformFunctionCall + // Mark the object as destroyed + bc->ObjInfo(offset, asOBJ_UNINIT); + } + } + } +} + +void asCCompiler::LineInstr(asCByteCode *bc, size_t pos) +{ + int r, c; + script->ConvertPosToRowCol(pos, &r, &c); + bc->Line(r, c, script->idx); +} + +void asCCompiler::CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc) +{ + *hasReturn = false; + bool isFinished = false; + bool hasUnreachableCode = false; + bool hasReturnBefore = false; + + if( ownVariableScope ) + { + bc->Block(true); + AddVariableScope(); + } + + asCScriptNode *node = block->firstChild; + while( node ) + { +#ifdef AS_DEBUG + // Keep the current line in a variable so it will be easier + // to determine where in a script an assert is occurring. + int currentLine = 0; + script->ConvertPosToRowCol(node->tokenPos, ¤tLine, 0); +#endif + + if( !hasUnreachableCode && (*hasReturn || isFinished) ) + { + // Empty statements don't count + if( node->nodeType != snExpressionStatement || node->firstChild ) + { + hasUnreachableCode = true; + Warning(TXT_UNREACHABLE_CODE, node); + } + + if( *hasReturn ) + hasReturnBefore = true; + } + + if( node->nodeType == snBreak || node->nodeType == snContinue ) + isFinished = true; + + asCByteCode statement(engine); + if( node->nodeType == snDeclaration ) + CompileDeclaration(node, &statement); + else + CompileStatement(node, hasReturn, &statement); + + // Ignore missing returns in unreachable code paths + if( !(*hasReturn) && hasReturnBefore ) + *hasReturn = true; + + LineInstr(bc, node->tokenPos); + bc->AddCode(&statement); + + if( !hasCompileErrors ) + { + asASSERT( tempVariables.GetLength() == 0 ); + asASSERT( reservedVariables.GetLength() == 0 ); + } + + node = node->next; + } + + if( ownVariableScope ) + { + // Deallocate variables in this block, in reverse order + for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) + { + sVariable *v = variables->variables[n]; + + // Call variable destructors here, for variables not yet destroyed + // If the block is terminated with a break, continue, or + // return the variables are already destroyed + if( !isFinished && !*hasReturn ) + CallDestructor(v->type, v->stackOffset, v->onHeap, bc); + + // Don't deallocate function parameters + if( v->stackOffset > 0 ) + DeallocateVariable(v->stackOffset); + } + + RemoveVariableScope(); + bc->Block(false); + } +} + +// Entry +int asCCompiler::CompileGlobalVariable(asCBuilder *in_builder, asCScriptCode *in_script, asCScriptNode *in_node, sGlobalVariableDescription *in_gvar, asCScriptFunction *in_outFunc) +{ + Reset(in_builder, in_script, in_outFunc); + m_globalVar = in_gvar; + + // Add a variable scope (even though variables can't be declared) + AddVariableScope(); + + in_gvar->isPureConstant = false; + + // Parse the initialization nodes + asCParser parser(builder); + if (in_node) + { + int r = parser.ParseVarInit(in_script, in_node); + if (r < 0) + return r; + + in_node = parser.GetScriptNode(); + } + + asCExprContext compiledCtx(engine); + bool preCompiled = false; + if (in_gvar->datatype.IsAuto()) + { + preCompiled = CompileAutoType(in_gvar->datatype, compiledCtx, in_node, in_gvar->declaredAtNode); + if (!preCompiled) + { + // If it wasn't possible to determine the type from the expression then there + // is no need to continue with the initialization. The error was already reported + // in CompileAutoType. + return -1; + } + } + if( in_gvar->property == 0 ) + { + in_gvar->property = builder->module->AllocateGlobalProperty(in_gvar->name.AddressOf(), in_gvar->datatype, in_gvar->ns); + in_gvar->index = in_gvar->property->id; + } + + // Compile the expression + asCExprContext ctx(engine); + asQWORD constantValue = 0; + if( CompileInitialization(in_node, &ctx.bc, in_gvar->datatype, in_gvar->declaredAtNode, in_gvar->index, &constantValue, 1, preCompiled ? &compiledCtx : 0) ) + { + // Should the variable be marked as pure constant? + if( in_gvar->datatype.IsPrimitive() && in_gvar->datatype.IsReadOnly() ) + { + in_gvar->isPureConstant = true; + in_gvar->constantValue = constantValue; + } + } + + // Concatenate the bytecode + int varSize = GetVariableOffset((int)variableAllocations.GetLength()) - 1; + + // Add information on the line number for the global variable + size_t pos = 0; + if( in_gvar->declaredAtNode ) + pos = in_gvar->declaredAtNode->tokenPos; + else if( in_gvar->initializationNode ) + pos = in_gvar->initializationNode->tokenPos; + LineInstr(&byteCode, pos); + + // Reserve space for all local variables + outFunc->scriptData->variableSpace = varSize; + + ctx.bc.OptimizeLocally(tempVariableOffsets); + + byteCode.AddCode(&ctx.bc); + + // Deallocate variables in this block, in reverse order + for( int n = (int)variables->variables.GetLength() - 1; n >= 0; --n ) + { + sVariable *v = variables->variables[n]; + + // Call variable destructors here, for variables not yet destroyed + CallDestructor(v->type, v->stackOffset, v->onHeap, &byteCode); + + DeallocateVariable(v->stackOffset); + } + + if( hasCompileErrors ) return -1; + + // At this point there should be no variables allocated + asASSERT(variableAllocations.GetLength() == freeVariables.GetLength()); + + // Remove the variable scope again + RemoveVariableScope(); + + byteCode.Ret(0); + + FinalizeFunction(); + +#ifdef AS_DEBUG + // DEBUG: output byte code + byteCode.DebugOutput(("___init_" + in_gvar->name + ".txt").AddressOf(), outFunc); +#endif + + return 0; +} + +void asCCompiler::DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node) +{ + // Don't do anything if this is not a deferred global function + if( !ctx->IsGlobalFunc() ) + return; + + // Determine the namespace + asSNameSpace *ns = 0; + asCString name = ""; + int pos = ctx->methodName.FindLast("::"); + if( pos >= 0 ) + { + asCString nsName = ctx->methodName.SubString(0, pos+2); + + // Cut off the :: + if( nsName.GetLength() > 2 ) + nsName.SetLength(nsName.GetLength()-2); + + ns = DetermineNameSpace(nsName); + name = ctx->methodName.SubString(pos+2); + } + else + { + DetermineNameSpace(""); + name = ctx->methodName; + } + + asCArray funcs; + if( ns ) + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + + // CompileVariableAccess should guarantee that at least one function is exists + asASSERT( funcs.GetLength() > 0 ); + + if( funcs.GetLength() > 1 ) + { + asCString str; + str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, ctx->methodName.AddressOf()); + Error(str, node); + + // Fall through so the compiler can continue as if only one function was matching + } + + // A shared object may not access global functions unless they too are shared (e.g. registered functions) + if( !builder->GetFunctionDescription(funcs[0])->IsShared() && + outFunc->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, builder->GetFunctionDescription(funcs[0])->GetDeclaration()); + Error(msg, node); + + // Fall through so the compiler can continue anyway + } + + // Push the function pointer on the stack + ctx->bc.InstrPTR(asBC_FuncPtr, builder->GetFunctionDescription(funcs[0])); + ctx->type.Set(asCDataType::CreateType(engine->FindMatchingFuncdef(builder->GetFunctionDescription(funcs[0]), builder->module), false)); + ctx->type.dataType.MakeHandle(true); + ctx->type.isExplicitHandle = true; + ctx->methodName = ""; +} + +void asCCompiler::CompileInitAsCopy(asCDataType &dt, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination) +{ + bool isObjectOnHeap = derefDestination ? false : IsVariableOnHeap(offset); + + // Use copy constructor if available. + asCObjectType *ot = CastToObjectType(dt.GetTypeInfo()); + if(!dt.IsObjectHandle() && ot && (ot->beh.copyconstruct || ot->beh.copyfactory)) + { + PrepareForAssignment(&dt, arg, node, true); + int r = CallCopyConstructor(dt, offset, isObjectOnHeap, bc, arg, node, 0, derefDestination); + if( r < 0 && tempVariables.Exists(offset) ) + Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node); + } + else + { + // TODO: Need to reserve variables, as the default constructor may need + // to allocate temporary variables to compute default args + + // Allocate and construct the temporary object before whatever is already in the bytecode + asCByteCode tmpBC(engine); + int r = CallDefaultConstructor(dt, offset, isObjectOnHeap, &tmpBC, node, 0, derefDestination); + if( r < 0 ) + { + if( tempVariables.Exists(offset) ) + Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node); + return; + } + + tmpBC.AddCode(bc); + bc->AddCode(&tmpBC); + + // Assign the evaluated expression to the temporary variable + PrepareForAssignment(&dt, arg, node, true); + bc->AddCode(&arg->bc); + + // Call the opAssign method to assign the value to the temporary object + dt.MakeReference(isObjectOnHeap); + asCExprValue type; + type.Set(dt); + type.isTemporary = true; + type.stackOffset = (short)offset; + + if( dt.IsObjectHandle() ) + type.isExplicitHandle = true; + + bc->InstrSHORT(asBC_PSF, (short)offset); + if( derefDestination ) + bc->Instr(asBC_RDSPtr); + + r = PerformAssignment(&type, &arg->type, bc, node); + if( r < 0 ) + { + if( tempVariables.Exists(offset) ) + Error(TXT_FAILED_TO_CREATE_TEMP_OBJ, node); + return; + } + + // Pop the reference that was pushed on the stack if the result is an object + if( type.dataType.IsObject() || type.dataType.IsFuncdef() ) + bc->Instr(asBC_PopPtr); + + // If the assignment operator returned an object by value it will + // be in a temporary variable which we need to destroy now + if( type.isTemporary && type.stackOffset != (short)offset ) + ReleaseTemporaryVariable(type.stackOffset, bc); + + // Release the original value too in case it is a temporary + ReleaseTemporaryVariable(arg->type, bc); + } +} + +int asCCompiler::PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction, int refType, bool isMakingCopy) +{ + asCDataType param = *paramType; + if( paramType->GetTokenType() == ttQuestion ) + { + // The function is expecting a var type. If the argument is a function name, we must now decide which function it is + DetermineSingleFunc(ctx, node); + + // Since the function is expecting a var type ?, then we don't want to convert the argument to anything else + param = ctx->type.dataType; + param.MakeHandle(ctx->type.isExplicitHandle || ctx->type.IsNullConstant()); + + // Treat the void expression like a null handle when working with var types + if( ctx->IsVoidExpression() ) + param = asCDataType::CreateNullHandle(); + + // If value assign is disabled for reference types, then make + // sure to always pass the handle to ? parameters + if( builder->engine->ep.disallowValueAssignForRefType && + ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) ) + { + param.MakeHandle(true); + } + + param.MakeReference(paramType->IsReference()); + param.MakeReadOnly(paramType->IsReadOnly()); + } + else + param = *paramType; + + asCDataType dt = param; + + // Need to protect arguments by reference + if( isFunction && dt.IsReference() ) + { + // Allocate a temporary variable of the same type as the argument + dt.MakeReference(false); + + int offset; + if( refType == asTM_INREF ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // Add the type id as hidden arg if the parameter is a ? type + if( paramType->GetTokenType() == ttQuestion ) + { + asCByteCode tmpBC(engine); + + // Place the type id on the stack as a hidden parameter + tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param)); + + // Insert the code before the expression code + tmpBC.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmpBC); + } + + if( dt.IsPrimitive() ) + { + // If the reference is const, then it is not necessary to make a copy if the value already is a variable + // Even if the same variable is passed in another argument as non-const then there is no problem + IsVariableInitialized(&ctx->type, node); + + if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true); + + if( !(param.IsReadOnly() && ctx->type.isVariable) ) + ConvertToTempVariable(ctx); + + PushVariableOnStack(ctx, true); + ctx->type.dataType.MakeReadOnly(param.IsReadOnly()); + } + else if( ctx->type.dataType.IsNullHandle() ) + { + // Make sure the argument type can support handles (or is itself a handle) + if( !dt.SupportHandles() && !dt.IsObjectHandle() ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + ctx->type.Set(param); + return -1; + } + + // Need to initialize a local temporary variable to + // represent the null handle when passed as reference + asASSERT( ctx->bc.GetLastInstr() == asBC_PshNull ); + ctx->bc.Instr(asBC_PopPtr); + + dt.MakeHandle(true); + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Push the reference to the variable on the stack + ctx->bc.InstrWORD(asBC_PSF, (short)offset); + + ctx->type.SetVariable(dt, offset, true); + ctx->type.isExplicitHandle = true; + } + else + { + IsVariableInitialized(&ctx->type, node); + + if( !isMakingCopy ) + { + // For parameters expecting a reference to a handle we need to make sure the argument + // is really a handle, and not just a reference to the object. Do this check before the + // implicit conversion so it can be treated correctly. + if (dt.IsObjectHandle() && !ctx->type.dataType.IsObjectHandle()) + { + // Make a refCopy into a local handle variable + // Allocate a handle variable + dt.MakeHandle(true); + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + Dereference(ctx, true); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + // Release the original temporary variable + if( ctx->type.isTemporary ) + ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc); + + ctx->type.SetVariable(dt, offset, true); + } + + // Even though the parameter expects a reference, it is only meant to be + // used as input value and doesn't have to refer to the actual object, so it + // is OK to do an implicit conversion. + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true); + if( !ctx->type.dataType.IsEqualExceptRefAndConst(param) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), param.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + ctx->type.Set(param); + return -1; + } + + // The compiler must guarantee that the object stays alive during the execution + // of the function, and it must also guarantee that the value isn't modified by + // the function. + + // If the argument is a temporary local variable then it is safe to be passed to + // the function as it is, since the local variable will stay alive, and since it + // is temporary there is no side effect if the function modifies it. + + // If the parameter is read-only and therefore guaranteed not to be modified by the + // function, then it is enough that the variable is local to guarantee the lifetime. + if( !ctx->type.isTemporary && !(param.IsReadOnly() && (ctx->type.isVariable || ctx->type.isRefSafe)) ) + { + if( ctx->type.dataType.IsFuncdef() || ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && param.IsReadOnly() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED)) ) + { + // Funcdefs only need an extra handle to guarantee the lifetime. + + // If the object is a reference type (except scoped reference types), and the + // parameter is a const reference, then it is not necessary to make a copy of the + // object. The compiler just needs to hold a handle to guarantee the lifetime. + + // Allocate a handle variable + dt.MakeHandle(true); + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + Dereference(ctx, true); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + // The type should be set to the param type instead of dt to guarantee + // that the expression keeps the correct type for variable ? args. Otherwise + // MoveArgsToStack will use the wrong bytecode to move the arg to the stack + bool isExplicitHandle = ctx->type.isExplicitHandle; + ctx->type.SetVariable(param, offset, true); + ctx->type.dataType.MakeHandle(true); + ctx->type.isExplicitHandle = isExplicitHandle; + } + else + { + // Make a copy of the object to guarantee that the original isn't modified + asASSERT(!dt.IsFuncdef()); + + // Allocate and initialize a temporary local object + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); + + // Push the object pointer on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + if( dt.IsObject() && !dt.IsObjectHandle() ) + ctx->bc.Instr(asBC_RDSPtr); + + // Set the resulting type + ctx->type.Set(dt); + ctx->type.isTemporary = true; + ctx->type.stackOffset = short(offset); + if( dt.IsObjectHandle() ) + ctx->type.isExplicitHandle = true; + ctx->type.dataType.MakeReference(false); + if( paramType->IsReadOnly() ) + ctx->type.dataType.MakeReadOnly(true); + } + } + + // When calling a function expecting a var arg with a parameter received as reference to handle + // then it is necessary to copy the handle to a local variable, otherwise MoveArgsToStack will + // not be able to do the correct double dereference to put the reference to the object on the stack. + if (paramType->GetTokenType() == ttQuestion && !param.IsObjectHandle() && ctx->type.isVariable) + { + sVariable *var = variables->GetVariableByOffset(ctx->type.stackOffset); + if (var && var->type.IsReference() && var->type.IsObjectHandle()) + { + // Copy the handle to local variable + + // Allocate a handle variable + dt.MakeHandle(true); + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + Dereference(ctx, true); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if (ctx->type.dataType.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + // The type should be set to the param type instead of dt to guarantee + // that the expression keeps the correct type for variable ? args. Otherwise + // MoveArgsToStack will use the wrong bytecode to move the arg to the stack + ctx->type.SetVariable(param, offset, true); + } + } + } + else + { + // We must guarantee that the address to the value is on the stack + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && + !ctx->type.dataType.IsObjectHandle() && + ctx->type.dataType.IsReference() ) + Dereference(ctx, true); + } + } + } + else if( refType == asTM_OUTREF ) + { + // Add the type id as hidden arg if the parameter is a ? type + if( paramType->GetTokenType() == ttQuestion ) + { + asCByteCode tmpBC(engine); + + // Place the type id on the stack as a hidden parameter + tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param)); + + // Insert the code before the expression code + tmpBC.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmpBC); + } + + // If the expression is marked as clean, then it can be used directly + // without the need to allocate another temporary value as it is known + // that the argument has no other value than the default + if( ctx->isCleanArg ) + { + // Must be a local variable + asASSERT( ctx->type.isVariable ); + } + else + { + // Null handles and void expressions must be marked as explicit + // handles for correct treatement in MoveArgsToStack + if (dt.IsNullHandle()) + ctx->type.isExplicitHandle = true; + + // Make sure the variable is not used in the expression + dt.MakeReadOnly(false); + offset = AllocateVariableNotIn(dt, true, false, ctx); + + if( dt.IsPrimitive() ) + { + ctx->type.SetVariable(dt, offset, true); + PushVariableOnStack(ctx, true); + } + else + { + // Allocate and construct the temporary object + asCByteCode tmpBC(engine); + CallDefaultConstructor(dt, offset, IsVariableOnHeap(offset), &tmpBC, node); + + // Insert the code before the expression code + tmpBC.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmpBC); + + dt.MakeReference(!(dt.IsObject() || dt.IsFuncdef()) || dt.IsObjectHandle()); + asCExprValue type; + type.Set(dt); + type.isTemporary = true; + type.stackOffset = (short)offset; + + type.isExplicitHandle = ctx->type.isExplicitHandle; + ctx->type = type; + + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsObjectHandle() ) + ctx->bc.Instr(asBC_RDSPtr); + } + + // After the function returns the temporary variable will + // be assigned to the expression, if it is a valid lvalue + } + } + else if( refType == asTM_INOUTREF ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // Add the type id as hidden arg if the parameter is a ? type + if( paramType->GetTokenType() == ttQuestion ) + { + asCByteCode tmpBC(engine); + + // Place the type id on the stack as a hidden parameter + tmpBC.InstrDWORD(asBC_TYPEID, engine->GetTypeIdFromDataType(param)); + + // Insert the code before the expression code + tmpBC.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmpBC); + } + + // Literal constants cannot be passed to inout ref arguments + if( !ctx->type.isVariable && + ctx->type.isConstant && + !ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType) ) + { + // Unless unsafe references are turned on and the reference is const + if( param.IsReadOnly() && engine->ep.allowUnsafeReferences ) + { + // Since the parameter is a const & make a copy. + ConvertToTempVariable(ctx); + ctx->type.dataType.MakeReadOnly(true); + } + else + { + Error(TXT_NOT_VALID_REFERENCE, node); + return -1; + } + } + + // Allow anonymous init lists to be converted to the arg type + if( ctx->IsAnonymousInitList() ) + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, true); + + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.GetTypeInfo() != dt.GetTypeInfo() ) + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV, true, false); + + // Only objects that support object handles + // can be guaranteed to be safe. Local variables are + // already safe, so there is no need to add an extra + // references + if( !engine->ep.allowUnsafeReferences && + !ctx->type.isVariable && + (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && + !ctx->type.dataType.IsObjectHandle() && + ((ctx->type.dataType.GetBehaviour()->addref && + ctx->type.dataType.GetBehaviour()->release) || + (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT) || + ctx->type.dataType.IsFuncdef()) ) + { + // Store a handle to the object as local variable + asCExprContext tmp(engine); + dt = ctx->type.dataType; + dt.MakeHandle(true); + dt.MakeReference(false); + dt.MakeReadOnly(false); + + offset = AllocateVariableNotIn(dt, true, false, ctx); + + // Copy the handle + if( !ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReference() ) + ctx->bc.Instr(asBC_RDSPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + if( ctx->type.dataType.IsFuncdef() ) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrWORD(asBC_PSF, (asWORD)offset); + + dt.MakeHandle(false); + dt.MakeReference(true); + + // Release previous temporary variable stored in the context (if any) + if( ctx->type.isTemporary ) + ReleaseTemporaryVariable(ctx->type.stackOffset, &ctx->bc); + + ctx->type.SetVariable(dt, offset, true); + } + + // Make sure the reference to the value is on the stack + // For objects, the reference needs to be dereferenced so the pointer on the stack is to the actual object + // For handles, the reference shouldn't be changed because the pointer on the stack should be to the handle + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && ctx->type.dataType.IsReference() && !param.IsObjectHandle() ) + Dereference(ctx, true); + else if( ctx->type.isVariable && !(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) ) + ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); + else if( ctx->type.dataType.IsPrimitive() ) + ctx->bc.Instr(asBC_PshRPtr); + else if( ctx->type.dataType.IsObjectHandle() && !ctx->type.dataType.IsReference() ) + ImplicitConversion(ctx, param, node, asIC_IMPLICIT_CONV, true, false); + } + } + else + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + if( dt.IsPrimitive() ) + { + IsVariableInitialized(&ctx->type, node); + + if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); + + // Implicitly convert primitives to the parameter type + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV); + + if( ctx->type.isVariable ) + { + PushVariableOnStack(ctx, dt.IsReference()); + } + else if( ctx->type.isConstant ) + { + ConvertToVariable(ctx); + PushVariableOnStack(ctx, dt.IsReference()); + } + } + else + { + IsVariableInitialized(&ctx->type, node); + + // Implicitly convert primitives to the parameter type + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV); + + // Was the conversion successful? + if( !ctx->type.dataType.IsEqualExceptRef(dt) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), dt.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + ctx->type.Set(dt); + return -1; + } + + if( dt.IsObjectHandle() ) + ctx->type.isExplicitHandle = true; + + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsNullHandle() && !dt.IsReference() ) + { + // Objects passed by value must be placed in temporary variables + // so that they are guaranteed to not be referenced anywhere else. + // The object must also be allocated on the heap, as the memory will + // be deleted by the called function. + + // Handles passed by value must also be placed in a temporary variable + // to guarantee that the object referred to isn't freed too early. + + // TODO: value on stack: How can we avoid this unnecessary allocation? + + // Don't make temporary copies of handles if it is going to be used + // for handle assignment anyway, i.e. REFCPY. + if( !(!isFunction && isMakingCopy && ctx->type.dataType.IsObjectHandle() && ctx->type.isVariable) ) + PrepareTemporaryVariable(node, ctx, true); + } + } + } + + // Don't put any pointer on the stack yet + if( param.IsReference() || ((param.IsObject() || param.IsFuncdef()) && !param.IsNullHandle()) ) + { + // &inout parameter may leave the reference on the stack already + // references considered safe too, i.e. when the life time is known + if( refType != asTM_INOUTREF && !ctx->type.isRefSafe ) + { + asASSERT( ctx->type.isVariable || ctx->type.isRefSafe || ctx->type.isTemporary || isMakingCopy ); + + if( ctx->type.isVariable || ctx->type.isTemporary ) + { + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrSHORT(asBC_VAR, ctx->type.stackOffset); + + ProcessDeferredParams(ctx); + } + } + } + + return 0; +} + +int asCCompiler::PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args) +{ + // When a match has been found, compile the final byte code using correct parameter types + asCScriptFunction *descr = builder->GetFunctionDescription(funcId); + + asASSERT( descr->parameterTypes.GetLength() == args.GetLength() ); + + // If the function being called is the opAssign or copy constructor for the same type + // as the argument, then we should avoid making temporary copy of the argument + bool makingCopy = false; + if( descr->parameterTypes.GetLength() == 1 && + descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) && + (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || + (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) + makingCopy = true; + + // Add code for arguments + asCExprContext e(engine); + for( int n = (int)args.GetLength()-1; n >= 0; n-- ) + { + // Make sure PrepareArgument doesn't use any variable that is already + // being used by the argument or any of the following argument expressions + int l = int(reservedVariables.GetLength()); + for( int m = n; m >= 0; m-- ) + args[m]->bc.GetVarsUsed(reservedVariables); + + int r = PrepareArgument2(&e, args[n], &descr->parameterTypes[n], true, descr->inOutFlags[n], makingCopy); + reservedVariables.SetLength(l); + + if (r < 0) + return r; + } + + bc->AddCode(&e.bc); + + return 0; +} + +void asCCompiler::MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset) +{ + asCScriptFunction *descr = builder->GetFunctionDescription(funcId); + + int offset = 0; + if( addOneToOffset ) + offset += AS_PTR_SIZE; + + // The address of where the return value should be stored is push on top of the arguments + if( descr->DoesReturnOnStack() ) + offset += AS_PTR_SIZE; + +#ifdef AS_DEBUG + // If the function being called is the opAssign or copy constructor for the same type + // as the argument, then we should avoid making temporary copy of the argument + bool makingCopy = false; + if( descr->parameterTypes.GetLength() == 1 && + descr->parameterTypes[0].IsEqualExceptRefAndConst(args[0]->type.dataType) && + (((descr->name == "opAssign" || descr->name == "$beh0") && descr->objectType && descr->objectType == args[0]->type.dataType.GetTypeInfo()) || + (descr->objectType == 0 && args[0]->type.dataType.GetTypeInfo() && descr->name == args[0]->type.dataType.GetTypeInfo()->name)) ) + makingCopy = true; +#endif + + // Move the objects that are sent by value to the stack just before the call + for( asUINT n = 0; n < descr->parameterTypes.GetLength(); n++ ) + { + if( descr->parameterTypes[n].IsReference() ) + { + if( (descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef()) && !descr->parameterTypes[n].IsObjectHandle() ) + { + if( descr->inOutFlags[n] != asTM_INOUTREF && !args[n]->type.isRefSafe ) + { +#ifdef AS_DEBUG + // This assert is inside AS_DEBUG because of the variable makingCopy which is only defined in debug mode + asASSERT( args[n]->type.isVariable || args[n]->type.isTemporary || makingCopy ); +#endif + + if( (args[n]->type.isVariable || args[n]->type.isTemporary) ) + { + if( !IsVariableOnHeap(args[n]->type.stackOffset) ) + // TODO: runtime optimize: Actually the reference can be pushed on the stack directly + // as the value allocated on the stack is guaranteed to be safe + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); + } + } + if( args[n]->type.dataType.IsObjectHandle() ) + bc->InstrWORD(asBC_ChkNullS, (asWORD)offset); + } + else if( descr->inOutFlags[n] != asTM_INOUTREF ) + { + // If the argument is already known to be safe, i.e. has a guaranteed lifetime, + // then the address on the stack is already pointing to the correct object so no + // need to do anything else + if (!args[n]->type.isRefSafe) + { + if (descr->parameterTypes[n].GetTokenType() == ttQuestion && + (args[n]->type.dataType.IsObject() || args[n]->type.dataType.IsFuncdef()) && + !args[n]->type.dataType.IsObjectHandle()) + { + // Send the object as a reference to the object, + // and not to the variable holding the object + if (!IsVariableOnHeap(args[n]->type.stackOffset)) + // TODO: runtime optimize: Actually the reference can be pushed on the stack directly + // as the value allocated on the stack is guaranteed to be safe + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); + } + else if (descr->parameterTypes[n].GetTokenType() == ttQuestion && + args[n]->type.dataType.IsObjectHandle() && !args[n]->type.isExplicitHandle) + { + // The object handle is being passed as an object, so dereference it before + // the call so the reference will be to the object rather than to the handle + if (engine->ep.disallowValueAssignForRefType) + { + // With disallow value assign all ref type objects are always passed by handle + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); + } + else + { + // If the variable is really an argument of @& type, then it is necessary + // to use asBC_GETOBJREF so the pointer is correctly dereferenced. + sVariable *var = variables->GetVariableByOffset(args[n]->type.stackOffset); + if (var == 0 || !var->type.IsReference() || !var->type.IsObjectHandle()) + bc->InstrWORD(asBC_GETREF, (asWORD)offset); + else + bc->InstrWORD(asBC_GETOBJREF, (asWORD)offset); + } + } + } + } + else if( descr->parameterTypes[n].IsObject() || descr->parameterTypes[n].IsFuncdef() ) + { + asASSERT(!args[n]->type.isRefSafe); + + // TODO: value on stack: What can we do to avoid this unnecessary allocation? + // The object must be allocated on the heap, because this memory will be deleted in as_callfunc_xxx + asASSERT(IsVariableOnHeap(args[n]->type.stackOffset)); + + // The pointer in the variable will be moved to the stack + bc->InstrWORD(asBC_GETOBJ, (asWORD)offset); + + // Deallocate the variable slot so it can be reused, but do not attempt to + // free the content of the variable since it was moved to the stack for the call + DeallocateVariable(args[n]->type.stackOffset); + args[n]->type.isTemporary = false; + } + + offset += descr->parameterTypes[n].GetSizeOnStackDWords(); + } +} + +int asCCompiler::CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs) +{ + asASSERT(node->nodeType == snArgList); + + // Count arguments + asCScriptNode *arg = node->firstChild; + int argCount = 0; + while( arg ) + { + if( arg->nodeType != snNamedArgument ) + argCount++; + arg = arg->next; + } + + // Prepare the arrays + args.SetLength(argCount); + int n; + for( n = 0; n < argCount; n++ ) + args[n] = 0; + + n = argCount-1; + + // Compile the arguments in reverse order (as they will be pushed on the stack) + bool anyErrors = false, inPositionalArguments = false; + arg = node->lastChild; + while( arg ) + { + asCScriptNode *asgNode = arg, *namedNode = 0; + if( asgNode->nodeType == snNamedArgument ) + { + if( inPositionalArguments ) + { + Error(TXT_POS_ARG_AFTER_NAMED_ARG, node); + return -1; + } + + asgNode = arg->firstChild->next; + namedNode = arg->firstChild; + + asASSERT( namedNode->nodeType == snIdentifier ); + } + else + inPositionalArguments = true; + + asCExprContext expr(engine); + int r = CompileAssignment(asgNode, &expr); + if( r < 0 ) anyErrors = true; + + asCExprContext *ctx = asNEW(asCExprContext)(engine); + if( ctx == 0 ) + { + // Out of memory + return -1; + } + MergeExprBytecodeAndType(ctx, &expr); + + if( inPositionalArguments ) + { + args[n] = ctx; + n--; + } + else + { + asSNamedArgument namedArg; + namedArg.name = asCString(&script->code[namedNode->tokenPos], namedNode->tokenLength); + namedArg.ctx = ctx; + + // Error out when multiple arguments with the same name are passed + for( asUINT a = 0; a < namedArgs.GetLength(); ++a ) + { + if( namedArgs[a].name == namedArg.name ) + { + Error(TXT_DUPLICATE_NAMED_ARG, asgNode); + anyErrors = true; + break; + } + } + + namedArgs.PushLast(namedArg); + } + + arg = arg->prev; + } + + return anyErrors ? -1 : 0; +} + +int asCCompiler::CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *objectType, asCArray *namedArgs) +{ + asCScriptFunction *func = builder->GetFunctionDescription(funcId); + if( func == 0 || args.GetLength() >= (asUINT)func->GetParamCount() ) + return 0; + + // Make sure to use the real function for virtual functions + if( func->funcType == asFUNC_VIRTUAL ) + { + asASSERT( objectType ); + func = objectType->virtualFunctionTable[func->vfTableIdx]; + } + + // Make sure none of the variables used in the previous arguments are reused in the default arguments + bool anyErrors = false; + int prevReservedVars = reservedVariables.GetLength(); + + int explicitArgs = (int)args.GetLength(); + + for( int p = 0; p < explicitArgs; p++ ) + args[p]->bc.GetVarsUsed(reservedVariables); + + // Make space for all the new arguments + args.SetLength(func->parameterTypes.GetLength()); + for( asUINT c = explicitArgs; c < args.GetLength(); c++ ) + args[c] = 0; + + // Add the named arguments to the argument list in the right position + if( namedArgs ) + { + for( asUINT n = 0; n < namedArgs->GetLength(); ++n ) + { + asSNamedArgument &named = (*namedArgs)[n]; + named.ctx->bc.GetVarsUsed(reservedVariables); + + // Find the right spot to put it in + asUINT index = asUINT(-1); + for( asUINT j = 0; j < func->parameterTypes.GetLength(); ++j ) + { + if( func->parameterNames[j] == (*namedArgs)[n].name ) + { + index = j; + break; + } + } + + asASSERT( index < args.GetLength() ); + args[index] = named.ctx; + named.ctx = 0; + } + } + + // Compile the arguments in reverse order (as they will be pushed on the stack) + for( int n = (int)func->parameterTypes.GetLength() - 1; n >= explicitArgs; n-- ) + { + if( args[n] != 0 ) continue; + if( func->defaultArgs[n] == 0 ) { anyErrors = true; continue; } + + // Parse the default arg string + asCParser parser(builder); + asCScriptCode *code = builder->FindOrAddCode("default arg", func->defaultArgs[n]->AddressOf(), func->defaultArgs[n]->GetLength()); + int r = parser.ParseExpression(code); + if( r < 0 ) + { + asCString msg; + msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration()); + Error(msg, node); + anyErrors = true; + continue; + } + + asCScriptNode *arg = parser.GetScriptNode(); + + // Temporarily set the script code to the default arg expression + asCScriptCode *origScript = script; + script = code; + + // Don't allow the expression to access local variables + isCompilingDefaultArg = true; + + // Temporarily set the namespace in the output function to the namespace of the called + // function so that the default arguments are evaluated in the correct namespace + asSNameSpace *origNameSpace = outFunc->nameSpace; + outFunc->nameSpace = func->nameSpace; + + asCExprContext expr(engine); + r = CompileExpression(arg, &expr); + + // Restore the namespace + outFunc->nameSpace = origNameSpace; + + // Don't allow address of class method + if( expr.IsClassMethod() ) + { + // TODO: Improve error message + Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg); + r = -1; + } + + // Make sure the expression can be implicitly converted to the parameter type + if( r >= 0 ) + { + asCArray funcs; + funcs.PushLast(func->id); + asCArray matches; + if( MatchArgument(funcs, matches, &expr, n) == 0 ) + { + Error(TXT_DEF_ARG_TYPE_DOESNT_MATCH, arg); + r = -1; + } + } + + isCompilingDefaultArg = false; + + script = origScript; + + if( r < 0 ) + { + asCString msg; + msg.Format(TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s, n, func->GetDeclaration()); + Error(msg, node); + anyErrors = true; + continue; + } + + args[n] = asNEW(asCExprContext)(engine); + if( args[n] == 0 ) + { + // Out of memory + reservedVariables.SetLength(prevReservedVars); + return -1; + } + + MergeExprBytecodeAndType(args[n], &expr); + if (args[n]->exprNode) + { + // Disconnect the node from the parser, and tell the compiler to free it when complete + args[n]->exprNode->DisconnectParent(); + nodesToFreeUponComplete.PushLast(args[n]->exprNode); + } + } + + reservedVariables.SetLength(prevReservedVars); + return anyErrors ? -1 : 0; +} + +asUINT asCCompiler::MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs, asCObjectType *objectType, bool isConstMethod, bool silent, bool allowObjectConstruct, const asCString &scope) +{ + asCArray origFuncs = funcs; // Keep the original list for error message + asUINT cost = 0; + asUINT n; + + if( funcs.GetLength() > 0 ) + { + // Check the number of parameters in the found functions + asUINT totalArgs = (asUINT)args.GetLength(); + if( namedArgs != 0 ) + totalArgs += (asUINT)namedArgs->GetLength(); + + for( n = 0; n < funcs.GetLength(); ++n ) + { + asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]); + + if( desc->parameterTypes.GetLength() != totalArgs ) + { + bool noMatch = true; + if( totalArgs < desc->parameterTypes.GetLength() ) + { + // For virtual functions, the default args are defined in the real function of the object + if( desc->funcType == asFUNC_VIRTUAL ) + desc = objectType->virtualFunctionTable[desc->vfTableIdx]; + + // Count the number of default args + asUINT defaultArgs = 0; + for( asUINT d = 0; d < desc->defaultArgs.GetLength(); d++ ) + if( desc->defaultArgs[d] ) + defaultArgs++; + + if( totalArgs >= desc->parameterTypes.GetLength() - defaultArgs ) + noMatch = false; + } + + if( noMatch ) + { + // remove it from the list + if( n == funcs.GetLength()-1 ) + funcs.PopLast(); + else + funcs[n] = funcs.PopLast(); + n--; + } + } + } + + // Match functions with the parameters, and discard those that do not match + asCArray matchingFuncs; + matchingFuncs.SetLengthNoConstruct( funcs.GetLength() ); + for ( n = 0; n < funcs.GetLength(); ++n ) + { + matchingFuncs[n].funcId = funcs[n]; + matchingFuncs[n].cost = 0; + } + + // Match positionally passed arguments + for( n = 0; n < args.GetLength(); ++n ) + { + asCArray tempFuncs; + MatchArgument(funcs, tempFuncs, args[n], n, allowObjectConstruct); + + // Intersect the found functions with the list of matching functions + for( asUINT f = 0; f < matchingFuncs.GetLength(); f++ ) + { + asUINT c; + for( c = 0; c < tempFuncs.GetLength(); c++ ) + { + if( matchingFuncs[f].funcId == tempFuncs[c].funcId ) + { + // Sum argument cost + matchingFuncs[f].cost += tempFuncs[c].cost; + break; + + } // End if match + } + + // Was the function a match? + if( c == tempFuncs.GetLength() ) + { + // No, remove it from the list + if( f == matchingFuncs.GetLength()-1 ) + matchingFuncs.PopLast(); + else + matchingFuncs[f] = matchingFuncs.PopLast(); + f--; + } + } + } + + // Match named arguments + if( namedArgs != 0 ) + { + for( asUINT i = 0; i < matchingFuncs.GetLength(); ++i ) + { + asCScriptFunction *desc = builder->GetFunctionDescription(matchingFuncs[i].funcId); + if( desc->funcType == asFUNC_VIRTUAL ) + desc = objectType->virtualFunctionTable[desc->vfTableIdx]; + + // Match every named argument to an argument in the function + for( n = 0; n < namedArgs->GetLength(); ++n ) + (*namedArgs)[n].match = asUINT(-1); + + bool matchedAll = true; + for( asUINT j = 0; j < desc->parameterTypes.GetLength(); ++j ) + { + asUINT match = asUINT(-1); + for( n = 0; n < namedArgs->GetLength(); ++n ) + { + asSNamedArgument &namedArg = (*namedArgs)[n]; + if( desc->parameterNames[j] == namedArg.name ) + { + namedArg.match = j; + match = n; + break; + } + } + + // Check that every position is filled somehow + if( j >= args.GetLength() ) + { + if( match == asUINT(-1) && !desc->defaultArgs[j] ) + { + // No argument was found for this, and there is no + // default, so it doesn't work. + matchedAll = false; + break; + } + } + else + { + if( match != asUINT(-1) ) + { + // Can't name an argument that was already passed + matchedAll = false; + break; + } + } + } + + // Check that every named argument was matched + if( matchedAll ) + { + for( n = 0; n < namedArgs->GetLength(); ++n ) + { + asSNamedArgument &named = (*namedArgs)[n]; + + if( named.match == asUINT(-1) ) + { + matchedAll = false; + break; + } + + // Add to the cost + cost = MatchArgument(desc, named.ctx, named.match, allowObjectConstruct); + if( cost == asUINT(-1) ) + { + matchedAll = false; + break; + } + + matchingFuncs[i].cost += cost; + } + } + + if( !matchedAll ) + { + // Remove the function, we didn't match all the arguments. + if( i == matchingFuncs.GetLength()-1 ) + matchingFuncs.PopLast(); + else + matchingFuncs[i] = matchingFuncs.PopLast(); + i--; + } + } + } + + // Select the overload(s) with the lowest overall cost + funcs.SetLength(0); + asUINT bestCost = asUINT(-1); + for( n = 0; n < matchingFuncs.GetLength(); ++n ) + { + cost = matchingFuncs[n].cost; + if( cost < bestCost ) + { + funcs.SetLength(0); + bestCost = cost; + } + if( cost == bestCost ) + funcs.PushLast( matchingFuncs[n].funcId ); + } + + // Cost returned is equivalent to the best cost discovered + cost = bestCost; + } + + if( !isConstMethod ) + FilterConst(funcs); + + if( funcs.GetLength() != 1 && !silent ) + { + // Build a readable string of the function with parameter types + bool attemptsPassingClassMethod = false; + asCString str; + if( scope != "" && scope != "::" ) + str = scope + "::"; + str += name; + str += "("; + for( n = 0; n < args.GetLength(); n++ ) + { + if( n > 0 ) + str += ", "; + if( args[n]->methodName != "" ) + { + if( args[n]->IsClassMethod() ) + { + attemptsPassingClassMethod = true; + str += args[n]->type.dataType.GetTypeInfo()->GetName(); + str += "::"; + } + str += args[n]->methodName; + } + else if (args[n]->IsAnonymousInitList()) + { + str += "{...}"; + } + else + str += args[n]->type.dataType.Format(outFunc->nameSpace); + } + if( namedArgs != 0 ) + { + for( n = 0; n < namedArgs->GetLength(); n++ ) + { + if( n > 0 || args.GetLength() ) + str += ", "; + + asSNamedArgument &named = (*namedArgs)[n]; + str += named.name; + str += ": "; + if( named.ctx->methodName != "" ) + str += named.ctx->methodName; + else + str += named.ctx->type.dataType.Format(outFunc->nameSpace); + } + } + str += ")"; + + if( isConstMethod ) + str += " const"; + + if( objectType && scope == "" ) + str = objectType->name + "::" + str; + + if( funcs.GetLength() == 0 ) + { + str.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, str.AddressOf()); + Error(str, node); + + if( attemptsPassingClassMethod ) + { + // Class methods must use delegate objects + Error(TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG, node); + } + else + { + // Print the list of candidates + if( origFuncs.GetLength() > 0 ) + { + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + builder->WriteInfo(script->name.AddressOf(), TXT_CANDIDATES_ARE, r, c, false); + PrintMatchingFuncs(origFuncs, node, objectType); + } + } + } + else + { + asASSERT( attemptsPassingClassMethod == false ); + + str.Format(TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s, str.AddressOf()); + Error(str, node); + + PrintMatchingFuncs(funcs, node, objectType); + } + } + + return cost; +} + +bool asCCompiler::CompileAutoType(asCDataType &type, asCExprContext &compiledCtx, asCScriptNode *node, asCScriptNode *errNode) +{ + if( node && node->nodeType == snAssignment ) + { + int r = CompileAssignment(node, &compiledCtx); + if( r >= 0 ) + { + // Must not have unused ambiguous names + if (compiledCtx.IsClassMethod() || compiledCtx.IsGlobalFunc()) + { + // TODO: Should mention that the problem is the ambiguous name + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + // Must not have unused anonymous functions + if (compiledCtx.IsLambda()) + { + // TODO: Should mention that the problem is the anonymous function + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + // Must not be a null handle + if (compiledCtx.type.dataType.IsNullHandle()) + { + // TODO: Should mention that the problem is the null pointer + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + return false; + } + + asCDataType newType = compiledCtx.type.dataType; + + // Handle const qualifier on auto + if (type.IsReadOnly()) + newType.MakeReadOnly(true); + else if (type.IsHandleToConst()) + newType.MakeHandleToConst(true); + else if (newType.IsPrimitive()) + newType.MakeReadOnly(false); + + // Handle reference/value stuff + newType.MakeReference(false); + if (!newType.IsObjectHandle()) + { + // We got a value object or an object reference. + // Turn the variable into a handle if specified + // as auto@, otherwise make it a 'value'. + if (type.IsHandleToAuto()) + { + if (newType.MakeHandle(true) < 0) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, errNode); + return false; + } + } + } + + // Implicit handle types should always be handles + if (newType.GetTypeInfo() && + (newType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)) + newType.MakeHandle(true); + + // For types that support handles auto should prefer handle + // as it is more efficient than making a copy + // TODO: 'auto a = ...;' and 'auto @a = ...;' works the same in this case. Is this what we want? + if( newType.SupportHandles() ) + newType.MakeHandle(true); + + type = newType; + return true; + } + + return false; + } + else + { + Error(TXT_CANNOT_RESOLVE_AUTO, errNode); + type = asCDataType::CreatePrimitive(ttInt, false); + return false; + } +} + +void asCCompiler::CompileDeclaration(asCScriptNode *decl, asCByteCode *bc) +{ + // Get the data type + asCDataType type = builder->CreateDataTypeFromNode(decl->firstChild, script, outFunc->nameSpace, false, outFunc->objectType); + + // Declare all variables in this declaration + asCScriptNode *node = decl->firstChild->next; + while( node ) + { + // If this is an auto type, we have to compile the assignment now to figure out the type + asCExprContext compiledCtx(engine); + bool preCompiled = false; + if (type.IsAuto()) + { + preCompiled = CompileAutoType(type, compiledCtx, node->next, node); + if (!preCompiled) + { + // If it wasn't possible to determine the type from the expression then there + // is no need to continue with the initialization. The error was already reported + // in CompileAutoType. + return; + } + } + + // Is the type allowed? + if( !type.CanBeInstantiated() ) + { + asCString str; + if( type.IsAbstractClass() ) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf()); + else if( type.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, type.Format(outFunc->nameSpace).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, type.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + // Don't continue, as it will most likely lead to further + // errors that may just mislead the script writer + return; + } + + // A shared object may not declare variables of non-shared types + if( outFunc->IsShared() ) + { + asCTypeInfo *ot = type.GetTypeInfo(); + if( ot && !ot->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, ot->name.AddressOf()); + Error(msg, decl); + } + } + + // Get the name of the identifier + asCString name(&script->code[node->tokenPos], node->tokenLength); + + // Verify that the name isn't used by a dynamic data type + // TODO: Must check against registered funcdefs too + if( engine->GetRegisteredType(name.AddressOf(), outFunc->nameSpace) != 0 ) + { + asCString str; + str.Format(TXT_ILLEGAL_VARIABLE_NAME_s, name.AddressOf()); + Error(str, node); + } + + int offset = AllocateVariable(type, false); + if( variables->DeclareVariable(name.AddressOf(), type, offset, IsVariableOnHeap(offset)) < 0 ) + { + // TODO: It might be an out-of-memory too + + asCString str; + str.Format(TXT_s_ALREADY_DECLARED, name.AddressOf()); + Error(str, node); + + // Don't continue after this error, as it will just + // lead to more errors that are likely false + return; + } + else + { + // Warn if this variable hides another variable in a higher scope + if( variables->parent && variables->parent->GetVariable(name.AddressOf()) ) + { + asCString str; + str.Format(TXT_s_HIDES_VAR_IN_OUTER_SCOPE, name.AddressOf()); + Warning(str, node); + } + } + + // Add marker that the variable has been declared + bc->VarDecl((int)outFunc->scriptData->variables.GetLength()); + outFunc->AddVariable(name, type, offset); + + // Keep the node for the variable decl + asCScriptNode *varNode = node; + + node = node->next; + + if( node == 0 || node->nodeType == snIdentifier ) + { + // Initialize with default constructor + CompileInitialization(0, bc, type, varNode, offset, 0, 0); + } + else + { + // Compile the initialization expression + asQWORD constantValue = 0; + if( CompileInitialization(node, bc, type, varNode, offset, &constantValue, 0, preCompiled ? &compiledCtx : 0) ) + { + // Check if the variable should be marked as pure constant + if( type.IsPrimitive() && type.IsReadOnly() ) + { + sVariable *v = variables->GetVariable(name.AddressOf()); + v->isPureConstant = true; + v->constantValue = constantValue; + } + } + node = node->next; + } + } + + bc->OptimizeLocally(tempVariableOffsets); +} + +// Returns true if the initialization expression is a constant expression +bool asCCompiler::CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled) +{ + bool isConstantExpression = false; + if( node && node->nodeType == snArgList ) + { + // Make sure it is an object and not a handle + if( type.GetTypeInfo() == 0 || type.IsObjectHandle() ) + { + Error(TXT_MUST_BE_OBJECT, node); + } + else + { + // Compile the arguments + asCArray args; + asCArray namedArgs; + if( CompileArgumentList(node, args, namedArgs) >= 0 ) + { + // Find all constructors + asCArray funcs; + asSTypeBehaviour *beh = type.GetBehaviour(); + if( beh ) + { + if( type.GetTypeInfo()->flags & asOBJ_REF ) + funcs = beh->factories; + else + funcs = beh->constructors; + } + + asCString str = type.Format(outFunc->nameSpace); + MatchFunctions(funcs, args, node, str.AddressOf(), &namedArgs); + + if( funcs.GetLength() == 1 ) + { + // Add the default values for arguments not explicitly supplied + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo()), &namedArgs); + + if( r == asSUCCESS ) + { + asCExprContext ctx(engine); + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) ) + { + if( isVarGlobOrMem == 0 ) + MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset); + else + { + MakeFunctionCall(&ctx, funcs[0], 0, args, node); + ctx.bc.Instr(asBC_RDSPtr); + if( isVarGlobOrMem == 1 ) + { + // Store the returned handle in the global variable + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + } + else + { + // Store the returned handle in the member + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + if( type.IsFuncdef()) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); + } + + // Pop the reference left by the function call + ctx.bc.Instr(asBC_PopPtr); + } + else + { + bool onHeap = false; + + if( isVarGlobOrMem == 0 ) + { + // When the object is allocated on the heap, the address where the + // reference will be stored must be pushed on the stack before the + // arguments. This reference on the stack is safe, even if the script + // is suspended during the evaluation of the arguments. + onHeap = IsVariableOnHeap(offset); + if( onHeap ) + ctx.bc.InstrSHORT(asBC_PSF, (short)offset); + } + else if( isVarGlobOrMem == 1 ) + { + // Push the address of the location where the variable will be stored on the stack. + // This reference is safe, because the addresses of the global variables cannot change. + onHeap = true; + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + } + else + { + // Value types may be allocated inline if they are POD types + onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); + if( onHeap ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + } + + PrepareFunctionCall(funcs[0], &ctx.bc, args); + MoveArgsToStack(funcs[0], &ctx.bc, args, false); + + // When the object is allocated on the stack, the address to the + // object is pushed on the stack after the arguments as the object pointer + if( !onHeap ) + { + if( isVarGlobOrMem == 2 ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + else + { + ctx.bc.InstrSHORT(asBC_PSF, (short)offset); + } + } + + PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); + + if( isVarGlobOrMem == 0 ) + { + // Mark the object in the local variable as initialized + ctx.bc.ObjInfo(offset, asOBJ_INIT); + } + } + bc->AddCode(&ctx.bc); + } + } + } + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + } + } + else if( node && node->nodeType == snInitList ) + { + asCExprValue ti; + ti.Set(type); + ti.isVariable = (isVarGlobOrMem == 0); + ti.isTemporary = false; + ti.stackOffset = (short)offset; + ti.isLValue = true; + + CompileInitList(&ti, node, bc, isVarGlobOrMem); + } + else if( node && node->nodeType == snAssignment ) + { + // Compile the expression + asCExprContext newExpr(engine); + asCExprContext* expr; + int r = 0; + + if( preCompiled ) + { + expr = preCompiled; + } + else + { + expr = &newExpr; + r = CompileAssignment(node, expr); + } + + // handles initialized with null doesn't need any bytecode + // since handles will be initialized to null by default anyway + if (type.IsObjectHandle() && expr->type.IsNullConstant() && expr->bc.IsSimpleExpression() ) + return false; + + // Look for appropriate constructor + asCArray funcs; + asCArray args; + + // Handles must use the handle assignment operation. + // Types that are ASHANDLE must not allow the use of the constructor in this case, + // because it is ambiguous whether a value assignment or handle assignment will be done. + // Only do this if the expression is of the same type, as the expression is an assignment + // and an initialization constructor may not have the same meaning. + // TODO: Should allow initialization constructor if it is declared as allowed for implicit conversions. + if( !type.IsObjectHandle() && !expr->type.isExplicitHandle && + !(type.GetTypeInfo() && (type.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE)) && + type.IsEqualExceptRefAndConst(expr->type.dataType) ) + { + asSTypeBehaviour *beh = type.GetBehaviour(); + if( beh ) + { + if( type.GetTypeInfo()->flags & asOBJ_REF ) + funcs = beh->factories; + else + funcs = beh->constructors; + } + + asCString str = type.Format(outFunc->nameSpace); + args.PushLast(expr); + MatchFunctions(funcs, args, node, str.AddressOf(), 0, 0, 0, true); + + // Make sure the argument is of the right type (and not just compatible with the expression) + if (funcs.GetLength() == 1) + { + asCScriptFunction *f = engine->scriptFunctions[funcs[0]]; + if (!f->parameterTypes[0].IsEqualExceptRefAndConst(expr->type.dataType)) + funcs.PopLast(); + } + } + + if( funcs.GetLength() == 1 ) + { + // Use the constructor + + // TODO: clean-up: A large part of this is identical to the initalization with argList above + + // Add the default values for arguments not explicitly supplied + r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(type.GetTypeInfo())); + + if( r == asSUCCESS ) + { + asCExprContext ctx(engine); + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_REF) ) + { + if( isVarGlobOrMem == 0 ) + MakeFunctionCall(&ctx, funcs[0], 0, args, node, true, offset); + else + { + MakeFunctionCall(&ctx, funcs[0], 0, args, node); + ctx.bc.Instr(asBC_RDSPtr); + if( isVarGlobOrMem == 1 ) + { + // Store the returned handle in the global variable + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + } + else + { + // Store the returned handle in the member + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + if( type.IsFuncdef() ) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, type.GetTypeInfo()); + ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); + } + + // Pop the reference left by the function call + ctx.bc.Instr(asBC_PopPtr); + } + else + { + bool onHeap = false; + + if( isVarGlobOrMem == 0 ) + { + // When the object is allocated on the heap, the address where the + // reference will be stored must be pushed on the stack before the + // arguments. This reference on the stack is safe, even if the script + // is suspended during the evaluation of the arguments. + onHeap = IsVariableOnHeap(offset); + if( onHeap ) + ctx.bc.InstrSHORT(asBC_PSF, (short)offset); + } + else if( isVarGlobOrMem == 1 ) + { + // Push the address of the location where the variable will be stored on the stack. + // This reference is safe, because the addresses of the global variables cannot change. + onHeap = true; + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + } + else + { + // Value types may be allocated inline if they are POD types + onHeap = !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF); + if( onHeap ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + } + + PrepareFunctionCall(funcs[0], &ctx.bc, args); + MoveArgsToStack(funcs[0], &ctx.bc, args, false); + + // When the object is allocated on the stack, the address to the + // object is pushed on the stack after the arguments as the object pointer + if( !onHeap ) + { + if( isVarGlobOrMem == 2 ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + else + { + ctx.bc.InstrSHORT(asBC_PSF, (short)offset); + } + } + + PerformFunctionCall(funcs[0], &ctx, onHeap, &args, CastToObjectType(type.GetTypeInfo())); + + if( isVarGlobOrMem == 0 ) + { + // Mark the object in the local variable as initialized + ctx.bc.ObjInfo(offset, asOBJ_INIT); + } + } + bc->AddCode(&ctx.bc); + } + } + else + { + // Call the default constructur, then call the assignment operator + asCExprContext ctx(engine); + + // Call the default constructor here + if( isVarGlobOrMem == 0 ) + CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), &ctx.bc, errNode); + else if( isVarGlobOrMem == 1 ) + CallDefaultConstructor(type, offset, true, &ctx.bc, errNode, isVarGlobOrMem); + else if( isVarGlobOrMem == 2 ) + CallDefaultConstructor(type, offset, type.IsReference(), &ctx.bc, errNode, isVarGlobOrMem); + + if( r >= 0 ) + { + if( type.IsPrimitive() ) + { + if( type.IsReadOnly() && expr->type.isConstant ) + { + ImplicitConversion(expr, type, node, asIC_IMPLICIT_CONV); + + // Tell caller that the expression is a constant so it can mark the variable as pure constant + isConstantExpression = true; + *constantValue = expr->type.GetConstantData(); + } + + asCExprContext lctx(engine); + if( isVarGlobOrMem == 0 ) + lctx.type.SetVariable(type, offset, false); + else if( isVarGlobOrMem == 1 ) + { + lctx.type.Set(type); + lctx.type.dataType.MakeReference(true); + + // If it is an enum value, i.e. offset is negative, that is being compiled then + // we skip this as the bytecode won't be used anyway, only the constant value + if( offset >= 0 ) + lctx.bc.InstrPTR(asBC_LDG, engine->globalProperties[offset]->GetAddressOfValue()); + } + else + { + asASSERT( isVarGlobOrMem == 2 ); + lctx.type.Set(type); + lctx.type.dataType.MakeReference(true); + + // Load the reference of the primitive member into the register + lctx.bc.InstrSHORT(asBC_PSF, 0); + lctx.bc.Instr(asBC_RDSPtr); + lctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + lctx.bc.Instr(asBC_PopRPtr); + } + lctx.type.dataType.MakeReadOnly(false); + lctx.type.isLValue = true; + + DoAssignment(&ctx, &lctx, expr, node, node, ttAssignment, node); + ProcessDeferredParams(&ctx); + } + else + { + // TODO: runtime optimize: Here we should look for the best matching constructor, instead of + // just the copy constructor. Only if no appropriate constructor is + // available should the assignment operator be used. + + asCExprContext lexpr(engine); + lexpr.type.Set(type); + if( isVarGlobOrMem == 0 ) + lexpr.type.dataType.MakeReference(IsVariableOnHeap(offset)); + else if( isVarGlobOrMem == 1 ) + lexpr.type.dataType.MakeReference(true); + else if( isVarGlobOrMem == 2 ) + { + if( !lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef() || (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_REF) ) + lexpr.type.dataType.MakeReference(true); + } + + // Allow initialization of constant variables + lexpr.type.dataType.MakeReadOnly(false); + + if( type.IsObjectHandle() ) + lexpr.type.isExplicitHandle = true; + + if( isVarGlobOrMem == 0 ) + { + lexpr.bc.InstrSHORT(asBC_PSF, (short)offset); + lexpr.type.stackOffset = (short)offset; + lexpr.type.isVariable = true; + } + else if( isVarGlobOrMem == 1 ) + { + lexpr.bc.InstrPTR(asBC_PGA, engine->globalProperties[offset]->GetAddressOfValue()); + } + else + { + lexpr.bc.InstrSHORT(asBC_PSF, 0); + lexpr.bc.Instr(asBC_RDSPtr); + lexpr.bc.InstrSHORT_DW(asBC_ADDSi, (short)offset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + lexpr.type.stackOffset = -1; + } + lexpr.type.isLValue = true; + + + // If left expression resolves into a registered type + // check if the assignment operator is overloaded, and check + // the type of the right hand expression. If none is found + // the default action is a direct copy if it is the same type + // and a simple assignment. + bool assigned = false; + // Even though an ASHANDLE can be an explicit handle the overloaded operator needs to be called + if( (lexpr.type.dataType.IsObject() || lexpr.type.dataType.IsFuncdef()) && (!lexpr.type.isExplicitHandle || (lexpr.type.dataType.GetTypeInfo() && (lexpr.type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) ) + { + bool useHndlAssign = false; + if (lexpr.type.dataType.IsHandleToAsHandleType()) + { + useHndlAssign = true; + + // Make sure the right hand expression is treated as a handle + if (!expr->type.isExplicitHandle && !expr->type.IsNullConstant() ) + { + // TODO: Clean-up: This code is from CompileExpressionPreOp. Create a reusable function + // Convert the expression to a handle + if (!expr->type.dataType.IsObjectHandle() && expr->type.dataType.GetTypeInfo() && !(expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) + { + asCDataType to = expr->type.dataType; + to.MakeHandle(true); + to.MakeReference(true); + to.MakeHandleToConst(expr->type.dataType.IsReadOnly()); + ImplicitConversion(expr, to, node, asIC_IMPLICIT_CONV, true, false); + + asASSERT(expr->type.dataType.IsObjectHandle()); + } + else if (expr->type.dataType.GetTypeInfo() && expr->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) + { + // For the ASHANDLE type we'll simply set the expression as a handle + expr->type.dataType.MakeHandle(true); + } + + if( !expr->type.dataType.IsObjectHandle() && !expr->type.dataType.SupportHandles()) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); + } + expr->type.isExplicitHandle = true; + } + } + assigned = CompileOverloadedDualOperator(node, &lexpr, expr, false, &ctx, useHndlAssign); + if( assigned ) + { + // Pop the resulting value + if( !ctx.type.dataType.IsPrimitive() ) + ctx.bc.Instr(asBC_PopPtr); + + // Release the argument + ProcessDeferredParams(&ctx); + + // Release temporary variable that may be allocated by the overloaded operator + ReleaseTemporaryVariable(ctx.type, &ctx.bc); + } + } + + if( !assigned ) + { + PrepareForAssignment(&lexpr.type.dataType, expr, node, false); + + // If the expression is constant and the variable also is constant + // then mark the variable as pure constant. This will allow the compiler + // to optimize expressions with this variable. + if( type.IsReadOnly() && expr->type.isConstant ) + { + isConstantExpression = true; + *constantValue = expr->type.GetConstantQW(); + } + + // Add expression code to bytecode + MergeExprBytecode(&ctx, expr); + + // Add byte code for storing value of expression in variable + ctx.bc.AddCode(&lexpr.bc); + + PerformAssignment(&lexpr.type, &expr->type, &ctx.bc, errNode); + + // Release temporary variables used by expression + ReleaseTemporaryVariable(expr->type, &ctx.bc); + + ctx.bc.Instr(asBC_PopPtr); + + ProcessDeferredParams(&ctx); + } + } + } + + bc->AddCode(&ctx.bc); + } + } + else + { + asASSERT( node == 0 ); + + // Call the default constructor here, as no explicit initialization is done + if( isVarGlobOrMem == 0 ) + CallDefaultConstructor(type, offset, IsVariableOnHeap(offset), bc, errNode); + else if( isVarGlobOrMem == 1 ) + CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); + else if( isVarGlobOrMem == 2 ) + { + if( !(type.IsObject() || type.IsFuncdef()) || type.IsReference() || (type.GetTypeInfo()->flags & asOBJ_REF) ) + CallDefaultConstructor(type, offset, true, bc, errNode, isVarGlobOrMem); + else + CallDefaultConstructor(type, offset, false, bc, errNode, isVarGlobOrMem); + } + } + + return isConstantExpression; +} + +void asCCompiler::CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem) +{ + // Check if the type supports initialization lists + if( var->dataType.GetTypeInfo() == 0 || + var->dataType.GetBehaviour()->listFactory == 0 ) + { + asCString str; + str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, var->dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + return; + } + + // Construct the buffer with the elements + + // Find the list factory + int funcId = var->dataType.GetBehaviour()->listFactory; + asASSERT( engine->scriptFunctions[funcId]->listPattern ); + + // TODO: runtime optimize: A future optimization should be to use the stack space directly + // for small buffers so that the dynamic allocation is skipped + + // Create a new special object type for the lists. Both asCRestore and the + // context exception handler will need this to know how to parse the buffer. + asCObjectType *listPatternType = engine->GetListPatternType(funcId); + + // Allocate a temporary variable to hold the pointer to the buffer + int bufferVar = AllocateVariable(asCDataType::CreateType(listPatternType, false), true); + asUINT bufferSize = 0; + + // Evaluate all elements of the list + asCExprContext valueExpr(engine); + asCScriptNode *el = node; + asSListPatternNode *patternNode = engine->scriptFunctions[listPatternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; + int elementsInSubList = -1; + int r = CompileInitListElement(patternNode, el, engine->GetTypeIdFromDataType(asCDataType::CreateType(listPatternType, false)), short(bufferVar), bufferSize, valueExpr.bc, elementsInSubList); + asASSERT( r || patternNode == 0 ); + if (r < 0) + { + asCString msg; + msg.Format(TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s, var->dataType.Format(outFunc->nameSpace).AddressOf()); + Error(msg, node); + } + + // After all values have been evaluated we know the final size of the buffer + asCExprContext allocExpr(engine); + allocExpr.bc.InstrSHORT_DW(asBC_AllocMem, short(bufferVar), bufferSize); + + // Merge the bytecode into the final sequence + bc->AddCode(&allocExpr.bc); + bc->AddCode(&valueExpr.bc); + + // The object itself is the last to be created and will receive the pointer to the buffer + asCArray args; + asCExprContext arg1(engine); + arg1.type.Set(asCDataType::CreatePrimitive(ttUInt, false)); + arg1.type.dataType.MakeReference(true); + arg1.bc.InstrSHORT(asBC_PshVPtr, short(bufferVar)); + args.PushLast(&arg1); + + asCExprContext ctx(engine); + + if( var->isVariable ) + { + asASSERT( isVarGlobOrMem == 0 ); + + if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF ) + { + ctx.bc.AddCode(&arg1.bc); + + // Call factory and store the handle in the given variable + PerformFunctionCall(funcId, &ctx, false, &args, 0, true, var->stackOffset); + ctx.bc.Instr(asBC_PopPtr); + } + else + { + // Call the constructor + + // When the object is allocated on the heap, the address where the + // reference will be stored must be pushed on the stack before the + // arguments. This reference on the stack is safe, even if the script + // is suspended during the evaluation of the arguments. + bool onHeap = IsVariableOnHeap(var->stackOffset); + if( onHeap ) + ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset); + + ctx.bc.AddCode(&arg1.bc); + + // When the object is allocated on the stack, the address to the + // object is pushed on the stack after the arguments as the object pointer + if( !onHeap ) + ctx.bc.InstrSHORT(asBC_PSF, var->stackOffset); + + PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo())); + + // Mark the object in the local variable as initialized + ctx.bc.ObjInfo(var->stackOffset, asOBJ_INIT); + } + } + else + { + if( var->dataType.GetTypeInfo()->GetFlags() & asOBJ_REF ) + { + ctx.bc.AddCode(&arg1.bc); + + PerformFunctionCall(funcId, &ctx, false, &args); + + ctx.bc.Instr(asBC_RDSPtr); + if( isVarGlobOrMem == 1 ) + { + // Store the returned handle in the global variable + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue()); + } + else + { + // Store the returned handle in the member + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + if (var->dataType.IsFuncdef()) + ctx.bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx.bc.InstrPTR(asBC_REFCPY, var->dataType.GetTypeInfo()); + ctx.bc.Instr(asBC_PopPtr); + ReleaseTemporaryVariable(ctx.type.stackOffset, &ctx.bc); + } + else + { + bool onHeap = true; + + // Put the address where the object pointer will be placed on the stack + if( isVarGlobOrMem == 1 ) + ctx.bc.InstrPTR(asBC_PGA, engine->globalProperties[var->stackOffset]->GetAddressOfValue()); + else + { + onHeap = !(var->dataType.IsObject() || var->dataType.IsFuncdef()) || var->dataType.IsReference() || (var->dataType.GetTypeInfo()->flags & asOBJ_REF); + if( onHeap ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + } + + // Add the address of the list buffer as the argument + ctx.bc.AddCode(&arg1.bc); + + if( !onHeap ) + { + ctx.bc.InstrSHORT(asBC_PSF, 0); + ctx.bc.Instr(asBC_RDSPtr); + ctx.bc.InstrSHORT_DW(asBC_ADDSi, (short)var->stackOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(outFunc->objectType, false))); + } + + // Call the ALLOC instruction to allocate memory and invoke constructor + PerformFunctionCall(funcId, &ctx, onHeap, &args, CastToObjectType(var->dataType.GetTypeInfo())); + } + } + + bc->AddCode(&ctx.bc); + + // Free the temporary buffer. The FREE instruction will make sure to destroy + // each element in the buffer so there is no need to do this manually + bc->InstrW_PTR(asBC_FREE, short(bufferVar), listPatternType); + ReleaseTemporaryVariable(bufferVar, bc); +} + +int asCCompiler::CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &bcInit, int &elementsInSubList) +{ + if( patternNode->type == asLPT_START ) + { + if( valueNode == 0 || valueNode->nodeType != snInitList ) + { + Error(TXT_EXPECTED_LIST, valueNode); + return -1; + } + + // Compile all values until asLPT_END + patternNode = patternNode->next; + asCScriptNode *node = valueNode->firstChild; + while( patternNode->type != asLPT_END ) + { + // Check for missing value here, else the error reporting will not have a source position to report the error for + if( node == 0 && patternNode->type == asLPT_TYPE ) + { + Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, valueNode); + return -1; + } + + asCScriptNode *errNode = node; + int r = CompileInitListElement(patternNode, node, bufferTypeId, bufferVar, bufferSize, bcInit, elementsInSubList); + if( r < 0 ) return r; + + if( r == 1 ) + { + asASSERT( engine->ep.disallowEmptyListElements ); + // Empty elements in the middle are not allowed + Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode); + } + + asASSERT( patternNode ); + } + + if( node ) + { + Error(TXT_TOO_MANY_VALUES_FOR_LIST, valueNode); + return -1; + } + + // Move to the next node + valueNode = valueNode->next; + patternNode = patternNode->next; + } + else if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ) + { + // TODO: list: repeat_inner should make sure the list has the same size as the inner list, i.e. square area + // TODO: list: repeat_prev should make sure the list is the same size as the previous + + asEListPatternNodeType repeatType = patternNode->type; + asCScriptNode *firstValue = valueNode; + + // The following values will be repeated N times + patternNode = patternNode->next; + + // Keep track of the patternNode so it can be reset + asSListPatternNode *nextNode = patternNode; + + // Align the buffer size to 4 bytes in case previous value was smaller than 4 bytes + if( bufferSize & 0x3 ) + bufferSize += 4 - (bufferSize & 0x3); + + // The first dword will hold the number of elements in the list + asDWORD currSize = bufferSize; + bufferSize += 4; + asUINT countElements = 0; + + int elementsInSubSubList = -1; + + asCExprContext ctx(engine); + while( valueNode ) + { + patternNode = nextNode; + asCScriptNode *errNode = valueNode; + int r = CompileInitListElement(patternNode, valueNode, bufferTypeId, bufferVar, bufferSize, ctx.bc, elementsInSubSubList); + if( r < 0 ) return r; + + if( r == 0 ) + countElements++; + else + { + asASSERT( r == 1 && engine->ep.disallowEmptyListElements ); + if( valueNode ) + { + // Empty elements in the middle are not allowed + Error(TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED, errNode); + } + } + } + + if( countElements == 0 ) + { + // Skip the sub pattern that was expected to be repeated, otherwise the caller will try to match these when we return + patternNode = nextNode; + if( patternNode->type == asLPT_TYPE ) + patternNode = patternNode->next; + else if( patternNode->type == asLPT_START ) + { + int subCount = 1; + do + { + patternNode = patternNode->next; + if( patternNode->type == asLPT_START ) + subCount++; + else if( patternNode->type == asLPT_END ) + subCount--; + } while( subCount > 0 ); + patternNode = patternNode->next; + } + } + + // For repeat_same each repeated sublist must have the same size to form a rectangular array + if( repeatType == asLPT_REPEAT_SAME && elementsInSubList != -1 && asUINT(elementsInSubList) != countElements ) + { + if( countElements < asUINT(elementsInSubList) ) + Error(TXT_NOT_ENOUGH_VALUES_FOR_LIST, firstValue); + else + Error(TXT_TOO_MANY_VALUES_FOR_LIST, firstValue); + + return -1; + } + else + { + // Return to caller the amount of elments in this sublist + elementsInSubList = countElements; + } + + // The first dword in the buffer will hold the number of elements + bcInit.InstrSHORT_DW_DW(asBC_SetListSize, bufferVar, currSize, countElements); + + // Add the values + bcInit.AddCode(&ctx.bc); + } + else if( patternNode->type == asLPT_TYPE ) + { + bool isEmpty = false; + + // Determine the size of the element + asUINT size = 0; + + asCDataType dt = reinterpret_cast(patternNode)->dataType; + + if( valueNode->nodeType == snAssignment || valueNode->nodeType == snInitList ) + { + asCExprContext lctx(engine); + asCExprContext rctx(engine); + + if( valueNode->nodeType == snAssignment ) + { + // Compile the assignment expression + CompileAssignment(valueNode, &rctx); + + if( dt.GetTokenType() == ttQuestion ) + { + // Make sure the type is not ambiguous + DetermineSingleFunc(&rctx, valueNode); + + // We now know the type + dt = rctx.type.dataType; + dt.MakeReadOnly(false); + dt.MakeReference(false); + + // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. + if( bufferSize & 0x3 ) + bufferSize += 4 - (bufferSize & 0x3); + + // When value assignment for reference types us disabled, make sure all ref types are passed in as handles + if (engine->ep.disallowValueAssignForRefType && dt.SupportHandles()) + dt.MakeHandle(true); + + // Place the type id in the buffer + bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, engine->GetTypeIdFromDataType(dt)); + bufferSize += 4; + } + } + else if( valueNode->nodeType == snInitList ) + { + if( dt.GetTokenType() == ttQuestion ) + { + // Can't use init lists with var type as it is not possible to determine what type should be allocated + asCString str; + str.Format(TXT_INIT_LIST_CANNOT_BE_USED_WITH_s, "?"); + Error(str.AddressOf(), valueNode); + rctx.type.SetDummy(); + dt = rctx.type.dataType; + } + else + { + // Allocate a temporary variable that will be initialized with the list + int offset = AllocateVariable(dt, true); + + rctx.type.Set(dt); + rctx.type.isVariable = true; + rctx.type.isTemporary = true; + rctx.type.stackOffset = (short)offset; + + CompileInitList(&rctx.type, valueNode, &rctx.bc, 0); + + // Put the object on the stack + rctx.bc.InstrSHORT(asBC_PSF, rctx.type.stackOffset); + + // It is a reference that we place on the stack + rctx.type.dataType.MakeReference(true); + } + } + + // Determine size of the element + if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) ) + size = dt.GetSizeInMemoryBytes(); + else + size = AS_PTR_SIZE*4; + + // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. + if( size >= 4 && (bufferSize & 0x3) ) + bufferSize += 4 - (bufferSize & 0x3); + + // Compile the lvalue + lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + lctx.type.Set(dt); + lctx.type.isLValue = true; + if( dt.IsPrimitive() ) + { + lctx.bc.Instr(asBC_PopRPtr); + lctx.type.dataType.MakeReference(true); + } + else if( dt.IsObjectHandle() || + dt.GetTypeInfo()->flags & asOBJ_REF ) + { + lctx.type.isExplicitHandle = true; + lctx.type.dataType.MakeReference(true); + } + else + { + asASSERT( dt.GetTypeInfo()->flags & asOBJ_VALUE ); + + // Make sure the object has been constructed before the assignment + // TODO: runtime optimize: Use copy constructor instead of assignment to initialize the objects + asSTypeBehaviour *beh = dt.GetBehaviour(); + int func = 0; + if( beh ) func = beh->construct; + if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) + { + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); + Error(str, valueNode); + } + else if( func ) + { + // Call the constructor as a normal function + bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + bcInit.AddCode(&ctx.bc); + } + } + + if( lctx.type.dataType.IsNullHandle() ) + { + // Don't add any code to assign a null handle. RefCpy doesn't work without a known type. + // The buffer is already initialized to zero in asBC_AllocMem anyway. + asASSERT( rctx.bc.GetLastInstr() == asBC_PshNull ); + asASSERT( reinterpret_cast(patternNode)->dataType.GetTokenType() == ttQuestion ); + } + else + { + asCExprContext ctx(engine); + DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); + + if( !lctx.type.dataType.IsPrimitive() ) + ctx.bc.Instr(asBC_PopPtr); + + // Release temporary variables used by expression + ReleaseTemporaryVariable(ctx.type, &ctx.bc); + + ProcessDeferredParams(&ctx); + + bcInit.AddCode(&ctx.bc); + } + } + else + { + if( builder->engine->ep.disallowEmptyListElements ) + { + // Empty elements are not allowed, except if it is the last in the list + isEmpty = true; + } + else + { + // There is no specific value so we need to fill it with a default value + if( dt.GetTokenType() == ttQuestion ) + { + // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. + if( bufferSize & 0x3 ) + bufferSize += 4 - (bufferSize & 0x3); + + // Place the type id for a null handle in the buffer + bcInit.InstrSHORT_DW_DW(asBC_SetListType, bufferVar, bufferSize, 0); + bufferSize += 4; + + dt = asCDataType::CreateNullHandle(); + + // No need to initialize the handle as the buffer is already initialized with zeroes + } + else if( dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_VALUE ) + { + // For value types with default constructor we need to call the constructor + asSTypeBehaviour *beh = dt.GetBehaviour(); + int func = 0; + if( beh ) func = beh->construct; + if( func == 0 && (dt.GetTypeInfo()->flags & asOBJ_POD) == 0 ) + { + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); + Error(str, valueNode); + } + else if( func ) + { + // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. + if( bufferSize & 0x3 ) + bufferSize += 4 - (bufferSize & 0x3); + + // Call the constructor as a normal function + bcInit.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + + asCExprContext ctx(engine); + PerformFunctionCall(func, &ctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + bcInit.AddCode(&ctx.bc); + } + } + else if( !dt.IsObjectHandle() && dt.GetTypeInfo() && dt.GetTypeInfo()->flags & asOBJ_REF ) + { + // For ref types (not handles) we need to call the default factory + asSTypeBehaviour *beh = dt.GetBehaviour(); + int func = 0; + if( beh ) func = beh->factory; + if( func == 0 ) + { + asCString str; + str.Format(TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s, dt.GetTypeInfo()->GetName()); + Error(str, valueNode); + } + else if( func ) + { + asCExprContext rctx(engine); + PerformFunctionCall(func, &rctx, false, 0, CastToObjectType(dt.GetTypeInfo())); + + // Values on the list must be aligned to 32bit boundaries, except if the type is smaller than 32bit. + if( bufferSize & 0x3 ) + bufferSize += 4 - (bufferSize & 0x3); + + asCExprContext lctx(engine); + lctx.bc.InstrSHORT_DW(asBC_PshListElmnt, bufferVar, bufferSize); + lctx.type.Set(dt); + lctx.type.isLValue = true; + lctx.type.isExplicitHandle = true; + lctx.type.dataType.MakeReference(true); + + asCExprContext ctx(engine); + DoAssignment(&ctx, &lctx, &rctx, valueNode, valueNode, ttAssignment, valueNode); + + if( !lctx.type.dataType.IsPrimitive() ) + ctx.bc.Instr(asBC_PopPtr); + + // Release temporary variables used by expression + ReleaseTemporaryVariable(ctx.type, &ctx.bc); + + ProcessDeferredParams(&ctx); + + bcInit.AddCode(&ctx.bc); + } + } + } + } + + if( !isEmpty ) + { + // Determine size of the element + if( dt.IsPrimitive() || (!dt.IsNullHandle() && (dt.GetTypeInfo()->flags & asOBJ_VALUE)) ) + size = dt.GetSizeInMemoryBytes(); + else + size = AS_PTR_SIZE*4; + asASSERT( size <= 4 || (size & 0x3) == 0 ); + + bufferSize += size; + } + + // Move to the next element + patternNode = patternNode->next; + valueNode = valueNode->next; + + if( isEmpty ) + { + // The caller will determine if the empty element should be ignored or not + return 1; + } + } + else + asASSERT( false ); + + return 0; +} + +void asCCompiler::CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc) +{ + // Don't clear the hasReturn flag if this is an empty statement + // to avoid false errors of 'not all paths return' + if( statement->nodeType != snExpressionStatement || statement->firstChild ) + *hasReturn = false; + + if (statement->nodeType == snStatementBlock) + CompileStatementBlock(statement, true, hasReturn, bc); + else if (statement->nodeType == snIf) + CompileIfStatement(statement, hasReturn, bc); + else if (statement->nodeType == snFor) + CompileForStatement(statement, bc); + else if (statement->nodeType == snWhile) + CompileWhileStatement(statement, bc); + else if (statement->nodeType == snDoWhile) + CompileDoWhileStatement(statement, bc); + else if (statement->nodeType == snExpressionStatement) + CompileExpressionStatement(statement, bc); + else if (statement->nodeType == snBreak) + CompileBreakStatement(statement, bc); + else if (statement->nodeType == snContinue) + CompileContinueStatement(statement, bc); + else if (statement->nodeType == snSwitch) + CompileSwitchStatement(statement, hasReturn, bc); + else if (statement->nodeType == snTryCatch) + CompileTryCatch(statement, hasReturn, bc); + else if (statement->nodeType == snReturn) + { + CompileReturnStatement(statement, bc); + *hasReturn = true; + } + else + asASSERT(false); +} + +void asCCompiler::CompileSwitchStatement(asCScriptNode *snode, bool *, asCByteCode *bc) +{ + // TODO: inheritance: Must guarantee that all options in the switch case call a constructor, or that none call it. + + // Reserve label for break statements + int breakLabel = nextLabel++; + breakLabels.PushLast(breakLabel); + + // Add a variable scope that will be used by CompileBreak + // to know where to stop deallocating variables + AddVariableScope(true, false); + + //--------------------------- + // Compile the switch expression + //------------------------------- + + // Compile the switch expression + asCExprContext expr(engine); + CompileAssignment(snode->firstChild, &expr); + + // Verify that the expression is a primitive type + if( !expr.type.dataType.IsIntegerType() && !expr.type.dataType.IsUnsignedType() ) + { + Error(TXT_SWITCH_MUST_BE_INTEGRAL, snode->firstChild); + return; + } + + if( ProcessPropertyGetAccessor(&expr, snode) < 0 ) + return; + + // TODO: Need to support 64bit integers + // Convert the expression to a 32bit variable + asCDataType to; + if( expr.type.dataType.IsIntegerType() ) + to.SetTokenType(ttInt); + else if( expr.type.dataType.IsUnsignedType() ) + to.SetTokenType(ttUInt); + + // Make sure the value is in a variable + if( expr.type.dataType.IsReference() ) + ConvertToVariable(&expr); + + ImplicitConversion(&expr, to, snode->firstChild, asIC_IMPLICIT_CONV, true); + + ConvertToVariable(&expr); + int offset = expr.type.stackOffset; + + ProcessDeferredParams(&expr); + + //------------------------------- + // Determine case values and labels + //-------------------------------- + + // Remember the first label so that we can later pass the + // correct label to each CompileCase() + int firstCaseLabel = nextLabel; + int defaultLabel = 0; + + asCArray caseValues; + asCArray caseLabels; + + // Compile all case comparisons and make them jump to the right label + asCScriptNode *cnode = snode->firstChild->next; + while( cnode ) + { + // Each case should have a constant expression + if( cnode->firstChild && cnode->firstChild->nodeType == snExpression ) + { + // Compile expression + asCExprContext c(engine); + CompileExpression(cnode->firstChild, &c); + + // Verify that the result is a constant + if( !c.type.isConstant ) + Error(TXT_SWITCH_CASE_MUST_BE_CONSTANT, cnode->firstChild); + + // Verify that the result is an integral number + if (!c.type.dataType.IsIntegerType() && !c.type.dataType.IsUnsignedType()) + Error(TXT_SWITCH_MUST_BE_INTEGRAL, cnode->firstChild); + else + { + ImplicitConversion(&c, to, cnode->firstChild, asIC_IMPLICIT_CONV, true); + + // Has this case been declared already? + if (caseValues.IndexOf(c.type.GetConstantDW()) >= 0) + Error(TXT_DUPLICATE_SWITCH_CASE, cnode->firstChild); + + // TODO: Optimize: We can insert the numbers sorted already + + // Store constant for later use + caseValues.PushLast(c.type.GetConstantDW()); + + // Reserve label for this case + caseLabels.PushLast(nextLabel++); + } + } + else + { + // TODO: It shouldn't be necessary for the default case to be the last one. + // Is default the last case? + if( cnode->next ) + { + Error(TXT_DEFAULT_MUST_BE_LAST, cnode); + break; + } + + // Reserve label for this case + defaultLabel = nextLabel++; + } + + cnode = cnode->next; + } + + // check for empty switch + if (caseValues.GetLength() == 0) + { + Error(TXT_EMPTY_SWITCH, snode); + return; + } + + if( defaultLabel == 0 ) + defaultLabel = breakLabel; + + //--------------------------------- + // Output the optimized case comparisons + // with jumps to the case code + //------------------------------------ + + // Sort the case values by increasing value. Do the sort together with the labels + // A simple bubble sort is sufficient since we don't expect a huge number of values + for( asUINT fwd = 1; fwd < caseValues.GetLength(); fwd++ ) + { + for( int bck = fwd - 1; bck >= 0; bck-- ) + { + int bckp = bck + 1; + if( caseValues[bck] > caseValues[bckp] ) + { + // Swap the values in both arrays + int swap = caseValues[bckp]; + caseValues[bckp] = caseValues[bck]; + caseValues[bck] = swap; + + swap = caseLabels[bckp]; + caseLabels[bckp] = caseLabels[bck]; + caseLabels[bck] = swap; + } + else + break; + } + } + + // Find ranges of consecutive numbers + asCArray ranges; + ranges.PushLast(0); + asUINT n; + for( n = 1; n < caseValues.GetLength(); ++n ) + { + // We can join numbers that are less than 5 numbers + // apart since the output code will still be smaller + if( caseValues[n] > caseValues[n-1] + 5 ) + ranges.PushLast(n); + } + + // If the value is larger than the largest case value, jump to default + int tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); + expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[caseValues.GetLength()-1]); + expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); + expr.bc.InstrDWORD(asBC_JP, defaultLabel); + ReleaseTemporaryVariable(tmpOffset, &expr.bc); + + // TODO: runtime optimize: We could possibly optimize this even more by doing a + // binary search instead of a linear search through the ranges + + // For each range + int range; + for( range = 0; range < (int)ranges.GetLength(); range++ ) + { + // Find the largest value in this range + int maxRange = caseValues[ranges[range]]; + int index = ranges[range]; + for( ; (index < (int)caseValues.GetLength()) && (caseValues[index] <= maxRange + 5); index++ ) + maxRange = caseValues[index]; + + // If there are only 2 numbers then it is better to compare them directly + if( index - ranges[range] > 2 ) + { + // If the value is smaller than the smallest case value in the range, jump to default + tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); + expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]); + expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); + expr.bc.InstrDWORD(asBC_JS, defaultLabel); + ReleaseTemporaryVariable(tmpOffset, &expr.bc); + + int nextRangeLabel = nextLabel++; + // If this is the last range we don't have to make this test + if( range < (int)ranges.GetLength() - 1 ) + { + // If the value is larger than the largest case value in the range, jump to the next range + tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); + expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, maxRange); + expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); + expr.bc.InstrDWORD(asBC_JP, nextRangeLabel); + ReleaseTemporaryVariable(tmpOffset, &expr.bc); + } + + // Jump forward according to the value + tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); + expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[ranges[range]]); + expr.bc.InstrW_W_W(asBC_SUBi, tmpOffset, offset, tmpOffset); + ReleaseTemporaryVariable(tmpOffset, &expr.bc); + expr.bc.JmpP(tmpOffset, maxRange - caseValues[ranges[range]]); + + // Add the list of jumps to the correct labels (any holes, jump to default) + index = ranges[range]; + for( int i = caseValues[index]; i <= maxRange; i++ ) + { + if( caseValues[index] == i ) + expr.bc.InstrINT(asBC_JMP, caseLabels[index++]); + else + expr.bc.InstrINT(asBC_JMP, defaultLabel); + } + + expr.bc.Label((short)nextRangeLabel); + } + else + { + // Simply make a comparison with each value + for( int i = ranges[range]; i < index; ++i ) + { + tmpOffset = AllocateVariable(asCDataType::CreatePrimitive(ttInt, false), true); + expr.bc.InstrSHORT_DW(asBC_SetV4, (short)tmpOffset, caseValues[i]); + expr.bc.InstrW_W(asBC_CMPi, offset, tmpOffset); + expr.bc.InstrDWORD(asBC_JZ, caseLabels[i]); + ReleaseTemporaryVariable(tmpOffset, &expr.bc); + } + } + } + + // Catch any value that falls trough + expr.bc.InstrINT(asBC_JMP, defaultLabel); + + // Release the temporary variable previously stored + ReleaseTemporaryVariable(expr.type, &expr.bc); + + // TODO: optimize: Should optimize each piece individually + expr.bc.OptimizeLocally(tempVariableOffsets); + + //---------------------------------- + // Output case implementations + //---------------------------------- + + // Compile case implementations, each one with the label before it + cnode = snode->firstChild->next; + while( cnode ) + { + // Each case should have a constant expression + if( cnode->firstChild && cnode->firstChild->nodeType == snExpression ) + { + expr.bc.Label((short)firstCaseLabel++); + + CompileCase(cnode->firstChild->next, &expr.bc); + } + else + { + expr.bc.Label((short)defaultLabel); + + // Is default the last case? + if( cnode->next ) + { + // We've already reported this error + break; + } + + CompileCase(cnode->firstChild, &expr.bc); + } + + cnode = cnode->next; + } + + //-------------------------------- + + bc->AddCode(&expr.bc); + + // Add break label + bc->Label((short)breakLabel); + + breakLabels.PopLast(); + RemoveVariableScope(); +} + +void asCCompiler::CompileCase(asCScriptNode *node, asCByteCode *bc) +{ + bool isFinished = false; + bool hasReturn = false; + bool hasUnreachableCode = false; + while( node ) + { + if( !hasUnreachableCode && (hasReturn || isFinished) ) + { + hasUnreachableCode = true; + Warning(TXT_UNREACHABLE_CODE, node); + break; + } + + if( node->nodeType == snBreak || node->nodeType == snContinue ) + isFinished = true; + + asCByteCode statement(engine); + if( node->nodeType == snDeclaration ) + { + Error(TXT_DECL_IN_SWITCH, node); + + // Compile it anyway to avoid further compiler errors + CompileDeclaration(node, &statement); + } + else + CompileStatement(node, &hasReturn, &statement); + + LineInstr(bc, node->tokenPos); + bc->AddCode(&statement); + + if( !hasCompileErrors ) + asASSERT( tempVariables.GetLength() == 0 ); + + node = node->next; + } +} + +void asCCompiler::CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc) +{ + // We will use one label before and another after the catch statement + int beforeCatchLabel = nextLabel++; + int afterCatchLabel = nextLabel++; + + // Compile the try block + bool hasReturnTry; + asCByteCode tryBC(engine); + CompileStatement(node->firstChild, &hasReturnTry, &tryBC); + + // Add marker to unwind exception until here, then jump to catch block + bc->TryBlock((short)beforeCatchLabel); + + // Add the byte code + LineInstr(bc, node->firstChild->tokenPos); + bc->AddCode(&tryBC); + + // Add jump to after catch + bc->InstrINT(asBC_JMP, afterCatchLabel); + + // Compile the catch block + bool hasReturnCatch; + asCByteCode catchBC(engine); + CompileStatement(node->firstChild->next, &hasReturnCatch, &catchBC); + + // Add marker to tell bytecode optimizer that this is a catch + // block so the code is not removed as unreachable code + bc->Label((short)beforeCatchLabel); + + // Add the byte code + LineInstr(bc, node->firstChild->next->tokenPos); + bc->AddCode(&catchBC); + + // Add the label after catch + bc->Label((short)afterCatchLabel); + + // The try/catch statement only has return (i.e. no code after + // the try/catch block will be executed) if both blocks have + *hasReturn = hasReturnTry && hasReturnCatch; +} + +void asCCompiler::CompileIfStatement(asCScriptNode *inode, bool *hasReturn, asCByteCode *bc) +{ + // We will use one label for the if statement + // and possibly another for the else statement + int afterLabel = nextLabel++; + + // Compile the expression + asCExprContext expr(engine); + int r = CompileAssignment(inode->firstChild, &expr); + if( r == 0 ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), inode, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, inode->firstChild); + else + { + if( !expr.type.isConstant ) + { + if( ProcessPropertyGetAccessor(&expr, inode) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&expr); + + // Add a test + expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); + expr.bc.Instr(asBC_ClrHi); + expr.bc.InstrDWORD(asBC_JZ, afterLabel); + ReleaseTemporaryVariable(expr.type, &expr.bc); + + expr.bc.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&expr.bc); + } +#if AS_SIZEOF_BOOL == 1 + else if( expr.type.GetConstantB() == 0 ) +#else + else if (expr.type.GetConstantDW() == 0) +#endif + { + // Jump to the else case + bc->InstrINT(asBC_JMP, afterLabel); + + // TODO: Should we warn that the expression will always go to the else? + } + } + } + + // Compile the if statement + bool origIsConstructorCalled = m_isConstructorCalled; + + bool hasReturn1; + asCByteCode ifBC(engine); + CompileStatement(inode->firstChild->next, &hasReturn1, &ifBC); + + // Add the byte code + LineInstr(bc, inode->firstChild->next->tokenPos); + bc->AddCode(&ifBC); + + if( inode->firstChild->next->nodeType == snExpressionStatement && inode->firstChild->next->firstChild == 0 ) + { + // Don't allow if( expr ); + Error(TXT_IF_WITH_EMPTY_STATEMENT, inode->firstChild->next); + } + + // If one of the statements call the constructor, the other must as well + // otherwise it is possible the constructor is never called + bool constructorCall1 = false; + bool constructorCall2 = false; + if( !origIsConstructorCalled && m_isConstructorCalled ) + constructorCall1 = true; + + // Do we have an else statement? + if( inode->firstChild->next != inode->lastChild ) + { + // Reset the constructor called flag so the else statement can call the constructor too + m_isConstructorCalled = origIsConstructorCalled; + + int afterElse = 0; + if( !hasReturn1 ) + { + afterElse = nextLabel++; + + // Add jump to after the else statement + bc->InstrINT(asBC_JMP, afterElse); + } + + // Add label for the else statement + bc->Label((short)afterLabel); + + bool hasReturn2; + asCByteCode elseBC(engine); + CompileStatement(inode->lastChild, &hasReturn2, &elseBC); + + // Add byte code for the else statement + LineInstr(bc, inode->lastChild->tokenPos); + bc->AddCode(&elseBC); + + if( inode->lastChild->nodeType == snExpressionStatement && inode->lastChild->firstChild == 0 ) + { + // Don't allow if( expr ) {} else; + Error(TXT_ELSE_WITH_EMPTY_STATEMENT, inode->lastChild); + } + + if( !hasReturn1 ) + { + // Add label for the end of else statement + bc->Label((short)afterElse); + } + + // The if statement only has return if both alternatives have + *hasReturn = hasReturn1 && hasReturn2; + + if( !origIsConstructorCalled && m_isConstructorCalled ) + constructorCall2 = true; + } + else + { + // Add label for the end of if statement + bc->Label((short)afterLabel); + *hasReturn = false; + } + + // Make sure both or neither conditions call a constructor + if( (constructorCall1 && !constructorCall2) || + (constructorCall2 && !constructorCall1) ) + { + Error(TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR, inode); + } + + m_isConstructorCalled = origIsConstructorCalled || constructorCall1 || constructorCall2; +} + +void asCCompiler::CompileForStatement(asCScriptNode *fnode, asCByteCode *bc) +{ + // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables + AddVariableScope(true, true); + + // We will use three labels for the for loop + int conditionLabel = nextLabel++; + int afterLabel = nextLabel++; + int continueLabel = nextLabel++; + int insideLabel = nextLabel++; + + continueLabels.PushLast(continueLabel); + breakLabels.PushLast(afterLabel); + + //--------------------------------------- + // Compile the initialization statement + asCByteCode initBC(engine); + LineInstr(&initBC, fnode->firstChild->tokenPos); + if( fnode->firstChild->nodeType == snDeclaration ) + CompileDeclaration(fnode->firstChild, &initBC); + else + CompileExpressionStatement(fnode->firstChild, &initBC); + + //----------------------------------- + // Compile the condition statement + asCExprContext expr(engine); + asCScriptNode *second = fnode->firstChild->next; + if( second->firstChild ) + { + int r = CompileAssignment(second->firstChild, &expr); + if( r >= 0 ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), second->firstChild, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, second); + else + { + if( ProcessPropertyGetAccessor(&expr, second) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&expr); + + // If expression is false exit the loop + expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); + expr.bc.Instr(asBC_ClrHi); + expr.bc.InstrDWORD(asBC_JNZ, insideLabel); + ReleaseTemporaryVariable(expr.type, &expr.bc); + + expr.bc.OptimizeLocally(tempVariableOffsets); + + // Prepend the line instruction for the condition + asCByteCode tmp(engine); + LineInstr(&tmp, second->firstChild->tokenPos); + tmp.AddCode(&expr.bc); + expr.bc.AddCode(&tmp); + } + } + } + + //--------------------------- + // Compile the increment statement(s) + asCByteCode nextBC(engine); + asCScriptNode *cnode = second->next; + while( cnode && cnode->nodeType == snExpressionStatement && cnode != fnode->lastChild ) + { + LineInstr(&nextBC, cnode->tokenPos); + CompileExpressionStatement(cnode, &nextBC); + cnode = cnode->next; + } + + //------------------------------ + // Compile loop statement + bool hasReturn; + asCByteCode forBC(engine); + CompileStatement(fnode->lastChild, &hasReturn, &forBC); + + //------------------------------- + // Join the code pieces + bc->AddCode(&initBC); + bc->InstrDWORD(asBC_JMP, conditionLabel); + + bc->Label((short)insideLabel); + + // Add a suspend bytecode inside the loop to guarantee + // that the application can suspend the execution + bc->Instr(asBC_SUSPEND); + bc->InstrPTR(asBC_JitEntry, 0); + + LineInstr(bc, fnode->lastChild->tokenPos); + bc->AddCode(&forBC); + + bc->Label((short)continueLabel); + bc->AddCode(&nextBC); + + bc->Label((short)conditionLabel); + if( expr.bc.GetLastInstr() == -1 ) + // There is no condition, so we just always jump + bc->InstrDWORD(asBC_JMP, insideLabel); + else + bc->AddCode(&expr.bc); + + bc->Label((short)afterLabel); + + continueLabels.PopLast(); + breakLabels.PopLast(); + + // Deallocate variables in this block, in reverse order + for( int n = (int)variables->variables.GetLength() - 1; n >= 0; n-- ) + { + sVariable *v = variables->variables[n]; + + // Call variable destructors here, for variables not yet destroyed + CallDestructor(v->type, v->stackOffset, v->onHeap, bc); + + // Don't deallocate function parameters + if( v->stackOffset > 0 ) + DeallocateVariable(v->stackOffset); + } + + RemoveVariableScope(); +} + +void asCCompiler::CompileWhileStatement(asCScriptNode *wnode, asCByteCode *bc) +{ + // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables + AddVariableScope(true, true); + + // We will use two labels for the while loop + int beforeLabel = nextLabel++; + int afterLabel = nextLabel++; + + continueLabels.PushLast(beforeLabel); + breakLabels.PushLast(afterLabel); + + // Add label before the expression + bc->Label((short)beforeLabel); + + // Compile expression + asCExprContext expr(engine); + int r = CompileAssignment(wnode->firstChild, &expr); + if( r == 0 ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->firstChild, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); + else + { + if( ProcessPropertyGetAccessor(&expr, wnode) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&expr); + + // Jump to end of statement if expression is false + expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); + expr.bc.Instr(asBC_ClrHi); + expr.bc.InstrDWORD(asBC_JZ, afterLabel); + ReleaseTemporaryVariable(expr.type, &expr.bc); + + expr.bc.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&expr.bc); + } + } + + // Add a suspend bytecode inside the loop to guarantee + // that the application can suspend the execution + bc->Instr(asBC_SUSPEND); + bc->InstrPTR(asBC_JitEntry, 0); + + // Compile statement + bool hasReturn; + asCByteCode whileBC(engine); + CompileStatement(wnode->lastChild, &hasReturn, &whileBC); + + // Add byte code for the statement + LineInstr(bc, wnode->lastChild->tokenPos); + bc->AddCode(&whileBC); + + // Jump to the expression + bc->InstrINT(asBC_JMP, beforeLabel); + + // Add label after the statement + bc->Label((short)afterLabel); + + continueLabels.PopLast(); + breakLabels.PopLast(); + + RemoveVariableScope(); +} + +void asCCompiler::CompileDoWhileStatement(asCScriptNode *wnode, asCByteCode *bc) +{ + // Add a variable scope that will be used by CompileBreak/Continue to know where to stop deallocating variables + AddVariableScope(true, true); + + // We will use two labels for the while loop + int beforeLabel = nextLabel++; + int beforeTest = nextLabel++; + int afterLabel = nextLabel++; + + continueLabels.PushLast(beforeTest); + breakLabels.PushLast(afterLabel); + + // Add label before the statement + bc->Label((short)beforeLabel); + + // Compile statement + bool hasReturn; + asCByteCode whileBC(engine); + CompileStatement(wnode->firstChild, &hasReturn, &whileBC); + + // Add byte code for the statement + LineInstr(bc, wnode->firstChild->tokenPos); + bc->AddCode(&whileBC); + + // Add label before the expression + bc->Label((short)beforeTest); + + // Add a suspend bytecode inside the loop to guarantee + // that the application can suspend the execution + bc->Instr(asBC_SUSPEND); + bc->InstrPTR(asBC_JitEntry, 0); + + // Add a line instruction + LineInstr(bc, wnode->lastChild->tokenPos); + + // Compile expression + asCExprContext expr(engine); + CompileAssignment(wnode->lastChild, &expr); + + // Allow value types to be converted to bool using 'bool opImplConv()' + if( expr.type.dataType.GetTypeInfo() && (expr.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&expr, asCDataType::CreatePrimitive(ttBool, false), wnode->lastChild, asIC_IMPLICIT_CONV); + + if( !expr.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + Error(TXT_EXPR_MUST_BE_BOOL, wnode->firstChild); + else + { + if( ProcessPropertyGetAccessor(&expr, wnode) < 0 ) + return; + ConvertToVariable(&expr); + ProcessDeferredParams(&expr); + + // Jump to next iteration if expression is true + expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); + expr.bc.Instr(asBC_ClrHi); + expr.bc.InstrDWORD(asBC_JNZ, beforeLabel); + ReleaseTemporaryVariable(expr.type, &expr.bc); + + expr.bc.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&expr.bc); + } + + // Add label after the statement + bc->Label((short)afterLabel); + + continueLabels.PopLast(); + breakLabels.PopLast(); + + RemoveVariableScope(); +} + +void asCCompiler::CompileBreakStatement(asCScriptNode *node, asCByteCode *bc) +{ + if( breakLabels.GetLength() == 0 ) + { + Error(TXT_INVALID_BREAK, node); + return; + } + + // Add destructor calls for all variables that will go out of scope + // Put this clean up in a block to allow exception handler to understand them + bc->Block(true); + asCVariableScope *vs = variables; + while( !vs->isBreakScope ) + { + for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- ) + CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc); + + vs = vs->parent; + } + bc->Block(false); + + bc->InstrINT(asBC_JMP, breakLabels[breakLabels.GetLength()-1]); +} + +void asCCompiler::CompileContinueStatement(asCScriptNode *node, asCByteCode *bc) +{ + if( continueLabels.GetLength() == 0 ) + { + Error(TXT_INVALID_CONTINUE, node); + return; + } + + // Add destructor calls for all variables that will go out of scope + // Put this clean up in a block to allow exception handler to understand them + bc->Block(true); + asCVariableScope *vs = variables; + while( !vs->isContinueScope ) + { + for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- ) + CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc); + + vs = vs->parent; + } + bc->Block(false); + + bc->InstrINT(asBC_JMP, continueLabels[continueLabels.GetLength()-1]); +} + +void asCCompiler::CompileExpressionStatement(asCScriptNode *enode, asCByteCode *bc) +{ + if( enode->firstChild ) + { + // Compile the expression + asCExprContext expr(engine); + CompileAssignment(enode->firstChild, &expr); + + // Must not have unused ambiguous names + if( expr.IsClassMethod() || expr.IsGlobalFunc() ) + Error(TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME, enode); + + // Must not have unused anonymous functions + if( expr.IsLambda() ) + Error(TXT_INVALID_EXPRESSION_LAMBDA, enode); + + // If we get here and there is still an unprocessed property + // accessor, then process it as a get access. Don't call if there is + // already a compile error, or we might report an error that is not valid + if( !hasCompileErrors ) + if( ProcessPropertyGetAccessor(&expr, enode) < 0 ) + return; + + // Pop the value from the stack + if( !expr.type.dataType.IsPrimitive() ) + expr.bc.Instr(asBC_PopPtr); + + // Release temporary variables used by expression + ReleaseTemporaryVariable(expr.type, &expr.bc); + + ProcessDeferredParams(&expr); + + expr.bc.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&expr.bc); + } +} + +void asCCompiler::PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap) +{ + // The input can be either an object or funcdef, either as handle or reference + asASSERT(ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()); + + // If the object already is stored in temporary variable then nothing needs to be done + // Note, a type can be temporary without being a variable, in which case it is holding off + // on releasing a previously used object. + if( ctx->type.isTemporary && ctx->type.isVariable && + !(forceOnHeap && !IsVariableOnHeap(ctx->type.stackOffset)) ) + { + // If the temporary object is currently not a reference + // the expression needs to be reevaluated to a reference + if( !ctx->type.dataType.IsReference() ) + { + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); + ctx->type.dataType.MakeReference(true); + } + + return; + } + + // Allocate temporary variable + asCDataType dt = ctx->type.dataType; + dt.MakeReference(false); + dt.MakeReadOnly(false); + + int offset = AllocateVariable(dt, true, forceOnHeap); + + // Objects stored on the stack are not considered references + dt.MakeReference(IsVariableOnHeap(offset)); + + asCExprValue lvalue; + lvalue.Set(dt); + lvalue.isExplicitHandle = ctx->type.isExplicitHandle; + bool isExplicitHandle = ctx->type.isExplicitHandle; + + bool prevIsTemp = ctx->type.isTemporary; + int prevStackOffset = ctx->type.stackOffset; + + CompileInitAsCopy(dt, offset, &ctx->bc, ctx, node, false); + + // Release the previous temporary variable if it hasn't already been released + if( prevIsTemp && tempVariables.Exists(prevStackOffset) ) + ReleaseTemporaryVariable(prevStackOffset, &ctx->bc); + + // Push the reference to the temporary variable on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + + ctx->type.Set(dt); + ctx->type.isTemporary = true; + ctx->type.stackOffset = (short)offset; + ctx->type.isVariable = true; + ctx->type.isExplicitHandle = isExplicitHandle; + ctx->type.dataType.MakeReference(IsVariableOnHeap(offset)); +} + +void asCCompiler::CompileReturnStatement(asCScriptNode *rnode, asCByteCode *bc) +{ + // Get return type and location + sVariable *v = variables->GetVariable("return"); + + // Basic validations + if( v->type.GetSizeOnStackDWords() > 0 && !rnode->firstChild ) + { + Error(TXT_MUST_RETURN_VALUE, rnode); + return; + } + else if( v->type.GetSizeOnStackDWords() == 0 && rnode->firstChild ) + { + Error(TXT_CANT_RETURN_VALUE, rnode); + return; + } + + // Compile the expression + if( rnode->firstChild ) + { + // Compile the expression + asCExprContext expr(engine); + int r = CompileAssignment(rnode->firstChild, &expr); + if( r < 0 ) return; + + if( v->type.IsReference() ) + { + // The expression that gives the reference must not use any of the + // variables that must be destroyed upon exit, because then it means + // reference will stay alive while the clean-up is done, which could + // potentially mean that the reference is invalidated by the clean-up. + // + // When the function is returning a reference, the clean-up of the + // variables must be done before the evaluation of the expression. + // + // A reference to a global variable, or a class member for class methods + // should be allowed to be returned. + + if( !(expr.type.dataType.IsReference() || + (expr.type.dataType.IsObject() && !expr.type.dataType.IsObjectHandle())) ) + { + // Clean up the potential deferred parameters + ProcessDeferredParams(&expr); + Error(TXT_NOT_VALID_REFERENCE, rnode); + return; + } + + // No references to local variables, temporary variables, or parameters + // are allowed to be returned, since they go out of scope when the function + // returns. Even reference parameters are disallowed, since it is not possible + // to know the scope of them. The exception is the 'this' pointer, which + // is treated by the compiler as a local variable, but isn't really so. + if( (expr.type.isVariable && !(expr.type.stackOffset == 0 && outFunc->objectType)) || expr.type.isTemporary ) + { + // Clean up the potential deferred parameters + ProcessDeferredParams(&expr); + Error(TXT_CANNOT_RETURN_REF_TO_LOCAL, rnode); + return; + } + + // The type must match exactly as we cannot convert + // the reference without loosing the original value + if( !(v->type.IsEqualExceptConst(expr.type.dataType) || + ((expr.type.dataType.IsObject() || expr.type.dataType.IsFuncdef()) && + !expr.type.dataType.IsObjectHandle() && + v->type.IsEqualExceptRefAndConst(expr.type.dataType))) || + (!v->type.IsReadOnly() && expr.type.dataType.IsReadOnly()) ) + { + // Clean up the potential deferred parameters + ProcessDeferredParams(&expr); + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf()); + Error(str, rnode); + return; + } + + // The expression must not have any deferred expressions, because the evaluation + // of these cannot be done without keeping the reference which is not safe + if( expr.deferredParams.GetLength() ) + { + // Clean up the potential deferred parameters + ProcessDeferredParams(&expr); + Error(TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM, rnode); + return; + } + + // Make sure the expression isn't using any local variables that + // will need to be cleaned up before the function completes + asCArray usedVars; + expr.bc.GetVarsUsed(usedVars); + for( asUINT n = 0; n < usedVars.GetLength(); n++ ) + { + int var = GetVariableSlot(usedVars[n]); + if( var != -1 ) + { + asCDataType dt = variableAllocations[var]; + if( dt.IsObject() ) + { + ProcessDeferredParams(&expr); + Error(TXT_REF_CANT_BE_RETURNED_LOCAL_VARS, rnode); + return; + } + } + } + + // Can't return the reference if could point to a local variable + if( expr.type.isRefToLocal ) + { + ProcessDeferredParams(&expr); + Error(TXT_REF_CANT_BE_TO_LOCAL_VAR, rnode); + return; + } + + // All objects in the function must be cleaned up before the expression + // is evaluated, otherwise there is a possibility that the cleanup will + // invalidate the reference. + + // Destroy the local variables before loading + // the reference into the register. This will + // be done before the expression is evaluated. + DestroyVariables(bc); + + // For primitives the reference is already in the register, + // but for non-primitives the reference is on the stack so we + // need to load it into the register + if( !expr.type.dataType.IsPrimitive() ) + { + if( !expr.type.dataType.IsObjectHandle() && + expr.type.dataType.IsReference() ) + expr.bc.Instr(asBC_RDSPtr); + + expr.bc.Instr(asBC_PopRPtr); + } + + // There are no temporaries to release so we're done + } + else // if( !v->type.IsReference() ) + { + if( ProcessPropertyGetAccessor(&expr, rnode) < 0 ) + return; + + // Prepare the value for assignment + IsVariableInitialized(&expr.type, rnode->firstChild); + + if( v->type.IsPrimitive() ) + { + if( expr.type.dataType.IsReference() ) ConvertToVariable(&expr); + + // Implicitly convert the value to the return type + ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV); + + // Verify that the conversion was successful + if( expr.type.dataType != v->type ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf()); + Error(str, rnode); + return; + } + else + { + ConvertToVariable(&expr); + + // Clean up the local variables and process deferred parameters + DestroyVariables(&expr.bc); + ProcessDeferredParams(&expr); + + ReleaseTemporaryVariable(expr.type, &expr.bc); + + // Load the variable in the register + if( v->type.GetSizeOnStackDWords() == 1 ) + expr.bc.InstrSHORT(asBC_CpyVtoR4, expr.type.stackOffset); + else + expr.bc.InstrSHORT(asBC_CpyVtoR8, expr.type.stackOffset); + } + } + else if( v->type.IsObject() || v->type.IsFuncdef() ) + { + // Value types are returned on the stack, in a location + // that has been reserved by the calling function. + if( outFunc->DoesReturnOnStack() ) + { + // TODO: runtime optimize: If the return type has a constructor that takes the type of the expression, + // it should be called directly instead of first converting the expression and + // then copy the value. + if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) ) + { + ImplicitConversion(&expr, v->type, rnode->firstChild, asIC_IMPLICIT_CONV); + if( !v->type.IsEqualExceptRefAndConst(expr.type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, expr.type.dataType.Format(outFunc->nameSpace).AddressOf(), v->type.Format(outFunc->nameSpace).AddressOf()); + Error(str, rnode->firstChild); + return; + } + } + + int offset = outFunc->objectType ? -AS_PTR_SIZE : 0; + CompileInitAsCopy(v->type, offset, &expr.bc, &expr, rnode->firstChild, true); + + // Clean up the local variables and process deferred parameters + DestroyVariables(&expr.bc); + ProcessDeferredParams(&expr); + } + else + { + asASSERT( (v->type.GetTypeInfo()->flags & asOBJ_REF) || v->type.IsFuncdef() ); + + // Prepare the expression to be loaded into the object + // register. This will place the reference in local variable + PrepareArgument(&v->type, &expr, rnode->firstChild, false, 0); + + // Pop the reference to the temporary variable + expr.bc.Instr(asBC_PopPtr); + + // Clean up the local variables and process deferred parameters + DestroyVariables(&expr.bc); + ProcessDeferredParams(&expr); + + // Load the object pointer into the object register + // LOADOBJ also clears the address in the variable + expr.bc.InstrSHORT(asBC_LOADOBJ, expr.type.stackOffset); + + // LOADOBJ cleared the address in the variable so the object will not be freed + // here, but the temporary variable must still be freed so the slot can be reused + // By releasing without the bytecode we do just that. + ReleaseTemporaryVariable(expr.type, 0); + } + } + } + + expr.bc.OptimizeLocally(tempVariableOffsets); + bc->AddCode(&expr.bc); + } + else + { + // For functions that don't return anything + // we just detroy the local variables + DestroyVariables(bc); + } + + // Jump to the end of the function + bc->InstrINT(asBC_JMP, 0); +} + +void asCCompiler::DestroyVariables(asCByteCode *bc) +{ + // Call destructor on all variables except for the function parameters + // Put the clean-up in a block to allow exception handler to understand this + bc->Block(true); + asCVariableScope *vs = variables; + while( vs ) + { + for( int n = (int)vs->variables.GetLength() - 1; n >= 0; n-- ) + if( vs->variables[n]->stackOffset > 0 ) + CallDestructor(vs->variables[n]->type, vs->variables[n]->stackOffset, vs->variables[n]->onHeap, bc); + + vs = vs->parent; + } + bc->Block(false); +} + +void asCCompiler::AddVariableScope(bool isBreakScope, bool isContinueScope) +{ + variables = asNEW(asCVariableScope)(variables); + if( variables == 0 ) + { + // Out of memory + return; + } + variables->isBreakScope = isBreakScope; + variables->isContinueScope = isContinueScope; +} + +void asCCompiler::RemoveVariableScope() +{ + if( variables ) + { + asCVariableScope *var = variables; + variables = variables->parent; + asDELETE(var,asCVariableScope); + } +} + +void asCCompiler::Error(const asCString &msg, asCScriptNode *node) +{ + asCString str; + + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + + builder->WriteError(script->name, msg, r, c); + + hasCompileErrors = true; +} + +void asCCompiler::Warning(const asCString &msg, asCScriptNode *node) +{ + asCString str; + + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + + builder->WriteWarning(script->name, msg, r, c); +} + +void asCCompiler::Information(const asCString &msg, asCScriptNode *node) +{ + asCString str; + + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + + builder->WriteInfo(script->name, msg, r, c, false); +} + +void asCCompiler::PrintMatchingFuncs(asCArray &funcs, asCScriptNode *node, asCObjectType *inType) +{ + int r = 0, c = 0; + asASSERT( node ); + if( node ) script->ConvertPosToRowCol(node->tokenPos, &r, &c); + + for( unsigned int n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]); + if( inType && func->funcType == asFUNC_VIRTUAL ) + func = inType->virtualFunctionTable[func->vfTableIdx]; + + builder->WriteInfo(script->name, func->GetDeclaration(true, false, true), r, c, false); + + if (func->objectType && (func->objectType->flags & asOBJ_TEMPLATE)) + { + // Check for funcdefs in the arguments that may have been generated by the template instance, so these can be shown to user + for (unsigned int p = 0; p < func->GetParamCount(); p++) + { + int typeId = 0; + func->GetParam(p, &typeId); + asITypeInfo *ti = engine->GetTypeInfoById(typeId); + if (ti && (ti->GetFlags() & asOBJ_FUNCDEF)) + { + asCString msg; + msg.Format(TXT_WHERE_s_IS_s, ti->GetName(), ti->GetFuncdefSignature()->GetDeclaration()); + builder->WriteInfo(script->name, msg.AddressOf(), r, c, false); + } + } + } + } +} + +int asCCompiler::AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx) +{ + int l = int(reservedVariables.GetLength()); + ctx->bc.GetVarsUsed(reservedVariables); + int var = AllocateVariable(type, isTemporary, forceOnHeap); + reservedVariables.SetLength(l); + return var; +} + +int asCCompiler::AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap, bool asReference) +{ + asCDataType t(type); + t.MakeReference(asReference); + + if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 1 ) + t.SetTokenType(ttInt); + + if( t.IsPrimitive() && t.GetSizeOnStackDWords() == 2 ) + t.SetTokenType(ttDouble); + + // Only null handles have the token type unrecognized token + asASSERT( t.IsObjectHandle() || t.GetTokenType() != ttUnrecognizedToken ); + + bool isOnHeap = true; + if( t.IsPrimitive() || + (t.GetTypeInfo() && (t.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && !forceOnHeap) ) + { + // Primitives and value types (unless overridden) are allocated on the stack + isOnHeap = false; + } + + // Find a free location with the same type + for( asUINT n = 0; n < freeVariables.GetLength(); n++ ) + { + int slot = freeVariables[n]; + + if( variableAllocations[slot].IsEqualExceptConst(t) && + variableIsTemporary[slot] == isTemporary && + variableIsOnHeap[slot] == isOnHeap ) + { + // We can't return by slot, must count variable sizes + int offset = GetVariableOffset(slot); + + // Verify that it is not in the list of reserved variables + bool isUsed = false; + if( reservedVariables.GetLength() ) + isUsed = reservedVariables.Exists(offset); + + if( !isUsed ) + { + if( n != freeVariables.GetLength() - 1 ) + freeVariables[n] = freeVariables.PopLast(); + else + freeVariables.PopLast(); + + if( isTemporary ) + tempVariables.PushLast(offset); + + return offset; + } + } + } + + variableAllocations.PushLast(t); + variableIsTemporary.PushLast(isTemporary); + variableIsOnHeap.PushLast(isOnHeap); + + int offset = GetVariableOffset((int)variableAllocations.GetLength()-1); + + if( isTemporary ) + { + // Add offset to the currently allocated temporary variables + tempVariables.PushLast(offset); + + // Add offset to all known offsets to temporary variables, whether allocated or not + tempVariableOffsets.PushLast(offset); + } + + return offset; +} + +int asCCompiler::GetVariableOffset(int varIndex) +{ + // Return offset to the last dword on the stack + + // Start at 1 as offset 0 is reserved for the this pointer (or first argument for global functions) + int varOffset = 1; + + // Skip lower variables + for( int n = 0; n < varIndex; n++ ) + { + if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() ) + varOffset += variableAllocations[n].GetSizeInMemoryDWords(); + else + varOffset += variableAllocations[n].GetSizeOnStackDWords(); + } + + if( varIndex < (int)variableAllocations.GetLength() ) + { + // For variables larger than 1 dword the returned offset should be to the last dword + int size; + if( !variableIsOnHeap[varIndex] && variableAllocations[varIndex].IsObject() ) + size = variableAllocations[varIndex].GetSizeInMemoryDWords(); + else + size = variableAllocations[varIndex].GetSizeOnStackDWords(); + if( size > 1 ) + varOffset += size-1; + } + + return varOffset; +} + + +int asCCompiler::GetVariableSlot(int offset) +{ + int varOffset = 1; + for( asUINT n = 0; n < variableAllocations.GetLength(); n++ ) + { + if( !variableIsOnHeap[n] && variableAllocations[n].IsObject() ) + varOffset += -1 + variableAllocations[n].GetSizeInMemoryDWords(); + else + varOffset += -1 + variableAllocations[n].GetSizeOnStackDWords(); + + if( varOffset == offset ) + return n; + + varOffset++; + } + + return -1; +} + +bool asCCompiler::IsVariableOnHeap(int offset) +{ + int varSlot = GetVariableSlot(offset); + if( varSlot < 0 ) + { + // This happens for function arguments that are considered as on the heap + return true; + } + + return variableIsOnHeap[varSlot]; +} + +void asCCompiler::DeallocateVariable(int offset) +{ + // Remove temporary variable + int n; + for( n = 0; n < (int)tempVariables.GetLength(); n++ ) + { + if( offset == tempVariables[n] ) + { + if( n == (int)tempVariables.GetLength()-1 ) + tempVariables.PopLast(); + else + tempVariables[n] = tempVariables.PopLast(); + break; + } + } + + // Mark the variable slot available for new allocations + n = GetVariableSlot(offset); + if( n != -1 ) + { + freeVariables.PushLast(n); + return; + } + + // We might get here if the variable was implicitly declared + // because it was used before a formal declaration, in this case + // the offset is 0x7FFF + + asASSERT(offset == 0x7FFF); +} + +void asCCompiler::ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc) +{ + if( t.isTemporary ) + { + ReleaseTemporaryVariable(t.stackOffset, bc); + t.isTemporary = false; + } +} + +void asCCompiler::ReleaseTemporaryVariable(int offset, asCByteCode *bc) +{ + asASSERT( tempVariables.Exists(offset) ); + + if( bc ) + { + // We need to call the destructor on the true variable type + int n = GetVariableSlot(offset); + asASSERT( n >= 0 ); + if( n >= 0 ) + { + asCDataType dt = variableAllocations[n]; + bool isOnHeap = variableIsOnHeap[n]; + + // Call destructor + CallDestructor(dt, offset, isOnHeap, bc); + } + } + + DeallocateVariable(offset); +} + +void asCCompiler::Dereference(asCExprContext *ctx, bool generateCode) +{ + if( ctx->type.dataType.IsReference() ) + { + if( ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef() ) + { + ctx->type.dataType.MakeReference(false); + if( generateCode ) + ctx->bc.Instr(asBC_RDSPtr); + } + else + { + // This should never happen as primitives are treated differently + asASSERT(false); + } + } +} + +bool asCCompiler::IsVariableInitialized(asCExprValue *type, asCScriptNode *node) +{ + // No need to check if there is no variable scope + if( variables == 0 ) return true; + + // Temporary variables are assumed to be initialized + if( type->isTemporary ) return true; + + // Verify that it is a variable + if( !type->isVariable ) return true; + + // Find the variable + sVariable *v = variables->GetVariableByOffset(type->stackOffset); + + // The variable isn't found if it is a constant, in which case it is guaranteed to be initialized + if( v == 0 ) return true; + + if( v->isInitialized ) return true; + + // Complex types don't need this test + if( v->type.IsObject() || v->type.IsFuncdef() ) return true; + + // Mark as initialized so that the user will not be bothered again + v->isInitialized = true; + + // Write warning + asCString str; + str.Format(TXT_s_NOT_INITIALIZED, (const char *)v->name.AddressOf()); + Warning(str, node); + + return false; +} + +void asCCompiler::PrepareOperand(asCExprContext *ctx, asCScriptNode *node) +{ + // Check if the variable is initialized (if it indeed is a variable) + IsVariableInitialized(&ctx->type, node); + + asCDataType to = ctx->type.dataType; + to.MakeReference(false); + + ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV); + + ProcessDeferredParams(ctx); +} + +void asCCompiler::PrepareForAssignment(asCDataType *lvalue, asCExprContext *rctx, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr) +{ + // Reserve the temporary variables used in the lvalue expression so they won't end up being used by the rvalue too + int l = int(reservedVariables.GetLength()); + if( lvalueExpr ) lvalueExpr->bc.GetVarsUsed(reservedVariables); + + if( ProcessPropertyGetAccessor(rctx, node) < 0 ) + return; + + // Make sure the rvalue is initialized if it is a variable + IsVariableInitialized(&rctx->type, node); + + if( lvalue->IsPrimitive() ) + { + if( rctx->type.dataType.IsPrimitive() ) + { + if( rctx->type.dataType.IsReference() ) + { + // Cannot do implicit conversion of references so we first convert the reference to a variable + ConvertToVariableNotIn(rctx, lvalueExpr); + } + } + + // Implicitly convert the value to the right type + ImplicitConversion(rctx, *lvalue, node, asIC_IMPLICIT_CONV); + + // Check data type + if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + rctx->type.SetDummy(); + } + + // Make sure the rvalue is a variable + if( !rctx->type.isVariable ) + ConvertToVariableNotIn(rctx, lvalueExpr); + } + else + { + asCDataType to = *lvalue; + to.MakeReference(false); + + // TODO: ImplicitConversion should know to do this by itself + // First convert to a handle which will do a reference cast + if( !lvalue->IsObjectHandle() && + (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) + to.MakeHandle(true); + + // Don't allow the implicit conversion to create an object + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary); + + if( !lvalue->IsObjectHandle() && + (lvalue->GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) + { + // Then convert to a reference, which will validate the handle + to.MakeHandle(false); + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true, !toTemporary); + } + + // Check data type + if( !lvalue->IsEqualExceptRefAndConst(rctx->type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lvalue->Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + else + { + // If the assignment will be made with the copy behaviour then the rvalue must not be a reference + asASSERT(!lvalue->IsObject() || !rctx->type.dataType.IsReference()); + } + } + + // Unreserve variables + reservedVariables.SetLength(l); +} + +bool asCCompiler::IsLValue(asCExprValue &type) +{ + if( !type.isLValue ) return false; + if( type.dataType.IsReadOnly() ) return false; + if( !type.dataType.IsObject() && !type.isVariable && !type.dataType.IsReference() ) return false; + return true; +} + +int asCCompiler::PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node) +{ + if( lvalue->dataType.IsReadOnly() ) + { + Error(TXT_REF_IS_READ_ONLY, node); + return -1; + } + + if( lvalue->dataType.IsPrimitive() ) + { + if( lvalue->isVariable ) + { + // Copy the value between the variables directly + if( lvalue->dataType.GetSizeInMemoryDWords() == 1 ) + bc->InstrW_W(asBC_CpyVtoV4, lvalue->stackOffset, rvalue->stackOffset); + else + bc->InstrW_W(asBC_CpyVtoV8, lvalue->stackOffset, rvalue->stackOffset); + + // Mark variable as initialized + sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset); + if( v ) v->isInitialized = true; + } + else if( lvalue->dataType.IsReference() ) + { + // Copy the value of the variable to the reference in the register + int s = lvalue->dataType.GetSizeInMemoryBytes(); + if( s == 1 ) + bc->InstrSHORT(asBC_WRTV1, rvalue->stackOffset); + else if( s == 2 ) + bc->InstrSHORT(asBC_WRTV2, rvalue->stackOffset); + else if( s == 4 ) + bc->InstrSHORT(asBC_WRTV4, rvalue->stackOffset); + else if( s == 8 ) + bc->InstrSHORT(asBC_WRTV8, rvalue->stackOffset); + } + else + { + Error(TXT_NOT_VALID_LVALUE, node); + return -1; + } + } + else if( !lvalue->isExplicitHandle ) + { + asCExprContext ctx(engine); + ctx.type = *lvalue; + Dereference(&ctx, true); + *lvalue = ctx.type; + bc->AddCode(&ctx.bc); + + asSTypeBehaviour *beh = lvalue->dataType.GetBehaviour(); + if( beh && beh->copy && beh->copy != engine->scriptTypeBehaviours.beh.copy ) + { + asCExprContext res(engine); + PerformFunctionCall(beh->copy, &res, false, 0, CastToObjectType(lvalue->dataType.GetTypeInfo())); + + bc->AddCode(&res.bc); + *lvalue = res.type; + } + else if( beh && beh->copy == engine->scriptTypeBehaviours.beh.copy ) + { + // Call the default copy operator for script classes + // This is done differently because the default copy operator + // is registered as returning int&, but in reality it returns + // a reference to the object. + // TODO: Avoid this special case by implementing a copystub for + // script classes that uses the default copy operator + bc->Call(asBC_CALLSYS, beh->copy, 2*AS_PTR_SIZE); + bc->Instr(asBC_PshRPtr); + } + else + { + // Default copy operator + if( lvalue->dataType.GetSizeInMemoryDWords() == 0 || + !(lvalue->dataType.GetTypeInfo()->flags & asOBJ_POD) ) + { + asCString msg; + msg.Format(TXT_NO_DEFAULT_COPY_OP_FOR_s, lvalue->dataType.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + return -1; + } + + // Copy larger data types from a reference + // TODO: runtime optimize: COPY should pop both arguments and store the reference in the register. + bc->InstrSHORT_DW(asBC_COPY, (short)lvalue->dataType.GetSizeInMemoryDWords(), engine->GetTypeIdFromDataType(lvalue->dataType)); + } + } + else + { + // TODO: The object handle can be stored in a variable as well + if( !lvalue->dataType.IsReference() ) + { + Error(TXT_NOT_VALID_REFERENCE, node); + return -1; + } + + if( lvalue->dataType.IsFuncdef() ) + bc->InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + bc->InstrPTR(asBC_REFCPY, lvalue->dataType.GetTypeInfo()); + + // Mark variable as initialized + if( variables ) + { + sVariable *v = variables->GetVariableByOffset(lvalue->stackOffset); + if( v ) v->isInitialized = true; + } + } + + return 0; +} + +bool asCCompiler::CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode) +{ + bool conversionDone = false; + + asCArray ops; + + // A ref cast must not remove the constness + bool isConst = ctx->type.dataType.IsObjectConst(); + + // Find a suitable opCast or opImplCast method + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( (isExplicit && func->name == "opCast") || + func->name == "opImplCast" ) + { + // Is the operator for the output type? + if( func->returnType.GetTypeInfo() != to.GetTypeInfo() ) + continue; + + // Can't call a non-const function on a const object + if( isConst && !func->IsReadOnly() ) + continue; + + ops.PushLast(func->id); + } + } + + // Filter the list by constness to remove const methods if there are matching non-const methods + FilterConst(ops, !isConst); + + // If there is multiple matches, then pick the most appropriate one + if (ops.GetLength() > 1) + { + // This should only happen if an explicit cast is compiled + // and the type has both the opCast and opImplCast + asASSERT(isExplicit); + asASSERT(ops.GetLength() == 2); + + for (asUINT n = 0; n < ops.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[ops[n]]; + if (func->name == "opImplCast") + { + ops.RemoveIndex(n); + n--; + } + } + } + + // Should only have one behaviour for each output type + if( ops.GetLength() == 1 ) + { + conversionDone = true; + if( generateCode ) + { + // TODO: runtime optimize: Instead of producing bytecode for checking if the handle is + // null, we can create a special CALLSYS instruction that checks + // if the object pointer is null and if so sets the object register + // to null directly without executing the function. + // + // Alternatively I could force the ref cast behaviours be global + // functions with 1 parameter, even though they should still be + // registered with RegisterObjectBehaviour() + + if( (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) + { + // Add code to avoid calling the cast behaviour if the handle is already null, + // because that will raise a null pointer exception due to the cast behaviour + // being a class method, and the this pointer cannot be null. + + if (!ctx->type.isVariable) + { + Dereference(ctx, true); + ConvertToVariable(ctx); + } + + // The reference on the stack will not be used + ctx->bc.Instr(asBC_PopPtr); + + // TODO: runtime optimize: should have immediate comparison for null pointer + int offset = AllocateVariable(asCDataType::CreateNullHandle(), true); + // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though) + ctx->bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset); + ctx->bc.InstrW_W(asBC_CmpPtr, ctx->type.stackOffset, offset); + DeallocateVariable(offset); + + int afterLabel = nextLabel++; + ctx->bc.InstrDWORD(asBC_JZ, afterLabel); + + // Call the cast operator + ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); + ctx->bc.Instr(asBC_RDSPtr); + ctx->type.dataType.MakeReference(false); + + asCArray args; + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + ctx->bc.Instr(asBC_PopPtr); + + int endLabel = nextLabel++; + + ctx->bc.InstrINT(asBC_JMP, endLabel); + ctx->bc.Label((short)afterLabel); + + // Make a NULL pointer + ctx->bc.InstrSHORT(asBC_ClrVPtr, ctx->type.stackOffset); + ctx->bc.Label((short)endLabel); + + // Push the reference to the handle on the stack + ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); + } + else + { + // Value types cannot be null, so there is no need to check for this. + + // Likewise for reference types that are registered with asOBJ_NOHANDLE + // as those are only expected as registered global properties that cannot + // be modified anyway. + + // Call the cast operator + asCArray args; + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + } + } + else + { + asCScriptFunction *func = engine->scriptFunctions[ops[0]]; + ctx->type.Set(func->returnType); + } + } + else if( ops.GetLength() == 0 && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) && to.IsObjectHandle() ) + { + // Check for the generic ref cast method: void opCast(?&out) + // This option only works if the expected type is a handle + for( asUINT n = 0; ot && n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( (isExplicit && func->name == "opCast") || + func->name == "opImplCast" ) + { + // Does the operator take the ?&out parameter? + if( func->returnType.GetTokenType() != ttVoid || + func->parameterTypes.GetLength() != 1 || + func->parameterTypes[0].GetTokenType() != ttQuestion || + func->inOutFlags[0] != asTM_OUTREF ) + continue; + + ops.PushLast(func->id); + } + } + + // Filter the list by constness to remove const methods if there are matching non-const methods + FilterConst(ops, !isConst); + + // If there is multiple matches, then pick the most appropriate one + if (ops.GetLength() > 1) + { + // This should only happen if an explicit cast is compiled + // and the type has both the opCast and opImplCast + asASSERT(isExplicit); + asASSERT(ops.GetLength() == 2); + + for (asUINT n = 0; n < ops.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[ops[n]]; + if (func->name == "opImplCast") + { + ops.RemoveIndex(n); + n--; + } + } + } + + if( ops.GetLength() == 1 ) + { + conversionDone = true; + if( generateCode ) + { + int afterLabel = 0; + bool doNullCheck = false; + bool releaseTempVariable = false; + asCExprContext tmp(engine); + if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_NOHANDLE)) + { + tmp.bc.AddCode(&ctx->bc); + tmp.Merge(ctx); + + // Add code to avoid calling the cast behaviour if the handle is already null, + // because that will raise a null pointer exception due to the cast behaviour + // being a class method, and the this pointer cannot be null. + doNullCheck = true; + if (!ctx->type.isVariable) + { + Dereference(&tmp, true); + ConvertToVariable(&tmp); + releaseTempVariable = true; + } + + // The reference on the stack will not be used + tmp.bc.Instr(asBC_PopPtr); + + // TODO: runtime optimize: should have immediate comparison for null pointer + int offset = AllocateVariable(asCDataType::CreateNullHandle(), true); + // TODO: runtime optimize: ClrVPtr is not necessary, because the VM should initialize the variable to null anyway (it is currently not done for null pointers though) + tmp.bc.InstrSHORT(asBC_ClrVPtr, (asWORD)offset); + tmp.bc.InstrW_W(asBC_CmpPtr, tmp.type.stackOffset, offset); + DeallocateVariable(offset); + + afterLabel = nextLabel++; + tmp.bc.InstrDWORD(asBC_JZ, afterLabel); + + // Place the object pointer on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)tmp.type.stackOffset); + } + + // Allocate a temporary variable of the requested handle type + int stackOffset = AllocateVariableNotIn(to, true, false, ctx); + + // Pass the reference of that variable to the function as output parameter + asCDataType toRef(to); + toRef.MakeReference(true); + asCArray args; + asCExprContext arg(engine); + arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); + // Don't mark the variable as temporary, so it won't be freed too early + arg.type.SetVariable(toRef, stackOffset, false); + arg.type.isLValue = true; + arg.type.isExplicitHandle = true; + args.PushLast(&arg); + + // Call the behaviour method + MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + if (doNullCheck) + { + // Add the call after the null check + tmp.bc.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmp.bc); + + int endLabel = nextLabel++; + + ctx->bc.InstrINT(asBC_JMP, endLabel); + ctx->bc.Label((short)afterLabel); + + // Make a NULL pointer + ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)stackOffset); + ctx->bc.Label((short)endLabel); + } + + // If a temporary variable was allocated in the tmp to convert + // the input expression to a variable, it must be released here + if (releaseTempVariable && tmp.type.isTemporary) + ReleaseTemporaryVariable(tmp.type.stackOffset, &ctx->bc); + + // Use the reference to the variable as the result of the expression + // Now we can mark the variable as temporary + ctx->type.SetVariable(toRef, stackOffset, true); + ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset); + } + else + { + // All casts are legal + ctx->type.Set(to); + } + } + } + + // If the script object didn't implement a matching opCast or opImplCast + // then check if the desired type is part of the hierarchy + if( !conversionDone && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) ) + { + // We need it to be a reference + if( !ctx->type.dataType.IsReference() ) + { + asCDataType toRef = ctx->type.dataType; + toRef.MakeReference(true); + ImplicitConversion(ctx, toRef, 0, isExplicit ? asIC_EXPLICIT_REF_CAST : asIC_IMPLICIT_CONV, generateCode); + } + + if( isExplicit ) + { + // Allow dynamic cast between object handles (only for script objects). + // At run time this may result in a null handle, + // which when used will throw an exception + conversionDone = true; + if( generateCode ) + { + ctx->bc.InstrDWORD(asBC_Cast, engine->GetTypeIdFromDataType(to)); + + // Allocate a temporary variable for the returned object + int returnOffset = AllocateVariable(to, true); + + // Move the pointer from the object register to the temporary variable + ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset); + + ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset); + + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + ctx->type.SetVariable(to, returnOffset, true); + ctx->type.dataType.MakeReference(true); + } + else + { + ctx->type.dataType = to; + ctx->type.dataType.MakeReference(true); + } + } + else + { + if( CastToObjectType(ctx->type.dataType.GetTypeInfo())->DerivesFrom(to.GetTypeInfo()) ) + { + conversionDone = true; + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + } + + // A ref cast must not remove the constness + if( isConst ) + ctx->type.dataType.MakeHandleToConst(true); + } + + return conversionDone; +} + +asUINT asCCompiler::ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &toOrig, asCScriptNode *node, EImplicitConv convType, bool generateCode) +{ + asCDataType to = toOrig; + to.MakeReference(false); + asASSERT( !ctx->type.dataType.IsReference() ); + + // Maybe no conversion is needed + if( to.IsEqualExceptConst(ctx->type.dataType) ) + { + // A primitive is const or not + ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + return asCC_NO_CONV; + } + + // Is the conversion an ambiguous enum value? + if( ctx->enumValue != "" ) + { + if( to.IsEnumType() ) + { + // Attempt to resolve an ambiguous enum value + asCDataType out; + asDWORD value; + if( builder->GetEnumValueFromType(CastToEnumType(to.GetTypeInfo()), ctx->enumValue.AddressOf(), out, value) ) + { + ctx->type.SetConstantDW(out, value); + ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + + // Reset the enum value since we no longer need it + ctx->enumValue = ""; + + // It wasn't really a conversion. The compiler just resolved the ambiguity (or not) + return asCC_NO_CONV; + } + } + + // The enum value is ambiguous + if( node && generateCode ) + Error(TXT_FOUND_MULTIPLE_ENUM_VALUES, node); + + // Set a dummy to allow the compiler to try to continue the conversion + ctx->type.SetDummy(); + } + + // Determine the cost of this conversion + asUINT cost = asCC_NO_CONV; + if( (to.IsIntegerType() || to.IsUnsignedType()) && (ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) ) + cost = asCC_INT_FLOAT_CONV; + else if ((to.IsFloatType() || to.IsDoubleType()) && (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType())) + cost = asCC_INT_FLOAT_CONV; + else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() == ctx->type.dataType.GetSizeInMemoryBytes() ) + cost = asCC_ENUM_SAME_SIZE_CONV; + else if (ctx->type.dataType.IsEnumType() && to.IsIntegerType() && to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes()) + cost = asCC_ENUM_DIFF_SIZE_CONV; + else if( to.IsUnsignedType() && ctx->type.dataType.IsIntegerType() ) + cost = asCC_SIGNED_CONV; + else if( to.IsIntegerType() && ctx->type.dataType.IsUnsignedType() ) + cost = asCC_SIGNED_CONV; + else if( to.GetSizeInMemoryBytes() != ctx->type.dataType.GetSizeInMemoryBytes() ) + cost = asCC_PRIMITIVE_SIZE_CONV; + + // Start by implicitly converting constant values + if( ctx->type.isConstant ) + { + ImplicitConversionConstant(ctx, to, node, convType); + ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + return cost; + } + + // Allow implicit conversion between numbers + if( generateCode ) + { + // When generating the code the decision has already been made, so we don't bother determining the cost + + // Convert smaller types to 32bit first + int s = ctx->type.dataType.GetSizeInMemoryBytes(); + if( s < 4 ) + { + ConvertToTempVariable(ctx); + if( ctx->type.dataType.IsIntegerType() ) + { + if( s == 1 ) + ctx->bc.InstrSHORT(asBC_sbTOi, ctx->type.stackOffset); + else if( s == 2 ) + ctx->bc.InstrSHORT(asBC_swTOi, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(ttInt); + } + else if( ctx->type.dataType.IsUnsignedType() ) + { + if( s == 1 ) + ctx->bc.InstrSHORT(asBC_ubTOi, ctx->type.stackOffset); + else if( s == 2 ) + ctx->bc.InstrSHORT(asBC_uwTOi, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(ttUInt); + } + } + + if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) || + (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) ) + { + if( ctx->type.dataType.IsIntegerType() || + ctx->type.dataType.IsUnsignedType() ) + { + if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + } + else if( ctx->type.dataType.IsFloatType() ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_fTOi, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + else if( ctx->type.dataType.IsDoubleType() ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_dTOi, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + + // Convert to smaller integer if necessary + s = to.GetSizeInMemoryBytes(); + if( s < 4 ) + { + ConvertToTempVariable(ctx); + if( s == 1 ) + ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset); + else if( s == 2 ) + ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset); + } + } + else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 ) + { + if( ctx->type.dataType.IsIntegerType() || + ctx->type.dataType.IsUnsignedType() ) + { + if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + if( ctx->type.dataType.IsUnsignedType() ) + ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset); + else + ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + } + else if( ctx->type.dataType.IsFloatType() ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_fTOi64, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + else if( ctx->type.dataType.IsDoubleType() ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_dTOi64, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + } + else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 ) + { + if( ctx->type.dataType.IsIntegerType() || + ctx->type.dataType.IsUnsignedType() ) + { + if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_i64TOi, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + } + else if( ctx->type.dataType.IsFloatType() ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_fTOu, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + else if( ctx->type.dataType.IsDoubleType() ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_dTOu, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + + // Convert to smaller integer if necessary + s = to.GetSizeInMemoryBytes(); + if( s < 4 ) + { + ConvertToTempVariable(ctx); + if( s == 1 ) + ctx->bc.InstrSHORT(asBC_iTOb, ctx->type.stackOffset); + else if( s == 2 ) + ctx->bc.InstrSHORT(asBC_iTOw, ctx->type.stackOffset); + } + } + else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 ) + { + if( ctx->type.dataType.IsIntegerType() || + ctx->type.dataType.IsUnsignedType() ) + { + if( ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + if( ctx->type.dataType.IsUnsignedType() ) + ctx->bc.InstrW_W(asBC_uTOi64, offset, ctx->type.stackOffset); + else + ctx->bc.InstrW_W(asBC_iTOi64, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + } + else if( ctx->type.dataType.IsFloatType() ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_fTOu64, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + else if( ctx->type.dataType.IsDoubleType() ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_dTOu64, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + + if( convType != asIC_EXPLICIT_VAL_CAST ) + Warning(TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC, node); + } + } + else if( to.IsFloatType() ) + { + if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_iTOf, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_i64TOf, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_uTOf, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_u64TOf, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + else if( ctx->type.dataType.IsDoubleType() ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_dTOf, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + } + else if( to.IsDoubleType() ) + { + if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_iTOd, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_i64TOd, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_uTOd, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + else if( ctx->type.dataType.IsUnsignedType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + ConvertToTempVariable(ctx); + ctx->bc.InstrSHORT(asBC_u64TOd, ctx->type.stackOffset); + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + else if( ctx->type.dataType.IsFloatType() ) + { + ConvertToTempVariable(ctx); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + int offset = AllocateVariable(to, true); + ctx->bc.InstrW_W(asBC_fTOd, offset, ctx->type.stackOffset); + ctx->type.SetVariable(to, offset, true); + } + } + } + else + { + if( ((to.IsIntegerType() && !to.IsEnumType()) || to.IsUnsignedType() || + to.IsFloatType() || to.IsDoubleType() || + (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST)) && + (ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() || + ctx->type.dataType.IsFloatType() || ctx->type.dataType.IsDoubleType()) ) + { + ctx->type.dataType.SetTokenType(to.GetTokenType()); + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + } + } + + // Primitive types on the stack, can be const or non-const + ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + return cost; +} + +asUINT asCCompiler::ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode * /*node*/, EImplicitConv /*convType*/, bool generateCode) +{ + asASSERT( to.IsFuncdef() && ctx->IsLambda() ); + + asCScriptFunction *funcDef = CastToFuncdefType(to.GetTypeInfo())->funcdef; + + // Check that the lambda has the correct amount of arguments + asUINT count = 0; + asCScriptNode *argNode = ctx->exprNode->firstChild; + while( argNode->nodeType != snStatementBlock ) + { + // Check if the specified parameter types match the funcdef + if (argNode->nodeType == snDataType) + { + asCDataType dt = builder->CreateDataTypeFromNode(argNode, script, outFunc->nameSpace, false, outFunc->objectType); + asETypeModifiers inOutFlag; + dt = builder->ModifyDataTypeFromNode(dt, argNode->next, script, &inOutFlag, 0); + + if (count >= funcDef->parameterTypes.GetLength() || + funcDef->parameterTypes[count] != dt || + funcDef->inOutFlags[count] != inOutFlag) + return asCC_NO_CONV; + + argNode = argNode->next; + } + + if( argNode->nodeType == snIdentifier ) + count++; + argNode = argNode->next; + } + + if (funcDef->parameterTypes.GetLength() != count) + return asCC_NO_CONV; + + asASSERT(argNode->nodeType == snStatementBlock); + + // The Lambda can be used as this funcdef + ctx->type.dataType = to; + + if( generateCode ) + { + // Build a unique name for the anonymous function + asCString name; + if( m_globalVar ) + name.Format("$%s$%d", m_globalVar->name.AddressOf(), numLambdas++); + else + name.Format("$%s$%d", outFunc->GetDeclaration(), numLambdas++); + + // Register the lambda with the builder for later compilation + asCScriptFunction *func = builder->RegisterLambda(ctx->exprNode, script, funcDef, name, outFunc->nameSpace); + asASSERT( func == 0 || funcDef->IsSignatureExceptNameEqual(func) ); + ctx->bc.InstrPTR(asBC_FuncPtr, func); + + // Clear the expression node as it is no longer valid + ctx->exprNode = 0; + } + + return asCC_CONST_CONV; +} + +asUINT asCCompiler::ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) +{ + asASSERT( ctx->type.dataType.GetTokenType() != ttUnrecognizedToken || + ctx->type.dataType.IsNullHandle() || + ctx->IsAnonymousInitList() ); + + if( to.IsFuncdef() && ctx->IsLambda() ) + return ImplicitConvLambdaToFunc(ctx, to, node, convType, generateCode); + + if (ctx->IsAnonymousInitList()) + { + if (to.GetBehaviour() && to.GetBehaviour()->listFactory) + { + if (generateCode) + CompileAnonymousInitList(ctx->exprNode, ctx, to); + else + ctx->type.dataType = to; + } + return asCC_NO_CONV; + } + + // No conversion from void to any other type + if( ctx->type.dataType.GetTokenType() == ttVoid ) + return asCC_NO_CONV; + + // No conversion from class method to any type (it requires delegate) + if( ctx->IsClassMethod() ) + return asCC_NO_CONV; + + // Do we want a var type? + if( to.GetTokenType() == ttQuestion ) + { + // Any type can be converted to a var type, but only when not generating code + asASSERT( !generateCode ); + + ctx->type.dataType = to; + + return asCC_VARIABLE_CONV; + } + // Do we want a primitive? + else if( to.IsPrimitive() ) + { + if( !ctx->type.dataType.IsPrimitive() ) + return ImplicitConvObjectToPrimitive(ctx, to, node, convType, generateCode); + else + return ImplicitConvPrimitiveToPrimitive(ctx, to, node, convType, generateCode); + } + else // The target is a complex type + { + if( ctx->type.dataType.IsPrimitive() ) + return ImplicitConvPrimitiveToObject(ctx, to, node, convType, generateCode, allowObjectConstruct); + else if( ctx->type.IsNullConstant() || ctx->type.dataType.GetTypeInfo() ) + return ImplicitConvObjectToObject(ctx, to, node, convType, generateCode, allowObjectConstruct); + } + + return asCC_NO_CONV; +} + +asUINT asCCompiler::ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) +{ + if( ctx->type.isExplicitHandle ) + { + // An explicit handle cannot be converted to a primitive + if( convType != asIC_IMPLICIT_CONV && node ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + return asCC_NO_CONV; + } + + // Find matching value cast behaviours + // Here we're only interested in those that convert the type to a primitive type + asCArray funcs; + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + if( ot == 0 ) + { + if( convType != asIC_IMPLICIT_CONV && node ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + return asCC_NO_CONV; + } + + + if( convType == asIC_EXPLICIT_VAL_CAST ) + { + for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) + { + // accept both implicit and explicit cast + asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]]; + if( (mthd->name == "opConv" || mthd->name == "opImplConv") && + mthd->parameterTypes.GetLength() == 0 && + mthd->returnType.IsPrimitive() ) + funcs.PushLast(ot->methods[n]); + } + } + else + { + for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) + { + // accept only implicit cast + asCScriptFunction *mthd = engine->scriptFunctions[ot->methods[n]]; + if( mthd->name == "opImplConv" && + mthd->parameterTypes.GetLength() == 0 && + mthd->returnType.IsPrimitive() ) + funcs.PushLast(ot->methods[n]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + int funcId = 0; + if( to.IsMathType() ) + { + // This matrix describes the priorities of the types to search for, for each target type + // The first column is the target type, the priorities goes from left to right + eTokenType matchMtx[10][10] = + { + {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8}, + {ttFloat, ttDouble, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8}, + {ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat}, + {ttUInt64, ttInt64, ttUInt, ttInt, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat}, + {ttInt, ttUInt, ttInt64, ttUInt64, ttInt16, ttUInt16, ttInt8, ttUInt8, ttDouble, ttFloat}, + {ttUInt, ttInt, ttUInt64, ttInt64, ttUInt16, ttInt16, ttUInt8, ttInt8, ttDouble, ttFloat}, + {ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttInt8, ttUInt8, ttDouble, ttFloat}, + {ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttUInt8, ttInt8, ttDouble, ttFloat}, + {ttInt8, ttUInt8, ttInt16, ttUInt16, ttInt, ttUInt, ttInt64, ttUInt64, ttDouble, ttFloat}, + {ttUInt8, ttInt8, ttUInt16, ttInt16, ttUInt, ttInt, ttUInt64, ttInt64, ttDouble, ttFloat}, + }; + + // Which row to use? + eTokenType *row = 0; + for( unsigned int type = 0; type < 10; type++ ) + { + if( to.GetTokenType() == matchMtx[type][0] ) + { + row = &matchMtx[type][0]; + break; + } + } + + // Find the best matching cast operator + if( row ) + { + asCDataType target(to); + + // Priority goes from left to right in the matrix + for( unsigned int attempt = 0; attempt < 10 && funcId == 0; attempt++ ) + { + target.SetTokenType(row[attempt]); + for( unsigned int n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]); + if( descr->returnType.IsEqualExceptRefAndConst(target) ) + { + funcId = funcs[n]; + break; + } + } + } + } + } + else + { + // Only accept the exact conversion for non-math types + + // Find the matching cast operator + for( unsigned int n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[n]); + if( descr->returnType.IsEqualExceptRefAndConst(to) ) + { + funcId = funcs[n]; + break; + } + } + } + + // Did we find a suitable function? + if( funcId != 0 ) + { + asCScriptFunction *descr = builder->GetFunctionDescription(funcId); + if( generateCode ) + { + Dereference(ctx, true); + PerformFunctionCall(funcId, ctx); + } + else + ctx->type.Set(descr->returnType); + + // Allow one more implicit conversion to another primitive type + return asCC_OBJ_TO_PRIMITIVE_CONV + ImplicitConversion(ctx, to, node, convType, generateCode, false); + } + + // TODO: clean-up: This part is similar to what is in ImplicitConvObjectValue + // If no direct conversion is found we should look for the generic form 'void opConv(?&out)' + funcs.SetLength(0); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") || + func->name == "opImplConv" ) + { + // Does the operator take the ?&out parameter? + if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) || + func->parameterTypes.GetLength() != 1 || + func->parameterTypes[0].GetTokenType() != ttQuestion || + func->inOutFlags[0] != asTM_OUTREF ) + continue; + + funcs.PushLast(ot->methods[n]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + // If there are multiple valid value casts, then we must choose the most appropriate one + if (funcs.GetLength() > 1) + { + // This should only happen in case of explicit value cast and + // the application has registered both opImplConv and opConv + asASSERT(convType == asIC_EXPLICIT_VAL_CAST); + asASSERT(funcs.GetLength() == 2); + + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; + if (func->name == "opImplConv") + { + funcs.RemoveIndex(n); + n--; + } + } + } + + if( funcs.GetLength() == 1 ) + { + if( generateCode ) + { + // Allocate a temporary variable of the requested type + int stackOffset = AllocateVariableNotIn(to, true, false, ctx); + CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node); + + // Pass the reference of that variable to the function as output parameter + asCDataType toRef(to); + toRef.MakeReference(true); + toRef.MakeReadOnly(false); + asCArray args; + asCExprContext arg(engine); + // Don't mark the variable as temporary, so it won't be freed too early + arg.type.SetVariable(toRef, stackOffset, false); + arg.type.isLValue = true; + arg.exprNode = node; + args.PushLast(&arg); + + // Call the behaviour method + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + // Use the reference to the variable as the result of the expression + // Now we can mark the variable as temporary + toRef.MakeReference(false); + ctx->type.SetVariable(toRef, stackOffset, true); + } + else + ctx->type.Set(to); + + return asCC_OBJ_TO_PRIMITIVE_CONV; + } + + if( convType != asIC_IMPLICIT_CONV && node ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + return asCC_NO_CONV; +} + + +asUINT asCCompiler::ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) +{ + // Convert null to any object type handle, but not to a non-handle type + if( ctx->type.IsNullConstant() && ctx->methodName == "" ) + { + if( to.IsObjectHandle() ) + { + ctx->type.dataType = to; + return asCC_REF_CONV; + } + return asCC_NO_CONV; + } + + asASSERT(ctx->type.dataType.GetTypeInfo() || ctx->methodName != ""); + + // First attempt to convert the base type without instantiating another instance + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && ctx->methodName == "" ) + { + // If the to type is an interface and the from type implements it, then we can convert it immediately + if( ctx->type.dataType.GetTypeInfo()->Implements(to.GetTypeInfo()) ) + { + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + return asCC_REF_CONV; + } + // If the to type is a class and the from type derives from it, then we can convert it immediately + else if( ctx->type.dataType.GetTypeInfo()->DerivesFrom(to.GetTypeInfo()) ) + { + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + return asCC_REF_CONV; + } + // If the types are not equal yet, then we may still be able to find a reference cast + else if( ctx->type.dataType.GetTypeInfo() != to.GetTypeInfo() ) + { + // We may still be able to find an implicit ref cast behaviour + CompileRefCast(ctx, to, convType == asIC_EXPLICIT_REF_CAST, node, generateCode); + + // Was the conversion done? + if( ctx->type.dataType.GetTypeInfo() == to.GetTypeInfo() ) + return asCC_REF_CONV; + } + } + + // Convert matching function types + if( to.IsFuncdef() ) + { + // If the input expression is already a funcdef, check if it can be converted + if( ctx->type.dataType.IsFuncdef() && + to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) + { + asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; + asCScriptFunction *fromFunc = CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef; + if( toFunc->IsSignatureExceptNameEqual(fromFunc) ) + { + ctx->type.dataType.SetTypeInfo(to.GetTypeInfo()); + return asCC_REF_CONV; + } + } + + // If the input expression is a deferred function ref, check if there is a matching func + if( ctx->methodName != "" ) + { + // Determine the namespace + asSNameSpace *ns = 0; + asCString name = ""; + int pos = ctx->methodName.FindLast("::"); + if( pos >= 0 ) + { + asCString nsName = ctx->methodName.SubString(0, pos+2); + // Trim off the last :: + if( nsName.GetLength() > 2 ) + nsName.SetLength(nsName.GetLength()-2); + ns = DetermineNameSpace(nsName); + name = ctx->methodName.SubString(pos+2); + } + else + { + DetermineNameSpace(""); + name = ctx->methodName; + } + + asCArray funcs; + if( ns ) + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + + // Check if any of the functions have perfect match + asCScriptFunction *toFunc = CastToFuncdefType(to.GetTypeInfo())->funcdef; + for( asUINT n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *func = builder->GetFunctionDescription(funcs[n]); + if( toFunc->IsSignatureExceptNameEqual(func) ) + { + if( generateCode ) + { + ctx->bc.InstrPTR(asBC_FuncPtr, func); + + // Make sure the identified function is shared if we're compiling a shared function + if( !func->IsShared() && outFunc->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, func->GetDeclaration()); + Error(msg, node); + } + } + + ctx->type.dataType = asCDataType::CreateType(to.GetTypeInfo(), false); + return asCC_REF_CONV; + } + } + } + } + + return asCC_NO_CONV; +} + +asUINT asCCompiler::ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode) +{ + asUINT cost = asCC_NO_CONV; + + // If the base type is still different, and we are allowed to instance + // another object then we can try an implicit value cast + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) + { + // TODO: Implement support for implicit constructor/factory + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + if( ot == 0 ) + return cost; + + asCArray funcs; + if( convType == asIC_EXPLICIT_VAL_CAST ) + { + for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + + // accept both implicit and explicit cast + if( (func->name == "opConv" || + func->name == "opImplConv") && + func->returnType.GetTypeInfo() == to.GetTypeInfo() && + func->parameterTypes.GetLength() == 0 ) + funcs.PushLast(ot->methods[n]); + } + } + else + { + for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + + // accept only implicit cast + if( func->name == "opImplConv" && + func->returnType.GetTypeInfo() == to.GetTypeInfo() && + func->parameterTypes.GetLength() == 0 ) + funcs.PushLast(ot->methods[n]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + // If there are multiple valid value casts, then we must choose the most appropriate one + if (funcs.GetLength() > 1) + { + // This should only happen in case of explicit value cast and + // the application has registered both opImplConv and opConv + asASSERT(convType == asIC_EXPLICIT_VAL_CAST); + asASSERT(funcs.GetLength() == 2); + + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; + if (func->name == "opImplConv") + { + funcs.RemoveIndex(n); + n--; + } + } + } + + if( funcs.GetLength() == 1 ) + { + asCScriptFunction *f = builder->GetFunctionDescription(funcs[0]); + if( generateCode ) + { + Dereference(ctx, true); + + bool useVariable = false; + int stackOffset = 0; + + if( f->DoesReturnOnStack() ) + { + useVariable = true; + stackOffset = AllocateVariable(f->returnType, true); + + // Push the pointer to the pre-allocated space for the return value + ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset)); + + // The object pointer is already on the stack, but should be the top + // one, so we need to swap the pointers in order to get the correct + ctx->bc.Instr(asBC_SwapPtr); + } + + PerformFunctionCall(funcs[0], ctx, false, 0, 0, useVariable, stackOffset); + } + else + ctx->type.Set(f->returnType); + + cost = asCC_TO_OBJECT_CONV; + } + else + { + // TODO: cleanup: This part is similar to the second half of ImplicitConvObjectToPrimitive + // Look for a value cast with variable type + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( ((convType == asIC_EXPLICIT_VAL_CAST) && func->name == "opConv") || + func->name == "opImplConv" ) + { + // Does the operator take the ?&out parameter? + if( func->returnType != asCDataType::CreatePrimitive(ttVoid, false) || + func->parameterTypes.GetLength() != 1 || + func->parameterTypes[0].GetTokenType() != ttQuestion || + func->inOutFlags[0] != asTM_OUTREF ) + continue; + + funcs.PushLast(ot->methods[n]); + } + } + + FilterConst(funcs, !ctx->type.dataType.IsReadOnly()); + + // If there are multiple valid value casts, then we must choose the most appropriate one + if (funcs.GetLength() > 1) + { + // This should only happen in case of explicit value cast and + // the application has registered both opImplConv and opConv + asASSERT(convType == asIC_EXPLICIT_VAL_CAST); + asASSERT(funcs.GetLength() == 2); + + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[funcs[n]]; + if (func->name == "opImplConv") + { + funcs.RemoveIndex(n); + n--; + } + } + } + + if( funcs.GetLength() == 1 ) + { + cost = asCC_TO_OBJECT_CONV; + if( generateCode ) + { + // Allocate a temporary variable of the requested type + int stackOffset = AllocateVariableNotIn(to, true, false, ctx); + CallDefaultConstructor(to, stackOffset, IsVariableOnHeap(stackOffset), &ctx->bc, node); + + // Pass the reference of that variable to the function as output parameter + asCDataType toRef(to); + toRef.MakeReference(false); + asCExprContext arg(engine); + arg.bc.InstrSHORT(asBC_PSF, (short)stackOffset); + + // If this an object on the heap, the pointer must be dereferenced + if( IsVariableOnHeap(stackOffset) ) + arg.bc.Instr(asBC_RDSPtr); + + // Don't mark the variable as temporary, so it won't be freed too early + arg.type.SetVariable(toRef, stackOffset, false); + arg.type.isLValue = true; + arg.exprNode = node; + + // Mark the argument as clean, so that MakeFunctionCall knows it + // doesn't have to make a copy of it in order to protect the value + arg.isCleanArg = true; + + // Call the behaviour method + asCArray args; + args.PushLast(&arg); + MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + + // Use the reference to the variable as the result of the expression + // Now we can mark the variable as temporary + ctx->type.SetVariable(toRef, stackOffset, true); + ctx->bc.InstrSHORT(asBC_PSF, (short)stackOffset); + } + else + { + // All casts are legal + ctx->type.Set(to); + } + } + else if( CastToObjectType(to.GetTypeInfo()) ) + { + // If no opConv/opImplConv methods were found on the object, then try to find a conversion constructor on the target type + if( to.GetTypeInfo()->flags & asOBJ_REF ) + funcs = CastToObjectType(to.GetTypeInfo())->beh.factories; + else + funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; + + // If not explicit cast, remove any explicit conversion constructors + for (asUINT n = 0; n < funcs.GetLength(); n++) + { + asCScriptFunction *f = engine->scriptFunctions[funcs[n]]; + if( f == 0 || f->parameterTypes.GetLength() != 1 || (convType != asIC_EXPLICIT_VAL_CAST && f->IsExplicit()) ) + funcs.RemoveIndex(n--); + } + + asCArray args; + args.PushLast(ctx); + + cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false); + + // Did we find a matching constructor? + if (funcs.GetLength() == 1) + { + if (generateCode) + { + // TODO: This should really reuse the code from CompileConstructCall + + // Allocate the new object + asCExprValue tempObj; + asCExprContext e(engine); + bool onHeap = false; + if (to.GetTypeInfo()->flags & asOBJ_VALUE) + { + tempObj.dataType = to; + tempObj.dataType.MakeReference(false); + tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true); + tempObj.dataType.MakeReference(true); + tempObj.isTemporary = true; + tempObj.isVariable = true; + + onHeap = IsVariableOnHeap(tempObj.stackOffset); + + // Push the address of the object on the stack + if (onHeap) + e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); + } + + PrepareFunctionCall(funcs[0], &e.bc, args); + MoveArgsToStack(funcs[0], &e.bc, args, false); + + if (to.GetTypeInfo()->flags & asOBJ_VALUE) + { + // If the object is allocated on the stack, then call the constructor as a normal function + if (onHeap) + { + int offset = 0; + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); + offset = descr->parameterTypes[0].GetSizeOnStackDWords(); + + e.bc.InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + } + + PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + if (to.GetTypeInfo()->flags & asOBJ_VALUE) + { + // Add tag that the object has been initialized + e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); + + // The constructor doesn't return anything, + // so we have to manually inform the type of + // the return value + e.type = tempObj; + if (!onHeap) + e.type.dataType.MakeReference(false); + + // Push the address of the object on the stack again + e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + } + + MergeExprBytecodeAndType(ctx, &e); + } + else + { + ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false)); + } + } + } + } + } + + return cost; +} + +asUINT asCCompiler::ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode, bool allowObjectConstruct) +{ + // First try a ref cast + asUINT cost = ImplicitConvObjectRef(ctx, to, node, convType, generateCode); + + // If the desired type is an asOBJ_ASHANDLE then we'll assume it is allowed to implicitly + // construct the object through any of the available constructors + if( to.GetTypeInfo() && (to.GetTypeInfo()->flags & asOBJ_ASHANDLE) && to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) + { + asCArray funcs; + funcs = CastToObjectType(to.GetTypeInfo())->beh.constructors; + + asCArray args; + args.PushLast(ctx); + + cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, node, 0, 0, 0, false, true, false); + + // Did we find a matching constructor? + if( funcs.GetLength() == 1 ) + { + if( generateCode ) + { + // If the ASHANDLE receives a variable type parameter, then we need to + // make sure the expression is treated as a handle and not as a value + asCScriptFunction *func = engine->scriptFunctions[funcs[0]]; + if( func->parameterTypes[0].GetTokenType() == ttQuestion ) + { + if( !ctx->type.isExplicitHandle ) + { + asCDataType toHandle = ctx->type.dataType; + toHandle.MakeHandle(true); + toHandle.MakeReference(true); + toHandle.MakeHandleToConst(ctx->type.dataType.IsReadOnly()); + ImplicitConversion(ctx, toHandle, node, asIC_IMPLICIT_CONV, true, false); + + asASSERT( ctx->type.dataType.IsObjectHandle() ); + } + ctx->type.isExplicitHandle = true; + } + + // TODO: This should really reuse the code from CompileConstructCall + + // Allocate the new object + asCExprValue tempObj; + tempObj.dataType = to; + tempObj.dataType.MakeReference(false); + tempObj.stackOffset = (short)AllocateVariable(tempObj.dataType, true); + tempObj.dataType.MakeReference(true); + tempObj.isTemporary = true; + tempObj.isVariable = true; + + bool onHeap = IsVariableOnHeap(tempObj.stackOffset); + + // Push the address of the object on the stack + asCExprContext e(engine); + if( onHeap ) + e.bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); + + PrepareFunctionCall(funcs[0], &e.bc, args); + MoveArgsToStack(funcs[0], &e.bc, args, false); + + // If the object is allocated on the stack, then call the constructor as a normal function + if( onHeap ) + { + int offset = 0; + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); + offset = descr->parameterTypes[0].GetSizeOnStackDWords(); + + e.bc.InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + + PerformFunctionCall(funcs[0], &e, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + // Add tag that the object has been initialized + e.bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); + + // The constructor doesn't return anything, + // so we have to manually inform the type of + // the return value + e.type = tempObj; + if( !onHeap ) + e.type.dataType.MakeReference(false); + + // Push the address of the object on the stack again + e.bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + + MergeExprBytecodeAndType(ctx, &e); + } + else + { + ctx->type.Set(asCDataType::CreateType(to.GetTypeInfo(), false)); + } + } + } + + // If the base type is still different, and we are allowed to instance + // another object then we can try an implicit value cast + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() && allowObjectConstruct ) + { + // Attempt implicit value cast + cost = ImplicitConvObjectValue(ctx, to, node, convType, generateCode); + } + + // If we still haven't converted the base type to the correct type, then there is + // no need to continue as it is not possible to do the conversion + if( to.GetTypeInfo() != ctx->type.dataType.GetTypeInfo() ) + return asCC_NO_CONV; + + + if( to.IsObjectHandle() ) + { + // There is no extra cost in converting to a handle + + // reference to handle -> handle + // reference -> handle + // object -> handle + // handle -> reference to handle + // reference -> reference to handle + // object -> reference to handle + + if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly() && !to.IsHandleToConst()) || + (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst() && !to.IsHandleToConst()) ) + { + // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const + // TODO: NEWSTRING: Should have an engine property to warn or error on this + if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) + { + if (generateCode) + PrepareTemporaryVariable(node, ctx); + else + { + ctx->type.dataType.MakeReadOnly(false); + ctx->type.isConstant = false; + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + else if( convType != asIC_IMPLICIT_CONV ) + { + asASSERT(node); + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + } + + if( !ctx->type.dataType.IsObjectHandle() ) + { + // An object type can be directly converted to a handle of the + // same type by doing a ref copy to a new variable + if( ctx->type.dataType.SupportHandles() ) + { + asCDataType dt = ctx->type.dataType; + dt.MakeHandle(true); + dt.MakeReference(false); + + if( generateCode ) + { + // If the expression is already a local variable, then it is not + // necessary to do a ref copy, as the ref objects on the stack are + // really handles, only the handles cannot be modified. + if( ctx->type.isVariable ) + { + bool isHandleToConst = ctx->type.dataType.IsReadOnly(); + ctx->type.dataType.MakeReadOnly(false); + ctx->type.dataType.MakeHandle(true); + ctx->type.dataType.MakeReadOnly(true); + ctx->type.dataType.MakeHandleToConst(isHandleToConst); + + if( to.IsReference() && !ctx->type.dataType.IsReference() ) + { + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); + ctx->type.dataType.MakeReference(true); + } + else if( ctx->type.dataType.IsReference() ) + { + ctx->bc.Instr(asBC_RDSPtr); + ctx->type.dataType.MakeReference(false); + } + } + else + { + int offset = AllocateVariable(dt, true); + + if( ctx->type.dataType.IsReference() ) + ctx->bc.Instr(asBC_RDSPtr); + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + if (dt.IsFuncdef()) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, dt.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + if( to.IsReference() ) + dt.MakeReference(true); + else + ctx->bc.Instr(asBC_RDSPtr); + + ctx->type.SetVariable(dt, offset, true); + } + } + else + ctx->type.dataType = dt; + + // When this conversion is done the expression is no longer an lvalue + ctx->type.isLValue = false; + } + } + + if( ctx->type.dataType.IsObjectHandle() ) + { + // A handle to non-const can be converted to a + // handle to const, but not the other way + if( to.IsHandleToConst() ) + ctx->type.dataType.MakeHandleToConst(true); + + // A const handle can be converted to a non-const + // handle and vice versa as the handle is just a value + ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + } + + if( to.IsReference() && !ctx->type.dataType.IsReference() ) + { + if( generateCode ) + { + asASSERT( ctx->type.dataType.IsObjectHandle() ); + + // If the input type is a handle, then a simple ref copy is enough + bool isExplicitHandle = ctx->type.isExplicitHandle; + ctx->type.isExplicitHandle = ctx->type.dataType.IsObjectHandle(); + + // If the input type is read-only we'll need to temporarily + // remove this constness, otherwise the assignment will fail + bool typeIsReadOnly = ctx->type.dataType.IsReadOnly(); + ctx->type.dataType.MakeReadOnly(false); + + // If the object already is a temporary variable, then the copy + // doesn't have to be made as it is already a unique object + PrepareTemporaryVariable(node, ctx); + + ctx->type.dataType.MakeReadOnly(typeIsReadOnly); + ctx->type.isExplicitHandle = isExplicitHandle; + } + + // A non-reference can be converted to a reference, + // by putting the value in a temporary variable + ctx->type.dataType.MakeReference(true); + + // Since it is a new temporary variable it doesn't have to be const + ctx->type.dataType.MakeReadOnly(to.IsReadOnly()); + } + else if( !to.IsReference() && ctx->type.dataType.IsReference() ) + { + Dereference(ctx, generateCode); + } + } + else // if( !to.IsObjectHandle() ) + { + if( !to.IsReference() ) + { + // reference to handle -> object + // handle -> object + // reference -> object + + // An implicit handle can be converted to an object by adding a check for null pointer + if( ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle ) + { + if( generateCode ) + { + if( ctx->type.dataType.IsReference() ) + { + // The pointer on the stack refers to the handle + ctx->bc.Instr(asBC_ChkRefS); + } + else + { + // The pointer on the stack refers to the object + ctx->bc.Instr(asBC_CHKREF); + } + } + + ctx->type.dataType.MakeHandle(false); + } + + // A const object can be converted to a non-const object through a copy + if( ctx->type.dataType.IsReadOnly() && !to.IsReadOnly() && + allowObjectConstruct ) + { + // Does the object type allow a copy to be made? + if( ctx->type.dataType.CanBeCopied() ) + { + if( generateCode ) + { + // Make a temporary object with the copy + PrepareTemporaryVariable(node, ctx); + } + + // In case the object was already in a temporary variable, then the function + // didn't really do anything so we need to remove the constness here + ctx->type.dataType.MakeReadOnly(false); + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + } + + if( ctx->type.dataType.IsReference() ) + { + // This may look strange, but a value type allocated on the stack is already + // correct, so nothing should be done other than remove the mark as reference. + // For types allocated on the heap, it is necessary to dereference the pointer + // that is currently on the stack + if( IsVariableOnHeap(ctx->type.stackOffset) ) + Dereference(ctx, generateCode); + else + ctx->type.dataType.MakeReference(false); + } + + // A non-const object can be converted to a const object directly + if( !ctx->type.dataType.IsReadOnly() && to.IsReadOnly() ) + { + ctx->type.dataType.MakeReadOnly(true); + } + } + else // if( to.IsReference() ) + { + // reference to handle -> reference + // handle -> reference + // object -> reference + + if( ctx->type.dataType.IsReference() ) + { + if( ctx->type.isExplicitHandle && ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) + { + // ASHANDLE objects are really value types, so explicit handle can be removed + ctx->type.isExplicitHandle = false; + ctx->type.dataType.MakeHandle(false); + } + + // A reference to a handle can be converted to a reference to an object + // by first reading the address, then verifying that it is not null + if( !to.IsObjectHandle() && ctx->type.dataType.IsObjectHandle() && !ctx->type.isExplicitHandle ) + { + ctx->type.dataType.MakeHandle(false); + if( generateCode ) + ctx->bc.Instr(asBC_ChkRefS); + } + + // A reference to a non-const can be converted to a reference to a const + if( to.IsReadOnly() ) + ctx->type.dataType.MakeReadOnly(true); + else if( ctx->type.dataType.IsReadOnly() && allowObjectConstruct ) + { + // A reference to a const can be converted to a reference to a + // non-const by copying the object to a temporary variable + ctx->type.dataType.MakeReadOnly(false); + + if( generateCode ) + { + // If the object already is a temporary variable, then the copy + // doesn't have to be made as it is already a unique object + PrepareTemporaryVariable(node, ctx); + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + } + else // if( !ctx->type.dataType.IsReference() ) + { + // A non-reference handle can be converted to a non-handle reference by checking against null handle + if( ctx->type.dataType.IsObjectHandle() ) + { + bool readOnly = false; + if( ctx->type.dataType.IsHandleToConst() ) + readOnly = true; + + if( generateCode ) + { + if( ctx->type.isVariable ) + ctx->bc.InstrSHORT(asBC_ChkNullV, ctx->type.stackOffset); + else + ctx->bc.Instr(asBC_CHKREF); + } + ctx->type.dataType.MakeHandle(false); + ctx->type.dataType.MakeReference(true); + + // Make sure a handle to const isn't converted to non-const reference + if( readOnly ) + ctx->type.dataType.MakeReadOnly(true); + } + else + { + // A value type allocated on the stack is differentiated + // by it not being a reference. But it can be handled as + // reference by pushing the pointer on the stack + if( (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && + (ctx->type.isVariable || ctx->type.isTemporary) && + !IsVariableOnHeap(ctx->type.stackOffset) ) + { + // Actually the pointer is already pushed on the stack in + // CompileVariableAccess, so we don't need to do anything else + } + else if( generateCode ) + { + // A non-reference can be converted to a reference, + // by putting the value in a temporary variable + + // If the input type is read-only we'll need to temporarily + // remove this constness, otherwise the assignment will fail + bool typeIsReadOnly = ctx->type.dataType.IsReadOnly(); + ctx->type.dataType.MakeReadOnly(false); + + // If the object already is a temporary variable, then the copy + // doesn't have to be made as it is already a unique object + PrepareTemporaryVariable(node, ctx); + + ctx->type.dataType.MakeReadOnly(typeIsReadOnly); + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + + // This may look strange as the conversion was to make the expression a reference + // but a value type allocated on the stack is a reference even without the type + // being marked as such. + ctx->type.dataType.MakeReference(IsVariableOnHeap(ctx->type.stackOffset)); + } + + if (to.IsReadOnly()) + { + // This doesn't cost anything + ctx->type.dataType.MakeReadOnly(true); + } + + if (!to.IsReadOnly() && ctx->type.dataType.IsReadOnly()) + { + // A const object can be converted to a non-const object through a copy + if (allowObjectConstruct || convType == asIC_EXPLICIT_VAL_CAST) + { + ctx->type.dataType.MakeReadOnly(false); + + if (generateCode) + { + // Make a temporary copy of the object in order to make it non-const + PrepareTemporaryVariable(node, ctx); + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + + // String literals can be implicitly converted to temporary local variables in order to pass them to functions expecting non-const + // TODO: NEWSTRING: Should have an engine property to warn or error on this + if (ctx->type.isConstant && ctx->type.dataType.IsEqualExceptRefAndConst(engine->stringType)) + { + if (generateCode) + PrepareTemporaryVariable(node, ctx); + else + { + ctx->type.dataType.MakeReadOnly(false); + ctx->type.isConstant = false; + } + + // Add the cost for the copy + cost += asCC_TO_OBJECT_CONV; + } + } + } + } + } + + return cost; +} + +asUINT asCCompiler::ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv isExplicit, bool generateCode, bool allowObjectConstruct) +{ + asCObjectType *objType = CastToObjectType(to.GetTypeInfo()); + asASSERT( objType || CastToFuncdefType(to.GetTypeInfo()) ); + if( !objType ) + return asCC_NO_CONV; + + asCArray funcs; + if (objType->flags & asOBJ_VALUE) + { + // For value types the object must have a constructor that takes a single primitive argument either by value or as input reference + for (asUINT n = 0; n < objType->beh.constructors.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[objType->beh.constructors[n]]; + if (func->parameterTypes.GetLength() == 1 && + func->parameterTypes[0].IsPrimitive() && + !(func->inOutFlags[0] & asTM_OUTREF) && + (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit()) ) + { + funcs.PushLast(func->id); + } + } + } + else if (objType->flags & asOBJ_REF) + { + // For ref types the object must have a factory that takes a single primitive argument either by value or as input reference + for (asUINT n = 0; n < objType->beh.factories.GetLength(); n++) + { + asCScriptFunction *func = engine->scriptFunctions[objType->beh.factories[n]]; + if (func->parameterTypes.GetLength() == 1 && + func->parameterTypes[0].IsPrimitive() && + !(func->inOutFlags[0] & asTM_OUTREF) && + (isExplicit == asIC_EXPLICIT_VAL_CAST || !func->IsExplicit())) + { + funcs.PushLast(func->id); + } + } + } + + if( funcs.GetLength() == 0 ) + return asCC_NO_CONV; + + // Check if it is possible to choose a best match + asCExprContext arg(engine); + arg.type = ctx->type; + arg.exprNode = ctx->exprNode; // Use the same node for compiler messages + asCArray args; + args.PushLast(&arg); + asUINT cost = asCC_TO_OBJECT_CONV + MatchFunctions(funcs, args, 0, 0, 0, objType, false, true, false); + if( funcs.GetLength() != 1 ) + return asCC_NO_CONV; + + if( !generateCode ) + { + ctx->type.Set(to); + return cost; + } + + // TODO: clean up: This part is similar to CompileConstructCall(). It should be put in a common function + + // Clear the type of ctx, as the type is moved to the arg + ctx->type.SetDummy(); + + // Value types and script types are allocated through the constructor + asCExprValue tempObj; + bool onHeap = false; + + if (!(objType->flags & asOBJ_REF)) + { + tempObj.dataType = to; + tempObj.stackOffset = (short)AllocateVariable(to, true); + tempObj.dataType.MakeReference(true); + tempObj.isTemporary = true; + tempObj.isVariable = true; + + onHeap = IsVariableOnHeap(tempObj.stackOffset); + + // Push the address of the object on the stack + if (onHeap) + ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); + } + + PrepareFunctionCall(funcs[0], &ctx->bc, args); + MoveArgsToStack(funcs[0], &ctx->bc, args, false); + + if( !(objType->flags & asOBJ_REF) ) + { + // If the object is allocated on the stack, then call the constructor as a normal function + if( onHeap ) + { + int offset = 0; + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); + for( asUINT n = 0; n < args.GetLength(); n++ ) + offset += descr->parameterTypes[n].GetSizeOnStackDWords(); + + ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + + PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + // Add tag that the object has been initialized + ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); + + // The constructor doesn't return anything, + // so we have to manually inform the type of + // the return value + ctx->type = tempObj; + if( !onHeap ) + ctx->type.dataType.MakeReference(false); + + // Push the address of the object on the stack again + ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + } + else + { + // Call the factory to create the reference type + PerformFunctionCall(funcs[0], ctx, false, &args); + + // Make another pass to make sure the result has the correct handle and reference settings + ImplicitConversion(ctx, to, node, isExplicit, generateCode, allowObjectConstruct); + } + + return cost; +} + +void asCCompiler::ImplicitConversionConstant(asCExprContext *from, const asCDataType &to, asCScriptNode *node, EImplicitConv convType) +{ + asASSERT(from->type.isConstant); + + // TODO: node should be the node of the value that is + // converted (not the operator that provokes the implicit + // conversion) + + // If the base type is correct there is no more to do + if( to.IsEqualExceptRefAndConst(from->type.dataType) ) return; + + // References cannot be constants + if( from->type.dataType.IsReference() ) return; + + if( (to.IsIntegerType() && to.GetSizeInMemoryDWords() == 1 && !to.IsEnumType()) || + (to.IsEnumType() && convType == asIC_EXPLICIT_VAL_CAST) ) + { + if( from->type.dataType.IsFloatType() || + from->type.dataType.IsDoubleType() || + from->type.dataType.IsUnsignedType() || + from->type.dataType.IsIntegerType() ) + { + asCDataType targetDt; + if (to.IsEnumType()) + targetDt = to; + else + targetDt = asCDataType::CreatePrimitive(ttInt, true); + + // Transform the value + // Float constants can be implicitly converted to int + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + int ic = int(fc); + + if( float(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(targetDt, ic); + } + // Double constants can be implicitly converted to int + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + int ic = int(fc); + + if( double(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(targetDt, ic); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Verify that it is possible to convert to signed without getting negative + if( from->type.dataType.GetSizeInMemoryBytes() == 4 && + int(from->type.GetConstantDW()) < 0 && + convType != asIC_EXPLICIT_VAL_CAST && + node != 0 ) + Warning(TXT_CHANGE_SIGN, node); + + // Convert to 32bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantDW(targetDt, from->type.GetConstantB()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 2) + from->type.SetConstantDW(targetDt, from->type.GetConstantW()); + else + from->type.dataType = targetDt; + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + if (asQWORD(from->type.GetConstantQW()) >> 31) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + // Convert to 32bit + from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); + } + else if (from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2) + { + if (int(from->type.GetConstantQW()) != asINT64(from->type.GetConstantQW())) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + // Convert to 32bit + from->type.SetConstantDW(targetDt, int(from->type.GetConstantQW())); + } + else if (from->type.dataType.IsIntegerType() && + from->type.dataType.GetSizeInMemoryBytes() < 4) + { + // Convert to 32bit + if (from->type.dataType.GetSizeInMemoryBytes() == 1) + from->type.SetConstantDW(targetDt, (asINT8)from->type.GetConstantB()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 2) + from->type.SetConstantDW(targetDt, (asINT16)from->type.GetConstantW()); + } + else + { + // Only int32 and enums should come here and as these are 32bit + // already nothing needs to be done except set the target type + asASSERT((from->type.dataType.GetTokenType() == ttInt || + from->type.dataType.IsEnumType()) && + from->type.dataType.GetSizeInMemoryBytes() == 4); + + from->type.dataType = targetDt; + } + } + + // Check if a downsize is necessary + if( to.IsIntegerType() && + from->type.dataType.IsIntegerType() && + from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() ) + { + // Verify if it is possible + if( to.GetSizeInMemoryBytes() == 1 ) + { + if( asINT8(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT8(from->type.GetConstantDW())); + } + else if( to.GetSizeInMemoryBytes() == 2 ) + { + if( asINT16(from->type.GetConstantDW()) != int(from->type.GetConstantDW()) ) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asINT16(from->type.GetConstantDW())); + } + } + } + else if( to.IsIntegerType() && to.GetSizeInMemoryDWords() == 2 ) + { + // Float constants can be implicitly converted to int + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + asINT64 ic = asINT64(fc); + + if( float(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); + } + // Double constants can be implicitly converted to int + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + asINT64 ic = asINT64(fc); + + if( double(ic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), ic); + } + else if( from->type.dataType.IsUnsignedType() ) + { + // Convert to 64bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), from->type.GetConstantDW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 8 ) + { + if( asINT64(from->type.GetConstantQW()) < 0 ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); + } + from->type.dataType = asCDataType::CreatePrimitive(ttInt64, true); + } + } + else if( from->type.dataType.IsIntegerType() ) + { + // Convert to 64bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT8)from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (asINT16)from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), (int)from->type.GetConstantDW()); + } + } + else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 1 ) + { + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + // Some compilers set the value to 0 when converting a negative float to unsigned int. + // To maintain a consistent behaviour across compilers we convert to int first. + asUINT uic = asUINT(int(fc)); + + if( float(uic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); + + // Try once more, in case of a smaller type + ImplicitConversionConstant(from, to, node, convType); + } + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + // Some compilers set the value to 0 when converting a negative double to unsigned int. + // To maintain a consistent behaviour across compilers we convert to int first. + asUINT uic = asUINT(int(fc)); + + if( double(uic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), uic); + + // Try once more, in case of a smaller type + ImplicitConversionConstant(from, to, node, convType); + } + else if( from->type.dataType.IsIntegerType() ) + { + // Verify that it is possible to convert to unsigned without loosing negative + if( (from->type.dataType.GetSizeInMemoryBytes() > 4 && asINT64(from->type.GetConstantQW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 4 && int(from->type.GetConstantDW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 2 && asINT16(from->type.GetConstantW()) < 0) || + (from->type.dataType.GetSizeInMemoryBytes() == 1 && asINT8(from->type.GetConstantB()) < 0)) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); + } + + // Check if any data is lost + if( from->type.dataType.GetSizeInMemoryBytes() > 4 && (from->type.GetConstantQW() >> 32) != 0 && (from->type.GetConstantQW() >> 32) != 0xFFFFFFFF ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + } + + // Convert to 32bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT8)from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (asINT16)from->type.GetConstantW()); + else if (from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)from->type.GetConstantDW()); + else + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), (int)(asINT64)from->type.GetConstantQW()); + + // Try once more, in case of a smaller type + ImplicitConversionConstant(from, to, node, convType); + } + else if( from->type.dataType.IsUnsignedType() && + from->type.dataType.GetSizeInMemoryBytes() < 4 ) + { + // Convert to 32bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), from->type.GetConstantW()); + + // Try once more, in case of a smaller type + ImplicitConversionConstant(from, to, node, convType); + } + else if( from->type.dataType.IsUnsignedType() && + from->type.dataType.GetSizeInMemoryBytes() > to.GetSizeInMemoryBytes() ) + { + // Verify if it is possible + if( to.GetSizeInMemoryBytes() == 1 ) + { + if( asBYTE(from->type.GetConstantDW()) != from->type.GetConstantDW() ) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantB(asCDataType::CreatePrimitive(to.GetTokenType(), true), asBYTE(from->type.GetConstantDW())); + } + else if( to.GetSizeInMemoryBytes() == 2 ) + { + if( asWORD(from->type.GetConstantDW()) != from->type.GetConstantDW()) + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asWORD(from->type.GetConstantDW())); + } + else if (to.GetSizeInMemoryBytes() == 4) + { + if( asDWORD(from->type.GetConstantQW()) != from->type.GetConstantQW()) + if (convType != asIC_EXPLICIT_VAL_CAST && node) Warning(TXT_VALUE_TOO_LARGE_FOR_TYPE, node); + + from->type.SetConstantDW(asCDataType::CreatePrimitive(to.GetTokenType(), true), asDWORD(from->type.GetConstantQW())); + } + } + } + else if( to.IsUnsignedType() && to.GetSizeInMemoryDWords() == 2 ) + { + if( from->type.dataType.IsFloatType() ) + { + float fc = from->type.GetConstantF(); + // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers + asQWORD uic = asQWORD(asINT64(fc)); + +#if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6 + // MSVC6 doesn't support this conversion + if( float(uic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } +#endif + + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); + } + else if( from->type.dataType.IsDoubleType() ) + { + double fc = from->type.GetConstantD(); + // Convert first to int64 then to uint64 to avoid negative float becoming 0 on gnuc base compilers + asQWORD uic = asQWORD(asINT64(fc)); + +#if !defined(_MSC_VER) || _MSC_VER > 1200 // MSVC++ 6 + // MSVC6 doesn't support this conversion + if( double(uic) != fc ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } +#endif + + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), uic); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Convert to 64bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT8)from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(asINT16)from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), (asINT64)(int)from->type.GetConstantDW()); + + // Verify that it is possible to convert to unsigned without loosing negative + if( asINT64(from->type.GetConstantQW()) < 0 ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); + } + + from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + // Verify that it is possible to convert to unsigned without loosing negative + if( asINT64(from->type.GetConstantQW()) < 0 ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_CHANGE_SIGN, node); + } + + from->type.dataType = asCDataType::CreatePrimitive(ttUInt64, true); + } + else if( from->type.dataType.IsUnsignedType() ) + { + // Convert to 64bit + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantB()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantW()); + else if( from->type.dataType.GetSizeInMemoryBytes() == 4 ) + from->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), from->type.GetConstantDW()); + } + } + else if( to.IsFloatType() ) + { + if( from->type.dataType.IsDoubleType() ) + { + double ic = from->type.GetConstantD(); + float fc = float(ic); + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + int ic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + ic = (asINT8)from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + ic = (asINT16)from->type.GetConstantW(); + else + ic = (int)from->type.GetConstantDW(); + float fc = float(ic); + + if( int(fc) != ic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + float fc = float(asINT64(from->type.GetConstantQW())); + if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + unsigned int uic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + uic = from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + uic = from->type.GetConstantW(); + else + uic = from->type.GetConstantDW(); + float fc = float(uic); + + if( (unsigned int)(fc) != uic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + float fc = float((asINT64)from->type.GetConstantQW()); + + if( asQWORD(fc) != from->type.GetConstantQW()) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantF(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + } + else if( to.IsDoubleType() ) + { + if( from->type.dataType.IsFloatType() ) + { + float ic = from->type.GetConstantF(); + double fc = double(ic); + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + int ic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + ic = (asINT8)from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + ic = (asINT16)from->type.GetConstantW(); + else + ic = (int)from->type.GetConstantDW(); + double fc = double(ic); + + if( int(fc) != ic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsIntegerType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + double fc = double(asINT64(from->type.GetConstantQW())); + + if( asINT64(fc) != asINT64(from->type.GetConstantQW()) ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + // Must properly convert value in case the from value is smaller + unsigned int uic; + if( from->type.dataType.GetSizeInMemoryBytes() == 1 ) + uic = from->type.GetConstantB(); + else if( from->type.dataType.GetSizeInMemoryBytes() == 2 ) + uic = from->type.GetConstantW(); + else + uic = from->type.GetConstantDW(); + double fc = double(uic); + + if( (unsigned int)(fc) != uic ) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + else if( from->type.dataType.IsUnsignedType() && from->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + double fc = double((asINT64)from->type.GetConstantQW()); + + if( asQWORD(fc) != from->type.GetConstantQW()) + { + if( convType != asIC_EXPLICIT_VAL_CAST && node ) Warning(TXT_NOT_EXACT, node); + } + + from->type.SetConstantD(asCDataType::CreatePrimitive(to.GetTokenType(), true), fc); + } + } +} + +int asCCompiler::DoAssignment(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode) +{ + // Don't allow any operators on expressions that take address of class method + // If methodName is set but the type is not an object, then it is a global function + if( lctx->methodName != "" || rctx->IsClassMethod() ) + { + Error(TXT_INVALID_OP_ON_METHOD, opNode); + return -1; + } + + // Implicit handle types should always be treated as handles in assignments + if (lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) ) + { + lctx->type.dataType.MakeHandle(true); + lctx->type.isExplicitHandle = true; + } + + // If the left hand expression is a property accessor, then that should be used + // to do the assignment instead of the ordinary operator. The exception is when + // the property accessor is for a handle property, and the operation is a value + // assignment. + if( (lctx->property_get || lctx->property_set) && + !(lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle) ) + { + if( op != ttAssignment ) + { + // Generate the code for the compound assignment, i.e. get the value, apply operator, then set the value + return ProcessPropertyGetSetAccessor(ctx, lctx, rctx, op, opNode); + } + + // It is not allowed to do a handle assignment on a property + // accessor that doesn't take a handle in the set accessor. + if( lctx->property_set && lctx->type.isExplicitHandle ) + { + // set_opIndex has 2 arguments, where as normal setters have only 1 + asCArray& parameterTypes = + builder->GetFunctionDescription(lctx->property_set)->parameterTypes; + if( !parameterTypes[parameterTypes.GetLength() - 1].IsObjectHandle() ) + { + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, opNode); + + Error(TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP, opNode); + return -1; + } + } + + MergeExprBytecodeAndType(ctx, lctx); + + return ProcessPropertySetAccessor(ctx, rctx, opNode); + } + else if( lctx->property_get && lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle ) + { + // Get the handle to the object that will be used for the value assignment + if( ProcessPropertyGetAccessor(lctx, opNode) < 0 ) + return -1; + } + + if( lctx->type.dataType.IsPrimitive() ) + { + if( !lctx->type.isLValue ) + { + Error(TXT_NOT_LVALUE, lexpr); + return -1; + } + + if( op != ttAssignment ) + { + // Compute the operator before the assignment + asCExprValue lvalue = lctx->type; + + if( lctx->type.isTemporary && !lctx->type.isVariable ) + { + // The temporary variable must not be freed until the + // assignment has been performed. lvalue still holds + // the information about the temporary variable + lctx->type.isTemporary = false; + } + + asCExprContext o(engine); + CompileOperator(opNode, lctx, rctx, &o); + MergeExprBytecode(rctx, &o); + rctx->type = o.type; + + // Convert the rvalue to the right type and validate it + PrepareForAssignment(&lvalue.dataType, rctx, rexpr, false); + + MergeExprBytecode(ctx, rctx); + lctx->type = lvalue; + + // The lvalue continues the same, either it was a variable, or a reference in the register + } + else + { + // Convert the rvalue to the right type and validate it + PrepareForAssignment(&lctx->type.dataType, rctx, rexpr, false, lctx); + + MergeExprBytecode(ctx, rctx); + MergeExprBytecode(ctx, lctx); + } + + ReleaseTemporaryVariable(rctx->type, &ctx->bc); + + PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode); + + ctx->type = lctx->type; + } + else if( lctx->type.isExplicitHandle ) + { + if( !lctx->type.isLValue ) + { + Error(TXT_NOT_LVALUE, lexpr); + return -1; + } + + // Object handles don't have any compound assignment operators + if( op != ttAssignment ) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, lexpr); + return -1; + } + + if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) + { + // The object is a value type but that should be treated as a handle + + // Make sure the right hand value is a handle + if( !rctx->type.isExplicitHandle && + !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) ) + { + // Function names can be considered handles already + if( rctx->methodName == "" ) + { + asCDataType dt = rctx->type.dataType; + dt.MakeHandle(true); + dt.MakeReference(false); + + PrepareArgument(&dt, rctx, rexpr, true, asTM_INREF); + if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, rexpr); + return -1; + } + } + + if (!rctx->type.dataType.IsObjectHandle() && !rctx->type.dataType.SupportHandles()) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, rexpr); + return -1; + } + + // Mark the right hand expression as explicit handle even if the user didn't do it, otherwise + // the code for moving the argument to the stack may not know to correctly handle the argument type + // in case of variable parameter type. + rctx->type.isExplicitHandle = true; + } + + if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx, true) ) + { + // An overloaded assignment operator was found (or a compilation error occured) + return 0; + } + + // The object must implement the opAssign method + asCString msg; + msg.Format(TXT_NO_APPROPRIATE_OPHNDLASSIGN_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(msg.AddressOf(), opNode); + return -1; + } + else + { + asCDataType dt = lctx->type.dataType; + dt.MakeReference(false); + + PrepareArgument(&dt, rctx, rexpr, false, asTM_INREF , true); + if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, rexpr); + return -1; + } + + MergeExprBytecode(ctx, rctx); + MergeExprBytecode(ctx, lctx); + + if(!rctx->type.isRefSafe) + ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE); + + PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode); + + ReleaseTemporaryVariable(rctx->type, &ctx->bc); + + ctx->type = lctx->type; + + // After the handle assignment the original handle is left on the stack + ctx->type.dataType.MakeReference(false); + } + } + else // if( lctx->type.dataType.IsObject() ) + { + // The lvalue reference may be marked as a temporary, if for example + // it was originated as a handle returned from a function. In such + // cases it must be possible to assign values to it anyway. + if( lctx->type.dataType.IsObjectHandle() && !lctx->type.isExplicitHandle ) + { + // Convert the handle to a object reference + asCDataType to; + to = lctx->type.dataType; + to.MakeHandle(false); + ImplicitConversion(lctx, to, lexpr, asIC_IMPLICIT_CONV); + lctx->type.isLValue = true; // Handle may not have been an lvalue, but the dereferenced object is + } + + // Check for overloaded assignment operator + if( CompileOverloadedDualOperator(opNode, lctx, rctx, false, ctx) ) + { + // An overloaded assignment operator was found (or a compilation error occured) + return 0; + } + + // No registered operator was found. In case the operation is a direct + // assignment and the rvalue is the same type as the lvalue, then we can + // still use the byte-for-byte copy to do the assignment + + if( op != ttAssignment ) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, lexpr); + return -1; + } + + // If the left hand expression is simple, i.e. without any + // function calls or allocations of memory, then we can avoid + // doing a copy of the right hand expression (done by PrepareArgument). + // Instead the reference to the value can be placed directly on the + // stack. + // + // This optimization should only be done for value types, where + // the application developer is responsible for making the + // implementation safe against unwanted destruction of the input + // reference before the time. + bool simpleExpr = (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) && lctx->bc.IsSimpleExpression(); + + // Implicitly convert the rvalue to the type of the lvalue + bool needConversion = false; + if( !lctx->type.dataType.IsEqualExceptRefAndConst(rctx->type.dataType) ) + needConversion = true; + + if( !simpleExpr || needConversion ) + { + if( rctx->type.dataType.IsObjectHandle() && !rctx->type.isExplicitHandle && + !lctx->type.dataType.IsObjectHandle() && rctx->type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() ) + { + // Make the conversion from handle to non-handle without creating + // a copy of the object (otherwise done by PrepareArgument) + asCDataType dt = rctx->type.dataType; + dt.MakeHandle(false); + ImplicitConversion(rctx, dt, rexpr, asIC_IMPLICIT_CONV); + needConversion = false; + } + + asCDataType dt = lctx->type.dataType; + dt.MakeReference(true); + // A funcdef can be accessed by ref, but only as read-only + if( dt.IsFuncdef() && !dt.IsObjectHandle() ) + dt.MakeReadOnly(true); + int r = PrepareArgument(&dt, rctx, rexpr, true, 1, !needConversion); + if( r < 0 ) + return -1; + if( !dt.IsEqualExceptRefAndConst(rctx->type.dataType) ) + { + asCString str; + str.Format(TXT_CANT_IMPLICITLY_CONVERT_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, rexpr); + return -1; + } + } + else + { + // Process any property accessor first, before placing the final reference on the stack + if( ProcessPropertyGetAccessor(rctx, rexpr) < 0 ) + return -1; + + if( rctx->type.dataType.IsReference() && (!(rctx->type.isVariable || rctx->type.isTemporary) || IsVariableOnHeap(rctx->type.stackOffset)) ) + rctx->bc.Instr(asBC_RDSPtr); + } + + MergeExprBytecode(ctx, rctx); + MergeExprBytecode(ctx, lctx); + + if( !simpleExpr || needConversion ) + { + if( !rctx->type.isRefSafe && (rctx->type.isVariable || rctx->type.isTemporary) ) + { + if( !IsVariableOnHeap(rctx->type.stackOffset) ) + // TODO: runtime optimize: Actually the reference can be pushed on the stack directly + // as the value allocated on the stack is guaranteed to be safe. + // The bytecode optimizer should be able to determine this and optimize away the VAR + GETREF + ctx->bc.InstrWORD(asBC_GETREF, AS_PTR_SIZE); + else + ctx->bc.InstrWORD(asBC_GETOBJREF, AS_PTR_SIZE); + } + } + + PerformAssignment(&lctx->type, &rctx->type, &ctx->bc, opNode); + + ReleaseTemporaryVariable(rctx->type, &ctx->bc); + + ctx->type = lctx->type; + } + + return 0; +} + +int asCCompiler::CompileAssignment(asCScriptNode *expr, asCExprContext *ctx) +{ + asASSERT(expr->nodeType == snAssignment); + + asCScriptNode *lexpr = expr->firstChild; + if( lexpr->next ) + { + // Compile the two expression terms + asCExprContext lctx(engine), rctx(engine); + int rr = CompileAssignment(lexpr->next->next, &rctx); + int lr = CompileCondition(lexpr, &lctx); + + if( lr >= 0 && rr >= 0 ) + return DoAssignment(ctx, &lctx, &rctx, lexpr, lexpr->next->next, lexpr->next->tokenType, lexpr->next); + + // Since the operands failed, the assignment was not computed + ctx->type.SetDummy(); + return -1; + } + + return CompileCondition(lexpr, ctx); +} + +int asCCompiler::CompileCondition(asCScriptNode *expr, asCExprContext *ctx) +{ + asCExprValue ctype; + + // Compile the conditional expression + asCScriptNode *cexpr = expr->firstChild; + if( cexpr->next ) + { + //------------------------------- + // Compile the condition + asCExprContext e(engine); + int r = CompileExpression(cexpr, &e); + if( r < 0 ) + e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + + // Allow value types to be converted to bool using 'bool opImplConv()' + if( e.type.dataType.GetTypeInfo() && (e.type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(&e, asCDataType::CreatePrimitive(ttBool, false), cexpr, asIC_IMPLICIT_CONV); + + if( r >= 0 && !e.type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + { + Error(TXT_EXPR_MUST_BE_BOOL, cexpr); + e.type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + } + ctype = e.type; + + if( ProcessPropertyGetAccessor(&e, cexpr) < 0) + return -1; + + if( e.type.dataType.IsReference() ) ConvertToVariable(&e); + ProcessDeferredParams(&e); + + //------------------------------- + // Compile the left expression + asCExprContext le(engine); + int lr = CompileAssignment(cexpr->next, &le); + + // Resolve any function names already + DetermineSingleFunc(&le, cexpr->next); + + //------------------------------- + // Compile the right expression + asCExprContext re(engine); + int rr = CompileAssignment(cexpr->next->next, &re); + DetermineSingleFunc(&re, cexpr->next->next); + + if( lr >= 0 && rr >= 0 ) + { + // Don't allow any operators on expressions that take address of class method + if( le.IsClassMethod() || re.IsClassMethod() ) + { + Error(TXT_INVALID_OP_ON_METHOD, expr); + return -1; + } + + if( ProcessPropertyGetAccessor(&le, cexpr->next) < 0 ) + return -1; + if( ProcessPropertyGetAccessor(&re, cexpr->next->next) < 0 ) + return -1; + + bool isExplicitHandle = le.type.isExplicitHandle || re.type.isExplicitHandle; + + // Allow a 0 or null in the first case to be implicitly converted to the second type + if( le.type.isConstant && le.type.GetConstantData() == 0 && le.type.dataType.IsIntegerType() ) + { + asCDataType to = re.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(true); + ImplicitConversionConstant(&le, to, cexpr->next, asIC_IMPLICIT_CONV); + } + else if( le.type.IsNullConstant() ) + { + asCDataType to = re.type.dataType; + to.MakeHandle(true); + ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); + } + + // Allow either case to be converted to const @ if the other is const @ + if( (le.type.dataType.IsHandleToConst() && !le.type.IsNullConstant()) || (re.type.dataType.IsHandleToConst() && !re.type.dataType.IsNullHandle()) ) + { + le.type.dataType.MakeHandleToConst(true); + re.type.dataType.MakeHandleToConst(true); + } + + // Allow an anonymous initialization list to be converted to the type in the other condition + if (le.IsAnonymousInitList() && re.type.dataType.GetBehaviour() && re.type.dataType.GetBehaviour()->listFactory) + { + asCDataType to = re.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(false); + ImplicitConversion(&le, to, cexpr->next, asIC_IMPLICIT_CONV); + } + else if (re.IsAnonymousInitList() && le.type.dataType.GetBehaviour() && le.type.dataType.GetBehaviour()->listFactory) + { + asCDataType to = le.type.dataType; + to.MakeReference(false); + to.MakeReadOnly(false); + ImplicitConversion(&re, to, cexpr->next->next, asIC_IMPLICIT_CONV); + } + + if (le.IsAnonymousInitList() ) + { + Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next); + return -1; + } + else if (re.IsAnonymousInitList()) + { + Error(TXT_CANNOT_RESOLVE_AUTO, cexpr->next->next); + return -1; + } + + //--------------------------------- + // Output the byte code + int afterLabel = nextLabel++; + int elseLabel = nextLabel++; + + // If left expression is void, then we don't need to store the result + if( le.type.dataType.IsEqualExceptConst(asCDataType::CreatePrimitive(ttVoid, false)) ) + { + // Put the code for the condition expression on the output + MergeExprBytecode(ctx, &e); + + // Added the branch decision + ctx->type = e.type; + ConvertToVariable(ctx); + ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); + ctx->bc.Instr(asBC_ClrHi); + ctx->bc.InstrDWORD(asBC_JZ, elseLabel); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + // Add the left expression + MergeExprBytecode(ctx, &le); + ctx->bc.InstrINT(asBC_JMP, afterLabel); + + // Add the right expression + ctx->bc.Label((short)elseLabel); + MergeExprBytecode(ctx, &re); + ctx->bc.Label((short)afterLabel); + + // Make sure both expressions have the same type + if( le.type.dataType != re.type.dataType ) + Error(TXT_BOTH_MUST_BE_SAME, expr); + + // Set the type of the result + ctx->type = le.type; + } + else if (le.type.IsNullConstant() && re.type.IsNullConstant()) + { + // Special case for when both results are 'null' + // TODO: Other expressions where both results are identical literal constants can probably also be handled this way + + // Put the code for the condition expression on the output + MergeExprBytecode(ctx, &e); + + // Load the result into the register, but ignore the value since both paths give the same response + ctx->type = e.type; + ConvertToVariable(ctx); + ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + // Return a null constant + ctx->bc.Instr(asBC_PshNull); + ctx->type.SetNullConstant(); + } + else + { + // Allow "(a ? b : c) = d;" and "return (a ? b : c);" (where the latter returns the reference) + // + // Restrictions for the condition to be used as lvalue: + // 1. both b and c must be of the same type and be lvalue references + // 2. neither of the expressions can have any deferred arguments + // that would have to be cleaned up after the reference + // 3. neither expression can be temporary + // + // If either expression is local, the resulting lvalue is not valid + // for return since it is not allowed to return references to local + // variables. + // + // The reference to the local variable must be loaded into the register, + // the resulting expression must not be considered as a local variable + // with a stack offset (i.e. it will not be allowed to use asBC_VAR) + + if( le.type.isLValue && re.type.isLValue && + le.deferredParams.GetLength() == 0 && re.deferredParams.GetLength() ==0 && + !le.type.isTemporary && !re.type.isTemporary && + le.type.dataType == re.type.dataType ) + { + // Put the code for the condition expression on the output + MergeExprBytecode(ctx, &e); + + // Add the branch decision + ctx->type = e.type; + ConvertToVariable(ctx); + ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); + ctx->bc.Instr(asBC_ClrHi); + ctx->bc.InstrDWORD(asBC_JZ, elseLabel); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + // Start of the left expression + MergeExprBytecode(ctx, &le); + if( !le.type.dataType.IsReference() && le.type.isVariable ) + { + // Load the address of the variable into the register + ctx->bc.InstrSHORT(asBC_LDV, le.type.stackOffset); + } + + ctx->bc.InstrINT(asBC_JMP, afterLabel); + + // Start of the right expression + ctx->bc.Label((short)elseLabel); + + MergeExprBytecode(ctx, &re); + if( !re.type.dataType.IsReference() && re.type.isVariable ) + { + // Load the address of the variable into the register + ctx->bc.InstrSHORT(asBC_LDV, re.type.stackOffset); + } + + ctx->bc.Label((short)afterLabel); + + // In case the options were to objects, it is necessary to dereference the pointer on + // the stack so it will point to the actual object, instead of the variable + if( le.type.dataType.IsReference() && le.type.dataType.IsObject() && !le.type.dataType.IsObjectHandle() ) + { + asASSERT( re.type.dataType.IsReference() && re.type.dataType.IsObject() && !re.type.dataType.IsObjectHandle() ); + + ctx->bc.Instr(asBC_RDSPtr); + } + + // The result is an lvalue + ctx->type.isLValue = true; + ctx->type.dataType = le.type.dataType; + if( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsObjectHandle() ) + ctx->type.dataType.MakeReference(true); + else + ctx->type.dataType.MakeReference(false); + + // It can't be a treated as a variable, since we don't know which one was used + ctx->type.isVariable = false; + ctx->type.isTemporary = false; + + // Must remember if the reference was to a local variable, since it must not be allowed to be returned + ctx->type.isRefToLocal = le.type.isVariable || le.type.isRefToLocal || re.type.isVariable || re.type.isRefToLocal; + } + else + { + // Allocate temporary variable and copy the result to that one + asCExprValue temp; + temp = le.type; + temp.dataType.MakeReference(false); + temp.dataType.MakeReadOnly(false); + + // Make sure the variable isn't used in any of the expressions, + // as it would be overwritten which may cause crashes or less visible bugs + int l = int(reservedVariables.GetLength()); + e.bc.GetVarsUsed(reservedVariables); + le.bc.GetVarsUsed(reservedVariables); + re.bc.GetVarsUsed(reservedVariables); + int offset = AllocateVariable(temp.dataType, true, false); + reservedVariables.SetLength(l); + + temp.SetVariable(temp.dataType, offset, true); + + // TODO: copy: Use copy constructor if available. See PrepareTemporaryVariable() + + CallDefaultConstructor(temp.dataType, offset, IsVariableOnHeap(offset), &ctx->bc, expr); + + // Put the code for the condition expression on the output + MergeExprBytecode(ctx, &e); + + // Add the branch decision + ctx->type = e.type; + ConvertToVariable(ctx); + ctx->bc.InstrSHORT(asBC_CpyVtoR4, ctx->type.stackOffset); + ctx->bc.Instr(asBC_ClrHi); + ctx->bc.InstrDWORD(asBC_JZ, elseLabel); + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + // Assign the result of the left expression to the temporary variable + asCExprValue rtemp; + rtemp = temp; + if( rtemp.dataType.IsObjectHandle() ) + rtemp.isExplicitHandle = true; + + PrepareForAssignment(&rtemp.dataType, &le, cexpr->next, true); + MergeExprBytecode(ctx, &le); + + if( !rtemp.dataType.IsPrimitive() ) + { + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + rtemp.dataType.MakeReference(IsVariableOnHeap(offset)); + } + asCExprValue result; + result = rtemp; + PerformAssignment(&result, &le.type, &ctx->bc, cexpr->next); + if( !result.dataType.IsPrimitive() ) + ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer) + + // Release the old temporary variable + ReleaseTemporaryVariable(le.type, &ctx->bc); + + ctx->bc.InstrINT(asBC_JMP, afterLabel); + + // Start of the right expression + ctx->bc.Label((short)elseLabel); + + // Copy the result to the same temporary variable + PrepareForAssignment(&rtemp.dataType, &re, cexpr->next, true); + MergeExprBytecode(ctx, &re); + + if( !rtemp.dataType.IsPrimitive() ) + { + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + rtemp.dataType.MakeReference(IsVariableOnHeap(offset)); + } + result = rtemp; + PerformAssignment(&result, &re.type, &ctx->bc, cexpr->next); + if( !result.dataType.IsPrimitive() ) + ctx->bc.Instr(asBC_PopPtr); // Pop the original value (always a pointer) + + // Release the old temporary variable + ReleaseTemporaryVariable(re.type, &ctx->bc); + + ctx->bc.Label((short)afterLabel); + + // Make sure both expressions have the same type + if( !le.type.dataType.IsEqualExceptConst(re.type.dataType) ) + Error(TXT_BOTH_MUST_BE_SAME, expr); + + // Set the temporary variable as output + ctx->type = rtemp; + ctx->type.isExplicitHandle = isExplicitHandle; + + if( !ctx->type.dataType.IsPrimitive() ) + { + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + ctx->type.dataType.MakeReference(IsVariableOnHeap(offset)); + } + + // Make sure the output isn't marked as being a literal constant + ctx->type.isConstant = false; + } + } + } + else + { + ctx->type.SetDummy(); + return -1; + } + } + else + return CompileExpression(cexpr, ctx); + + return 0; +} + +int asCCompiler::CompileExpression(asCScriptNode *expr, asCExprContext *ctx) +{ + asASSERT(expr->nodeType == snExpression); + + // Convert to polish post fix, i.e: a+b => ab+ + asCArray postfix; + ConvertToPostFix(expr, postfix); + + // Compile the postfix formatted expression + return CompilePostFixExpression(&postfix, ctx); +} + +void asCCompiler::ConvertToPostFix(asCScriptNode *expr, asCArray &postfix) +{ + // The algorithm that I've implemented here is similar to + // Djikstra's Shunting Yard algorithm, though I didn't know it at the time. + // ref: http://en.wikipedia.org/wiki/Shunting-yard_algorithm + + // Count the nodes in order to preallocate the buffers + int count = 0; + asCScriptNode *node = expr->firstChild; + while( node ) + { + count++; + node = node->next; + } + + asCArray stackA(count); + asCArray &stackB = postfix; + stackB.Allocate(count, false); + + node = expr->firstChild; + while( node ) + { + int precedence = GetPrecedence(node); + + while( stackA.GetLength() > 0 && + precedence <= GetPrecedence(stackA[stackA.GetLength()-1]) ) + stackB.PushLast(stackA.PopLast()); + + stackA.PushLast(node); + + node = node->next; + } + + while( stackA.GetLength() > 0 ) + stackB.PushLast(stackA.PopLast()); +} + +int asCCompiler::CompilePostFixExpression(asCArray *postfix, asCExprContext *ctx) +{ + // Shouldn't send any byte code + asASSERT(ctx->bc.GetLastInstr() == -1); + + // Set the context to a dummy type to avoid further + // errors in case the expression fails to compile + ctx->type.SetDummy(); + + // Evaluate the operands and operators + asCArray free; + asCArray expr; + int ret = 0; + for( asUINT n = 0; ret == 0 && n < postfix->GetLength(); n++ ) + { + asCScriptNode *node = (*postfix)[n]; + if( node->nodeType == snExprTerm ) + { + asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine); + expr.PushLast(e); + e->exprNode = node; + ret = CompileExpressionTerm(node, e); + } + else + { + asCExprContext *r = expr.PopLast(); + asCExprContext *l = expr.PopLast(); + + // Now compile the operator + asCExprContext *e = free.GetLength() ? free.PopLast() : asNEW(asCExprContext)(engine); + ret = CompileOperator(node, l, r, e); + + expr.PushLast(e); + + // Free the operands + l->Clear(); + free.PushLast(l); + r->Clear(); + free.PushLast(r); + } + } + + if( ret == 0 ) + { + asASSERT(expr.GetLength() == 1); + + // The final result should be moved to the output context + MergeExprBytecodeAndType(ctx, expr[0]); + } + + // Clean up + for( asUINT e = 0; e < expr.GetLength(); e++ ) + asDELETE(expr[e], asCExprContext); + for( asUINT f = 0; f < free.GetLength(); f++ ) + asDELETE(free[f], asCExprContext); + + return ret; +} + +int asCCompiler::CompileAnonymousInitList(asCScriptNode *node, asCExprContext *ctx, const asCDataType &dt) +{ + asASSERT(node->nodeType == snInitList); + + // Do not allow constructing non-shared types in shared functions + if (outFunc->IsShared() && + dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared()) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + } + + // If this is compiled from a default arg, then use the script code for the default arg + asCScriptCode *origCode = script; + if (ctx->origCode) + script = ctx->origCode; + + // Allocate and initialize the temporary object + int offset = AllocateVariable(dt, true); + CompileInitialization(node, &ctx->bc, dt, node, offset, 0, 0); + + // Push the reference to the object on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + ctx->type.SetVariable(dt, offset, true); + ctx->type.isLValue = false; + + // If the variable is allocated on the heap we have a reference, + // otherwise the actual object pointer is pushed on the stack. + if (IsVariableOnHeap(offset)) + ctx->type.dataType.MakeReference(true); + + // Clear the flag for anonymous initalization list as it is no + // longer true now that the object has been initialized. + ctx->isAnonymousInitList = false; + ctx->origCode = 0; + + script = origCode; + + return 0; +} + +int asCCompiler::CompileExpressionTerm(asCScriptNode *node, asCExprContext *ctx) +{ + // Shouldn't send any byte code + asASSERT(ctx->bc.GetLastInstr() == -1); + + // Check if this is an initialization of a temp object with an initialization list + if (node->firstChild ) + { + if (node->firstChild->nodeType == snDataType) + { + // Determine the type of the temporary object + asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); + + return CompileAnonymousInitList(node->lastChild, ctx, dt); + } + else if (node->firstChild->nodeType == snInitList) + { + // As the type is not yet known, the init list will be compiled at a + // later time when the type can be determined from the destination + ctx->SetAnonymousInitList(node->firstChild, script); + return 0; + } + } + + // Set the type as a dummy by default, in case of any compiler errors + ctx->type.SetDummy(); + + // Compile the value node + asCScriptNode *vnode = node->firstChild; + while( vnode->nodeType != snExprValue ) + vnode = vnode->next; + + asCExprContext v(engine); + int r = CompileExpressionValue(vnode, &v); + if( r < 0 ) + return r; + + // Compile post fix operators + asCScriptNode *pnode = vnode->next; + while( pnode ) + { + r = CompileExpressionPostOp(pnode, &v); + if( r < 0 ) + return r; + pnode = pnode->next; + } + + // Compile pre fix operators + pnode = vnode->prev; + while( pnode ) + { + r = CompileExpressionPreOp(pnode, &v); + if( r < 0 ) + return r; + pnode = pnode->prev; + } + + // Return the byte code and final type description + MergeExprBytecodeAndType(ctx, &v); + + return 0; +} + +// returns: +// SL_LOCALCONST = local constant +// SL_LOCALVAR = local variable +// SL_NOMATCH = no match +asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult) +{ + sVariable *v = 0; + if (variables) + v = variables->GetVariable(name.AddressOf()); + if (v) + { + if (v->isPureConstant) + { + outResult->type.SetConstantData(v->type, v->constantValue); + return SL_LOCALCONST; + } + + outResult->type.SetVariable(v->type, v->stackOffset, false); + return SL_LOCALVAR; + } + + return SL_NOMATCH; +} + +// returns: +// SL_CLASSPROPACCESS = class property accessor +// SL_CLASSPROP = class property +// SL_CLASSMETHOD = class method +// SL_CLASSTYPE = class child type +// SL_NOMATCH = no match +// SL_ERROR = error +asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult) +{ + // See if there are any matching property accessors + asCExprContext access(engine); + access.type.Set(asCDataType::CreateType(objType, false)); + access.type.dataType.MakeReference(true); + int r = 0; + // Indexed property access + asCExprContext dummyArg(engine); + r = FindPropertyAccessor(name, &access, &dummyArg, 0, 0, true); + if (r == 0) + { + // Normal property access + r = FindPropertyAccessor(name, &access, 0, 0, true); + } + if (r <= -3) return SL_ERROR; + if (r != 0) + { + // The symbol matches getters/setters (though not necessarily a compilable match) + MergeExprBytecodeAndType(outResult, &access); + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSPROPACCESS; + } + + // Look for matching properties + asCDataType dt; + dt = asCDataType::CreateType(objType, false); + asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); + if (prop) + { + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSPROP; + } + + // If it is not a property, it may still be the name of a method + asCObjectType *ot = objType; + for (asUINT n = 0; n < ot->methods.GetLength(); n++) + { + asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; + if (f->name == name && + (builder->module->m_accessMask & f->accessMask)) + { + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSMETHOD; + } + } + + // If it is not a method, then it can still be a child type + for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++) + { + if (ot->childFuncDefs[n]->name == name) + { + outResult->type.dataType.SetTypeInfo(objType); + return SL_CLASSTYPE; + } + } + + return SL_NOMATCH; +} + +// The purpose of this function is to find the entity that matches the symbol name respecting the scope and visibility hierarchy +// The 'outResult' will be used to return info on what was identified, but no code will be produced by this function +// input: +// name = the name of the symbol to look for +// scope = explicit scope informed +// objType = used to look for symbols within object type (e.g. when compiling post op), in this case no local or global symbols will be looked up +// returns: +// SL_NOMATCH = no matching symbol +// SL_LOCALCONST = local constant +// SL_LOCALVAR = local variable +// SL_THISPTR = this pointer +// SL_CLASSPROPACCESS = class property accessor, lookupResult->dataType holds the object type in which the member was found +// SL_CLASSPROP = class property, lookupResult->dataType holds the object type in which the member was found +// SL_CLASSMETHOD = class method, lookupResult->dataType holds the object type in which the member was found +// SL_CLASSTYPE = class child type, lookupResult->dataType holds the object type in which the member was found +// SL_GLOBALPROPACCESS = global property accessor, lookupResult->symbolNamespace holds the namespace where the symbol was identified +// SL_GLOBALCONST = global constant, lookupResult->symbolNamespace holds the namespace where the symbol was identified +// SL_GLOBALVAR = global variable, lookupResult->symbolNamespace holds the namespace where the symbol was identified +// SL_GLOBALFUNC = global function, lookupResult->symbolNamespace holds the namespace where the symbol was identified +// SL_GLOBALTYPE = type, lookupResult->dataType holds the type +// SL_ENUMVAL = enum value, lookupResult->dataType holds the enum type, unless ambigious. lookupResult->symbolNamespace holds the namespace where the symbol was identified +// SL_ERROR = error +asCCompiler::SYMBOLTYPE asCCompiler::SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult) +{ + asASSERT(outResult); + + // It is a local variable or parameter? + // This is not accessible by default arg expressions + if (!isCompilingDefaultArg && scope == "" && !objType ) + { + SYMBOLTYPE r = SymbolLookupLocalVar(name, outResult); + if (r != 0) + return r; + } + + // Is it a class member? + if (scope == "" && ((objType) || (outFunc && outFunc->objectType))) + { + // 'this' is not accessible by default arg expressions + if (name == THIS_TOKEN && !objType && !isCompilingDefaultArg) + { + asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()); + + // The object pointer is located at stack position 0 + outResult->type.SetVariable(dt, 0, false); + return SL_THISPTR; + } + + // 'super' is not accessible by default arg expressions + if (m_isConstructor && name == SUPER_TOKEN && !objType && !isCompilingDefaultArg) + { + // If the class is derived from another class, then super can be used to call the base' class constructor + if (outFunc && outFunc->objectType->derivedFrom) + { + outResult->type.dataType.SetTypeInfo(outFunc->objectType->derivedFrom); + return SL_CLASSMETHOD; + } + } + + // Look for members in the type + // class members are only accessible in default arg expressions as post op '.' + if( !isCompilingDefaultArg || (isCompilingDefaultArg && objType) ) + { + SYMBOLTYPE r = SymbolLookupMember(name, objType ? objType : outFunc->objectType, outResult); + if (r != 0) + return r; + } + } + + // Recursively search parent namespaces for global entities + asSNameSpace *currNamespace = DetermineNameSpace(""); + while( !objType && currNamespace ) + { + asCString currScope = scope; + + // If the scope contains ::identifier, then use the last identifier as the class name and the rest of it as the namespace + // TODO: child funcdef: A scope can include a template type, e.g. array + int n = currScope.FindLast("::"); + asCString typeName = n >= 0 ? currScope.SubString(n + 2) : currScope; + asCString nsName = n >= 0 ? currScope.SubString(0, n) : ""; + + // If the scope represents a type that the current class inherits + // from then that should be used instead of going through the namespaces + if (nsName == "" && (outFunc && outFunc->objectType)) + { + asCObjectType *ot = outFunc->objectType; + while (ot) + { + if (ot->name == typeName) + { + SYMBOLTYPE r = SymbolLookupMember(name, ot, outResult); + if (r != 0) + return r; + } + + ot = ot->derivedFrom; + } + } + + // If the scope starts with :: then search from the global scope + if (currScope.GetLength() < 2 || currScope[0] != ':') + { + if (nsName != "") + { + if (currNamespace->name != "") + nsName = currNamespace->name + "::" + nsName; + } + else + nsName = currNamespace->name; + } + else + nsName = nsName.SubString(2); + + // Get the namespace for this scope + asSNameSpace *ns = engine->FindNameSpace(nsName.AddressOf()); + if (ns) + { + // Is there a type with typeName in the namespace? + asCTypeInfo *scopeType = builder->GetType(typeName.AddressOf(), ns, 0); + + // Check if the symbol is a member of that type + if (scopeType) + { + // Is it an object type? + if (CastToObjectType(scopeType)) + { + SYMBOLTYPE r = SymbolLookupMember(name, CastToObjectType(scopeType), outResult); + if (r != 0) + return r; + } + + // Is it an enum type? + if (CastToEnumType(scopeType)) + { + asDWORD value = 0; + asCDataType dt; + if (builder->GetEnumValueFromType(CastToEnumType(scopeType), name.AddressOf(), dt, value)) + { + // an enum value was resolved + outResult->type.SetConstantDW(dt, value); + outResult->symbolNamespace = ns; + return SL_ENUMVAL; + } + } + } + } + + // Get the namespace for this scope. This may return null if the scope is an enum + nsName = currScope; + + // If the scope starts with :: then search from the global scope + if (currScope.GetLength() < 2 || currScope[0] != ':') + { + if (nsName != "") + { + if (currNamespace->name != "") + nsName = currNamespace->name + "::" + nsName; + } + else + nsName = currNamespace->name; + } + else + nsName = nsName.SubString(2); + + ns = engine->FindNameSpace(nsName.AddressOf()); + + // Is it a global property? + if (ns) + { + // See if there are any matching global property accessors + asCExprContext access(engine); + int r = 0; + // Indexed property access + asCExprContext dummyArg(engine); + r = FindPropertyAccessor(name, &access, &dummyArg, 0, ns); + if (r == 0) + { + // Normal property access + r = FindPropertyAccessor(name, &access, 0, ns); + } + if (r <= -3) return SL_ERROR; + if (r != 0) + { + // The symbol matches getters/setters (though not necessarily a compilable match) + MergeExprBytecodeAndType(outResult, &access); + outResult->symbolNamespace = ns; + return SL_GLOBALPROPACCESS; + } + + // See if there is any matching global property + bool isCompiled = true; + bool isPureConstant = false; + bool isAppProp = false; + asQWORD constantValue = 0; + asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp); + if (prop) + { + // If the global property is a pure constant + // we can allow the compiler to optimize it. Pure + // constants are global constant variables that were + // initialized by literal constants. + if (isPureConstant) + { + outResult->type.SetConstantData(prop->type, constantValue); + outResult->symbolNamespace = ns; + return SL_GLOBALCONST; + } + else + { + outResult->type.Set(prop->type); + outResult->symbolNamespace = ns; + return SL_GLOBALVAR; + } + } + } + + // Is it the name of a global function? + if (ns) + { + asCArray funcs; + + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + + if (funcs.GetLength() > 0) + { + // Defer the evaluation of which function until it is actually used + // Store the namespace and name of the function for later + outResult->type.SetUndefinedFuncHandle(engine); + outResult->methodName = ns ? ns->name + "::" + name : name; + outResult->symbolNamespace = ns; + return SL_GLOBALFUNC; + } + } + + // Check for type names + if (ns) + { + asCTypeInfo *type = builder->GetType(name.AddressOf(), ns, 0); + if (type) + { + outResult->type.dataType = asCDataType::CreateType(type, false); + return SL_GLOBALTYPE; + } + } + + // Is it an enum value? + if (ns && !engine->ep.requireEnumScope) + { + // Look for the enum value without explicitly informing the enum type + asDWORD value = 0; + asCDataType dt; + int e = builder->GetEnumValue(name.AddressOf(), dt, value, ns); + if (e) + { + if (e == 2) + { + // Ambiguous enum value: Save the name for resolution later. + // The ambiguity could be resolved now, but I hesitate + // to store too much information in the context. + outResult->enumValue = name.AddressOf(); + + // We cannot set a dummy value because it will pass through + // cleanly as an integer. + outResult->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0); + outResult->symbolNamespace = ns; + return SL_ENUMVAL; + } + else + { + // an enum value was resolved + outResult->type.SetConstantDW(dt, value); + outResult->symbolNamespace = ns; + return SL_ENUMVAL; + } + } + } + + // If the given scope starts with '::' then the search starts from global scope + if (scope.GetLength() >= 2 && scope[0] == ':') + break; + + // Move up to parent namespace + currNamespace = engine->GetParentNameSpace(currNamespace); + } + + // The name doesn't match any symbol + return SL_NOMATCH; +} + +int asCCompiler::CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional, asCObjectType *objType) +{ + asCExprContext lookupResult(engine); + SYMBOLTYPE symbolType = SymbolLookup(name, scope, objType, &lookupResult); + if (symbolType < 0) + { + // Give dummy value + ctx->type.SetDummy(); + + return -1; + } + if (symbolType == SL_NOMATCH) + { + // Give dummy value + ctx->type.SetDummy(); + + if (!isOptional) + { + // No matching symbol + asCString msg; + asCString smbl; + if (scope == "::") + smbl = scope; + else if (scope != "") + smbl = scope + "::"; + smbl += name; + msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf()); + Error(msg, errNode); + } + return -1; + } + + // It is a local variable or parameter? + if( symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR ) + { + // This is not accessible by default arg expressions + asASSERT(!isCompilingDefaultArg && scope == "" && !objType && variables); + + sVariable *v = variables->GetVariable(name.AddressOf()); + asASSERT(v); + + if( v->isPureConstant ) + ctx->type.SetConstantData(v->type, v->constantValue); + else if( v->type.IsPrimitive() ) + { + if( v->type.IsReference() ) + { + // Copy the reference into the register + ctx->bc.InstrSHORT(asBC_PshVPtr, (short)v->stackOffset); + ctx->bc.Instr(asBC_PopRPtr); + ctx->type.Set(v->type); + } + else + ctx->type.SetVariable(v->type, v->stackOffset, false); + + // Set as lvalue unless it is a const variable + if( !v->type.IsReadOnly() ) + ctx->type.isLValue = true; + } + else + { + ctx->bc.InstrSHORT(asBC_PSF, (short)v->stackOffset); + ctx->type.SetVariable(v->type, v->stackOffset, false); + + // If the variable is allocated on the heap we have a reference, + // otherwise the actual object pointer is pushed on the stack. + if( v->onHeap || v->type.IsObjectHandle() ) ctx->type.dataType.MakeReference(true); + + // Implicitly dereference handle parameters sent by reference + if( v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle()) ) + ctx->bc.Instr(asBC_RDSPtr); + + // Mark the object as safe for access unless it is a handle, as the + // life time of the object is guaranteed throughout the scope. + if( !v->type.IsObjectHandle() ) + ctx->type.isRefSafe = true; + + // Set as lvalue unless it is a const variable + if (!v->type.IsReadOnly()) + ctx->type.isLValue = true; + } + + return 0; + } + + // Is it a class member? + if (symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || symbolType == SL_CLASSMETHOD || symbolType == SL_THISPTR) + { + // This is not accessible by default arg expressions + asASSERT(!isCompilingDefaultArg); + + if (symbolType == SL_THISPTR) + { + asASSERT(name == THIS_TOKEN && !objType && scope == ""); + asCDataType dt = asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly()); + + // The object pointer is located at stack position 0 + ctx->bc.InstrSHORT(asBC_PSF, 0); + ctx->type.SetVariable(dt, 0, false); + ctx->type.dataType.MakeReference(true); + ctx->type.isLValue = true; + + // The 'this' handle is always considered safe (i.e. life time guaranteed) + ctx->type.isRefSafe = true; + + return 0; + } + + if (symbolType == SL_CLASSPROPACCESS) + { + if (scope != "") + { + // Cannot access non-static members like this + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + // See if there are any matching property accessors + asCExprContext access(engine); + if (objType) + access.type.Set(asCDataType::CreateType(objType, false)); + else + access.type.Set(asCDataType::CreateType(outFunc->objectType, outFunc->IsReadOnly())); + access.type.dataType.MakeReference(true); + int r = 0; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + { + // This is an index access, check if there is a property accessor that takes an index arg + asCExprContext dummyArg(engine); + r = FindPropertyAccessor(name, &access, &dummyArg, errNode, 0, true); + } + if (r == 0) + { + // Normal property access + r = FindPropertyAccessor(name, &access, errNode, 0, true); + } + if (r < 0) return -1; + + if (access.property_get == 0 && access.property_set == 0) + { + // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments + asCString msg; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf()); + else + msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + if (!objType) + { + // Prepare the bytecode for the member access + // This is only done when accessing through the implicit this pointer + ctx->bc.InstrSHORT(asBC_PSF, 0); + } + MergeExprBytecodeAndType(ctx, &access); + + return 0; + } + + if (symbolType == SL_CLASSPROP) + { + if (scope != "") + { + // Cannot access non-static members like this + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + asCDataType dt; + if (objType) + dt = asCDataType::CreateType(objType, false); + else + dt = asCDataType::CreateType(outFunc->objectType, false); + asCObjectProperty *prop = builder->GetObjectProperty(dt, name.AddressOf()); + asASSERT(prop); + + // Is the property access allowed? + if (prop->isPrivate && prop->isInherited) + { + if (engine->ep.privatePropAsProtected) + { + // The application is allowing inherited classes to access private properties of the parent + // class. This option is allowed to provide backwards compatibility with pre-2.30.0 versions + // as it was how the compiler behaved earlier. + asCString msg; + msg.Format(TXT_ACCESSING_PRIVATE_PROP_s, name.AddressOf()); + Warning(msg, errNode); + } + else + { + asCString msg; + msg.Format(TXT_INHERITED_PRIVATE_PROP_ACCESS_s, name.AddressOf()); + Error(msg, errNode); + } + } + + if (!objType) + { + // The object pointer is located at stack position 0 + // This is only done when accessing through the implicit this pointer + ctx->bc.InstrSHORT(asBC_PSF, 0); + ctx->type.SetVariable(dt, 0, false); + ctx->type.dataType.MakeReference(true); + Dereference(ctx, true); + } + + // TODO: This is the same as what is in CompileExpressionPostOp + // Put the offset on the stack + ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(dt)); + + if (prop->type.IsReference()) + ctx->bc.Instr(asBC_RDSPtr); + + // Reference to primitive must be stored in the temp register + if (prop->type.IsPrimitive()) + { + // TODO: runtime optimize: The ADD offset command should store the reference in the register directly + ctx->bc.Instr(asBC_PopRPtr); + } + + // Set the new type (keeping info about temp variable) + ctx->type.dataType = prop->type; + ctx->type.dataType.MakeReference(true); + ctx->type.isVariable = false; + ctx->type.isLValue = true; + + if (ctx->type.dataType.IsObject() && !ctx->type.dataType.IsObjectHandle()) + { + // Objects that are members are not references + ctx->type.dataType.MakeReference(false); + + // Objects that are members but not handles are safe as long as the parent object is safe + if (!objType || ctx->type.isRefSafe) + ctx->type.isRefSafe = true; + } + else if (ctx->type.dataType.IsObjectHandle()) + { + // Objects accessed through handles cannot be considered safe + // as the handle can be cleared at any time + ctx->type.isRefSafe = false; + } + + // If the object reference is const, the property will also be const + ctx->type.dataType.MakeReadOnly(outFunc->IsReadOnly()); + + return 0; + } + + if (symbolType == SL_CLASSMETHOD) + { + if (scope != "") + { + // Cannot access non-static members like this + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, errNode); + return -1; + } + +#if AS_DEBUG + // If it is not a property, it may still be the name of a method which can be used to create delegates + asCObjectType *ot = outFunc->objectType; + asCScriptFunction *func = 0; + for (asUINT n = 0; n < ot->methods.GetLength(); n++) + { + asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; + if (f->name == name && + (builder->module->m_accessMask & f->accessMask)) + { + func = f; + break; + } + } + + asASSERT(func); +#endif + // An object method was found. Keep the name of the method in the expression, but + // don't actually modify the bytecode at this point since it is not yet known what + // the method will be used for, or even what overloaded method should be used. + ctx->methodName = name; + + // Place the object pointer on the stack, as if the expression was this.func + if (!objType) + { + // The object pointer is located at stack position 0 + // This is only done when accessing through the implicit this pointer + ctx->bc.InstrSHORT(asBC_PSF, 0); + ctx->type.SetVariable(asCDataType::CreateType(outFunc->objectType, false), 0, false); + ctx->type.dataType.MakeReference(true); + Dereference(ctx, true); + } + + return 0; + } + } + + if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALVAR || symbolType == SL_GLOBALFUNC || symbolType == SL_ENUMVAL) + { + // Get the namespace from SymbolLookup + asSNameSpace *ns = lookupResult.symbolNamespace; + + if (symbolType == SL_GLOBALPROPACCESS) + { + // See if there are any matching global property accessors + asCExprContext access(engine); + int r = 0; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + { + // This is an index access, check if there is a property accessor that takes an index arg + asCExprContext dummyArg(engine); + r = FindPropertyAccessor(name, &access, &dummyArg, errNode, ns); + } + if (r == 0) + { + // Normal property access + r = FindPropertyAccessor(name, &access, errNode, ns); + } + if (r < 0) return -1; + + if (access.property_get == 0 && access.property_set == 0) + { + // Even though the symbol was identified in SymbolLookup, it doesn't match the arguments + asCString msg; + if (errNode->next && errNode->next->tokenType == ttOpenBracket) + msg.Format(TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX, name.AddressOf()); + else + msg.Format(TXT_PROP_ACCESS_s_EXPECTS_INDEX, name.AddressOf()); + Error(msg, errNode); + return -1; + } + + // Prepare the bytecode for the function call + MergeExprBytecodeAndType(ctx, &access); + + return 0; + } + + if (symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR) + { + bool isCompiled = true; + bool isPureConstant = false; + bool isAppProp = false; + asQWORD constantValue = 0; + asCGlobalProperty *prop = builder->GetGlobalProperty(name.AddressOf(), ns, &isCompiled, &isPureConstant, &constantValue, &isAppProp); + asASSERT(prop); + + // Verify that the global property has been compiled already + if (!isCompiled) + { + asCString str; + str.Format(TXT_UNINITIALIZED_GLOBAL_VAR_s, prop->name.AddressOf()); + Error(str, errNode); + return -1; + } + + // If the global property is a pure constant + // we can allow the compiler to optimize it. Pure + // constants are global constant variables that were + // initialized by literal constants. + if (isPureConstant) + ctx->type.SetConstantData(prop->type, constantValue); + else + { + // A shared type must not access global vars, unless they + // too are shared, e.g. application registered vars + if (outFunc->IsShared()) + { + if (!isAppProp) + { + asCString str; + str.Format(TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s, prop->name.AddressOf()); + Error(str, errNode); + + // Allow the compilation to continue to catch other problems + } + } + + ctx->type.Set(prop->type); + ctx->type.isLValue = true; + + if (ctx->type.dataType.IsPrimitive()) + { + // Load the address of the variable into the register + ctx->bc.InstrPTR(asBC_LDG, prop->GetAddressOfValue()); + + ctx->type.dataType.MakeReference(true); + } + else + { + // Push the address of the variable on the stack + ctx->bc.InstrPTR(asBC_PGA, prop->GetAddressOfValue()); + + // If the object is a value type or a non-handle variable to a reference type, + // then we must validate the existance as it could potentially be accessed + // before it is initialized. + // This check is not needed for application registered properties, since they + // are guaranteed to be valid by the application itself. + if (!isAppProp && + ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) || + !ctx->type.dataType.IsObjectHandle())) + { + ctx->bc.Instr(asBC_ChkRefS); + } + + // If the address pushed on the stack is to a value type or an object + // handle, then mark the expression as a reference. Addresses to a reference + // type aren't marked as references to get correct behaviour + if ((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE) || + ctx->type.dataType.IsObjectHandle()) + { + ctx->type.dataType.MakeReference(true); + } + else + { + asASSERT((ctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !ctx->type.dataType.IsObjectHandle()); + + // It's necessary to dereference the pointer so the pointer on the stack will point to the actual object + ctx->bc.Instr(asBC_RDSPtr); + } + } + } + + return 0; + } + + if (symbolType == SL_GLOBALFUNC) + { + asCArray funcs; + + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + asASSERT(funcs.GetLength() > 0); + + if (funcs.GetLength() > 0) + { + // Defer the evaluation of which function until it is actually used + // Store the namespace and name of the function for later + ctx->type.SetUndefinedFuncHandle(engine); + ctx->methodName = ns ? ns->name + "::" + name : name; + } + + return 0; + } + + if (symbolType == SL_ENUMVAL) + { + // The enum type and namespace must be returned from SymbolLookup + asCDataType dt = lookupResult.type.dataType; + if (!dt.IsEnumType()) + { + asASSERT(!engine->ep.requireEnumScope); + + // It is an ambigious enum value. The evaluation needs to be deferred for when the type is known + ctx->enumValue = name.AddressOf(); + ctx->symbolNamespace = lookupResult.symbolNamespace; + + // We cannot set a dummy value because it will pass through + // cleanly as an integer. + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttIdentifier, true), 0); + return 0; + } + + asDWORD value = 0; + builder->GetEnumValueFromType(CastToEnumType(lookupResult.type.dataType.GetTypeInfo()), name.AddressOf(), dt, value); + + // Even if the enum type is not shared, and we're compiling a shared object, + // the use of the values are still allowed, since they are treated as constants. + + // an enum value was resolved + ctx->type.SetConstantDW(dt, value); + return 0; + } + } + + // The result must have been identified above + if (symbolType == SL_GLOBALTYPE || symbolType == SL_CLASSTYPE) + { + // Give dummy value + ctx->type.SetDummy(); + + // The symbol matches a type + asCString msg; + asCString smbl; + if (scope == "::") + smbl = scope; + else if (scope != "") + smbl = scope + "::"; + smbl += name; + msg.Format(TXT_EXPR_s_IS_DATA_TYPE, smbl.AddressOf()); + Error(msg, errNode); + return -1; + } + + // Should not come here + asASSERT(false); + return 0; +} + +int asCCompiler::CompileExpressionValue(asCScriptNode *node, asCExprContext *ctx) +{ + // Shouldn't receive any byte code + asASSERT(ctx->bc.GetLastInstr() == -1); + + asCScriptNode *vnode = node->firstChild; + ctx->exprNode = vnode; + if( vnode->nodeType == snVariableAccess ) + { + // Determine the scope resolution of the variable + asCString scope = builder->GetScopeFromNode(vnode->firstChild, script, &vnode); + + // Determine the name of the variable + asASSERT(vnode->nodeType == snIdentifier ); + asCString name(&script->code[vnode->tokenPos], vnode->tokenLength); + + return CompileVariableAccess(name, scope, ctx, node); + } + else if( vnode->nodeType == snConstant ) + { + if( vnode->tokenType == ttIntConstant ) + { + asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); + + bool overflow = false; + asQWORD val = asStringScanUInt64(value.AddressOf(), 10, 0, &overflow); + + // Is the number bigger than a 64bit word? + if (overflow) + { + Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); + + // Set the value to zero to avoid further warnings + val = 0; + } + + // Do we need 64 bits? + // If the 31st bit is set we'll treat the value as a signed 64bit number to avoid + // incorrect warnings about changing signs if the value is assigned to a 64bit variable + if( val>>31 ) + { + // Only if the value uses the last bit of a 64bit word do we consider the number unsigned + if( val>>63 ) + ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val); + else + ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttInt64, true), val); + } + else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), asDWORD(val)); + } + else if( vnode->tokenType == ttBitsConstant ) + { + asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); + + // Let the function determine the radix from the prefix 0x = 16, 0d = 10, 0o = 8, or 0b = 2 + bool overflow = false; + asQWORD val = asStringScanUInt64(value.AddressOf(), 0, 0, &overflow); + + // Is the number bigger than a 64bit word? + if (overflow) + { + Error(TXT_VALUE_TOO_LARGE_FOR_TYPE, vnode); + + // Set the value to zero to avoid further warnings + val = 0; + } + + // Do we need 64 bits? + if( val>>32 ) + ctx->type.SetConstantQW(asCDataType::CreatePrimitive(ttUInt64, true), val); + else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), asDWORD(val)); + } + else if( vnode->tokenType == ttFloatConstant ) + { + asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); + + // TODO: Check for overflow + + size_t numScanned; + float v = float(asStringScanDouble(value.AddressOf(), &numScanned)); + ctx->type.SetConstantF(asCDataType::CreatePrimitive(ttFloat, true), v); +#ifndef AS_USE_DOUBLE_AS_FLOAT + // Don't check this if we have double as float, because then the whole token would be scanned (i.e. no f suffix) + asASSERT(numScanned == vnode->tokenLength - 1); +#endif + } + else if( vnode->tokenType == ttDoubleConstant ) + { + asCString value(&script->code[vnode->tokenPos], vnode->tokenLength); + + // TODO: Check for overflow + + size_t numScanned; + double v = asStringScanDouble(value.AddressOf(), &numScanned); + ctx->type.SetConstantD(asCDataType::CreatePrimitive(ttDouble, true), v); + asASSERT(numScanned == vnode->tokenLength); + } + else if( vnode->tokenType == ttTrue || + vnode->tokenType == ttFalse ) + { +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0); +#else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), vnode->tokenType == ttTrue ? VALUE_OF_BOOLEAN_TRUE : 0); +#endif + } + else if( vnode->tokenType == ttStringConstant || + vnode->tokenType == ttMultilineStringConstant || + vnode->tokenType == ttHeredocStringConstant ) + { + asCString str; + asCScriptNode *snode = vnode->firstChild; + if( script->code[snode->tokenPos] == '\'' && engine->ep.useCharacterLiterals ) + { + // Treat the single quoted string as a single character literal + str.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2); + + asDWORD val = 0; + if( str.GetLength() && (asBYTE)str[0] > 127 && engine->ep.scanner == 1 ) + { + // This is the start of a UTF8 encoded character. We need to decode it + val = asStringDecodeUTF8(str.AddressOf(), 0); + if( val == (asDWORD)-1 ) + Error(TXT_INVALID_CHAR_LITERAL, vnode); + } + else + { + val = ProcessStringConstant(str, snode); + if( val == (asDWORD)-1 ) + Error(TXT_INVALID_CHAR_LITERAL, vnode); + } + + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttUInt, true), val); + } + else + { + // Process the string constants + while( snode ) + { + asCString cat; + if( snode->tokenType == ttStringConstant ) + { + cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2); + ProcessStringConstant(cat, snode); + } + else if( snode->tokenType == ttMultilineStringConstant ) + { + if( !engine->ep.allowMultilineStrings ) + Error(TXT_MULTILINE_STRINGS_NOT_ALLOWED, snode); + + cat.Assign(&script->code[snode->tokenPos+1], snode->tokenLength-2); + ProcessStringConstant(cat, snode); + } + else if( snode->tokenType == ttHeredocStringConstant ) + { + cat.Assign(&script->code[snode->tokenPos+3], snode->tokenLength-6); + ProcessHeredocStringConstant(cat, snode); + } + + str += cat; + + snode = snode->next; + } + + // Call the string factory function to create a string object + if(engine->stringFactory == 0 ) + { + // Error + Error(TXT_STRINGS_NOT_RECOGNIZED, vnode); + + // Give dummy value + ctx->type.SetDummy(); + return -1; + } + else + { + void *strPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength())); + if (strPtr == 0) + { + // TODO: A better message is needed + Error(TXT_NULL_POINTER_ACCESS, vnode); + ctx->type.SetDummy(); + return -1; + } + + // Keep the pointer in the list for clean up at exit + usedStringConstants.PushLast(strPtr); + + // Push the pointer on the stack. The string factory already guarantees that the + // string object is valid throughout the lifetime of the script so no need to add + // reference count or make local copy. + ctx->bc.InstrPTR(asBC_PGA, strPtr); + ctx->type.Set(engine->stringType); + + // Mark the string as literal constant so the compiler knows it is allowed + // to treat it differently than an ordinary constant string variable + ctx->type.isConstant = true; + + // Mark the reference to the string constant as safe, so the compiler can + // avoid making unnecessary temporary copies when passing the reference to + // functions. + ctx->type.isRefSafe = true; + } + } + } + else if( vnode->tokenType == ttNull ) + { + ctx->bc.Instr(asBC_PshNull); + ctx->type.SetNullConstant(); + } + else + asASSERT(false); + } + else if( vnode->nodeType == snFunctionCall ) + { + // Determine the scope resolution + asCString scope = builder->GetScopeFromNode(vnode->firstChild, script); + + return CompileFunctionCall(vnode, ctx, 0, false, scope); + } + else if( vnode->nodeType == snConstructCall ) + { + return CompileConstructCall(vnode, ctx); + } + else if( vnode->nodeType == snAssignment ) + { + asCExprContext e(engine); + int r = CompileAssignment(vnode, &e); + if( r < 0 ) + { + ctx->type.SetDummy(); + return r; + } + MergeExprBytecodeAndType(ctx, &e); + } + else if( vnode->nodeType == snCast ) + { + // Implement the cast operator + return CompileConversion(vnode, ctx); + } + else if( vnode->nodeType == snUndefined && vnode->tokenType == ttVoid ) + { + // This is a void expression + ctx->SetVoidExpression(); + } + else if( vnode->nodeType == snFunction ) + { + // This is an anonymous function + // Defer the evaluation of the function until it is known where it + // will be used, which is where the signature will be defined + ctx->SetLambda(vnode); + } + else + asASSERT(false); + + return 0; +} + +asUINT asCCompiler::ProcessStringConstant(asCString &cstr, asCScriptNode *node, bool processEscapeSequences) +{ + int charLiteral = -1; + + // Process escape sequences + asCArray str((int)cstr.GetLength()); + + for( asUINT n = 0; n < cstr.GetLength(); n++ ) + { +#ifdef AS_DOUBLEBYTE_CHARSET + // Double-byte charset is only allowed for ASCII and not UTF16 encoded strings + if( (cstr[n] & 0x80) && engine->ep.scanner == 0 && engine->ep.stringEncoding != 1 ) + { + // This is the lead character of a double byte character + // include the trail character without checking it's value. + str.PushLast(cstr[n]); + n++; + str.PushLast(cstr[n]); + continue; + } +#endif + + asUINT val; + + if( processEscapeSequences && cstr[n] == '\\' ) + { + ++n; + if( n == cstr.GetLength() ) + { + if( charLiteral == -1 ) charLiteral = 0; + return charLiteral; + } + + // Hexadecimal escape sequences will allow the construction of + // invalid unicode sequences, but the string should also work as + // a bytearray so we must support this. The code for working with + // unicode text must be prepared to handle invalid unicode sequences + if( cstr[n] == 'x' || cstr[n] == 'X' ) + { + ++n; + if( n == cstr.GetLength() ) break; + + val = 0; + int c = engine->ep.stringEncoding == 1 ? 4 : 2; + for( ; c > 0 && n < cstr.GetLength(); c--, n++ ) + { + if( cstr[n] >= '0' && cstr[n] <= '9' ) + val = val*16 + cstr[n] - '0'; + else if( cstr[n] >= 'a' && cstr[n] <= 'f' ) + val = val*16 + cstr[n] - 'a' + 10; + else if( cstr[n] >= 'A' && cstr[n] <= 'F' ) + val = val*16 + cstr[n] - 'A' + 10; + else + break; + } + + // Rewind one, since the loop will increment it again + n--; + + // Hexadecimal escape sequences produce exact value, even if it is not proper unicode chars + if( engine->ep.stringEncoding == 0 ) + { + str.PushLast((asBYTE)val); + } + else + { +#ifndef AS_BIG_ENDIAN + str.PushLast((asBYTE)val); + str.PushLast((asBYTE)(val>>8)); +#else + str.PushLast((asBYTE)(val>>8)); + str.PushLast((asBYTE)val); +#endif + } + if( charLiteral == -1 ) charLiteral = val; + continue; + } + else if( cstr[n] == 'u' || cstr[n] == 'U' ) + { + // \u expects 4 hex digits + // \U expects 8 hex digits + bool expect2 = cstr[n] == 'u'; + int c = expect2 ? 4 : 8; + + val = 0; + + for( ; c > 0; c-- ) + { + ++n; + if( n == cstr.GetLength() ) break; + + if( cstr[n] >= '0' && cstr[n] <= '9' ) + val = val*16 + cstr[n] - '0'; + else if( cstr[n] >= 'a' && cstr[n] <= 'f' ) + val = val*16 + cstr[n] - 'a' + 10; + else if( cstr[n] >= 'A' && cstr[n] <= 'F' ) + val = val*16 + cstr[n] - 'A' + 10; + else + break; + } + + if( c != 0 ) + { + // Give warning about invalid code point + // TODO: Need code position for warning + asCString msg; + msg.Format(TXT_INVALID_UNICODE_FORMAT_EXPECTED_d, expect2 ? 4 : 8); + Warning(msg, node); + continue; + } + } + else + { + if( cstr[n] == '"' ) + val = '"'; + else if( cstr[n] == '\'' ) + val = '\''; + else if( cstr[n] == 'n' ) + val = '\n'; + else if( cstr[n] == 'r' ) + val = '\r'; + else if( cstr[n] == 't' ) + val = '\t'; + else if( cstr[n] == '0' ) + val = '\0'; + else if( cstr[n] == '\\' ) + val = '\\'; + else + { + // Invalid escape sequence + Warning(TXT_INVALID_ESCAPE_SEQUENCE, node); + continue; + } + } + } + else + { + if( engine->ep.scanner == 1 && (cstr[n] & 0x80) ) + { + unsigned int len; + val = asStringDecodeUTF8(&cstr[n], &len); + if( val == 0xFFFFFFFF ) + { + // Incorrect UTF8 encoding. Use only the first byte + // TODO: Need code position for warning + Warning(TXT_INVALID_UNICODE_SEQUENCE_IN_SRC, node); + val = (unsigned char)cstr[n]; + } + else + n += len-1; + } + else + val = (unsigned char)cstr[n]; + } + + // Add the character to the final string + char encodedValue[5]; + int len; + if( engine->ep.scanner == 1 && engine->ep.stringEncoding == 0 ) + { + // Convert to UTF8 encoded + len = asStringEncodeUTF8(val, encodedValue); + } + else if( engine->ep.stringEncoding == 1 ) + { + // Convert to 16bit wide character string (even if the script is scanned as ASCII) + len = asStringEncodeUTF16(val, encodedValue); + } + else + { + // Do not convert ASCII characters + encodedValue[0] = (asBYTE)val; + len = 1; + } + + if( len < 0 ) + { + // Give warning about invalid code point + // TODO: Need code position for warning + Warning(TXT_INVALID_UNICODE_VALUE, node); + } + else + { + // Add the encoded value to the final string + str.Concatenate(encodedValue, len); + if( charLiteral == -1 ) charLiteral = val; + } + } + + cstr.Assign(str.AddressOf(), str.GetLength()); + return charLiteral; +} + +void asCCompiler::ProcessHeredocStringConstant(asCString &str, asCScriptNode *node) +{ + // Remove first line if it only contains whitespace + bool isMultiline = false; + int start; + for( start = 0; start < (int)str.GetLength(); start++ ) + { + if( str[start] == '\n' ) + { + isMultiline = true; + + // Remove the linebreak as well + start++; + break; + } + + if( str[start] != ' ' && + str[start] != '\t' && + str[start] != '\r' ) + { + // Don't remove anything + start = 0; + break; + } + } + + // Remove the line after the last line break if it only contains whitespaces + int end; + for( end = (int)str.GetLength() - 1; end >= 0; end-- ) + { + if( str[end] == '\n' ) + { + // Don't remove the last line break + end++; + break; + } + + if( str[end] != ' ' && + str[end] != '\t' && + str[end] != '\r' ) + { + // Don't remove anything + end = (int)str.GetLength(); + break; + } + } + + if( end < 0 ) end = 0; + + asCString tmp; + if (end > start || engine->ep.heredocTrimMode != 2 ) + { + // if heredocTrimMode == 0 the string shouldn't be trimmed + // if heredocTrimMode == 1 the string should only be trimmed if it is multiline + // if heredocTrimMode == 2 the string should always be trimmed + if (engine->ep.heredocTrimMode == 2 || (isMultiline && engine->ep.heredocTrimMode == 1)) + tmp.Assign(&str[start], end - start); + else + tmp = str; + } + + ProcessStringConstant(tmp, node, false); + + str = tmp; +} + +int asCCompiler::CompileConversion(asCScriptNode *node, asCExprContext *ctx) +{ + asCExprContext expr(engine); + asCDataType to; + bool anyErrors = false; + EImplicitConv convType; + if( node->nodeType == snConstructCall || node->nodeType == snFunctionCall ) + { + convType = asIC_EXPLICIT_VAL_CAST; + + // Verify that there is only one argument + if( node->lastChild->firstChild == 0 || + node->lastChild->firstChild != node->lastChild->lastChild ) + { + Error(TXT_ONLY_ONE_ARGUMENT_IN_CAST, node->lastChild); + expr.type.SetDummy(); + anyErrors = true; + } + else if (node->lastChild->firstChild && + node->lastChild->firstChild->nodeType == snNamedArgument) + { + Error(TXT_INVALID_USE_OF_NAMED_ARGS, node->lastChild); + expr.type.SetDummy(); + anyErrors = true; + } + else + { + // Compile the expression + int r = CompileAssignment(node->lastChild->firstChild, &expr); + if( r < 0 ) + anyErrors = true; + } + + // Determine the requested type + to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); + to.MakeReadOnly(true); // Default to const + asASSERT(to.IsPrimitive()); + } + else + { + convType = asIC_EXPLICIT_REF_CAST; + + // Compile the expression + int r = CompileAssignment(node->lastChild, &expr); + if( r < 0 ) + anyErrors = true; + + // Determine the requested type + to = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace); + + // If the type support object handles, then use it + if( to.SupportHandles() ) + { + to.MakeHandle(true); + if( expr.type.dataType.IsObjectConst() ) + to.MakeHandleToConst(true); + } + else if( !to.IsObjectHandle() ) + { + // The cast operator can only be used for reference casts + Error(TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST, node->firstChild); + anyErrors = true; + } + } + + // Do not allow casting to non shared type if we're compiling a shared method + if( outFunc->IsShared() && + to.GetTypeInfo() && !to.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, to.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + anyErrors = true; + } + + if( anyErrors ) + { + // Assume that the error can be fixed and allow the compilation to continue + ctx->type.Set(to); + return -1; + } + + if( ProcessPropertyGetAccessor(&expr, node) < 0 ) + return -1; + + // Don't allow any operators on expressions that take address of class method + if( expr.IsClassMethod() ) + { + Error(TXT_INVALID_OP_ON_METHOD, node); + return -1; + } + + // We don't want a reference for conversion casts + if( convType == asIC_EXPLICIT_VAL_CAST && expr.type.dataType.IsReference() ) + { + if( expr.type.dataType.IsObject() ) + Dereference(&expr, true); + else + ConvertToVariable(&expr); + } + + ImplicitConversion(&expr, to, node, convType); + + IsVariableInitialized(&expr.type, node); + + // If no type conversion is really tried ignore it + if( to == expr.type.dataType ) + { + // This will keep information about constant type + MergeExprBytecode(ctx, &expr); + ctx->type = expr.type; + return 0; + } + + if( to.IsEqualExceptRefAndConst(expr.type.dataType) && to.IsPrimitive() ) + { + MergeExprBytecode(ctx, &expr); + ctx->type = expr.type; + ctx->type.dataType.MakeReadOnly(true); + return 0; + } + + // The implicit conversion already does most of the conversions permitted, + // here we'll only treat those conversions that require an explicit cast. + + bool conversionOK = false; + if( !expr.type.isConstant && expr.type.dataType != asCDataType::CreatePrimitive(ttVoid, false) ) + { + if( !expr.type.dataType.IsObject() ) + ConvertToTempVariable(&expr); + + if( to.IsObjectHandle() && + expr.type.dataType.IsObjectHandle() && + !(!to.IsHandleToConst() && expr.type.dataType.IsHandleToConst()) ) + { + conversionOK = CompileRefCast(&expr, to, true, node); + + MergeExprBytecode(ctx, &expr); + ctx->type = expr.type; + } + } + + if( conversionOK ) + return 0; + + // Conversion not available + ctx->type.SetDummy(); + + asCString strTo, strFrom; + + strTo = to.Format(outFunc->nameSpace); + strFrom = expr.type.dataType.Format(outFunc->nameSpace); + + asCString msg; + msg.Format(TXT_NO_CONVERSION_s_TO_s, strFrom.AddressOf(), strTo.AddressOf()); + + Error(msg, node); + return -1; +} + +void asCCompiler::AfterFunctionCall(int funcID, asCArray &args, asCExprContext *ctx, bool deferAll) +{ + // deferAll is set to true if for example the function returns a reference, since in + // this case the function might be returning a reference to one of the arguments. + + asCScriptFunction *descr = builder->GetFunctionDescription(funcID); + + // Parameters that are sent by reference should be assigned + // to the evaluated expression if it is an lvalue + + // Evaluate the arguments from last to first + int n = (int)descr->parameterTypes.GetLength() - 1; + for( ; n >= 0; n-- ) + { + // All &out arguments must be deferred, except if the argument is clean, in which case the actual reference was passed in to the function + // If deferAll is set all objects passed by reference or handle must be deferred + if( (descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] & asTM_OUTREF) && !args[n]->isCleanArg) || + (descr->parameterTypes[n].IsObject() && deferAll && (descr->parameterTypes[n].IsReference() || descr->parameterTypes[n].IsObjectHandle())) ) + { + asASSERT( !(descr->parameterTypes[n].IsReference() && (descr->inOutFlags[n] == asTM_OUTREF) && !args[n]->isCleanArg) || args[n]->origExpr ); + + // For &inout, only store the argument if it is for a temporary variable + if( engine->ep.allowUnsafeReferences || + descr->inOutFlags[n] != asTM_INOUTREF || args[n]->type.isTemporary ) + { + // Store the argument for later processing + asSDeferredParam outParam; + outParam.argNode = args[n]->exprNode; + outParam.argType = args[n]->type; + outParam.argInOutFlags = descr->inOutFlags[n]; + outParam.origExpr = args[n]->origExpr; + + ctx->deferredParams.PushLast(outParam); + } + } + else + { + // Release the temporary variable now + ReleaseTemporaryVariable(args[n]->type, &ctx->bc); + } + + // Move the argument's deferred expressions over to the final expression + for( asUINT m = 0; m < args[n]->deferredParams.GetLength(); m++ ) + { + ctx->deferredParams.PushLast(args[n]->deferredParams[m]); + args[n]->deferredParams[m].origExpr = 0; + } + args[n]->deferredParams.SetLength(0); + } +} + +void asCCompiler::ProcessDeferredParams(asCExprContext *ctx) +{ + if( isProcessingDeferredParams ) return; + + isProcessingDeferredParams = true; + + for( asUINT n = 0; n < ctx->deferredParams.GetLength(); n++ ) + { + asSDeferredParam outParam = ctx->deferredParams[n]; + if( outParam.argInOutFlags < asTM_OUTREF ) // &in, or not reference + { + // Just release the variable + ReleaseTemporaryVariable(outParam.argType, &ctx->bc); + } + else if( outParam.argInOutFlags == asTM_OUTREF ) + { + asCExprContext *expr = outParam.origExpr; + outParam.origExpr = 0; + + if( outParam.argType.dataType.IsObjectHandle() ) + { + // Implicitly convert the value to a handle + if( expr->type.dataType.IsObjectHandle() ) + expr->type.isExplicitHandle = true; + } + + // Verify that the expression result in a lvalue, or a property accessor + if( IsLValue(expr->type) || expr->property_get || expr->property_set ) + { + asCExprContext rctx(engine); + rctx.type = outParam.argType; + if( rctx.type.dataType.IsPrimitive() ) + rctx.type.dataType.MakeReference(false); + else + { + rctx.bc.InstrSHORT(asBC_PSF, outParam.argType.stackOffset); + rctx.type.dataType.MakeReference(IsVariableOnHeap(outParam.argType.stackOffset)); + if( expr->type.isExplicitHandle ) + rctx.type.isExplicitHandle = true; + } + + asCExprContext o(engine); + DoAssignment(&o, expr, &rctx, outParam.argNode, outParam.argNode, ttAssignment, outParam.argNode); + + if( !o.type.dataType.IsPrimitive() ) o.bc.Instr(asBC_PopPtr); + + // The assignment may itself have resulted in a new temporary variable, e.g. if + // the opAssign returns a non-reference. We must release this temporary variable + // since it won't be used + ReleaseTemporaryVariable(o.type, &o.bc); + + MergeExprBytecode(ctx, &o); + } + else + { + // We must still evaluate the expression + MergeExprBytecode(ctx, expr); + if( !expr->IsVoidExpression() && (!expr->type.isConstant || expr->type.IsNullConstant()) ) + ctx->bc.Instr(asBC_PopPtr); + + // Give an error, except if the argument is void, null or 0 which indicate the argument is explicitly to be ignored + if( !expr->IsVoidExpression() && !expr->type.IsNullConstant() && + !(expr->type.isConstant && expr->type.dataType.IsPrimitive() && expr->type.GetConstantData() == 0) ) + Error(TXT_ARG_NOT_LVALUE, outParam.argNode); + + ReleaseTemporaryVariable(outParam.argType, &ctx->bc); + } + + ReleaseTemporaryVariable(expr->type, &ctx->bc); + + // Delete the original expression context + asDELETE(expr, asCExprContext); + } + else // &inout + { + if( outParam.argType.isTemporary ) + ReleaseTemporaryVariable(outParam.argType, &ctx->bc); + else if( !outParam.argType.isVariable ) + { + if( outParam.argType.dataType.IsObject() && + ((outParam.argType.dataType.GetBehaviour()->addref && + outParam.argType.dataType.GetBehaviour()->release) || + (outParam.argType.dataType.GetTypeInfo()->flags & asOBJ_NOCOUNT)) ) + { + // Release the object handle that was taken to guarantee the reference + ReleaseTemporaryVariable(outParam.argType, &ctx->bc); + } + } + } + } + + ctx->deferredParams.SetLength(0); + isProcessingDeferredParams = false; +} + + +int asCCompiler::CompileConstructCall(asCScriptNode *node, asCExprContext *ctx) +{ + // The first node is a datatype node + asCString name; + asCExprValue tempObj; + bool onHeap = true; + asCArray funcs; + bool error = false; + + // It is possible that the name is really a constructor + asCDataType dt; + dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType); + if( dt.IsPrimitive() ) + { + // This is a cast to a primitive type + return CompileConversion(node, ctx); + } + + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE) ) + { + // Types declared as implicit handle must not attempt to construct a handle + dt.MakeHandle(false); + } + + // Don't accept syntax like object@(expr) + if( dt.IsObjectHandle() ) + { + asCString str; + str.Format(TXT_CANT_CONSTRUCT_s_USE_REF_CAST, dt.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + + // Make sure the desired type can actually be instantiated + // Delegates are allowed to be created through construct calls, + // even though they cannot be instantiated as variables + if( !dt.CanBeInstantiated() && !dt.IsFuncdef() ) + { + asCString str; + if( dt.IsAbstractClass() ) + str.Format(TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf()); + else if( dt.IsInterface() ) + str.Format(TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED, dt.Format(outFunc->nameSpace).AddressOf()); + else + // TODO: Improve error message to explain why + str.Format(TXT_DATA_TYPE_CANT_BE_s, dt.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + + // Do not allow constructing non-shared types in shared functions + if( outFunc->IsShared() && + dt.GetTypeInfo() && !dt.GetTypeInfo()->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s, dt.GetTypeInfo()->name.AddressOf()); + Error(msg, node); + return -1; + } + + // Compile the arguments + asCArray args; + asCArray namedArgs; + asCArray temporaryVariables; + if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) + { + // Check for a value cast behaviour + if( args.GetLength() == 1 ) + { + asCExprContext conv(engine); + conv.Copy(args[0]); + asUINT cost = ImplicitConversion(&conv, dt, node->lastChild, asIC_EXPLICIT_VAL_CAST, false); + + // Clean the property_arg in the temporary copy so + // it isn't deleted when conv goes out of scope + conv.property_arg = 0; + + // Don't use this if the cost is 0 because it would mean that nothing + // is done and the script wants a new value to be constructed + if( conv.type.dataType.IsEqualExceptRef(dt) && cost > 0 ) + { + // Make sure the result is a reference, just as if to a local variable + dt.MakeReference(true); + + // Make sure any property accessor is already evaluated + if( ProcessPropertyGetAccessor(args[0], args[0]->exprNode) < 0 ) + return -1; + + ImplicitConversion(args[0], dt, node->lastChild, asIC_EXPLICIT_VAL_CAST); + + ctx->bc.AddCode(&args[0]->bc); + ctx->type = args[0]->type; + + asDELETE(args[0], asCExprContext); + + return 0; + } + } + + // Check for possible constructor/factory + name = dt.Format(outFunc->nameSpace); + + asSTypeBehaviour *beh = dt.GetBehaviour(); + + if( !(dt.GetTypeInfo()->flags & asOBJ_REF) && !dt.IsFuncdef() ) + { + funcs = beh->constructors; + + // Value types and script types are allocated through the constructor + tempObj.dataType = dt; + tempObj.stackOffset = (short)AllocateVariable(dt, true); + tempObj.dataType.MakeReference(true); + tempObj.isTemporary = true; + tempObj.isVariable = true; + + onHeap = IsVariableOnHeap(tempObj.stackOffset); + + // Push the address of the object on the stack + if( onHeap ) + ctx->bc.InstrSHORT(asBC_VAR, tempObj.stackOffset); + } + else if( beh ) + funcs = beh->factories; + + // Special case: Allow calling func(void) with a void expression. + if( args.GetLength() == 1 && args[0]->type.dataType == asCDataType::CreatePrimitive(ttVoid, false) ) + { + // Evaluate the expression before the function call + MergeExprBytecode(ctx, args[0]); + asDELETE(args[0], asCExprContext); + args.SetLength(0); + } + + // Special case: If this is an object constructor and there are no arguments use the default constructor. + // If none has been registered, just allocate the variable and push it on the stack. + if( args.GetLength() == 0 ) + { + beh = tempObj.dataType.GetBehaviour(); + if( beh && beh->construct == 0 && !(dt.GetTypeInfo()->flags & asOBJ_REF) ) + { + // Call the default constructor + ctx->type = tempObj; + + if( onHeap ) + { + asASSERT(ctx->bc.GetLastInstr() == asBC_VAR); + ctx->bc.RemoveLastInstr(); + } + + CallDefaultConstructor(tempObj.dataType, tempObj.stackOffset, IsVariableOnHeap(tempObj.stackOffset), &ctx->bc, node); + + // Push the reference on the stack + ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + return 0; + } + } + + // Special case: If this is a construction of a delegate and the expression names an object method + if( dt.IsFuncdef() && args.GetLength() == 1 && args[0]->methodName != "" ) + { + // TODO: delegate: It is possible that the argument returns a function pointer already, in which + // case no object delegate will be created, but instead a delegate for a function pointer + // In theory a simple cast would be good in this case, but this is a construct call so it + // is expected that a new object is created. + + dt.MakeHandle(true); + ctx->type.Set(dt); + + // The delegate must be able to hold on to a reference to the object + if( !args[0]->type.dataType.SupportHandles() ) + { + Error(TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES, node); + error = true; + } + else + { + // Filter the available object methods to find the one that matches the func def + asCObjectType *type = CastToObjectType(args[0]->type.dataType.GetTypeInfo()); + asCScriptFunction *bestMethod = 0; + for( asUINT n = 0; n < type->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[type->methods[n]]; + + if( func->name != args[0]->methodName ) + continue; + + // If the expression is for a const object, then only const methods should be accepted + if( args[0]->type.dataType.IsReadOnly() && !func->IsReadOnly() ) + continue; + + if( func->IsSignatureExceptNameAndObjectTypeEqual(CastToFuncdefType(dt.GetTypeInfo())->funcdef) ) + { + bestMethod = func; + + // If the expression is non-const the non-const overloaded method has priority + if( args[0]->type.dataType.IsReadOnly() == func->IsReadOnly() ) + break; + } + } + + if( bestMethod ) + { + // The object pointer is already on the stack + MergeExprBytecode(ctx, args[0]); + + // Push the function pointer as an additional argument + ctx->bc.InstrPTR(asBC_FuncPtr, bestMethod); + + // Call the factory function for the delegate + asCArray delegateFuncs; + builder->GetFunctionDescriptions(DELEGATE_FACTORY, delegateFuncs, engine->nameSpaces[0]); + asASSERT(delegateFuncs.GetLength() == 1 ); + ctx->bc.Call(asBC_CALLSYS , delegateFuncs[0], 2*AS_PTR_SIZE); + + // Store the returned delegate in a temporary variable + int returnOffset = AllocateVariable(dt, true, false); + dt.MakeReference(true); + ctx->type.SetVariable(dt, returnOffset, true); + ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset); + + // Push a reference to the temporary variable on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset); + + // Clean up arguments + ReleaseTemporaryVariable(args[0]->type, &ctx->bc); + } + else + { + asCString msg; + msg.Format(TXT_NO_MATCHING_SIGNATURES_TO_s, CastToFuncdefType(dt.GetTypeInfo())->funcdef->GetDeclaration()); + Error(msg.AddressOf(), node); + error = true; + } + } + + // Clean-up arg + asDELETE(args[0], asCExprContext); + return error ? -1 : 0; + } + + MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, 0, false); + + if( funcs.GetLength() != 1 ) + { + // The error was reported by MatchFunctions() + error = true; + + // Dummy value + ctx->type.SetDummy(); + } + else + { + // TODO: Clean up: Merge this with MakeFunctionCall + + // Add the default values for arguments not explicitly supplied + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(dt.GetTypeInfo()), &namedArgs); + + if( r == asSUCCESS ) + { + asCByteCode objBC(engine); + + PrepareFunctionCall(funcs[0], &ctx->bc, args); + + MoveArgsToStack(funcs[0], &ctx->bc, args, false); + + if( !(dt.GetTypeInfo()->flags & asOBJ_REF) ) + { + // If the object is allocated on the stack, then call the constructor as a normal function + if( onHeap ) + { + int offset = 0; + asCScriptFunction *descr = builder->GetFunctionDescription(funcs[0]); + for( asUINT n = 0; n < args.GetLength(); n++ ) + offset += descr->parameterTypes[n].GetSizeOnStackDWords(); + + ctx->bc.InstrWORD(asBC_GETREF, (asWORD)offset); + } + else + ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + + PerformFunctionCall(funcs[0], ctx, onHeap, &args, CastToObjectType(tempObj.dataType.GetTypeInfo())); + + // Add tag that the object has been initialized + ctx->bc.ObjInfo(tempObj.stackOffset, asOBJ_INIT); + + // The constructor doesn't return anything, + // so we have to manually inform the type of + // the return value + ctx->type = tempObj; + if( !onHeap ) + ctx->type.dataType.MakeReference(false); + + // Push the address of the object on the stack again + ctx->bc.InstrSHORT(asBC_PSF, tempObj.stackOffset); + } + else + { + // Call the factory to create the reference type + PerformFunctionCall(funcs[0], ctx, false, &args); + } + } + else + error = true; + } + } + else + { + // Failed to compile the argument list, set the result to the dummy type + ctx->type.SetDummy(); + error = true; + } + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + + return error ? -1 : 0; +} + + +int asCCompiler::CompileFunctionCall(asCScriptNode *node, asCExprContext *ctx, asCObjectType *objectType, bool objIsConst, const asCString &scope) +{ + asCExprValue tempObj; + asCArray funcs; + int localVar = -1; + bool initializeMembers = false; + asCExprContext funcExpr(engine); + + asCScriptNode *nm = node->lastChild->prev; + asCString name(&script->code[nm->tokenPos], nm->tokenLength); + + // Find the matching entities + // If objectType is set then this is a post op expression and we shouldn't look for local variables + asCExprContext lookupResult(engine); + SYMBOLTYPE symbolType = SymbolLookup(name, scope, objectType, &lookupResult); + if (symbolType < 0) + return -1; + if (symbolType == SL_NOMATCH) + { + // No matching symbol + asCString msg; + asCString smbl; + if (scope == "::") + smbl = scope; + else if (scope != "") + smbl = scope + "::"; + smbl += name; + msg.Format(TXT_NO_MATCHING_SYMBOL_s, smbl.AddressOf()); + Error(msg, node); + return -1; + } + + // Is the symbol matching a variable/property? + if (symbolType == SL_LOCALCONST || symbolType == SL_LOCALVAR || + symbolType == SL_THISPTR || symbolType == SL_CLASSPROPACCESS || symbolType == SL_CLASSPROP || + symbolType == SL_GLOBALPROPACCESS || symbolType == SL_GLOBALCONST || symbolType == SL_GLOBALVAR || symbolType == SL_ENUMVAL) + { + // Variables/properties can be used as functions if they have the opCall + + // Compile the variable + // TODO: Take advantage of the known symbol, so it doesn't have to be looked up again + localVar = CompileVariableAccess(name, scope, &funcExpr, node, false, objectType); + if( localVar < 0 ) + return -1; + + if (funcExpr.type.dataType.IsFuncdef()) + { + funcs.PushLast(CastToFuncdefType(funcExpr.type.dataType.GetTypeInfo())->funcdef->id); + } + else if (funcExpr.type.dataType.IsObject()) + { + // Keep information about temporary variables as deferred expression so it can be properly cleaned up after the call + if (ctx->type.isTemporary) + { + asASSERT(objectType); + + asSDeferredParam deferred; + deferred.origExpr = 0; + deferred.argInOutFlags = asTM_INREF; + deferred.argNode = 0; + deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true); + + ctx->deferredParams.PushLast(deferred); + } + if (funcExpr.property_get == 0) + Dereference(ctx, true); + + // Add the bytecode for accessing the object on which opCall will be called + if (ctx->type.dataType.IsObject()) + { + // Make sure the ProcessPropertyGetAccess knows whether or not to + // dereference the original object before calling the get accessor + funcExpr.property_ref = ctx->type.dataType.IsReference(); + } + MergeExprBytecodeAndType(ctx, &funcExpr); + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + Dereference(ctx, true); + + objectType = CastToObjectType(funcExpr.type.dataType.GetTypeInfo()); + + // Get the opCall methods from the object type + if (funcExpr.type.dataType.IsObjectHandle()) + objIsConst = funcExpr.type.dataType.IsHandleToConst(); + else + objIsConst = funcExpr.type.dataType.IsReadOnly(); + + builder->GetObjectMethodDescriptions("opCall", CastToObjectType(funcExpr.type.dataType.GetTypeInfo()), funcs, objIsConst); + } + else + { + // The variable is not a function or object with opCall + asCString msg; + msg.Format(TXT_NOT_A_FUNC_s_IS_TYPE_s, name.AddressOf(), lookupResult.type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(msg, node); + return -1; + } + } + + // Is the symbol matching a class method? + if (symbolType == SL_CLASSMETHOD) + { + // If we're compiling a constructor and the name of the function is super then + // the constructor of the base class is being called. + // super cannot be prefixed with a scope operator + if (scope == "" && m_isConstructor && name == SUPER_TOKEN) + { + // If the class is not derived from anyone else, calling super should give an error + if (outFunc && outFunc->objectType->derivedFrom) + funcs = outFunc->objectType->derivedFrom->beh.constructors; + + // Must not allow calling base class' constructor multiple times + if (continueLabels.GetLength() > 0) + { + // If a continue label is set we are in a loop + Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS, node); + } + else if (breakLabels.GetLength() > 0) + { + // TODO: inheritance: Should eventually allow constructors in switch statements + // If a break label is set we are either in a loop or a switch statements + Error(TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH, node); + } + else if (m_isConstructorCalled) + { + Error(TXT_CANNOT_CALL_CONSTRUCTOR_TWICE, node); + } + m_isConstructorCalled = true; + + // We need to initialize the class members, but only after all the deferred arguments have been completed + initializeMembers = true; + } + else + { + // The scope can be used to specify the base class + builder->GetObjectMethodDescriptions(name.AddressOf(), CastToObjectType(lookupResult.type.dataType.GetTypeInfo()), funcs, objIsConst, scope, node, script); + } + + // If a class method is being called implicitly, then add the this pointer for the call + if (funcs.GetLength() && !objectType && outFunc->objectType) + { + // Verify that the identified function is actually part of the class hierarchy + if (!outFunc->objectType->DerivesFrom(lookupResult.type.dataType.GetTypeInfo())) + { + asCString msg; + asCString mthd; + if (scope == "") + mthd = name; + else if (scope == "::") + mthd = scope + name; + else + mthd = scope + "::" + name; + + msg.Format(TXT_METHOD_s_NOT_PART_OF_OBJECT_s, mthd.AddressOf(), outFunc->objectType->name.AddressOf()); + Error(msg, node); + return -1; + } + + objectType = outFunc->objectType; + + asCDataType dt = asCDataType::CreateType(objectType, false); + + // The object pointer is located at stack position 0 + ctx->bc.InstrSHORT(asBC_PSF, 0); + ctx->type.SetVariable(dt, 0, false); + ctx->type.dataType.MakeReference(true); + + Dereference(ctx, true); + } + else if (funcs.GetLength() && !objectType && !outFunc->objectType) + { + // Cannot call class methods directly without the object + asCString msg; + msg.Format(TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s, name.AddressOf()); + Error(msg, node); + return -1; + } + } + + // Is it a global function? + if (symbolType == SL_GLOBALFUNC) + { + // The symbol lookup identified the namespace to use + int n = lookupResult.methodName.FindLast("::"); + asSNameSpace *ns = engine->FindNameSpace(lookupResult.methodName.SubString(0, n).AddressOf()); + + builder->GetFunctionDescriptions(name.AddressOf(), funcs, ns); + } + + // Is it a type? + if (symbolType == SL_CLASSTYPE || symbolType == SL_GLOBALTYPE) + { + bool isValid = false; + asCDataType dt = builder->CreateDataTypeFromNode(node->firstChild, script, outFunc->nameSpace, false, outFunc->objectType, false, &isValid); + if (isValid) + return CompileConstructCall(node, ctx); + } + + // Compile the arguments + asCArray args; + asCArray namedArgs; + + bool isOK = true; + if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) + { + // Special case: Allow calling func(void) with an expression that evaluates to no datatype, but isn't exactly 'void' + if( args.GetLength() == 1 && args[0]->type.IsVoid() && !args[0]->IsVoidExpression() ) + { + // Evaluate the expression before the function call + MergeExprBytecode(ctx, args[0]); + asDELETE(args[0], asCExprContext); + args.SetLength(0); + } + + MatchFunctions(funcs, args, node, name.AddressOf(), &namedArgs, objectType, objIsConst, false, true, scope); + + if( funcs.GetLength() != 1 ) + { + // The error was reported by MatchFunctions() + + // Dummy value + ctx->type.SetDummy(); + isOK = false; + } + else + { + // Add the default values for arguments not explicitly supplied + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType, &namedArgs); + + // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or + // is it enough to make sure it is in a local variable? + + // For function pointer we must guarantee that the function is safe, i.e. + // by first storing the function pointer in a local variable (if it isn't already in one) + if( r == asSUCCESS ) + { + asCScriptFunction *func = builder->GetFunctionDescription(funcs[0]); + if( func->funcType == asFUNC_FUNCDEF ) + { + if( objectType && funcExpr.property_get <= 0 ) + { + // Dereference the object pointer to access the member + Dereference(ctx, true); + } + + if( funcExpr.property_get > 0 ) + { + if( ProcessPropertyGetAccessor(&funcExpr, node) < 0 ) + return -1; + Dereference(&funcExpr, true); + } + else + { + Dereference(&funcExpr, true); + ConvertToVariable(&funcExpr); + } + + // The actual function should be called as if a global function + objectType = 0; + + // The function call will be made directly from the local variable so the function pointer shouldn't be on the stack + funcExpr.bc.Instr(asBC_PopPtr); + + asCExprValue tmp = ctx->type; + MergeExprBytecodeAndType(ctx, &funcExpr); + ReleaseTemporaryVariable(tmp, &ctx->bc); + } + + r = MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, funcExpr.type.stackOffset); + if( r < 0 ) + { + ctx->type.SetDummy(); + isOK = false; + } + } + else + isOK = false; + } + } + else + { + // Failed to compile the argument list, set the dummy type and continue compilation + ctx->type.SetDummy(); + isOK = false; + } + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + + if( initializeMembers ) + { + asASSERT( m_isConstructor ); + + // Need to initialize members here, as they may use the properties of the base class + // If there are multiple paths that call super(), then there will also be multiple + // locations with initializations of the members. It is not possible to consolidate + // these in one place, as the expressions for the initialization are evaluated where + // they are compiled, which means that they may access different variables depending + // on the scope where super() is called. + // Members that don't have an explicit initialization expression will be initialized + // beginning of the constructor as they are guaranteed not to use at the any + // members of the base class. + CompileMemberInitialization(&ctx->bc, false); + } + + return isOK ? 0 : -1; +} + +asSNameSpace *asCCompiler::DetermineNameSpace(const asCString &scope) +{ + asSNameSpace *ns; + + if( scope == "" ) + { + // When compiling default argument expression the correct namespace is stored in the outFunc even for objects + if( outFunc->nameSpace->name != "" || isCompilingDefaultArg ) + ns = outFunc->nameSpace; + else if( outFunc->objectType && outFunc->objectType->nameSpace->name != "" ) + ns = outFunc->objectType->nameSpace; + else + ns = engine->nameSpaces[0]; + } + else if( scope == "::" ) + ns = engine->nameSpaces[0]; + else + ns = engine->FindNameSpace(scope.AddressOf()); + + return ns; +} + +int asCCompiler::CompileExpressionPreOp(asCScriptNode *node, asCExprContext *ctx) +{ + int op = node->tokenType; + + // Don't allow any prefix operators except handle on expressions that take address of class method + if( ctx->IsClassMethod() && op != ttHandle ) + { + Error(TXT_INVALID_OP_ON_METHOD, node); + return -1; + } + + // Don't allow any operators on void expressions + if( ctx->IsVoidExpression() ) + { + Error(TXT_VOID_CANT_BE_OPERAND, node); + return -1; + } + + IsVariableInitialized(&ctx->type, node); + + if( op == ttHandle ) + { + if( ctx->methodName != "" ) + { + // Don't allow taking the handle of a handle + if( ctx->type.isExplicitHandle ) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); + return -1; + } + } + else + { + // Don't allow taking handle of a handle, i.e. @@ + if( ctx->type.isExplicitHandle ) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); + return -1; + } + + // @null is allowed even though it is implicit + if( !ctx->type.IsNullConstant() ) + { + // Verify that the type allow its handle to be taken + if( !ctx->type.dataType.SupportHandles() && !ctx->type.dataType.IsObjectHandle() ) + { + Error(TXT_OBJECT_HANDLE_NOT_SUPPORTED, node); + return -1; + } + + // Objects that are not local variables are not references + // Objects allocated on the stack are also not marked as references + if( !ctx->type.dataType.IsReference() && + !((ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.isVariable) && + !(ctx->type.isVariable && !IsVariableOnHeap(ctx->type.stackOffset)) ) + { + Error(TXT_NOT_VALID_REFERENCE, node); + return -1; + } + + // Convert the expression to a handle + if( !ctx->type.dataType.IsObjectHandle() && !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) + { + asCDataType to = ctx->type.dataType; + to.MakeHandle(true); + to.MakeReference(true); + to.MakeHandleToConst(ctx->type.dataType.IsReadOnly()); + ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV, true, false); + + asASSERT( ctx->type.dataType.IsObjectHandle() ); + } + else if( ctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE ) + { + // For the ASHANDLE type we'll simply set the expression as a handle + ctx->type.dataType.MakeHandle(true); + } + } + } + + // Mark the expression as an explicit handle to avoid implicit conversions to non-handle expressions + ctx->type.isExplicitHandle = true; + } + else if( (op == ttMinus || op == ttPlus || op == ttBitNot || op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() ) + { + // Look for the appropriate method + // There is no overloadable operator for unary plus + const char *opName = 0; + switch( op ) + { + case ttMinus: opName = "opNeg"; break; + case ttBitNot: opName = "opCom"; break; + case ttInc: opName = "opPreInc"; break; + case ttDec: opName = "opPreDec"; break; + } + + if( opName ) + { + // TODO: Should convert this to something similar to CompileOverloadedDualOperator2 + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // TODO: If the value isn't const, then first try to find the non const method, and if not found try to find the const method + + // Find the correct method + bool isConst = ctx->type.dataType.IsObjectConst(); + asCArray funcs; + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( func->name == opName && + func->parameterTypes.GetLength() == 0 && + (!isConst || func->IsReadOnly()) ) + { + funcs.PushLast(func->id); + } + } + + // Did we find the method? + if( funcs.GetLength() == 1 ) + { + asCArray args; + return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + } + else if( funcs.GetLength() == 0 ) + { + asCString str; + str = asCString(opName) + "()"; + if( isConst ) + str += " const"; + str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + else if( funcs.GetLength() > 1 ) + { + Error(TXT_MORE_THAN_ONE_MATCHING_OP, node); + PrintMatchingFuncs(funcs, node); + + ctx->type.SetDummy(); + return -1; + } + } + else if( op == ttPlus ) + { + Error(TXT_ILLEGAL_OPERATION, node); + ctx->type.SetDummy(); + return -1; + } + } + else if( op == ttPlus || op == ttMinus ) + { + // This is only for primitives. Objects are treated in the above block + + // Make sure the type is a math type + if( !(ctx->type.dataType.IsIntegerType() || + ctx->type.dataType.IsUnsignedType() || + ctx->type.dataType.IsFloatType() || + ctx->type.dataType.IsDoubleType() ) ) + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + + + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + asCDataType to = ctx->type.dataType; + + if( ctx->type.dataType.IsUnsignedType() ) + { + if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) + to = asCDataType::CreatePrimitive(ttInt8, false); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) + to = asCDataType::CreatePrimitive(ttInt16, false); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) + to = asCDataType::CreatePrimitive(ttInt, false); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 ) + to = asCDataType::CreatePrimitive(ttInt64, false); + else + { + Error(TXT_INVALID_TYPE, node); + return -1; + } + } + + if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); + + // Use an explicit conversion in case of constants to avoid unnecessary warning about change of sign + ImplicitConversion(ctx, to, node, ctx->type.isConstant ? asIC_EXPLICIT_VAL_CAST : asIC_IMPLICIT_CONV); + + if( !ctx->type.isConstant ) + { + ConvertToTempVariable(ctx); + asASSERT(!ctx->type.isLValue); + + if( op == ttMinus ) + { + if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + ctx->bc.InstrSHORT(asBC_NEGi, ctx->type.stackOffset); + else if( ctx->type.dataType.IsIntegerType() && ctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + ctx->bc.InstrSHORT(asBC_NEGi64, ctx->type.stackOffset); + else if( ctx->type.dataType.IsFloatType() ) + ctx->bc.InstrSHORT(asBC_NEGf, ctx->type.stackOffset); + else if( ctx->type.dataType.IsDoubleType() ) + ctx->bc.InstrSHORT(asBC_NEGd, ctx->type.stackOffset); + else + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + + return 0; + } + } + else + { + if( op == ttMinus ) + { + if (ctx->type.dataType.IsIntegerType()) + { + if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) + ctx->type.SetConstantDW(-(int)ctx->type.GetConstantDW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) + ctx->type.SetConstantW(-(asINT16)ctx->type.GetConstantW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 1) + ctx->type.SetConstantB(-(asINT8)ctx->type.GetConstantB()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 8) + ctx->type.SetConstantQW(-(asINT64)ctx->type.GetConstantQW()); + } + else if( ctx->type.dataType.IsFloatType() ) + ctx->type.SetConstantF(-ctx->type.GetConstantF()); + else if( ctx->type.dataType.IsDoubleType() ) + ctx->type.SetConstantD(-ctx->type.GetConstantD()); + else + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + + return 0; + } + } + } + else if( op == ttNot ) + { + // Allow value types to be converted to bool using 'bool opImplConv()' + if( ctx->type.dataType.GetTypeInfo() && (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(ctx, asCDataType::CreatePrimitive(ttBool, false), node, asIC_IMPLICIT_CONV); + + if( ctx->type.dataType.IsEqualExceptRefAndConst(asCDataType::CreatePrimitive(ttBool, true)) ) + { + if( ctx->type.isConstant ) + { + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(ctx->type.GetConstantB() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + #else + ctx->type.SetConstantDW(ctx->type.GetConstantDW() == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + #endif + return 0; + } + + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + ConvertToTempVariable(ctx); + asASSERT(!ctx->type.isLValue); + + ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset); + } + else + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + } + else if( op == ttBitNot ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + asCDataType to = ctx->type.dataType; + + if( ctx->type.dataType.IsIntegerType() ) + { + if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) + to = asCDataType::CreatePrimitive(ttUInt8, false); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) + to = asCDataType::CreatePrimitive(ttUInt16, false); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) + to = asCDataType::CreatePrimitive(ttUInt, false); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 8 ) + to = asCDataType::CreatePrimitive(ttUInt64, false); + else + { + Error(TXT_INVALID_TYPE, node); + return -1; + } + } + + if( ctx->type.dataType.IsReference() ) ConvertToVariable(ctx); + ImplicitConversion(ctx, to, node, asIC_IMPLICIT_CONV); + + if( ctx->type.dataType.IsUnsignedType() ) + { + if( ctx->type.isConstant ) + { + if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) + ctx->type.SetConstantB(~ctx->type.GetConstantB()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 2) + ctx->type.SetConstantW(~ctx->type.GetConstantW()); + else if (ctx->type.dataType.GetSizeInMemoryBytes() == 4) + ctx->type.SetConstantDW(~ctx->type.GetConstantDW()); + else + ctx->type.SetConstantQW(~ctx->type.GetConstantQW()); + return 0; + } + + ConvertToTempVariable(ctx); + asASSERT(!ctx->type.isLValue); + + if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + ctx->bc.InstrSHORT(asBC_BNOT, ctx->type.stackOffset); + else + ctx->bc.InstrSHORT(asBC_BNOT64, ctx->type.stackOffset); + } + else + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + } + else if( op == ttInc || op == ttDec ) + { + // Need a reference to the primitive that will be updated + // The result of this expression is the same reference as before + + // Make sure the reference isn't a temporary variable + if( ctx->type.isTemporary ) + { + Error(TXT_REF_IS_TEMP, node); + return -1; + } + if( ctx->type.dataType.IsReadOnly() ) + { + Error(TXT_REF_IS_READ_ONLY, node); + return -1; + } + if( ctx->property_get || ctx->property_set ) + { + Error(TXT_INVALID_REF_PROP_ACCESS, node); + return -1; + } + if( !ctx->type.isLValue ) + { + Error(TXT_NOT_LVALUE, node); + return -1; + } + + if( ctx->type.isVariable && !ctx->type.dataType.IsReference() ) + ConvertToReference(ctx); + else if( !ctx->type.dataType.IsReference() ) + { + Error(TXT_NOT_VALID_REFERENCE, node); + return -1; + } + + if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) || + ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) ) + { + if( op == ttInc ) + ctx->bc.Instr(asBC_INCi64); + else + ctx->bc.Instr(asBC_DECi64); + } + else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt, false)) || + ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt, false)) ) + { + if( op == ttInc ) + ctx->bc.Instr(asBC_INCi); + else + ctx->bc.Instr(asBC_DECi); + } + else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) || + ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) ) + { + if( op == ttInc ) + ctx->bc.Instr(asBC_INCi16); + else + ctx->bc.Instr(asBC_DECi16); + } + else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) || + ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) ) + { + if( op == ttInc ) + ctx->bc.Instr(asBC_INCi8); + else + ctx->bc.Instr(asBC_DECi8); + } + else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttFloat, false)) ) + { + if( op == ttInc ) + ctx->bc.Instr(asBC_INCf); + else + ctx->bc.Instr(asBC_DECf); + } + else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttDouble, false)) ) + { + if( op == ttInc ) + ctx->bc.Instr(asBC_INCd); + else + ctx->bc.Instr(asBC_DECd); + } + else + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + } + else + { + // Unknown operator + asASSERT(false); + return -1; + } + + return 0; +} + +void asCCompiler::ConvertToReference(asCExprContext *ctx) +{ + if( ctx->type.isVariable && !ctx->type.dataType.IsReference() ) + { + ctx->bc.InstrSHORT(asBC_LDV, ctx->type.stackOffset); + ctx->type.dataType.MakeReference(true); + ctx->type.SetVariable(ctx->type.dataType, ctx->type.stackOffset, ctx->type.isTemporary); + } +} + +int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) +{ + return FindPropertyAccessor(name, ctx, 0, node, ns, isThisAccess); +} + +// Returns: +// 1 = a valid match was found +// 0 = no matching symbols (or feature disabled) +// -1 = ambiguous getters or setters, i.e. multiple methods match symbol name and signature +// -2 = mismatching type for getter and setter +// -3 = processing error, e.g. out of memory +int asCCompiler::FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess) +{ + // TODO: With asEP_PROPERTY_ACCESSOR_MODE == 3 this method doesn't need to validate the + // getter/setter as it is done at the time of declaration. Should deprecate the other options + + if( engine->ep.propertyAccessorMode == 0 ) + { + // Property accessors have been disabled by the application + return 0; + } + + int getId = 0, setId = 0; + asCString getName = "get_" + name; + asCString setName = "set_" + name; + asCArray multipleGetFuncs, multipleSetFuncs; + + if( ctx->type.dataType.IsObject() ) + { + asASSERT( ns == 0 ); + + // Don't look for property accessors in script classes if the script + // property accessors have been disabled by the application + if( !(ctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT) || + engine->ep.propertyAccessorMode >= 2 ) + { + // Check if the object has any methods with the corresponding accessor name(s) + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *f = engine->scriptFunctions[ot->methods[n]]; + + if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) + continue; + + // TODO: The type of the parameter should match the argument (unless the arg is a dummy) + if( f->name == getName && (int)f->parameterTypes.GetLength() == (arg?1:0) ) + { + if( getId == 0 ) + getId = ot->methods[n]; + else + { + if( multipleGetFuncs.GetLength() == 0 ) + multipleGetFuncs.PushLast(getId); + + multipleGetFuncs.PushLast(ot->methods[n]); + } + } + // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref? + if( f->name == setName && (int)f->parameterTypes.GetLength() == (arg?2:1) ) + { + if( setId == 0 ) + setId = ot->methods[n]; + else + { + if( multipleSetFuncs.GetLength() == 0 ) + multipleSetFuncs.PushLast(setId); + + multipleSetFuncs.PushLast(ot->methods[n]); + } + } + } + } + } + else + { + asASSERT( ns != 0 ); + + // Look for appropriate global functions. + asCArray funcs; + asUINT n; + builder->GetFunctionDescriptions(getName.AddressOf(), funcs, ns); + for( n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]); + + if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) + continue; + + // Ignore script functions, if the application has disabled script defined property accessors + if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT ) + continue; + + // TODO: The type of the parameter should match the argument (unless the arg is a dummy) + if( (int)f->parameterTypes.GetLength() == (arg?1:0) ) + { + if( getId == 0 ) + getId = funcs[n]; + else + { + if( multipleGetFuncs.GetLength() == 0 ) + multipleGetFuncs.PushLast(getId); + + multipleGetFuncs.PushLast(funcs[n]); + } + } + } + + funcs.SetLength(0); + builder->GetFunctionDescriptions(setName.AddressOf(), funcs, ns); + for( n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *f = builder->GetFunctionDescription(funcs[n]); + + if( engine->ep.propertyAccessorMode == 3 && !f->IsProperty() ) + continue; + + // Ignore script functions, if the application has disabled script defined property accessors + if( engine->ep.propertyAccessorMode == 1 && f->funcType == asFUNC_SCRIPT ) + continue; + + // TODO: getset: If the parameter is a reference, it must not be an out reference. Should we allow inout ref? + if( (int)f->parameterTypes.GetLength() == (arg?2:1) ) + { + if( setId == 0 ) + setId = funcs[n]; + else + { + if( multipleSetFuncs.GetLength() == 0 ) + multipleSetFuncs.PushLast(setId); + + multipleSetFuncs.PushLast(funcs[n]); + } + } + } + } + + bool isConst = ctx->type.dataType.IsObjectConst(); + + // Check for multiple matches + if( multipleGetFuncs.GetLength() > 0 ) + { + // Filter the list by constness + FilterConst(multipleGetFuncs, !isConst); + + if( multipleGetFuncs.GetLength() > 1 ) + { + if (node) + { + asCString str; + str.Format(TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s, name.AddressOf()); + Error(str, node); + + PrintMatchingFuncs(multipleGetFuncs, node); + } + + return -1; + } + else + { + // The id may have changed + getId = multipleGetFuncs[0]; + } + } + + if( multipleSetFuncs.GetLength() > 0 ) + { + // Filter the list by constness + FilterConst(multipleSetFuncs, !isConst); + + if( multipleSetFuncs.GetLength() > 1 ) + { + if (node) + { + asCString str; + str.Format(TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s, name.AddressOf()); + Error(str, node); + + PrintMatchingFuncs(multipleSetFuncs, node); + } + + return -1; + } + else + { + // The id may have changed + setId = multipleSetFuncs[0]; + } + } + + // Check for type compatibility between get and set accessor + if( getId && setId ) + { + asCScriptFunction *getFunc = builder->GetFunctionDescription(getId); + asCScriptFunction *setFunc = builder->GetFunctionDescription(setId); + + // It is permitted for a getter to return a handle and the setter to take a reference + int idx = (arg?1:0); + if( !getFunc->returnType.IsEqualExceptRefAndConst(setFunc->parameterTypes[idx]) && + !((getFunc->returnType.IsObjectHandle() && !setFunc->parameterTypes[idx].IsObjectHandle()) && + (getFunc->returnType.GetTypeInfo() == setFunc->parameterTypes[idx].GetTypeInfo())) ) + { + if (node) + { + asCString str; + str.Format(TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s, name.AddressOf()); + Error(str, node); + + asCArray funcs; + funcs.PushLast(getId); + funcs.PushLast(setId); + + PrintMatchingFuncs(funcs, node); + } + + return -2; + } + } + + // Check if we are within one of the accessors + int realGetId = getId; + int realSetId = setId; + if( outFunc->objectType && isThisAccess ) + { + // The property accessors would be virtual functions, so we need to find the real implementation + asCScriptFunction *getFunc = getId ? builder->GetFunctionDescription(getId) : 0; + if( getFunc && + getFunc->funcType == asFUNC_VIRTUAL && + outFunc->objectType->DerivesFrom(getFunc->objectType) ) + realGetId = outFunc->objectType->virtualFunctionTable[getFunc->vfTableIdx]->id; + asCScriptFunction *setFunc = setId ? builder->GetFunctionDescription(setId) : 0; + if( setFunc && + setFunc->funcType == asFUNC_VIRTUAL && + outFunc->objectType->DerivesFrom(setFunc->objectType) ) + realSetId = outFunc->objectType->virtualFunctionTable[setFunc->vfTableIdx]->id; + } + + // Avoid recursive call by not treating this as a property accessor call. + // This will also allow having the real property with the same name as the accessors. + if( (isThisAccess || outFunc->objectType == 0) && + ((realGetId && realGetId == outFunc->id) || + (realSetId && realSetId == outFunc->id)) ) + { + getId = 0; + setId = 0; + } + + if( getId || setId ) + { + // Property accessors were found, but we don't know which is to be used yet, so + // we just prepare the bytecode for the method call, and then store the function ids + // so that the right one can be used when we get there. + ctx->property_get = getId; + ctx->property_set = setId; + + bool isRefSafe = ctx->type.isRefSafe; + + if( ctx->type.dataType.IsObject() ) + { + // If the object is read-only then we need to remember that + if( (!ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsReadOnly()) || + (ctx->type.dataType.IsObjectHandle() && ctx->type.dataType.IsHandleToConst()) ) + ctx->property_const = true; + else + ctx->property_const = false; + + // If the object is a handle then we need to remember that + ctx->property_handle = ctx->type.dataType.IsObjectHandle(); + ctx->property_ref = ctx->type.dataType.IsReference(); + } + + // The setter's parameter type is used as the property type, + // unless only the getter is available + asCDataType dt; + if( setId ) + dt = builder->GetFunctionDescription(setId)->parameterTypes[(arg?1:0)]; + else + dt = builder->GetFunctionDescription(getId)->returnType; + + // Just change the type, the context must still maintain information + // about previous variable offset and the indicator of temporary variable. + int offset = ctx->type.stackOffset; + bool isTemp = ctx->type.isTemporary; + ctx->type.Set(dt); + ctx->type.stackOffset = (short)offset; + ctx->type.isTemporary = isTemp; + ctx->exprNode = node; + + // Remember if the object is safe, so the invocation of the property + // accessor doesn't needlessly make a safe copy of the handle + ctx->type.isRefSafe = isRefSafe; + + // Store the argument for later use + if( arg ) + { + ctx->property_arg = asNEW(asCExprContext)(engine); + if( ctx->property_arg == 0 ) + { + // Out of memory + return -3; + } + + MergeExprBytecodeAndType(ctx->property_arg, arg); + } + + return 1; + } + + // No accessor was found + return 0; +} + +int asCCompiler::ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node) +{ + // TODO: A lot of this code is similar to ProcessPropertyGetAccessor. Can we unify them? + + if( !ctx->property_set ) + { + Error(TXT_PROPERTY_HAS_NO_SET_ACCESSOR, node); + return -1; + } + + asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_set); + + // Make sure the arg match the property + asCArray funcs; + funcs.PushLast(ctx->property_set); + asCArray args; + if( ctx->property_arg ) + args.PushLast(ctx->property_arg); + args.PushLast(arg); + MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const); + if( funcs.GetLength() == 0 ) + { + // MatchFunctions already reported the error + if( ctx->property_arg ) + { + asDELETE(ctx->property_arg, asCExprContext); + ctx->property_arg = 0; + } + return -1; + } + + if( func->objectType ) + { + // Setup the context with the original type so the method call gets built correctly + ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const); + if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); + if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); + + // Don't allow the call if the object is read-only and the property accessor is not const + if( ctx->property_const && !func->IsReadOnly() ) + { + Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); + asCArray funcCandidates; + funcCandidates.PushLast(ctx->property_set); + PrintMatchingFuncs(funcCandidates, node); + } + } + + // Call the accessor + int r = MakeFunctionCall(ctx, ctx->property_set, func->objectType, args, node); + + ctx->property_get = 0; + ctx->property_set = 0; + if( ctx->property_arg ) + { + asDELETE(ctx->property_arg, asCExprContext); + ctx->property_arg = 0; + } + + return r; +} + +int asCCompiler::ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode) +{ + // TODO: Perhaps it might be interesting to allow the definition of compound setters for better + // performance, e.g. set_add_prop, set_mul_prop, etc. With these it would also be possible + // to support value types, since it would be a single call + + // Compound assignment for indexed property accessors is not supported yet + if( lctx->property_arg != 0 ) + { + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + Error(TXT_COMPOUND_ASGN_WITH_IDX_PROP, errNode); + return -1; + } + + // Compound assignments require both get and set accessors + if( lctx->property_set == 0 || lctx->property_get == 0 ) + { + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + Error(TXT_COMPOUND_ASGN_REQUIRE_GET_SET, errNode); + return -1; + } + + // Property accessors on value types (or scoped references types) are not supported since + // it is not possible to guarantee that the object will stay alive between the two calls + asCScriptFunction *func = engine->scriptFunctions[lctx->property_set]; + if( func->objectType && (func->objectType->flags & (asOBJ_VALUE | asOBJ_SCOPED)) ) + { + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + Error(TXT_COMPOUND_ASGN_ON_VALUE_TYPE, errNode); + return -1; + } + + // Translate the compound assignment to the corresponding dual operator + switch( op ) + { + case ttAddAssign: op = ttPlus; break; + case ttSubAssign: op = ttMinus; break; + case ttMulAssign: op = ttStar; break; + case ttDivAssign: op = ttSlash; break; + case ttModAssign: op = ttPercent; break; + case ttPowAssign: op = ttStarStar; break; + + case ttAndAssign: op = ttAmp; break; + case ttOrAssign: op = ttBitOr; break; + case ttXorAssign: op = ttBitXor; break; + + case ttShiftLeftAssign: op = ttBitShiftLeft; break; + case ttShiftRightAAssign: op = ttBitShiftRightArith; break; + case ttShiftRightLAssign: op = ttBitShiftRight; break; + + default: op = ttUnrecognizedToken; break; + } + + if( op == ttUnrecognizedToken ) + { + // Shouldn't happen + asASSERT(false); + + // Process the property to free the memory + ProcessPropertySetAccessor(lctx, rctx, errNode); + return -1; + } + + asCExprContext before(engine); + if( func->objectType && (func->objectType->flags & (asOBJ_REF|asOBJ_SCOPED)) == asOBJ_REF ) + { + // Keep a reference to the object in a local variable + before.bc.AddCode(&lctx->bc); + + asUINT len = reservedVariables.GetLength(); + rctx->bc.GetVarsUsed(reservedVariables); + before.bc.GetVarsUsed(reservedVariables); + + asCDataType dt = asCDataType::CreateObjectHandle(func->objectType, false); + int offset = AllocateVariable(dt, true); + + reservedVariables.SetLength(len); + + before.type.SetVariable(dt, offset, true); + + if( lctx->property_ref ) + before.bc.Instr(asBC_RDSPtr); + before.bc.InstrSHORT(asBC_PSF, (short)offset); + before.bc.InstrPTR(asBC_REFCPY, func->objectType); + before.bc.Instr(asBC_PopPtr); + + if( lctx->type.isTemporary ) + { + // Add the release of the temporary variable as a deferred expression + asSDeferredParam deferred; + deferred.origExpr = 0; + deferred.argInOutFlags = asTM_INREF; + deferred.argNode = 0; + deferred.argType.SetVariable(ctx->type.dataType, lctx->type.stackOffset, true); + before.deferredParams.PushLast(deferred); + } + + // Update the left expression to use the local variable + lctx->bc.InstrSHORT(asBC_PSF, (short)offset); + lctx->type.stackOffset = (short)offset; + lctx->property_ref = true; + + // Don't release the temporary variable too early + lctx->type.isTemporary = false; + + ctx->bc.AddCode(&before.bc); + } + + // Keep the original information on the property + asCExprContext llctx(engine); + llctx.type = lctx->type; + llctx.property_arg = lctx->property_arg; + llctx.property_const = lctx->property_const; + llctx.property_get = lctx->property_get; + llctx.property_handle = lctx->property_handle; + llctx.property_ref = lctx->property_ref; + llctx.property_set = lctx->property_set; + + // Compile the dual operator using the get accessor + CompileOperator(errNode, lctx, rctx, ctx, op, false); + + // If we made a local variable to hold the reference it must be reused + if( before.type.stackOffset ) + llctx.bc.InstrSHORT(asBC_PSF, before.type.stackOffset); + + // Compile the assignment using the set accessor + ProcessPropertySetAccessor(&llctx, ctx, errNode); + + MergeExprBytecodeAndType(ctx, &llctx); + + if( before.type.stackOffset ) + ReleaseTemporaryVariable(before.type.stackOffset, &ctx->bc); + + asASSERT( ctx->deferredParams.GetLength() == 0 ); + ctx->deferredParams = before.deferredParams; + ProcessDeferredParams(ctx); + + return 0; +} + +int asCCompiler::ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node) +{ + // If no property accessor has been prepared then don't do anything + if( !ctx->property_get && !ctx->property_set ) + return 0; + + if( !ctx->property_get ) + { + // Raise error on missing accessor + Error(TXT_PROPERTY_HAS_NO_GET_ACCESSOR, node); + return -1; + } + + asCExprValue objType = ctx->type; + asCScriptFunction *func = builder->GetFunctionDescription(ctx->property_get); + + // Make sure the arg match the property + asCArray funcs; + funcs.PushLast(ctx->property_get); + asCArray args; + if( ctx->property_arg ) + args.PushLast(ctx->property_arg); + MatchFunctions(funcs, args, node, func->GetName(), 0, func->objectType, ctx->property_const); + if( funcs.GetLength() == 0 ) + { + // MatchFunctions already reported the error + if( ctx->property_arg ) + { + asDELETE(ctx->property_arg, asCExprContext); + ctx->property_arg = 0; + } + return -1; + } + + if( func->objectType ) + { + // Setup the context with the original type so the method call gets built correctly + ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const); + if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); + if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); + + // Don't allow the call if the object is read-only and the property accessor is not const + if( ctx->property_const && !func->IsReadOnly() ) + { + Error(TXT_NON_CONST_METHOD_ON_CONST_OBJ, node); + asCArray funcCandidates; + funcCandidates.PushLast(ctx->property_get); + PrintMatchingFuncs(funcCandidates, node); + return -1; + } + } + + // The explicit handle flag must be remembered + bool isExplicitHandle = ctx->type.isExplicitHandle; + + // Call the accessor + int r = MakeFunctionCall(ctx, ctx->property_get, func->objectType, args, node); + if( isExplicitHandle ) + ctx->type.isExplicitHandle = true; + + // Clear the property get/set ids + ctx->property_get = 0; + ctx->property_set = 0; + if( ctx->property_arg ) + { + asDELETE(ctx->property_arg, asCExprContext); + ctx->property_arg = 0; + } + + return r; +} + +int asCCompiler::CompileExpressionPostOp(asCScriptNode *node, asCExprContext *ctx) +{ + // Don't allow any postfix operators on expressions that take address of class method + if( ctx->IsClassMethod() ) + { + Error(TXT_INVALID_OP_ON_METHOD, node); + return -1; + } + + // Don't allow any operators on void expressions + if( ctx->IsVoidExpression() ) + { + Error(TXT_VOID_CANT_BE_OPERAND, node); + return -1; + } + + // Check if the variable is initialized (if it indeed is a variable) + IsVariableInitialized(&ctx->type, node); + + int op = node->tokenType; + if( (op == ttInc || op == ttDec) && ctx->type.dataType.IsObject() ) + { + const char *opName = 0; + switch( op ) + { + case ttInc: opName = "opPostInc"; break; + case ttDec: opName = "opPostDec"; break; + } + + if( opName ) + { + // TODO: Should convert this to something similar to CompileOverloadedDualOperator2 + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // TODO: If the value isn't const, then first try to find the non const method, and if not found try to find the const method + + // Find the correct method + bool isConst = ctx->type.dataType.IsObjectConst(); + asCArray funcs; + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( func->name == opName && + func->parameterTypes.GetLength() == 0 && + (!isConst || func->IsReadOnly()) ) + { + funcs.PushLast(func->id); + } + } + + // Did we find the method? + if( funcs.GetLength() == 1 ) + { + asCArray args; + return MakeFunctionCall(ctx, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node); + } + else if( funcs.GetLength() == 0 ) + { + asCString str; + str = asCString(opName) + "()"; + if( isConst ) + str += " const"; + str.Format(TXT_FUNCTION_s_NOT_FOUND, str.AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + else if( funcs.GetLength() > 1 ) + { + Error(TXT_MORE_THAN_ONE_MATCHING_OP, node); + PrintMatchingFuncs(funcs, node); + + ctx->type.SetDummy(); + return -1; + } + } + } + else if( op == ttInc || op == ttDec ) + { + // Make sure the reference isn't a temporary variable + if( ctx->type.isTemporary ) + { + Error(TXT_REF_IS_TEMP, node); + return -1; + } + if( ctx->type.dataType.IsReadOnly() ) + { + Error(TXT_REF_IS_READ_ONLY, node); + return -1; + } + if( ctx->property_get || ctx->property_set ) + { + Error(TXT_INVALID_REF_PROP_ACCESS, node); + return -1; + } + if( !ctx->type.isLValue ) + { + Error(TXT_NOT_LVALUE, node); + return -1; + } + + if( ctx->type.isVariable && !ctx->type.dataType.IsReference() ) + ConvertToReference(ctx); + else if( !ctx->type.dataType.IsReference() ) + { + Error(TXT_NOT_VALID_REFERENCE, node); + return -1; + } + + // Copy the value to a temp before changing it + ConvertToTempVariable(ctx); + asASSERT(!ctx->type.isLValue); + + // Increment the value pointed to by the reference still in the register + asEBCInstr iInc = asBC_INCi, iDec = asBC_DECi; + if( ctx->type.dataType.IsDoubleType() ) + { + iInc = asBC_INCd; + iDec = asBC_DECd; + } + else if( ctx->type.dataType.IsFloatType() ) + { + iInc = asBC_INCf; + iDec = asBC_DECf; + } + else if( ctx->type.dataType.IsIntegerType() || ctx->type.dataType.IsUnsignedType() ) + { + if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt16, false)) || + ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt16, false)) ) + { + iInc = asBC_INCi16; + iDec = asBC_DECi16; + } + else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt8, false)) || + ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt8, false)) ) + { + iInc = asBC_INCi8; + iDec = asBC_DECi8; + } + else if( ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttInt64, false)) || + ctx->type.dataType.IsEqualExceptRef(asCDataType::CreatePrimitive(ttUInt64, false)) ) + { + iInc = asBC_INCi64; + iDec = asBC_DECi64; + } + } + else + { + Error(TXT_ILLEGAL_OPERATION, node); + return -1; + } + + if( op == ttInc ) ctx->bc.Instr(iInc); else ctx->bc.Instr(iDec); + } + else if( op == ttDot ) + { + if( node->firstChild->nodeType == snIdentifier ) + { + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // Get the property name + asCString name(&script->code[node->firstChild->tokenPos], node->firstChild->tokenLength); + + if( ctx->type.dataType.IsObject() ) + { + // We need to look for get/set property accessors. + // If found, the context stores information on the get/set accessors + // until it is known which is to be used. + int r = 0; + if( node->next && node->next->tokenType == ttOpenBracket ) + { + // The property accessor should take an index arg + asCExprContext dummyArg(engine); + r = FindPropertyAccessor(name, ctx, &dummyArg, node, 0); + } + if( r == 0 ) + r = FindPropertyAccessor(name, ctx, node, 0); + if( r != 0 ) + return r; + + if( !ctx->type.dataType.IsPrimitive() ) + Dereference(ctx, true); + + if( ctx->type.dataType.IsObjectHandle() ) + { + // Convert the handle to a normal object + asCDataType dt = ctx->type.dataType; + dt.MakeHandle(false); + + ImplicitConversion(ctx, dt, node, asIC_IMPLICIT_CONV); + + // The handle may not have been an lvalue, but the dereferenced object is + ctx->type.isLValue = true; + } + + bool isConst = ctx->type.dataType.IsObjectConst(); + + asCObjectProperty *prop = builder->GetObjectProperty(ctx->type.dataType, name.AddressOf()); + if( prop ) + { + // Is the property access allowed? + if( (prop->isPrivate || prop->isProtected) && (!outFunc || outFunc->objectType != ctx->type.dataType.GetTypeInfo()) ) + { + asCString msg; + if( prop->isPrivate ) + msg.Format(TXT_PRIVATE_PROP_ACCESS_s, name.AddressOf()); + else + msg.Format(TXT_PROTECTED_PROP_ACCESS_s, name.AddressOf()); + Error(msg, node); + } + + // Adjust the pointer for composite member + // This must always be done even if the offset is 0 because the asCWriter needs the meta data in ADDSi to identify the composite property + if( prop->compositeOffset || prop->isCompositeIndirect ) + ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->compositeOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); + if (prop->isCompositeIndirect) + ctx->bc.Instr(asBC_RDSPtr); + + // Put the offset on the stack + // This must always be done even if the offset is 0 so the type info is stored + ctx->bc.InstrSHORT_DW(asBC_ADDSi, (short)prop->byteOffset, engine->GetTypeIdFromDataType(asCDataType::CreateType(ctx->type.dataType.GetTypeInfo(), false))); + + if( prop->type.IsReference() ) + ctx->bc.Instr(asBC_RDSPtr); + + // Reference to primitive must be stored in the temp register + if( prop->type.IsPrimitive() ) + { + ctx->bc.Instr(asBC_PopRPtr); + } + + // Keep information about temporary variables as deferred expression + if( ctx->type.isTemporary ) + { + // Add the release of this reference, as a deferred expression + asSDeferredParam deferred; + deferred.origExpr = 0; + deferred.argInOutFlags = asTM_INREF; + deferred.argNode = 0; + deferred.argType.SetVariable(ctx->type.dataType, ctx->type.stackOffset, true); + + ctx->deferredParams.PushLast(deferred); + } + + // Set the new type and make sure it is not treated as a variable anymore + ctx->type.dataType = prop->type; + ctx->type.dataType.MakeReference(true); + ctx->type.isVariable = false; + ctx->type.isTemporary = false; + + if( (ctx->type.dataType.IsObject() || ctx->type.dataType.IsFuncdef()) && !ctx->type.dataType.IsObjectHandle() ) + { + // Objects that are members are not references + ctx->type.dataType.MakeReference(false); + + // The object is safe (life time guaranteed) if the parent object is also safe + } + else if (ctx->type.dataType.IsObjectHandle()) + { + // A object accessed through a handle cannot be considered safe, + // as it can be cleared at any time + ctx->type.isRefSafe = false; + } + + ctx->type.dataType.MakeReadOnly(isConst ? true : prop->type.IsReadOnly()); + } + else + { + // If the name is not a property, the compiler must check if the name matches + // a method, which can be used for constructing delegates + asIScriptFunction *func = 0; + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + for( asUINT n = 0; n < ot->methods.GetLength(); n++ ) + { + if( engine->scriptFunctions[ot->methods[n]]->name == name ) + { + func = engine->scriptFunctions[ot->methods[n]]; + break; + } + } + + if( func ) + { + // An object method was found. Keep the name of the method in the expression, but + // don't actually modify the bytecode at this point since it is not yet known what + // the method will be used for, or even what overloaded method should be used. + ctx->methodName = name; + } + else + { + asCString str; + str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + return -1; + } + } + } + else + { + asCString str; + str.Format(TXT_s_NOT_MEMBER_OF_s, name.AddressOf(), ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + return -1; + } + } + else + { + // Make sure it is an object we are accessing + if( !ctx->type.dataType.IsObject() ) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + return -1; + } + + // Process the get property accessor + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + + // Compile function call + int r = CompileFunctionCall(node->firstChild, ctx, CastToObjectType(ctx->type.dataType.GetTypeInfo()), ctx->type.dataType.IsObjectConst()); + if( r < 0 ) return r; + } + } + else if( op == ttOpenBracket ) + { + // If the property access takes an index arg and the argument hasn't been evaluated yet, + // then we should use that instead of processing it now. If the argument has already been + // evaluated, then we should process the property accessor as a get access now as the new + // index operator is on the result of that accessor. + asCString propertyName; + asSNameSpace *ns = 0; + if( ((ctx->property_get && builder->GetFunctionDescription(ctx->property_get)->GetParamCount() == 1) || + (ctx->property_set && builder->GetFunctionDescription(ctx->property_set)->GetParamCount() == 2)) && + (ctx->property_arg && ctx->property_arg->type.dataType.GetTokenType() == ttUnrecognizedToken) ) + { + // Determine the name of the property accessor + asCScriptFunction *func = 0; + if( ctx->property_get ) + func = builder->GetFunctionDescription(ctx->property_get); + else + func = builder->GetFunctionDescription(ctx->property_set); + propertyName = func->GetName(); + propertyName = propertyName.SubString(4); + + // Set the original type of the expression so we can re-evaluate the property accessor + if( func->objectType ) + { + ctx->type.dataType = asCDataType::CreateType(func->objectType, ctx->property_const); + if( ctx->property_handle ) ctx->type.dataType.MakeHandle(true); + if( ctx->property_ref ) ctx->type.dataType.MakeReference(true); + } + else + { + // Store the namespace where the function is declared + // so the same function can be found later + ctx->type.SetDummy(); + ns = func->nameSpace; + } + + ctx->property_get = ctx->property_set = 0; + if( ctx->property_arg ) + { + asDELETE(ctx->property_arg, asCExprContext); + ctx->property_arg = 0; + } + } + else + { + if( !ctx->type.dataType.IsObject() ) + { + asCString str; + str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + return -1; + } + + if( ProcessPropertyGetAccessor(ctx, node) < 0 ) + return -1; + } + + // Compile the expression + bool isOK = true; + asCArray args; + asCArray namedArgs; + asASSERT( node->firstChild->nodeType == snArgList ); + if( CompileArgumentList(node->firstChild, args, namedArgs) >= 0 ) + { + // Check for the existence of the opIndex method + bool lookForProperty = true; + if( propertyName == "" ) + { + bool isConst = ctx->type.dataType.IsObjectConst(); + asCObjectType *objectType = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + + asCArray funcs; + builder->GetObjectMethodDescriptions("opIndex", objectType, funcs, isConst); + if( funcs.GetLength() > 0 ) + { + // Since there are opIndex methods, the compiler should not look for get/set_opIndex accessors + lookForProperty = false; + + // Determine which of opIndex methods that match + MatchFunctions(funcs, args, node, "opIndex", 0, objectType, isConst); + if( funcs.GetLength() != 1 ) + { + // The error has already been reported by MatchFunctions + isOK = false; + } + else + { + // Add the default values for arguments not explicitly supplied + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], objectType); + + if( r < 0 ) + isOK = false; + else if( MakeFunctionCall(ctx, funcs[0], objectType, args, node, false, 0, ctx->type.stackOffset) < 0 ) + isOK = false; + } + } + } + if( lookForProperty && isOK ) + { + if( args.GetLength() != 1 ) + { + // TODO: opIndex: Implement support for multiple index arguments in set_opIndex too + Error(TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG, node); + isOK = false; + } + else + { + Dereference(ctx, true); + asCExprContext lctx(engine); + MergeExprBytecodeAndType(&lctx, ctx); + + // Check for accessors methods for the opIndex, either as get/set_opIndex or as get/set with the property name + int r = FindPropertyAccessor(propertyName == "" ? "opIndex" : propertyName.AddressOf(), &lctx, args[0], node, ns); + if (r == 0) + { + asCString str; + str.Format(TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP, ctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + isOK = false; + } + else if (r < 0) + isOK = false; + + if (isOK) + MergeExprBytecodeAndType(ctx, &lctx); + } + } + } + else + isOK = false; + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + + if( !isOK ) + return -1; + } + else if( op == ttOpenParanthesis ) + { + // TODO: Most of this is already done by CompileFunctionCall(). Can we share the code? + + // Make sure the expression is a funcdef or an object that may have opCall methods + if( !ctx->type.dataType.GetTypeInfo() || (!ctx->type.dataType.IsFuncdef() && !ctx->type.dataType.IsObject()) ) + { + Error(TXT_EXPR_DOESNT_EVAL_TO_FUNC, node); + return -1; + } + + // Compile arguments + bool isOK = true; + asCArray args; + asCArray namedArgs; + if( CompileArgumentList(node->lastChild, args, namedArgs) >= 0 ) + { + // Match arguments with the funcdef + asCArray funcs; + if( ctx->type.dataType.IsFuncdef() ) + { + funcs.PushLast(CastToFuncdefType(ctx->type.dataType.GetTypeInfo())->funcdef->id); + MatchFunctions(funcs, args, node, ctx->type.dataType.GetTypeInfo()->name.AddressOf(), &namedArgs); + } + else + { + bool isConst = ctx->type.dataType.IsObjectConst(); + + builder->GetObjectMethodDescriptions("opCall", CastToObjectType(ctx->type.dataType.GetTypeInfo()), funcs, isConst); + MatchFunctions(funcs, args, node, "opCall", &namedArgs, CastToObjectType(ctx->type.dataType.GetTypeInfo()), isConst); + } + + if( funcs.GetLength() != 1 ) + { + // The error was reported by MatchFunctions() + + // Dummy value + ctx->type.SetDummy(); + } + else + { + // Add the default values for arguments not explicitly supplied + int r = CompileDefaultAndNamedArgs(node, args, funcs[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), &namedArgs); + + // TODO: funcdef: Do we have to make sure the handle is stored in a temporary variable, or + // is it enough to make sure it is in a local variable? + + // For function pointer we must guarantee that the function is safe, i.e. + // by first storing the function pointer in a local variable (if it isn't already in one) + if( r == asSUCCESS ) + { + Dereference(ctx, true); + if( ctx->type.dataType.IsFuncdef() ) + { + if( !ctx->type.isVariable ) + ConvertToVariable(ctx); + + // Remove the reference from the stack as the asBC_CALLPTR instruction takes the variable as argument + ctx->bc.Instr(asBC_PopPtr); + } + + r = MakeFunctionCall(ctx, funcs[0], ctx->type.dataType.IsFuncdef() ? 0 : CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node, false, 0, ctx->type.stackOffset); + if( r < 0 ) + isOK = false; + } + else + isOK = false; + } + } + else + ctx->type.SetDummy(); + + // Cleanup + for( asUINT n = 0; n < args.GetLength(); n++ ) + if( args[n] ) + { + asDELETE(args[n], asCExprContext); + } + for( asUINT n = 0; n < namedArgs.GetLength(); n++ ) + if( namedArgs[n].ctx ) + { + asDELETE(namedArgs[n].ctx, asCExprContext); + } + + if( !isOK ) + return -1; + } + + return 0; +} + +int asCCompiler::GetPrecedence(asCScriptNode *op) +{ + // x ** y + // x * y, x / y, x % y + // x + y, x - y + // x <= y, x < y, x >= y, x > y + // x = =y, x != y, x xor y, x is y, x !is y + // x and y + // x or y + + // The following are not used in this function, + // but should have lower precedence than the above + // x ? y : z + // x = y + + // The expression term have the highest precedence + if( op->nodeType == snExprTerm ) + return 1; + + // Evaluate operators by token + int tokenType = op->tokenType; + if( tokenType == ttStarStar ) + return 0; + + if( tokenType == ttStar || tokenType == ttSlash || tokenType == ttPercent ) + return -1; + + if( tokenType == ttPlus || tokenType == ttMinus ) + return -2; + + if( tokenType == ttBitShiftLeft || + tokenType == ttBitShiftRight || + tokenType == ttBitShiftRightArith ) + return -3; + + if( tokenType == ttAmp ) + return -4; + + if( tokenType == ttBitXor ) + return -5; + + if( tokenType == ttBitOr ) + return -6; + + if( tokenType == ttLessThanOrEqual || + tokenType == ttLessThan || + tokenType == ttGreaterThanOrEqual || + tokenType == ttGreaterThan ) + return -7; + + if( tokenType == ttEqual || tokenType == ttNotEqual || tokenType == ttXor || tokenType == ttIs || tokenType == ttNotIs ) + return -8; + + if( tokenType == ttAnd ) + return -9; + + if( tokenType == ttOr ) + return -10; + + // Unknown operator + asASSERT(false); + + return 0; +} + +asUINT asCCompiler::MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct) +{ + matches.SetLength(0); + + for( asUINT n = 0; n < funcs.GetLength(); n++ ) + { + asCScriptFunction *desc = builder->GetFunctionDescription(funcs[n]); + + // Does the function have arguments enough? + if( (int)desc->parameterTypes.GetLength() <= paramNum ) + continue; + + int cost = MatchArgument(desc, argExpr, paramNum, allowObjectConstruct); + if( cost != -1 ) + matches.PushLast(asSOverloadCandidate(funcs[n], asUINT(cost))); + } + + return (asUINT)matches.GetLength(); +} + +int asCCompiler::MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct) +{ + // void expressions can match any out parameter, but nothing else + if( argExpr->IsVoidExpression() ) + { + if( desc->inOutFlags[paramNum] == asTM_OUTREF ) + return 0; + return -1; + } + + // Anonymous init lists can only match parameters that can be initialized with a list + if (argExpr->IsAnonymousInitList()) + { + if( (desc->parameterTypes[paramNum].IsReference() && (desc->inOutFlags[paramNum] & asTM_INREF) == 0) || + desc->parameterTypes[paramNum].GetBehaviour() == 0 || + desc->parameterTypes[paramNum].GetBehaviour()->listFactory == 0 ) + { + return -1; + } + return 0; + } + + // Can we make the match by implicit conversion? + asCExprContext ti(engine); + ti.type = argExpr->type; + ti.methodName = argExpr->methodName; + ti.enumValue = argExpr->enumValue; + ti.exprNode = argExpr->exprNode; + if( argExpr->type.dataType.IsPrimitive() ) + ti.type.dataType.MakeReference(false); + + // Don't allow the implicit conversion to make a copy in case the argument is expecting a reference to the true value + if (desc->parameterTypes[paramNum].IsReference() && desc->inOutFlags[paramNum] == asTM_INOUTREF) + allowObjectConstruct = false; + + int cost = ImplicitConversion(&ti, desc->parameterTypes[paramNum], 0, asIC_IMPLICIT_CONV, false, allowObjectConstruct); + + // If the function parameter is an inout-reference then it must not be possible to call the + // function with an incorrect argument type, even though the type can normally be converted. + if( desc->parameterTypes[paramNum].IsReference() && + desc->inOutFlags[paramNum] == asTM_INOUTREF && + desc->parameterTypes[paramNum].GetTokenType() != ttQuestion ) + { + // Observe, that the below checks are only necessary for when unsafe references have been + // enabled by the application. Without this the &inout reference form wouldn't be allowed + // for these value types. + + // Don't allow a primitive to be converted to a reference of another primitive type + if( desc->parameterTypes[paramNum].IsPrimitive() && + desc->parameterTypes[paramNum].GetTokenType() != argExpr->type.dataType.GetTokenType() ) + { + asASSERT( engine->ep.allowUnsafeReferences ); + return -1; + } + + // Don't allow an enum to be converted to a reference of another enum type + if( desc->parameterTypes[paramNum].IsEnumType() && + desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo() ) + { + asASSERT( engine->ep.allowUnsafeReferences ); + return -1; + } + + // Don't allow a non-handle expression to be converted to a reference to a handle + if( desc->parameterTypes[paramNum].IsObjectHandle() && + !argExpr->type.dataType.IsObjectHandle() ) + { + asASSERT( engine->ep.allowUnsafeReferences ); + return -1; + } + + // Don't allow a value type to be converted + if( (desc->parameterTypes[paramNum].GetTypeInfo() && (desc->parameterTypes[paramNum].GetTypeInfo()->GetFlags() & asOBJ_VALUE)) && + (desc->parameterTypes[paramNum].GetTypeInfo() != argExpr->type.dataType.GetTypeInfo()) ) + { + asASSERT( engine->ep.allowUnsafeReferences ); + return -1; + } + } + + // How well does the argument match the function parameter? + if( desc->parameterTypes[paramNum].IsEqualExceptRef(ti.type.dataType) ) + return cost; + + // No match is available + return -1; +} + +int asCCompiler::PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction, int refType, bool isMakingCopy) +{ + // Reference parameters whose value won't be used don't evaluate the expression + // Clean arguments (i.e. default value) will be passed in directly as there is nothing to protect + if( paramType->IsReference() && !(refType & asTM_INREF) && !arg->isCleanArg ) + { + // Store the original bytecode so that it can be reused when processing the deferred output parameter + asCExprContext *orig = asNEW(asCExprContext)(engine); + if( orig == 0 ) + { + // Out of memory + return -1; + } + MergeExprBytecodeAndType(orig, arg); + arg->origExpr = orig; + } + + int r = PrepareArgument(paramType, arg, arg->exprNode, isFunction, refType, isMakingCopy); + if (r < 0) + return r; + + // arg still holds the original expression for output parameters + ctx->bc.AddCode(&arg->bc); + + return 0; +} + +bool asCCompiler::CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool isHandle, eTokenType token) +{ + DetermineSingleFunc(lctx, node); + DetermineSingleFunc(rctx, node); + + ctx->exprNode = node; + + // What type of operator is it? + if( token == ttUnrecognizedToken ) + token = node->tokenType; + if( token == ttUnrecognizedToken ) + { + // This happens when the compiler is inferring an assignment + // operation from another action, for example in preparing a value + // as a function argument + token = ttAssignment; + } + + // boolean operators are not overloadable + if( token == ttAnd || + token == ttOr || + token == ttXor ) + return false; + + // Dual operators can also be implemented as class methods + if( token == ttEqual || + token == ttNotEqual ) + { + // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used + // Find the matching opEquals method + int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + if( r == 0 ) + { + // Try again by switching the order of the operands + r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + } + + if( r == 1 ) + { + if( token == ttNotEqual ) + ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset); + + // Success, don't continue + return true; + } + else if( r < 0 ) + { + // Compiler error, don't continue + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + return true; + } + } + + if( token == ttEqual || + token == ttNotEqual || + token == ttLessThan || + token == ttLessThanOrEqual || + token == ttGreaterThan || + token == ttGreaterThanOrEqual ) + { + bool swappedOrder = false; + + // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used + // Find the matching opCmp method + int r = CompileOverloadedDualOperator2(node, "opCmp", lctx, rctx, leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); + if( r == 0 ) + { + // Try again by switching the order of the operands + swappedOrder = true; + r = CompileOverloadedDualOperator2(node, "opCmp", rctx, lctx, !leftToRight, ctx, true, asCDataType::CreatePrimitive(ttInt, false)); + } + + if( r == 1 ) + { + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + + int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true); + + ctx->bc.InstrW_DW(asBC_CMPIi, ctx->type.stackOffset, 0); + + if( token == ttEqual ) + ctx->bc.Instr(asBC_TZ); + else if( token == ttNotEqual ) + ctx->bc.Instr(asBC_TNZ); + else if( (token == ttLessThan && !swappedOrder) || + (token == ttGreaterThan && swappedOrder) ) + ctx->bc.Instr(asBC_TS); + else if( (token == ttLessThanOrEqual && !swappedOrder) || + (token == ttGreaterThanOrEqual && swappedOrder) ) + ctx->bc.Instr(asBC_TNP); + else if( (token == ttGreaterThan && !swappedOrder) || + (token == ttLessThan && swappedOrder) ) + ctx->bc.Instr(asBC_TP); + else if( (token == ttGreaterThanOrEqual && !swappedOrder) || + (token == ttLessThanOrEqual && swappedOrder) ) + ctx->bc.Instr(asBC_TNS); + + ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); + + ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), a, true); + + // Success, don't continue + return true; + } + else if( r < 0 ) + { + // Compiler error, don't continue + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); + #endif + return true; + } + } + + // The rest of the operators are not commutative, and doesn't require specific return type + const char *op = 0, *op_r = 0; + switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested + { + case ttPlus: op = "opAdd"; op_r = "opAdd_r"; break; + case ttMinus: op = "opSub"; op_r = "opSub_r"; break; + case ttStar: op = "opMul"; op_r = "opMul_r"; break; + case ttSlash: op = "opDiv"; op_r = "opDiv_r"; break; + case ttPercent: op = "opMod"; op_r = "opMod_r"; break; + case ttStarStar: op = "opPow"; op_r = "opPow_r"; break; + case ttBitOr: op = "opOr"; op_r = "opOr_r"; break; + case ttAmp: op = "opAnd"; op_r = "opAnd_r"; break; + case ttBitXor: op = "opXor"; op_r = "opXor_r"; break; + case ttBitShiftLeft: op = "opShl"; op_r = "opShl_r"; break; + case ttBitShiftRight: op = "opShr"; op_r = "opShr_r"; break; + case ttBitShiftRightArith: op = "opUShr"; op_r = "opUShr_r"; break; + } + + // TODO: Might be interesting to support a concatenation operator, e.g. ~ + + if( op && op_r ) + { + // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used + // Find the matching operator method + int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, leftToRight, ctx); + if( r == 0 ) + { + // Try again by switching the order of the operands, and using the reversed operator + r = CompileOverloadedDualOperator2(node, op_r, rctx, lctx, !leftToRight, ctx); + } + + if( r == 1 ) + { + // Success, don't continue + return true; + } + else if( r < 0 ) + { + // Compiler error, don't continue + ctx->type.SetDummy(); + return true; + } + } + + // Assignment operators + op = 0; + if( isHandle ) + { + // Only asOBJ_ASHANDLE types can get here + asASSERT( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) ); + asASSERT( token == ttAssignment ); + + if( token == ttAssignment ) + op = "opHndlAssign"; + } + else + { + switch( int(token) ) // convert to int to avoid warning in gnuc that not all values are tested + { + case ttAssignment: op = "opAssign"; break; + case ttAddAssign: op = "opAddAssign"; break; + case ttSubAssign: op = "opSubAssign"; break; + case ttMulAssign: op = "opMulAssign"; break; + case ttDivAssign: op = "opDivAssign"; break; + case ttModAssign: op = "opModAssign"; break; + case ttPowAssign: op = "opPowAssign"; break; + case ttOrAssign: op = "opOrAssign"; break; + case ttAndAssign: op = "opAndAssign"; break; + case ttXorAssign: op = "opXorAssign"; break; + case ttShiftLeftAssign: op = "opShlAssign"; break; + case ttShiftRightLAssign: op = "opShrAssign"; break; + case ttShiftRightAAssign: op = "opUShrAssign"; break; + } + } + + if( op ) + { + if( builder->engine->ep.disallowValueAssignForRefType && + lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_REF) && !(lctx->type.dataType.GetTypeInfo()->flags & asOBJ_SCOPED) ) + { + if( token == ttAssignment ) + Error(TXT_DISALLOW_ASSIGN_ON_REF_TYPE, node); + else + Error(TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE, node); + + // Set a dummy output + ctx->type.Set(lctx->type.dataType); + return true; + } + + // TODO: Shouldn't accept const lvalue with the assignment operators + + // Find the matching operator method + int r = CompileOverloadedDualOperator2(node, op, lctx, rctx, false, ctx); + if( r == 1 ) + { + // Success, don't continue + return true; + } + else if( r < 0 ) + { + // Compiler error, don't continue + ctx->type.SetDummy(); + return true; + } + } + + // No suitable operator was found + return false; +} + +// Returns negative on compile error +// zero on no matching operator +// one on matching operator +int asCCompiler::CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *lctx, asCExprContext *rctx, bool leftToRight, asCExprContext *ctx, bool specificReturn, const asCDataType &returnType) +{ + // Find the matching method + if( lctx->type.dataType.IsObject() && + (!lctx->type.isExplicitHandle || + lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE) && + !lctx->type.IsNullConstant() ) + { + asUINT n; + + // Is the left value a const? + bool isConst = lctx->type.dataType.IsObjectConst(); + + asCArray funcs; + asCObjectType *ot = CastToObjectType(lctx->type.dataType.GetTypeInfo()); + asASSERT(ot); + for( n = 0; ot && n < ot->methods.GetLength(); n++ ) + { + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + asASSERT( func ); + if( func && func->name == methodName && + (!specificReturn || func->returnType == returnType) && + func->parameterTypes.GetLength() == 1 && + (!isConst || func->IsReadOnly()) ) + { + // Make sure the method is accessible by the module + if( builder->module->m_accessMask & func->accessMask ) + { + funcs.PushLast(func->id); + } + } + } + + // Which is the best matching function? + asCArray tempFuncs; + MatchArgument(funcs, tempFuncs, rctx, 0); + + // Find the lowest cost operator(s) + asCArray ops; + asUINT bestCost = asUINT(-1); + for( n = 0; n < tempFuncs.GetLength(); ++n ) + { + asUINT cost = tempFuncs[n].cost; + if( cost < bestCost ) + { + ops.SetLength(0); + bestCost = cost; + } + if( cost == bestCost ) + ops.PushLast(tempFuncs[n].funcId); + } + + // If the object is not const, then we need to prioritize non-const methods + if( !isConst ) + FilterConst(ops); + + // Did we find an operator? + if( ops.GetLength() == 1 ) + { + // Reserve the variables used in the right expression so the new temporary + // variable allocated for the left operand isn't accidentally overwritten. + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + + // Process the lctx expression as get accessor + if( ProcessPropertyGetAccessor(lctx, node) < 0 ) + return -1; + + reservedVariables.SetLength(l); + + asCExprContext tmpCtx(engine); + if (leftToRight) + { + // Make sure lctx is in fact a variable. If it is a reference there is no + // guarantee that the reference will stay alive throughout the evaluation of rctx + if (!lctx->type.isVariable) + { + // Reserve the variables used in the right expression so the new temporary + // variable allocated for the left operand isn't accidentally overwritten. + l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + + if (engine->ep.allowUnsafeReferences && lctx->type.dataType.IsObject() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_VALUE)) + { + // If the application allows unsafe references, then it is not necessary to + // make a copy of the object, just store the reference as a local variable + + // Allocate a temporary variable as reference to the type + asCDataType dt = lctx->type.dataType; + dt.MakeReference(true); + int offset = AllocateVariable(dt, true, false, true); + + Dereference(lctx, true); + + // Copy the pointer to the temporary variable + lctx->bc.InstrSHORT(asBC_PSF, (short)offset); + if (lctx->type.dataType.IsFuncdef()) + lctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + lctx->bc.InstrPTR(asBC_REFCPY, lctx->type.dataType.GetTypeInfo()); + + lctx->type.SetVariable(dt, offset, true); + } + else + { + if (lctx->type.dataType.SupportHandles()) + lctx->type.dataType.MakeHandle(true); + PrepareTemporaryVariable(node, lctx); + } + + reservedVariables.SetLength(l); + } + + // Move the bytecode for the left operand to a temporary context + // so we can later make sure this is computed first + tmpCtx.bc.AddCode(&lctx->bc); + tmpCtx.bc.Instr(asBC_PopPtr); + + // Add bytecode to push the object pointer computed in the left operand on the stack as the this pointer + // This will be placed after rctx by MakeFunctionCall below + lctx->bc.InstrWORD(asBC_PSF, lctx->type.stackOffset); + + // Implicitly dereference handle parameters sent by reference + sVariable *v = variables->GetVariableByOffset(lctx->type.stackOffset); + if (v && v->type.IsReference() && (!v->type.IsObject() || v->type.IsObjectHandle())) + lctx->bc.Instr(asBC_RDSPtr); + } + else + { + // Make sure the rvalue doesn't have deferred temporary variables that are also used in the lvalue, + // since that would cause the VM to overwrite the variable while executing the bytecode for the lvalue. + asCArray usedVars; + lctx->bc.GetVarsUsed(usedVars); + asUINT oldReservedVars = reservedVariables.GetLength(); + for (n = 0; n < rctx->deferredParams.GetLength(); n++) + { + if (rctx->deferredParams[n].argType.isTemporary && + usedVars.Exists(rctx->deferredParams[n].argType.stackOffset)) + { + if (reservedVariables.GetLength() == oldReservedVars) + reservedVariables.Concatenate(usedVars); + + // Allocate a new variable for the deferred argument + int offset = AllocateVariableNotIn(rctx->deferredParams[n].argType.dataType, true, false, rctx); + int oldVar = rctx->deferredParams[n].argType.stackOffset; + rctx->deferredParams[n].argType.stackOffset = short(offset); + rctx->bc.ExchangeVar(oldVar, offset); + ReleaseTemporaryVariable(oldVar, 0); + } + } + reservedVariables.SetLength(oldReservedVars); + } + + // Merge the bytecode so that it forms lvalue.methodName(rvalue) + asCArray args; + args.PushLast(rctx); + MergeExprBytecode(ctx, lctx); + ctx->type = lctx->type; + if( MakeFunctionCall(ctx, ops[0], CastToObjectType(ctx->type.dataType.GetTypeInfo()), args, node) < 0 ) + return -1; + + // Rearrange the bytecode so the left argument is computed first + if (leftToRight) + { + tmpCtx.bc.AddCode(&ctx->bc); + ctx->bc.AddCode(&tmpCtx.bc); + } + + // Found matching operator + return 1; + } + else if( ops.GetLength() > 1 ) + { + Error(TXT_MORE_THAN_ONE_MATCHING_OP, node); + PrintMatchingFuncs(ops, node); + + ctx->type.SetDummy(); + + // Compiler error + return -1; + } + } + + // No matching operator + return 0; +} + +int asCCompiler::MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable, int stackOffset, int funcPtrVar) +{ + if( objectType ) + Dereference(ctx, true); + + // Store the expression node for error reporting + if( ctx->exprNode == 0 ) + ctx->exprNode = node; + + asCByteCode objBC(engine); + objBC.AddCode(&ctx->bc); + + int r = PrepareFunctionCall(funcId, &ctx->bc, args); + if (r < 0) + return r; + + // Verify if any of the args variable offsets are used in the other code. + // If they are exchange the offset for a new one + asUINT n; + for( n = 0; n < args.GetLength(); n++ ) + { + if( args[n]->type.isTemporary && objBC.IsVarUsed(args[n]->type.stackOffset) ) + { + // Release the current temporary variable + ReleaseTemporaryVariable(args[n]->type, 0); + + asCDataType dt = args[n]->type.dataType; + dt.MakeReference(false); + + int l = int(reservedVariables.GetLength()); + objBC.GetVarsUsed(reservedVariables); + ctx->bc.GetVarsUsed(reservedVariables); + int newOffset = AllocateVariable(dt, true, IsVariableOnHeap(args[n]->type.stackOffset)); + reservedVariables.SetLength(l); + + asASSERT( IsVariableOnHeap(args[n]->type.stackOffset) == IsVariableOnHeap(newOffset) ); + + ctx->bc.ExchangeVar(args[n]->type.stackOffset, newOffset); + args[n]->type.stackOffset = (short)newOffset; + args[n]->type.isTemporary = true; + args[n]->type.isVariable = true; + } + } + + // If the function will return a value type on the stack, then we must allocate space + // for that here and push the address on the stack as a hidden argument to the function + asCScriptFunction *func = builder->GetFunctionDescription(funcId); + if( func->DoesReturnOnStack() ) + { + asASSERT(!useVariable); + + useVariable = true; + stackOffset = AllocateVariable(func->returnType, true); + ctx->bc.InstrSHORT(asBC_PSF, short(stackOffset)); + } + + ctx->bc.AddCode(&objBC); + + MoveArgsToStack(funcId, &ctx->bc, args, objectType ? true : false); + + PerformFunctionCall(funcId, ctx, false, &args, 0, useVariable, stackOffset, funcPtrVar); + + return 0; +} + +int asCCompiler::CompileOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op, bool leftToRight) +{ + // Don't allow any operators on expressions that take address of class method, but allow it on global functions + if( (lctx->IsClassMethod()) || (rctx->IsClassMethod()) ) + { + Error(TXT_INVALID_OP_ON_METHOD, node); + return -1; + } + + // Don't allow any operators on void expressions + if( lctx->IsVoidExpression() || rctx->IsVoidExpression() ) + { + Error(TXT_VOID_CANT_BE_OPERAND, node); + return -1; + } + + if( op == ttUnrecognizedToken ) + op = node->tokenType; + + IsVariableInitialized(&lctx->type, node); + IsVariableInitialized(&rctx->type, node); + + if( lctx->type.isExplicitHandle || rctx->type.isExplicitHandle || + lctx->type.IsNullConstant() || rctx->type.IsNullConstant() || + op == ttIs || op == ttNotIs ) + { + CompileOperatorOnHandles(node, lctx, rctx, ctx, op); + return 0; + } + else + { + // Compile an overloaded operator for the two operands + if( CompileOverloadedDualOperator(node, lctx, rctx, leftToRight, ctx, false, op) ) + return 0; + + // If both operands are objects, then we shouldn't continue + if( lctx->type.dataType.IsObject() && rctx->type.dataType.IsObject() ) + { + asCString str; + str.Format(TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), rctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + ctx->type.SetDummy(); + return -1; + } + + // Process the property get accessors (if any) + if( ProcessPropertyGetAccessor(lctx, node) < 0 ) + return -1; + if( ProcessPropertyGetAccessor(rctx, node) < 0 ) + return -1; + + // Make sure we have two variables or constants + if( lctx->type.dataType.IsReference() ) ConvertToVariableNotIn(lctx, rctx); + if( rctx->type.dataType.IsReference() ) ConvertToVariableNotIn(rctx, lctx); + + // Make sure lctx doesn't end up with a variable used in rctx + if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) ) + { + int offset = AllocateVariableNotIn(lctx->type.dataType, true, false, rctx); + rctx->bc.ExchangeVar(lctx->type.stackOffset, offset); + ReleaseTemporaryVariable(offset, 0); + } + + // Math operators + // + - * / % ** += -= *= /= %= **= + if( op == ttPlus || op == ttAddAssign || + op == ttMinus || op == ttSubAssign || + op == ttStar || op == ttMulAssign || + op == ttSlash || op == ttDivAssign || + op == ttPercent || op == ttModAssign || + op == ttStarStar || op == ttPowAssign ) + { + CompileMathOperator(node, lctx, rctx, ctx, op); + return 0; + } + + // Bitwise operators + // << >> >>> & | ^ <<= >>= >>>= &= |= ^= + if( op == ttAmp || op == ttAndAssign || + op == ttBitOr || op == ttOrAssign || + op == ttBitXor || op == ttXorAssign || + op == ttBitShiftLeft || op == ttShiftLeftAssign || + op == ttBitShiftRight || op == ttShiftRightLAssign || + op == ttBitShiftRightArith || op == ttShiftRightAAssign ) + { + CompileBitwiseOperator(node, lctx, rctx, ctx, op); + return 0; + } + + // Comparison operators + // == != < > <= >= + if( op == ttEqual || op == ttNotEqual || + op == ttLessThan || op == ttLessThanOrEqual || + op == ttGreaterThan || op == ttGreaterThanOrEqual ) + { + CompileComparisonOperator(node, lctx, rctx, ctx, op); + return 0; + } + + // Boolean operators + // && || ^^ + if( op == ttAnd || op == ttOr || op == ttXor ) + { + CompileBooleanOperator(node, lctx, rctx, ctx, op); + return 0; + } + } + + asASSERT(false); + return -1; +} + +void asCCompiler::ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude) +{ + int l = int(reservedVariables.GetLength()); + if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); + ConvertToTempVariable(ctx); + reservedVariables.SetLength(l); +} + +void asCCompiler::ConvertToTempVariable(asCExprContext *ctx) +{ + // This is only used for primitive types and null handles + asASSERT( ctx->type.dataType.IsPrimitive() || ctx->type.dataType.IsNullHandle() ); + + ConvertToVariable(ctx); + if( !ctx->type.isTemporary ) + { + if( ctx->type.dataType.IsPrimitive() ) + { + // Copy the variable to a temporary variable + int offset = AllocateVariable(ctx->type.dataType, true); + if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + ctx->bc.InstrW_W(asBC_CpyVtoV4, offset, ctx->type.stackOffset); + else + ctx->bc.InstrW_W(asBC_CpyVtoV8, offset, ctx->type.stackOffset); + ctx->type.SetVariable(ctx->type.dataType, offset, true); + } + else + { + // We should never get here + asASSERT(false); + } + } +} + +void asCCompiler::ConvertToVariable(asCExprContext *ctx) +{ + // We should never get here while the context is still an unprocessed property accessor + asASSERT(ctx->property_get == 0 && ctx->property_set == 0); + + int offset; + if( !ctx->type.isVariable && + (ctx->type.dataType.IsObjectHandle() || + (ctx->type.dataType.IsObject() && ctx->type.dataType.SupportHandles())) ) + { + offset = AllocateVariable(ctx->type.dataType, true); + if( ctx->type.IsNullConstant() ) + { + if( ctx->bc.GetLastInstr() == asBC_PshNull ) + ctx->bc.Instr(asBC_PopPtr); // Pop the null constant pushed onto the stack + ctx->bc.InstrSHORT(asBC_ClrVPtr, (short)offset); + } + else + { + Dereference(ctx, true); + + // Copy the object handle to a variable + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + if( ctx->type.dataType.IsFuncdef() ) + ctx->bc.InstrPTR(asBC_REFCPY, &engine->functionBehaviours); + else + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + ctx->bc.Instr(asBC_PopPtr); + } + + // As this is an object the reference must be placed on the stack + ctx->bc.InstrSHORT(asBC_PSF, (short)offset); + + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + ctx->type.SetVariable(ctx->type.dataType, offset, true); + ctx->type.dataType.MakeHandle(true); + ctx->type.dataType.MakeReference(true); + } + else if( (!ctx->type.isVariable || ctx->type.dataType.IsReference()) && + ctx->type.dataType.IsPrimitive() ) + { + if( ctx->type.isConstant ) + { + offset = AllocateVariable(ctx->type.dataType, true); + if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) + ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, ctx->type.GetConstantB()); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) + ctx->bc.InstrSHORT_W(asBC_SetV2, (short)offset, ctx->type.GetConstantW()); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 4 ) + ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, ctx->type.GetConstantDW()); + else + ctx->bc.InstrSHORT_QW(asBC_SetV8, (short)offset, ctx->type.GetConstantQW()); + + ctx->type.SetVariable(ctx->type.dataType, offset, true); + return; + } + else + { + asASSERT(ctx->type.dataType.IsPrimitive()); + asASSERT(ctx->type.dataType.IsReference()); + + ctx->type.dataType.MakeReference(false); + offset = AllocateVariable(ctx->type.dataType, true); + + // Read the value from the address in the register directly into the variable + if( ctx->type.dataType.GetSizeInMemoryBytes() == 1 ) + ctx->bc.InstrSHORT(asBC_RDR1, (short)offset); + else if( ctx->type.dataType.GetSizeInMemoryBytes() == 2 ) + ctx->bc.InstrSHORT(asBC_RDR2, (short)offset); + else if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + ctx->bc.InstrSHORT(asBC_RDR4, (short)offset); + else + ctx->bc.InstrSHORT(asBC_RDR8, (short)offset); + } + + ReleaseTemporaryVariable(ctx->type, &ctx->bc); + ctx->type.SetVariable(ctx->type.dataType, offset, true); + } +} + +void asCCompiler::ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude) +{ + int l = int(reservedVariables.GetLength()); + if( exclude ) exclude->bc.GetVarsUsed(reservedVariables); + ConvertToVariable(ctx); + reservedVariables.SetLength(l); +} + +void asCCompiler::ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node) +{ + asCArray funcs; + asCObjectType *ot = CastToObjectType(ctx->type.dataType.GetTypeInfo()); + if( ot ) + { + for( unsigned int n = 0; n < ot->methods.GetLength(); n++ ) + { + // Consider only implicit casts + asCScriptFunction *func = engine->scriptFunctions[ot->methods[n]]; + if( func->name == "opImplConv" && + func->returnType.IsPrimitive() && + func->parameterTypes.GetLength() == 0 ) + funcs.PushLast(ot->methods[n]); + } + + // Use the one with the highest precision + const eTokenType match[10] = {ttDouble, ttFloat, ttInt64, ttUInt64, ttInt, ttUInt, ttInt16, ttUInt16, ttInt8, ttUInt8}; + while( funcs.GetLength() > 1 ) + { + eTokenType returnType = builder->GetFunctionDescription(funcs[0])->returnType.GetTokenType(); + int value1 = 11, value2 = 11; + for( asUINT i = 0; i < 10; i++ ) + { + if( returnType == match[i] ) + { + value1 = i; + break; + } + } + + for( asUINT n = 1; n < funcs.GetLength(); n++ ) + { + returnType = builder->GetFunctionDescription(funcs[n])->returnType.GetTokenType(); + for( asUINT i = 0; i < 10; i++ ) + { + if( returnType == match[i] ) + { + value2 = i; + break; + } + } + + if( value2 >= value1 ) + { + // Remove this and continue searching + funcs.RemoveIndexUnordered(n--); + } + else + { + // Remove the first, and start over + funcs.RemoveIndexUnordered(0); + break; + } + } + } + + // Do the conversion + if( funcs.GetLength() ) + ImplicitConvObjectToPrimitive(ctx, builder->GetFunctionDescription(funcs[0])->returnType, node, asIC_IMPLICIT_CONV); + } +} + +void asCCompiler::CompileMathOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) +{ + // TODO: If a constant is only using 32bits, then a 32bit operation is preferred + + // TODO: clean up: This initial part is identical to CompileComparisonOperator. Make a common function out of it + + // If either operand is a non-primitive then use the primitive type + if( !lctx->type.dataType.IsPrimitive() ) + { + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + ImplicitConvObjectToBestMathType(lctx, node); + reservedVariables.SetLength(l); + } + if( !rctx->type.dataType.IsPrimitive() ) + { + int l = int(reservedVariables.GetLength()); + lctx->bc.GetVarsUsed(reservedVariables); + ImplicitConvObjectToBestMathType(rctx, node); + reservedVariables.SetLength(l); + } + + // Both types must now be primitives. Implicitly convert them so they match + asCDataType to; + if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() ) + to.SetTokenType(ttDouble); + else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() ) + to.SetTokenType(ttFloat); + else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + // Convert to int64 if both are signed or if one is non-constant and signed + if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || + (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) + to.SetTokenType(ttInt64); + else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) + to.SetTokenType(ttUInt64); + else + to.SetTokenType(ttInt64); + } + else + { + // Convert to int32 if both are signed or if one is non-constant and signed + if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || + (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) + to.SetTokenType(ttInt); + else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) + to.SetTokenType(ttUInt); + else + to.SetTokenType(ttInt); + } + + // If doing an operation with double constant and float variable, the constant should be converted to float + if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) || + (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) ) + to.SetTokenType(ttFloat); + + if( op == ttUnrecognizedToken ) + op = node->tokenType; + + // If integer division is disabled, convert to floating-point + if( engine->ep.disableIntegerDivision && + (op == ttSlash || op == ttDivAssign) && + (to.IsIntegerType() || to.IsUnsignedType()) ) + { + // Use double to avoid losing precision when dividing with 32bit ints + // For 64bit ints there is unfortunately no greater type so with those + // there is still a risk of loosing precision + to.SetTokenType(ttDouble); + } + + // Do the actual conversion + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + lctx->bc.GetVarsUsed(reservedVariables); + + if( lctx->type.dataType.IsReference() ) + ConvertToVariable(lctx); + if( rctx->type.dataType.IsReference() ) + ConvertToVariable(rctx); + + if( to.IsPrimitive() ) + { + // ttStarStar allows an integer, right-hand operand and a double + // left-hand operand. + if( (op == ttStarStar || op == ttPowAssign) && + lctx->type.dataType.IsDoubleType() && + (rctx->type.dataType.IsIntegerType() || + rctx->type.dataType.IsUnsignedType()) ) + { + to.SetTokenType(ttInt); + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true); + to.SetTokenType(ttDouble); + } + else + { + ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true); + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true); + } + } + reservedVariables.SetLength(l); + + // Verify that the conversion was successful + if( !lctx->type.dataType.IsIntegerType() && + !lctx->type.dataType.IsUnsignedType() && + !lctx->type.dataType.IsFloatType() && + !lctx->type.dataType.IsDoubleType() ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + ctx->type.SetDummy(); + return; + } + + if( !rctx->type.dataType.IsIntegerType() && + !rctx->type.dataType.IsUnsignedType() && + !rctx->type.dataType.IsFloatType() && + !rctx->type.dataType.IsDoubleType() ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_MATH_TYPE, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + ctx->type.SetDummy(); + return; + } + + bool isConstant = lctx->type.isConstant && rctx->type.isConstant; + + // Verify if we are dividing with a constant zero + if( rctx->type.isConstant && + (op == ttSlash || op == ttDivAssign || + op == ttPercent || op == ttModAssign) && + ((rctx->type.dataType.GetSizeInMemoryBytes() == 4 && rctx->type.GetConstantDW() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 8 && rctx->type.GetConstantQW() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 1 && rctx->type.GetConstantB() == 0) || + (rctx->type.dataType.GetSizeInMemoryBytes() == 2 && rctx->type.GetConstantW() == 0)) ) + { + Error(TXT_DIVIDE_BY_ZERO, node); + } + + if( !isConstant ) + { + ConvertToVariableNotIn(lctx, rctx); + ConvertToVariableNotIn(rctx, lctx); + ReleaseTemporaryVariable(lctx->type, &lctx->bc); + ReleaseTemporaryVariable(rctx->type, &rctx->bc); + + if( op == ttAddAssign || op == ttSubAssign || + op == ttMulAssign || op == ttDivAssign || + op == ttModAssign || op == ttPowAssign ) + { + // Merge the operands in the different order so that they are evaluated correctly + MergeExprBytecode(ctx, rctx); + MergeExprBytecode(ctx, lctx); + + // We must not process the deferred parameters yet, as + // it may overwrite the lvalue kept in the register + } + else + { + MergeExprBytecode(ctx, lctx); + MergeExprBytecode(ctx, rctx); + + ProcessDeferredParams(ctx); + } + + asEBCInstr instruction = asBC_ADDi; + if( lctx->type.dataType.IsIntegerType() || + lctx->type.dataType.IsUnsignedType() ) + { + if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + if( op == ttPlus || op == ttAddAssign ) + instruction = asBC_ADDi; + else if( op == ttMinus || op == ttSubAssign ) + instruction = asBC_SUBi; + else if( op == ttStar || op == ttMulAssign ) + instruction = asBC_MULi; + else if( op == ttSlash || op == ttDivAssign ) + { + if( lctx->type.dataType.IsIntegerType() ) + instruction = asBC_DIVi; + else + instruction = asBC_DIVu; + } + else if( op == ttPercent || op == ttModAssign ) + { + if( lctx->type.dataType.IsIntegerType() ) + instruction = asBC_MODi; + else + instruction = asBC_MODu; + } + else if( op == ttStarStar || op == ttPowAssign ) + { + if( lctx->type.dataType.IsIntegerType() ) + instruction = asBC_POWi; + else + instruction = asBC_POWu; + } + } + else + { + if( op == ttPlus || op == ttAddAssign ) + instruction = asBC_ADDi64; + else if( op == ttMinus || op == ttSubAssign ) + instruction = asBC_SUBi64; + else if( op == ttStar || op == ttMulAssign ) + instruction = asBC_MULi64; + else if( op == ttSlash || op == ttDivAssign ) + { + if( lctx->type.dataType.IsIntegerType() ) + instruction = asBC_DIVi64; + else + instruction = asBC_DIVu64; + } + else if( op == ttPercent || op == ttModAssign ) + { + if( lctx->type.dataType.IsIntegerType() ) + instruction = asBC_MODi64; + else + instruction = asBC_MODu64; + } + else if( op == ttStarStar || op == ttPowAssign ) + { + if( lctx->type.dataType.IsIntegerType() ) + instruction = asBC_POWi64; + else + instruction = asBC_POWu64; + } + } + } + else if( lctx->type.dataType.IsFloatType() ) + { + if( op == ttPlus || op == ttAddAssign ) + instruction = asBC_ADDf; + else if( op == ttMinus || op == ttSubAssign ) + instruction = asBC_SUBf; + else if( op == ttStar || op == ttMulAssign ) + instruction = asBC_MULf; + else if( op == ttSlash || op == ttDivAssign ) + instruction = asBC_DIVf; + else if( op == ttPercent || op == ttModAssign ) + instruction = asBC_MODf; + else if( op == ttStarStar || op == ttPowAssign ) + instruction = asBC_POWf; + } + else if( lctx->type.dataType.IsDoubleType() ) + { + if( rctx->type.dataType.IsIntegerType() ) + { + asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1); + + if( op == ttStarStar || op == ttPowAssign ) + instruction = asBC_POWdi; + else + asASSERT(false); // Should not be possible + } + else + { + if( op == ttPlus || op == ttAddAssign ) + instruction = asBC_ADDd; + else if( op == ttMinus || op == ttSubAssign ) + instruction = asBC_SUBd; + else if( op == ttStar || op == ttMulAssign ) + instruction = asBC_MULd; + else if( op == ttSlash || op == ttDivAssign ) + instruction = asBC_DIVd; + else if( op == ttPercent || op == ttModAssign ) + instruction = asBC_MODd; + else if( op == ttStarStar || op == ttPowAssign ) + instruction = asBC_POWd; + } + } + else + { + // Shouldn't be possible + asASSERT(false); + } + + // Do the operation + int a = AllocateVariable(lctx->type.dataType, true); + int b = lctx->type.stackOffset; + int c = rctx->type.stackOffset; + + ctx->bc.InstrW_W_W(instruction, a, b, c); + + ctx->type.SetVariable(lctx->type.dataType, a, true); + } + else + { + // Both values are constants + if( lctx->type.dataType.IsIntegerType() || + lctx->type.dataType.IsUnsignedType() ) + { + if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + int v = 0; + if( op == ttPlus ) + v = int(lctx->type.GetConstantDW()) + int(rctx->type.GetConstantDW()); + else if( op == ttMinus ) + v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); + else if( op == ttStar ) + v = int(lctx->type.GetConstantDW()) * int(rctx->type.GetConstantDW()); + else if( op == ttSlash ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = int(lctx->type.GetConstantDW()) / int(rctx->type.GetConstantDW()); + else + v = lctx->type.GetConstantDW() / rctx->type.GetConstantDW(); + } + else if( op == ttPercent ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantDW() == 0 || (int(rctx->type.GetConstantDW()) == -1 && lctx->type.GetConstantDW() == 0x80000000) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = int(lctx->type.GetConstantDW()) % int(rctx->type.GetConstantDW()); + else + v = lctx->type.GetConstantDW() % rctx->type.GetConstantDW(); + } + else if( op == ttStarStar ) + { + bool isOverflow; + if( lctx->type.dataType.IsIntegerType() ) + v = as_powi(int(lctx->type.GetConstantDW()), int(rctx->type.GetConstantDW()), isOverflow); + else + v = as_powu(lctx->type.GetConstantDW(), rctx->type.GetConstantDW(), isOverflow); + + if( isOverflow ) + Error(TXT_POW_OVERFLOW, node); + } + + ctx->type.SetConstantDW(lctx->type.dataType, v); + + // If the right value is greater than the left value in a minus operation, then we need to convert the type to int + if( lctx->type.dataType.GetTokenType() == ttUInt && op == ttMinus && lctx->type.GetConstantDW() < rctx->type.GetConstantDW()) + ctx->type.dataType.SetTokenType(ttInt); + } + else + { + asQWORD v = 0; + if( op == ttPlus ) + v = asINT64(lctx->type.GetConstantQW()) + asINT64(rctx->type.GetConstantQW()); + else if( op == ttMinus ) + v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); + else if( op == ttStar ) + v = asINT64(lctx->type.GetConstantQW()) * asINT64(rctx->type.GetConstantQW()); + else if( op == ttSlash ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = asINT64(lctx->type.GetConstantQW()) / asINT64(rctx->type.GetConstantQW()); + else + v = lctx->type.GetConstantQW() / rctx->type.GetConstantQW(); + } + else if( op == ttPercent ) + { + // TODO: Should probably report an error, rather than silently convert the value to 0 + if( rctx->type.GetConstantQW() == 0 || (rctx->type.GetConstantQW() == asQWORD(-1) && lctx->type.GetConstantQW() == (asQWORD(1)<<63)) ) + v = 0; + else + if( lctx->type.dataType.IsIntegerType() ) + v = asINT64(lctx->type.GetConstantQW()) % asINT64(rctx->type.GetConstantQW()); + else + v = lctx->type.GetConstantQW() % rctx->type.GetConstantQW(); + } + else if( op == ttStarStar ) + { + bool isOverflow; + if( lctx->type.dataType.IsIntegerType() ) + v = as_powi64(asINT64(lctx->type.GetConstantQW()), asINT64(rctx->type.GetConstantQW()), isOverflow); + else + v = as_powu64(lctx->type.GetConstantQW(), rctx->type.GetConstantQW(), isOverflow); + + if( isOverflow ) + Error(TXT_POW_OVERFLOW, node); + } + + ctx->type.SetConstantQW(lctx->type.dataType, v); + + // If the right value is greater than the left value in a minus operation, then we need to convert the type to int + if( lctx->type.dataType.GetTokenType() == ttUInt64 && op == ttMinus && lctx->type.GetConstantQW() < rctx->type.GetConstantQW()) + ctx->type.dataType.SetTokenType(ttInt64); + } + } + else if( lctx->type.dataType.IsFloatType() ) + { + float v = 0.0f; + if( op == ttPlus ) + v = lctx->type.GetConstantF() + rctx->type.GetConstantF(); + else if( op == ttMinus ) + v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); + else if( op == ttStar ) + v = lctx->type.GetConstantF() * rctx->type.GetConstantF(); + else if( op == ttSlash ) + { + if( rctx->type.GetConstantF() == 0 ) + v = 0; + else + v = lctx->type.GetConstantF() / rctx->type.GetConstantF(); + } + else if( op == ttPercent ) + { + if( rctx->type.GetConstantF() == 0 ) + v = 0; + else + v = fmodf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); + } + else if( op == ttStarStar ) + { + v = powf(lctx->type.GetConstantF(), rctx->type.GetConstantF()); + + if( v == HUGE_VAL ) + Error(TXT_POW_OVERFLOW, node); + } + + ctx->type.SetConstantF(lctx->type.dataType, v); + } + else if( lctx->type.dataType.IsDoubleType() ) + { + double v = 0.0; + if( rctx->type.dataType.IsIntegerType() ) + { + asASSERT(rctx->type.dataType.GetSizeInMemoryDWords() == 1); + + if( op == ttStarStar || op == ttPowAssign ) + { + v = pow(lctx->type.GetConstantD(), int(rctx->type.GetConstantDW())); + if( v == HUGE_VAL ) + Error(TXT_POW_OVERFLOW, node); + } + else + asASSERT(false); // Should not be possible + } + else + { + if( op == ttPlus ) + v = lctx->type.GetConstantD() + rctx->type.GetConstantD(); + else if( op == ttMinus ) + v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); + else if( op == ttStar ) + v = lctx->type.GetConstantD() * rctx->type.GetConstantD(); + else if( op == ttSlash ) + { + if( rctx->type.GetConstantD() == 0 ) + v = 0; + else + v = lctx->type.GetConstantD() / rctx->type.GetConstantD(); + } + else if( op == ttPercent ) + { + if( rctx->type.GetConstantD() == 0 ) + v = 0; + else + v = fmod(lctx->type.GetConstantD(), rctx->type.GetConstantD()); + } + else if( op == ttStarStar ) + { + v = pow(lctx->type.GetConstantD(), rctx->type.GetConstantD()); + if( v == HUGE_VAL ) + Error(TXT_POW_OVERFLOW, node); + } + } + + ctx->type.SetConstantD(lctx->type.dataType, v); + } + else + { + // Shouldn't be possible + asASSERT(false); + } + } +} + +void asCCompiler::CompileBitwiseOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) +{ + // TODO: If a constant is only using 32bits, then a 32bit operation is preferred + + if( op == ttUnrecognizedToken ) + op = node->tokenType; + if( op == ttAmp || op == ttAndAssign || + op == ttBitOr || op == ttOrAssign || + op == ttBitXor || op == ttXorAssign ) + { + // Also do not permit float/double to be implicitly converted to integer in this case + // as the user may think the result is a bitwise operation on the float value but it's not + if (lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType()) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + // Set an integer value and allow the compiler to continue + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); + return; + } + if (rctx->type.dataType.IsFloatType() || rctx->type.dataType.IsDoubleType()) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + // Set an integer value and allow the compiler to continue + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); + return; + } + + // Convert left hand operand to integer if it's not already one + asCDataType to; + if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || + rctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + to.SetTokenType(ttInt64); + else + to.SetTokenType(ttInt); + + // Do the actual conversion (keep sign/unsigned if possible) + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + if( lctx->type.dataType.IsUnsignedType() ) + to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 ); + else + to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 ); + ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true); + reservedVariables.SetLength(l); + + // Verify that the conversion was successful + if( lctx->type.dataType != to ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + // Convert right hand operand to same size as left hand + l = int(reservedVariables.GetLength()); + lctx->bc.GetVarsUsed(reservedVariables); + if( rctx->type.dataType.IsUnsignedType() ) + to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttUInt : ttUInt64 ); + else + to.SetTokenType( to.GetSizeOnStackDWords() == 1 ? ttInt : ttInt64 ); + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV, true); + reservedVariables.SetLength(l); + if( rctx->type.dataType != to ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + bool isConstant = lctx->type.isConstant && rctx->type.isConstant; + + if( !isConstant ) + { + ConvertToVariableNotIn(lctx, rctx); + ConvertToVariableNotIn(rctx, lctx); + ReleaseTemporaryVariable(lctx->type, &lctx->bc); + ReleaseTemporaryVariable(rctx->type, &rctx->bc); + + if( op == ttAndAssign || op == ttOrAssign || op == ttXorAssign ) + { + // Compound assignments execute the right hand value first + MergeExprBytecode(ctx, rctx); + MergeExprBytecode(ctx, lctx); + } + else + { + MergeExprBytecode(ctx, lctx); + MergeExprBytecode(ctx, rctx); + } + ProcessDeferredParams(ctx); + + asEBCInstr instruction = asBC_BAND; + if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + if( op == ttAmp || op == ttAndAssign ) + instruction = asBC_BAND; + else if( op == ttBitOr || op == ttOrAssign ) + instruction = asBC_BOR; + else if( op == ttBitXor || op == ttXorAssign ) + instruction = asBC_BXOR; + } + else + { + if( op == ttAmp || op == ttAndAssign ) + instruction = asBC_BAND64; + else if( op == ttBitOr || op == ttOrAssign ) + instruction = asBC_BOR64; + else if( op == ttBitXor || op == ttXorAssign ) + instruction = asBC_BXOR64; + } + + // Do the operation + int a = AllocateVariable(lctx->type.dataType, true); + int b = lctx->type.stackOffset; + int c = rctx->type.stackOffset; + + ctx->bc.InstrW_W_W(instruction, a, b, c); + + ctx->type.SetVariable(lctx->type.dataType, a, true); + } + else + { + if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + asQWORD v = 0; + if( op == ttAmp ) + v = lctx->type.GetConstantQW() & rctx->type.GetConstantQW(); + else if( op == ttBitOr ) + v = lctx->type.GetConstantQW() | rctx->type.GetConstantQW(); + else if( op == ttBitXor ) + v = lctx->type.GetConstantQW() ^ rctx->type.GetConstantQW(); + + // Remember the result + ctx->type.SetConstantQW(lctx->type.dataType, v); + } + else + { + asDWORD v = 0; + if( op == ttAmp ) + v = lctx->type.GetConstantDW() & rctx->type.GetConstantDW(); + else if( op == ttBitOr ) + v = lctx->type.GetConstantDW() | rctx->type.GetConstantDW(); + else if( op == ttBitXor ) + v = lctx->type.GetConstantDW() ^ rctx->type.GetConstantDW(); + + // Remember the result + ctx->type.SetConstantDW(lctx->type.dataType, v); + } + } + } + else if( op == ttBitShiftLeft || op == ttShiftLeftAssign || + op == ttBitShiftRight || op == ttShiftRightLAssign || + op == ttBitShiftRightArith || op == ttShiftRightAAssign ) + { + // Don't permit object to primitive conversion, since we don't know which integer type is the correct one + // Also do not permit float/double to be implicitly converted to integer in this case + if( lctx->type.dataType.IsObject() || lctx->type.dataType.IsFloatType() || lctx->type.dataType.IsDoubleType() ) + { + asCString str; + str.Format(TXT_ILLEGAL_OPERATION_ON_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + + // Set an integer value and allow the compiler to continue + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); + return; + } + + // Convert left hand operand to integer if it's not already one + asCDataType to = lctx->type.dataType; + if( lctx->type.dataType.IsUnsignedType() && + lctx->type.dataType.GetSizeInMemoryBytes() < 4 ) + { + // Upgrade to 32bit + to = asCDataType::CreatePrimitive(ttUInt, false); + } + else if( !lctx->type.dataType.IsUnsignedType() ) + { + if (lctx->type.dataType.GetSizeInMemoryDWords() == 2) + to = asCDataType::CreatePrimitive(ttInt64, false); + else + to = asCDataType::CreatePrimitive(ttInt, false); + } + + // Do the actual conversion + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV, true); + reservedVariables.SetLength(l); + + // Verify that the conversion was successful + if( lctx->type.dataType != to ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + // Right operand must be 32bit uint + l = int(reservedVariables.GetLength()); + lctx->bc.GetVarsUsed(reservedVariables); + ImplicitConversion(rctx, asCDataType::CreatePrimitive(ttUInt, true), node, asIC_IMPLICIT_CONV, true); + reservedVariables.SetLength(l); + if( !rctx->type.dataType.IsUnsignedType() ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "uint"); + Error(str, node); + } + + bool isConstant = lctx->type.isConstant && rctx->type.isConstant; + + if( !isConstant ) + { + ConvertToVariableNotIn(lctx, rctx); + ConvertToVariableNotIn(rctx, lctx); + ReleaseTemporaryVariable(lctx->type, &lctx->bc); + ReleaseTemporaryVariable(rctx->type, &rctx->bc); + + if( op == ttShiftLeftAssign || op == ttShiftRightLAssign || op == ttShiftRightAAssign ) + { + // Compound assignments execute the right hand value first + MergeExprBytecode(ctx, rctx); + MergeExprBytecode(ctx, lctx); + } + else + { + MergeExprBytecode(ctx, lctx); + MergeExprBytecode(ctx, rctx); + } + ProcessDeferredParams(ctx); + + asEBCInstr instruction = asBC_BSLL; + if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + if( op == ttBitShiftLeft || op == ttShiftLeftAssign ) + instruction = asBC_BSLL; + else if( op == ttBitShiftRight || op == ttShiftRightLAssign ) + instruction = asBC_BSRL; + else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign ) + instruction = asBC_BSRA; + } + else + { + if( op == ttBitShiftLeft || op == ttShiftLeftAssign ) + instruction = asBC_BSLL64; + else if( op == ttBitShiftRight || op == ttShiftRightLAssign ) + instruction = asBC_BSRL64; + else if( op == ttBitShiftRightArith || op == ttShiftRightAAssign ) + instruction = asBC_BSRA64; + } + + // Do the operation + int a = AllocateVariable(lctx->type.dataType, true); + int b = lctx->type.stackOffset; + int c = rctx->type.stackOffset; + + ctx->bc.InstrW_W_W(instruction, a, b, c); + + ctx->type.SetVariable(lctx->type.dataType, a, true); + } + else + { + if( lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + asDWORD v = 0; + if( op == ttBitShiftLeft ) + v = lctx->type.GetConstantDW() << rctx->type.GetConstantDW(); + else if( op == ttBitShiftRight ) + v = lctx->type.GetConstantDW() >> rctx->type.GetConstantDW(); + else if( op == ttBitShiftRightArith ) + v = int(lctx->type.GetConstantDW()) >> rctx->type.GetConstantDW(); + + ctx->type.SetConstantDW(lctx->type.dataType, v); + } + else + { + asQWORD v = 0; + if( op == ttBitShiftLeft ) + v = lctx->type.GetConstantQW() << rctx->type.GetConstantDW(); + else if( op == ttBitShiftRight ) + v = lctx->type.GetConstantQW() >> rctx->type.GetConstantDW(); + else if( op == ttBitShiftRightArith ) + v = asINT64(lctx->type.GetConstantQW()) >> rctx->type.GetConstantDW(); + + ctx->type.SetConstantQW(lctx->type.dataType, v); + } + } + } +} + +void asCCompiler::CompileComparisonOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) +{ + // Both operands must be of the same type + + // If either operand is a non-primitive then first convert them to the best number type + if( !lctx->type.dataType.IsPrimitive() ) + { + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + ImplicitConvObjectToBestMathType(lctx, node); + reservedVariables.SetLength(l); + } + if( !rctx->type.dataType.IsPrimitive() ) + { + int l = int(reservedVariables.GetLength()); + lctx->bc.GetVarsUsed(reservedVariables); + ImplicitConvObjectToBestMathType(rctx, node); + reservedVariables.SetLength(l); + } + + // Implicitly convert the operands to matching types + asCDataType to; + if( lctx->type.dataType.IsDoubleType() || rctx->type.dataType.IsDoubleType() ) + to.SetTokenType(ttDouble); + else if( lctx->type.dataType.IsFloatType() || rctx->type.dataType.IsFloatType() ) + to.SetTokenType(ttFloat); + else if( lctx->type.dataType.GetSizeInMemoryDWords() == 2 || rctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + // Convert to int64 if both are signed or if one is non-constant and signed + if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || + (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) + to.SetTokenType(ttInt64); + else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) + to.SetTokenType(ttUInt64); + else + to.SetTokenType(ttInt64); + } + else + { + // Convert to int32 if both are signed or if one is non-constant and signed + if( (lctx->type.dataType.IsIntegerType() && !lctx->type.isConstant) || + (rctx->type.dataType.IsIntegerType() && !rctx->type.isConstant) ) + to.SetTokenType(ttInt); + else if( lctx->type.dataType.IsUnsignedType() || rctx->type.dataType.IsUnsignedType() ) + to.SetTokenType(ttUInt); + else if( lctx->type.dataType.IsBooleanType() || rctx->type.dataType.IsBooleanType() ) + to.SetTokenType(ttBool); + else + to.SetTokenType(ttInt); + } + + // If doing an operation with double constant and float variable, the constant should be converted to float + if( (lctx->type.isConstant && lctx->type.dataType.IsDoubleType() && !rctx->type.isConstant && rctx->type.dataType.IsFloatType()) || + (rctx->type.isConstant && rctx->type.dataType.IsDoubleType() && !lctx->type.isConstant && lctx->type.dataType.IsFloatType()) ) + to.SetTokenType(ttFloat); + + asASSERT( to.GetTokenType() != ttUnrecognizedToken ); + + // Do we have a mismatch between the sign of the operand? + bool signMismatch = false; + for( int n = 0; !signMismatch && n < 2; n++ ) + { + asCExprContext *opCtx = n ? rctx : lctx; + + if( opCtx->type.dataType.IsUnsignedType() != to.IsUnsignedType() ) + { + // We have a mismatch, unless the value is a literal constant and the conversion won't affect its value + signMismatch = true; + if( opCtx->type.isConstant ) + { + if( opCtx->type.dataType.GetTokenType() == ttUInt64 || opCtx->type.dataType.GetTokenType() == ttInt64 ) + { + if( !(opCtx->type.GetConstantQW() & (asQWORD(1)<<63)) ) + signMismatch = false; + } + else if(opCtx->type.dataType.GetTokenType() == ttUInt || opCtx->type.dataType.GetTokenType() == ttInt || opCtx->type.dataType.IsEnumType() ) + { + if( !(opCtx->type.GetConstantDW() & (1<<31)) ) + signMismatch = false; + } + else if (opCtx->type.dataType.GetTokenType() == ttUInt16 || opCtx->type.dataType.GetTokenType() == ttInt16) + { + if (!(opCtx->type.GetConstantW() & (1 << 15))) + signMismatch = false; + } + else if (opCtx->type.dataType.GetTokenType() == ttUInt8 || opCtx->type.dataType.GetTokenType() == ttInt8) + { + if (!(opCtx->type.GetConstantB() & (1 << 7))) + signMismatch = false; + } + + // It's not necessary to check for floats or double, because if + // it was then the types for the conversion will never be unsigned + } + } + } + + // Check for signed/unsigned mismatch + if( signMismatch ) + Warning(TXT_SIGNED_UNSIGNED_MISMATCH, node); + + // Attempt to resolve ambiguous enumerations + if( lctx->type.dataType.IsEnumType() && rctx->enumValue != "" ) + ImplicitConversion(rctx, lctx->type.dataType, node, asIC_IMPLICIT_CONV); + else if( rctx->type.dataType.IsEnumType() && lctx->enumValue != "" ) + ImplicitConversion(lctx, rctx->type.dataType, node, asIC_IMPLICIT_CONV); + + // Do the actual conversion + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + + if( lctx->type.dataType.IsReference() ) + ConvertToVariable(lctx); + if( rctx->type.dataType.IsReference() ) + ConvertToVariable(rctx); + + ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV); + reservedVariables.SetLength(l); + + // Verify that the conversion was successful + bool ok = true; + if( !lctx->type.dataType.IsEqualExceptConst(to) ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + ok = false; + } + + if( !rctx->type.dataType.IsEqualExceptConst(to) ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + ok = false; + } + + if( !ok ) + { + // It wasn't possible to get two valid operands, so we just return + // a boolean result and let the compiler continue. +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); +#else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); +#endif + return; + } + + bool isConstant = lctx->type.isConstant && rctx->type.isConstant; + + if( op == ttUnrecognizedToken ) + op = node->tokenType; + + if( !isConstant ) + { + if( to.IsBooleanType() ) + { + if( op == ttEqual || op == ttNotEqual ) + { + // Must convert to temporary variable, because we are changing the value before comparison + ConvertToTempVariableNotIn(lctx, rctx); + ConvertToTempVariableNotIn(rctx, lctx); + ReleaseTemporaryVariable(lctx->type, &lctx->bc); + ReleaseTemporaryVariable(rctx->type, &rctx->bc); + + // Make sure they are equal if not false + lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset); + rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset); + + MergeExprBytecode(ctx, lctx); + MergeExprBytecode(ctx, rctx); + ProcessDeferredParams(ctx); + + int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true); + int b = lctx->type.stackOffset; + int c = rctx->type.stackOffset; + + if( op == ttEqual ) + { + ctx->bc.InstrW_W(asBC_CMPi,b,c); + ctx->bc.Instr(asBC_TZ); + ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); + } + else if( op == ttNotEqual ) + { + ctx->bc.InstrW_W(asBC_CMPi,b,c); + ctx->bc.Instr(asBC_TNZ); + ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); + } + + ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); + } + else + { + // TODO: Use TXT_ILLEGAL_OPERATION_ON + Error(TXT_ILLEGAL_OPERATION, node); +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), 0); +#else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), 0); +#endif + } + } + else + { + ConvertToVariableNotIn(lctx, rctx); + ConvertToVariableNotIn(rctx, lctx); + ReleaseTemporaryVariable(lctx->type, &lctx->bc); + ReleaseTemporaryVariable(rctx->type, &rctx->bc); + + MergeExprBytecode(ctx, lctx); + MergeExprBytecode(ctx, rctx); + ProcessDeferredParams(ctx); + + asEBCInstr iCmp = asBC_CMPi, iT = asBC_TZ; + + if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + iCmp = asBC_CMPi; + else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + iCmp = asBC_CMPu; + else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + iCmp = asBC_CMPi64; + else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + iCmp = asBC_CMPu64; + else if( lctx->type.dataType.IsFloatType() ) + iCmp = asBC_CMPf; + else if( lctx->type.dataType.IsDoubleType() ) + iCmp = asBC_CMPd; + else + asASSERT(false); + + if( op == ttEqual ) + iT = asBC_TZ; + else if( op == ttNotEqual ) + iT = asBC_TNZ; + else if( op == ttLessThan ) + iT = asBC_TS; + else if( op == ttLessThanOrEqual ) + iT = asBC_TNP; + else if( op == ttGreaterThan ) + iT = asBC_TP; + else if( op == ttGreaterThanOrEqual ) + iT = asBC_TNS; + + int a = AllocateVariable(asCDataType::CreatePrimitive(ttBool, true), true); + int b = lctx->type.stackOffset; + int c = rctx->type.stackOffset; + + ctx->bc.InstrW_W(iCmp, b, c); + ctx->bc.Instr(iT); + ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); + + ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); + } + } + else + { + if( to.IsBooleanType() ) + { + if( op == ttEqual || op == ttNotEqual ) + { + asDWORD lv, rv; + #if AS_SIZEOF_BOOL == 1 + lv = lctx->type.GetConstantB(); + rv = rctx->type.GetConstantB(); + #else + lv = lctx->type.GetConstantDW(); + rv = rctx->type.GetConstantDW(); + #endif + + // Make sure they are equal if not false + if (lv != 0) lv = VALUE_OF_BOOLEAN_TRUE; + if (rv != 0) rv = VALUE_OF_BOOLEAN_TRUE; + + asDWORD v = 0; + if (op == ttEqual) + v = (lv == rv) ? VALUE_OF_BOOLEAN_TRUE : 0; + else if (op == ttNotEqual) + v = (lv != rv) ? VALUE_OF_BOOLEAN_TRUE : 0; + + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)v); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), v); + #endif + } + else + { + // TODO: Use TXT_ILLEGAL_OPERATION_ON + Error(TXT_ILLEGAL_OPERATION, node); + } + } + else + { + int i = 0; + if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + int v = int(lctx->type.GetConstantDW()) - int(rctx->type.GetConstantDW()); + if( v < 0 ) i = -1; + if( v > 0 ) i = 1; + } + else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + { + asDWORD v1 = lctx->type.GetConstantDW(); + asDWORD v2 = rctx->type.GetConstantDW(); + if( v1 < v2 ) i = -1; + if( v1 > v2 ) i = 1; + } + else if( lctx->type.dataType.IsIntegerType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + asINT64 v = asINT64(lctx->type.GetConstantQW()) - asINT64(rctx->type.GetConstantQW()); + if( v < 0 ) i = -1; + if( v > 0 ) i = 1; + } + else if( lctx->type.dataType.IsUnsignedType() && lctx->type.dataType.GetSizeInMemoryDWords() == 2 ) + { + asQWORD v1 = lctx->type.GetConstantQW(); + asQWORD v2 = rctx->type.GetConstantQW(); + if( v1 < v2 ) i = -1; + if( v1 > v2 ) i = 1; + } + else if( lctx->type.dataType.IsFloatType() ) + { + float v = lctx->type.GetConstantF() - rctx->type.GetConstantF(); + if( v < 0 ) i = -1; + if( v > 0 ) i = 1; + } + else if( lctx->type.dataType.IsDoubleType() ) + { + double v = lctx->type.GetConstantD() - rctx->type.GetConstantD(); + if( v < 0 ) i = -1; + if( v > 0 ) i = 1; + } + + + if( op == ttEqual ) + i = (i == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + else if( op == ttNotEqual ) + i = (i != 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + else if( op == ttLessThan ) + i = (i < 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + else if( op == ttLessThanOrEqual ) + i = (i <= 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + else if( op == ttGreaterThan ) + i = (i > 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + else if( op == ttGreaterThanOrEqual ) + i = (i >= 0 ? VALUE_OF_BOOLEAN_TRUE : 0); + + #if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), (asBYTE)i); + #else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), i); + #endif + } + } +} + +void asCCompiler::PushVariableOnStack(asCExprContext *ctx, bool asReference) +{ + // Put the result on the stack + if( asReference ) + { + ctx->bc.InstrSHORT(asBC_PSF, ctx->type.stackOffset); + ctx->type.dataType.MakeReference(true); + } + else + { + if( ctx->type.dataType.GetSizeInMemoryDWords() == 1 ) + ctx->bc.InstrSHORT(asBC_PshV4, ctx->type.stackOffset); + else + ctx->bc.InstrSHORT(asBC_PshV8, ctx->type.stackOffset); + } +} + +void asCCompiler::CompileBooleanOperator(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType op) +{ + // Both operands must be booleans + asCDataType to; + to.SetTokenType(ttBool); + + // Do the actual conversion + int l = int(reservedVariables.GetLength()); + rctx->bc.GetVarsUsed(reservedVariables); + lctx->bc.GetVarsUsed(reservedVariables); + + // Allow value types to be converted to bool using 'bool opImplConv()' + if( lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); + if( rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_VALUE) ) + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV); + reservedVariables.SetLength(l); + + // Verify that the conversion was successful + if( !lctx->type.dataType.IsBooleanType() ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool"); + Error(str, node); + // Force the conversion to allow compilation to proceed + lctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + } + + if( !rctx->type.dataType.IsBooleanType() ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), "bool"); + Error(str, node); + // Force the conversion to allow compilation to proceed + rctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); + } + + bool isConstant = lctx->type.isConstant && rctx->type.isConstant; + + ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true)); + + // What kind of operator is it? + if( op == ttUnrecognizedToken ) + op = node->tokenType; + if( op == ttXor ) + { + if( !isConstant ) + { + // Must convert to temporary variable, because we are changing the value before comparison + ConvertToTempVariableNotIn(lctx, rctx); + ConvertToTempVariableNotIn(rctx, lctx); + ReleaseTemporaryVariable(lctx->type, &lctx->bc); + ReleaseTemporaryVariable(rctx->type, &rctx->bc); + + // Make sure they are equal if not false + lctx->bc.InstrWORD(asBC_NOT, lctx->type.stackOffset); + rctx->bc.InstrWORD(asBC_NOT, rctx->type.stackOffset); + + MergeExprBytecode(ctx, lctx); + MergeExprBytecode(ctx, rctx); + ProcessDeferredParams(ctx); + + int a = AllocateVariable(ctx->type.dataType, true); + int b = lctx->type.stackOffset; + int c = rctx->type.stackOffset; + + ctx->bc.InstrW_W_W(asBC_BXOR,a,b,c); + + ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); + } + else + { + // Make sure they are equal if not false +#if AS_SIZEOF_BOOL == 1 + if( lctx->type.GetConstantB() != 0 ) lctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); + if( rctx->type.GetConstantB() != 0 ) rctx->type.SetConstantB(VALUE_OF_BOOLEAN_TRUE); + + asBYTE v = 0; + v = lctx->type.GetConstantB() - rctx->type.GetConstantB(); + if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; + + ctx->type.isConstant = true; + ctx->type.SetConstantB(v); +#else + if( lctx->type.GetConstantDW() != 0 ) lctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); + if( rctx->type.GetConstantDW() != 0 ) rctx->type.SetConstantDW(VALUE_OF_BOOLEAN_TRUE); + + asDWORD v = 0; + v = lctx->type.GetConstantDW() - rctx->type.GetConstantDW(); + if( v != 0 ) v = VALUE_OF_BOOLEAN_TRUE; else v = 0; + + ctx->type.isConstant = true; + ctx->type.SetConstantDW(v); +#endif + } + } + else if( op == ttAnd || + op == ttOr ) + { + if( !isConstant ) + { + // If or-operator and first value is 1 the second value shouldn't be calculated + // if and-operator and first value is 0 the second value shouldn't be calculated + ConvertToVariable(lctx); + ReleaseTemporaryVariable(lctx->type, &lctx->bc); + MergeExprBytecode(ctx, lctx); + + int offset = AllocateVariable(asCDataType::CreatePrimitive(ttBool, false), true); + + int label1 = nextLabel++; + int label2 = nextLabel++; + + ctx->bc.InstrSHORT(asBC_CpyVtoR4, lctx->type.stackOffset); + ctx->bc.Instr(asBC_ClrHi); + if( op == ttAnd ) + { + ctx->bc.InstrDWORD(asBC_JNZ, label1); + ctx->bc.InstrW_DW(asBC_SetV4, (asWORD)offset, 0); + ctx->bc.InstrINT(asBC_JMP, label2); + } + else if( op == ttOr ) + { + ctx->bc.InstrDWORD(asBC_JZ, label1); +#if AS_SIZEOF_BOOL == 1 + ctx->bc.InstrSHORT_B(asBC_SetV1, (short)offset, VALUE_OF_BOOLEAN_TRUE); +#else + ctx->bc.InstrSHORT_DW(asBC_SetV4, (short)offset, VALUE_OF_BOOLEAN_TRUE); +#endif + ctx->bc.InstrINT(asBC_JMP, label2); + } + + ctx->bc.Label((short)label1); + ConvertToVariable(rctx); + ReleaseTemporaryVariable(rctx->type, &rctx->bc); + rctx->bc.InstrW_W(asBC_CpyVtoV4, offset, rctx->type.stackOffset); + MergeExprBytecode(ctx, rctx); + ctx->bc.Label((short)label2); + + ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, false), offset, true); + } + else + { +#if AS_SIZEOF_BOOL == 1 + asBYTE v = 0; + if( op == ttAnd ) + v = lctx->type.GetConstantB() && rctx->type.GetConstantB(); + else if( op == ttOr ) + v = lctx->type.GetConstantB() || rctx->type.GetConstantB(); + + // Remember the result + ctx->type.isConstant = true; + ctx->type.SetConstantB(v); +#else + asDWORD v = 0; + if( op == ttAnd ) + v = lctx->type.GetConstantDW() && rctx->type.GetConstantDW(); + else if( op == ttOr ) + v = lctx->type.GetConstantDW() || rctx->type.GetConstantDW(); + + // Remember the result + ctx->type.isConstant = true; + ctx->type.SetConstantDW(v); +#endif + } + } +} + +void asCCompiler::CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *lctx, asCExprContext *rctx, asCExprContext *ctx, eTokenType opToken) +{ + // Process the property accessor as get + if( ProcessPropertyGetAccessor(lctx, node) < 0 ) + return; + if( ProcessPropertyGetAccessor(rctx, node) < 0 ) + return; + + DetermineSingleFunc(lctx, node); + DetermineSingleFunc(rctx, node); + + // Make sure lctx doesn't end up with a variable used in rctx + if( lctx->type.isTemporary && rctx->bc.IsVarUsed(lctx->type.stackOffset) ) + { + asCArray vars; + rctx->bc.GetVarsUsed(vars); + int offset = AllocateVariable(lctx->type.dataType, true); + rctx->bc.ExchangeVar(lctx->type.stackOffset, offset); + ReleaseTemporaryVariable(offset, 0); + } + + if( opToken == ttUnrecognizedToken ) + opToken = node->tokenType; + + // Warn if not both operands are explicit handles or null handles + if( (opToken == ttEqual || opToken == ttNotEqual) && + ((!(lctx->type.isExplicitHandle || lctx->type.IsNullConstant()) && !(lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE))) || + (!(rctx->type.isExplicitHandle || rctx->type.IsNullConstant()) && !(rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_IMPLICIT_HANDLE)))) ) + { + Warning(TXT_HANDLE_COMPARISON, node); + } + + // If one of the operands is a value type used as handle, we should look for the opEquals method + if( ((lctx->type.dataType.GetTypeInfo() && (lctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE)) || + (rctx->type.dataType.GetTypeInfo() && (rctx->type.dataType.GetTypeInfo()->flags & asOBJ_ASHANDLE))) && + (opToken == ttEqual || opToken == ttIs || + opToken == ttNotEqual || opToken == ttNotIs) ) + { + // TODO: Should evaluate which of the two have the best match. If both have equal match, the first version should be used + // Find the matching opEquals method + int r = CompileOverloadedDualOperator2(node, "opEquals", lctx, rctx, true, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + if( r == 0 ) + { + // Try again by switching the order of the operands + r = CompileOverloadedDualOperator2(node, "opEquals", rctx, lctx, false, ctx, true, asCDataType::CreatePrimitive(ttBool, false)); + } + + if( r == 1 ) + { + if( opToken == ttNotEqual || opToken == ttNotIs ) + ctx->bc.InstrSHORT(asBC_NOT, ctx->type.stackOffset); + + // Success, don't continue + return; + } + else if( r == 0 ) + { + // Couldn't find opEquals method + Error(TXT_NO_APPROPRIATE_OPEQUALS, node); + } + + // Compiler error, don't continue +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); +#else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); +#endif + return; + } + + + // Implicitly convert null to the other type + asCDataType to; + if( lctx->type.IsNullConstant() ) + to = rctx->type.dataType; + else if( rctx->type.IsNullConstant() ) + to = lctx->type.dataType; + else + { + // Find a common base type + asCExprContext tmp(engine); + tmp.type = rctx->type; + ImplicitConversion(&tmp, lctx->type.dataType, 0, asIC_IMPLICIT_CONV, false); + if( tmp.type.dataType.GetTypeInfo() == lctx->type.dataType.GetTypeInfo() ) + to = lctx->type.dataType; + else + to = rctx->type.dataType; + + // Assume handle-to-const as it is not possible to convert handle-to-const to handle-to-non-const + to.MakeHandleToConst(true); + } + + // Need to pop the value if it is a null constant + if( lctx->type.IsNullConstant() ) + lctx->bc.Instr(asBC_PopPtr); + if( rctx->type.IsNullConstant() ) + rctx->bc.Instr(asBC_PopPtr); + + // Convert both sides to explicit handles + to.MakeHandle(true); + to.MakeReference(false); + + if( !to.IsObjectHandle() ) + { + // Compiler error, don't continue + Error(TXT_OPERANDS_MUST_BE_HANDLES, node); +#if AS_SIZEOF_BOOL == 1 + ctx->type.SetConstantB(asCDataType::CreatePrimitive(ttBool, true), true); +#else + ctx->type.SetConstantDW(asCDataType::CreatePrimitive(ttBool, true), true); +#endif + return; + } + + // Do the conversion + ImplicitConversion(lctx, to, node, asIC_IMPLICIT_CONV); + ImplicitConversion(rctx, to, node, asIC_IMPLICIT_CONV); + + // Both operands must be of the same type + + // Verify that the conversion was successful + if( !lctx->type.dataType.IsEqualExceptConst(to) ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, lctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + if( !rctx->type.dataType.IsEqualExceptConst(to) ) + { + asCString str; + str.Format(TXT_NO_CONVERSION_s_TO_s, rctx->type.dataType.Format(outFunc->nameSpace).AddressOf(), to.Format(outFunc->nameSpace).AddressOf()); + Error(str, node); + } + + // Make sure it really is handles that are being compared + if( !lctx->type.dataType.IsObjectHandle() ) + { + Error(TXT_OPERANDS_MUST_BE_HANDLES, node); + } + + ctx->type.Set(asCDataType::CreatePrimitive(ttBool, true)); + + if( opToken == ttEqual || opToken == ttNotEqual || opToken == ttIs || opToken == ttNotIs ) + { + // Make sure handles received as parameters by reference are copied to a local variable before the + // asBC_CmpPtr, so we don't end up comparing the reference to the handle instead of the handle itself + if( lctx->type.isVariable && !lctx->type.isTemporary && lctx->type.stackOffset <= 0 ) + lctx->type.isVariable = false; + if( rctx->type.isVariable && !rctx->type.isTemporary && rctx->type.stackOffset <= 0 ) + rctx->type.isVariable = false; + + // TODO: runtime optimize: don't do REFCPY if not necessary + ConvertToVariableNotIn(lctx, rctx); + ConvertToVariable(rctx); + + // Pop the pointers from the stack as they will not be used + lctx->bc.Instr(asBC_PopPtr); + rctx->bc.Instr(asBC_PopPtr); + + MergeExprBytecode(ctx, lctx); + MergeExprBytecode(ctx, rctx); + + int a = AllocateVariable(ctx->type.dataType, true); + int b = lctx->type.stackOffset; + int c = rctx->type.stackOffset; + + ctx->bc.InstrW_W(asBC_CmpPtr, b, c); + + if( opToken == ttEqual || opToken == ttIs ) + ctx->bc.Instr(asBC_TZ); + else if( opToken == ttNotEqual || opToken == ttNotIs ) + ctx->bc.Instr(asBC_TNZ); + + ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)a); + + ctx->type.SetVariable(asCDataType::CreatePrimitive(ttBool, true), a, true); + + ReleaseTemporaryVariable(lctx->type, &ctx->bc); + ReleaseTemporaryVariable(rctx->type, &ctx->bc); + ProcessDeferredParams(ctx); + } + else + { + // TODO: Use TXT_ILLEGAL_OPERATION_ON + Error(TXT_ILLEGAL_OPERATION, node); + } +} + + +void asCCompiler::PerformFunctionCall(int funcId, asCExprContext *ctx, bool isConstructor, asCArray *args, asCObjectType *objType, bool useVariable, int varOffset, int funcPtrVar) +{ + asCScriptFunction *descr = builder->GetFunctionDescription(funcId); + + // A shared object may not call non-shared functions + if( outFunc->IsShared() && !descr->IsShared() ) + { + asCString msg; + msg.Format(TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s, descr->GetDeclarationStr().AddressOf()); + Error(msg, ctx->exprNode); + } + + // Check if the function is private or protected + if (descr->IsPrivate()) + { + asCObjectType *type = descr->objectType; + if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR)) + type = CastToObjectType(descr->returnType.GetTypeInfo()); + + asASSERT(type); + + if( (type != outFunc->GetObjectType()) ) + { + asCString msg; + msg.Format(TXT_PRIVATE_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf()); + Error(msg, ctx->exprNode); + } + } + else if (descr->IsProtected()) + { + asCObjectType *type = descr->objectType; + if (type == 0 && descr->traits.GetTrait(asTRAIT_CONSTRUCTOR)) + type = CastToObjectType(descr->returnType.GetTypeInfo()); + + asASSERT(type); + + if (!(type == outFunc->objectType || (outFunc->objectType && outFunc->objectType->DerivesFrom(type)))) + { + asCString msg; + msg.Format(TXT_PROTECTED_METHOD_CALL_s, descr->GetDeclarationStr().AddressOf()); + Error(msg, ctx->exprNode); + } + } + + int argSize = descr->GetSpaceNeededForArguments(); + + // If we're calling a class method we must make sure the object is guaranteed to stay + // alive throughout the call by holding on to a reference in a local variable. This must + // be done for any methods that return references, and any calls on script objects. + // Application registered objects are assumed to know to keep themselves alive even + // if the method doesn't return a reference. + if( !ctx->type.isRefSafe && + descr->objectType && + (ctx->type.dataType.IsObjectHandle() || ctx->type.dataType.SupportHandles()) && + (descr->returnType.IsReference() || (ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCRIPT_OBJECT)) && + !(ctx->type.isVariable || ctx->type.isTemporary) && + !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_SCOPED) && + !(ctx->type.dataType.GetTypeInfo()->GetFlags() & asOBJ_ASHANDLE) ) + { + // TODO: runtime optimize: Avoid this for global variables, by storing a reference to the global variable once in a + // local variable and then refer to the same for each call. An alias for the global variable + // should be stored in the variable scope so that the compiler can find it. For loops and + // scopes that will always be executed, i.e. non-if scopes the alias should be stored in the + // higher scope to increase the probability of re-use. + + int tempRef = AllocateVariable(ctx->type.dataType, true); + ctx->bc.InstrSHORT(asBC_PSF, (short)tempRef); + ctx->bc.InstrPTR(asBC_REFCPY, ctx->type.dataType.GetTypeInfo()); + + // Add the release of this reference as a deferred expression + asSDeferredParam deferred; + deferred.origExpr = 0; + deferred.argInOutFlags = asTM_INREF; + deferred.argNode = 0; + deferred.argType.SetVariable(ctx->type.dataType, tempRef, true); + ctx->deferredParams.PushLast(deferred); + + // Forget the current type + ctx->type.SetDummy(); + } + + // Check if there is a need to add a hidden pointer for when the function returns an object by value + if( descr->DoesReturnOnStack() && !useVariable ) + { + useVariable = true; + varOffset = AllocateVariable(descr->returnType, true); + + // Push the pointer to the pre-allocated space for the return value + ctx->bc.InstrSHORT(asBC_PSF, short(varOffset)); + + if( descr->objectType ) + { + // The object pointer is already on the stack, but should be the top + // one, so we need to swap the pointers in order to get the correct + ctx->bc.Instr(asBC_SwapPtr); + } + } + + if( isConstructor ) + { + // Sometimes the value types are allocated on the heap, + // which is when this way of constructing them is used. + + asASSERT(useVariable == false); + + if( (objType->flags & asOBJ_TEMPLATE) ) + { + asASSERT( descr->funcType == asFUNC_SCRIPT ); + + // Find the id of the real constructor and not the generated stub + asUINT id = 0; + asDWORD *bc = descr->scriptData->byteCode.AddressOf(); + while( bc ) + { + if( (*(asBYTE*)bc) == asBC_CALLSYS ) + { + id = asBC_INTARG(bc); + break; + } + bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type]; + } + + asASSERT( id ); + + ctx->bc.InstrPTR(asBC_OBJTYPE, objType); + ctx->bc.Alloc(asBC_ALLOC, objType, id, argSize + AS_PTR_SIZE + AS_PTR_SIZE); + } + else + ctx->bc.Alloc(asBC_ALLOC, objType, descr->id, argSize+AS_PTR_SIZE); + + // The instruction has already moved the returned object to the variable + ctx->type.Set(asCDataType::CreatePrimitive(ttVoid, false)); + ctx->type.isLValue = false; + + // Clean up arguments + if( args ) + AfterFunctionCall(funcId, *args, ctx, false); + + ProcessDeferredParams(ctx); + + return; + } + else + { + if( descr->objectType ) + argSize += AS_PTR_SIZE; + + // If the function returns an object by value the address of the location + // where the value should be stored is passed as an argument too + if( descr->DoesReturnOnStack() ) + argSize += AS_PTR_SIZE; + + // TODO: runtime optimize: If it is known that a class method cannot be overridden the call + // should be made with asBC_CALL as it is faster. Examples where this + // is known is for example finalled methods where the class doesn't derive + // from any other, or even non-finalled methods but where it is known + // at compile time the true type of the object. The first should be + // quite easy to determine, but the latter will be quite complex and possibly + // not worth it. + if( descr->funcType == asFUNC_IMPORTED ) + ctx->bc.Call(asBC_CALLBND , descr->id, argSize); + // TODO: Maybe we need two different byte codes + else if( descr->funcType == asFUNC_INTERFACE || descr->funcType == asFUNC_VIRTUAL ) + ctx->bc.Call(asBC_CALLINTF, descr->id, argSize); + else if( descr->funcType == asFUNC_SCRIPT ) + ctx->bc.Call(asBC_CALL , descr->id, argSize); + else if( descr->funcType == asFUNC_SYSTEM ) + { + // Check if we can use the faster asBC_Thiscall1 instruction, i.e. one of + // type &obj::func(int) + // type &obj::func(uint) + if( descr->GetObjectType() && descr->returnType.IsReference() && + descr->parameterTypes.GetLength() == 1 && + (descr->parameterTypes[0].IsIntegerType() || descr->parameterTypes[0].IsUnsignedType()) && + descr->parameterTypes[0].GetSizeInMemoryBytes() == 4 && + !descr->parameterTypes[0].IsReference() ) + ctx->bc.Call(asBC_Thiscall1, descr->id, argSize); + else + ctx->bc.Call(asBC_CALLSYS , descr->id, argSize); + } + else if( descr->funcType == asFUNC_FUNCDEF ) + ctx->bc.CallPtr(asBC_CallPtr, funcPtrVar, argSize); + } + + if( (descr->returnType.IsObject() || descr->returnType.IsFuncdef()) && !descr->returnType.IsReference() ) + { + int returnOffset = 0; + + asCExprValue tmpExpr = ctx->type; + + if( descr->DoesReturnOnStack() ) + { + asASSERT( useVariable ); + + // The variable was allocated before the function was called + returnOffset = varOffset; + ctx->type.SetVariable(descr->returnType, returnOffset, true); + + // The variable was initialized by the function, so we need to mark it as initialized here + ctx->bc.ObjInfo(varOffset, asOBJ_INIT); + } + else + { + if( useVariable ) + { + // Use the given variable + returnOffset = varOffset; + ctx->type.SetVariable(descr->returnType, returnOffset, false); + } + else + { + // Allocate a temporary variable for the returned object + // The returned object will actually be allocated on the heap, so + // we must force the allocation of the variable to do the same + returnOffset = AllocateVariable(descr->returnType, true, !descr->returnType.IsObjectHandle()); + ctx->type.SetVariable(descr->returnType, returnOffset, true); + } + + // Move the pointer from the object register to the temporary variable + ctx->bc.InstrSHORT(asBC_STOREOBJ, (short)returnOffset); + } + + ReleaseTemporaryVariable(tmpExpr, &ctx->bc); + + ctx->type.dataType.MakeReference(IsVariableOnHeap(returnOffset)); + ctx->type.isLValue = false; // It is a reference, but not an lvalue + + // Clean up arguments + if( args ) + AfterFunctionCall(funcId, *args, ctx, false); + + ProcessDeferredParams(ctx); + + ctx->bc.InstrSHORT(asBC_PSF, (short)returnOffset); + } + else if( descr->returnType.IsReference() ) + { + asASSERT(useVariable == false); + + // We cannot clean up the arguments yet, because the + // reference might be pointing to one of them. + if( args ) + AfterFunctionCall(funcId, *args, ctx, true); + + // Do not process the output parameters yet, because it + // might invalidate the returned reference + + // If the context holds a variable that needs cleanup + // store it as a deferred parameter so it will be cleaned up + // afterwards. + if( ctx->type.isTemporary ) + { + asSDeferredParam defer; + defer.argNode = 0; + defer.argType = ctx->type; + defer.argInOutFlags = asTM_INOUTREF; + defer.origExpr = 0; + ctx->deferredParams.PushLast(defer); + } + + ctx->type.Set(descr->returnType); + if( !descr->returnType.IsPrimitive() ) + { + ctx->bc.Instr(asBC_PshRPtr); + if( descr->returnType.IsObject() && + !descr->returnType.IsObjectHandle() ) + { + // We are getting the pointer to the object + // not a pointer to a object variable + ctx->type.dataType.MakeReference(false); + } + } + + // A returned reference can be used as lvalue + ctx->type.isLValue = true; + } + else + { + asCExprValue tmpExpr = ctx->type; + + if( descr->returnType.GetSizeInMemoryBytes() ) + { + int offset; + if (useVariable) + offset = varOffset; + else + { + // Allocate a temporary variable to hold the value, but make sure + // the temporary variable isn't used in any of the deferred arguments + int l = int(reservedVariables.GetLength()); + for (asUINT n = 0; args && n < args->GetLength(); n++) + { + asCExprContext *expr = (*args)[n]->origExpr; + if (expr) + expr->bc.GetVarsUsed(reservedVariables); + } + offset = AllocateVariable(descr->returnType, true); + reservedVariables.SetLength(l); + } + + ctx->type.SetVariable(descr->returnType, offset, true); + + // Move the value from the return register to the variable + if( descr->returnType.GetSizeOnStackDWords() == 1 ) + ctx->bc.InstrSHORT(asBC_CpyRtoV4, (short)offset); + else if( descr->returnType.GetSizeOnStackDWords() == 2 ) + ctx->bc.InstrSHORT(asBC_CpyRtoV8, (short)offset); + } + else + ctx->type.Set(descr->returnType); + + ReleaseTemporaryVariable(tmpExpr, &ctx->bc); + + ctx->type.isLValue = false; + + // Clean up arguments + if( args ) + AfterFunctionCall(funcId, *args, ctx, false); + + ProcessDeferredParams(ctx); + } +} + +// This only merges the bytecode, but doesn't modify the type of the final context +void asCCompiler::MergeExprBytecode(asCExprContext *before, asCExprContext *after) +{ + before->bc.AddCode(&after->bc); + + for( asUINT n = 0; n < after->deferredParams.GetLength(); n++ ) + { + before->deferredParams.PushLast(after->deferredParams[n]); + after->deferredParams[n].origExpr = 0; + } + + after->deferredParams.SetLength(0); +} + +// This merges both bytecode and the type of the final context +void asCCompiler::MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after) +{ + MergeExprBytecode(before, after); + + before->Merge(after); +} + +void asCCompiler::FilterConst(asCArray &funcs, bool removeConst) +{ + if( funcs.GetLength() == 0 ) return; + + // This is only done for object methods + asCScriptFunction *desc = builder->GetFunctionDescription(funcs[0]); + if( !desc || desc->objectType == 0 ) return; + + // Check if there are any non-const matches + asUINT n; + bool foundNonConst = false; + for( n = 0; n < funcs.GetLength(); n++ ) + { + desc = builder->GetFunctionDescription(funcs[n]); + if( desc && desc->IsReadOnly() != removeConst ) + { + foundNonConst = true; + break; + } + } + + if( foundNonConst ) + { + // Remove all const methods + for( n = 0; n < funcs.GetLength(); n++ ) + { + desc = builder->GetFunctionDescription(funcs[n]); + if( desc && desc->IsReadOnly() == removeConst ) + { + if( n == funcs.GetLength() - 1 ) + funcs.PopLast(); + else + funcs[n] = funcs.PopLast(); + + n--; + } + } + } +} + +///////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +asCExprValue::asCExprValue() +{ + isTemporary = false; + stackOffset = 0; + isConstant = false; + isVariable = false; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; + isRefToLocal = false; + isRefSafe = false; +} + +void asCExprValue::Set(const asCDataType &dt) +{ + dataType = dt; + + isTemporary = false; + stackOffset = 0; + isConstant = false; + isVariable = false; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; + isRefToLocal = false; + isRefSafe = false; +} + +void asCExprValue::SetVariable(const asCDataType &in_dt, int in_stackOffset, bool in_isTemporary) +{ + Set(in_dt); + + this->isVariable = true; + this->isTemporary = in_isTemporary; + this->stackOffset = (short)in_stackOffset; +} + +void asCExprValue::SetConstantQW(const asCDataType &dt, asQWORD value) +{ + Set(dt); + + isConstant = true; + SetConstantQW(value); +} + +void asCExprValue::SetConstantDW(const asCDataType &dt, asDWORD value) +{ + Set(dt); + + isConstant = true; + SetConstantDW(value); +} + +void asCExprValue::SetConstantB(const asCDataType &dt, asBYTE value) +{ + Set(dt); + + isConstant = true; + SetConstantB(value); +} + +void asCExprValue::SetConstantW(const asCDataType &dt, asWORD value) +{ + Set(dt); + + isConstant = true; + SetConstantW(value); +} + +void asCExprValue::SetConstantF(const asCDataType &dt, float value) +{ + Set(dt); + + isConstant = true; + SetConstantF(value); +} + +void asCExprValue::SetConstantD(const asCDataType &dt, double value) +{ + Set(dt); + + isConstant = true; + SetConstantD(value); +} + +void asCExprValue::SetConstantQW(asQWORD value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + qwordValue = value; +} + +void asCExprValue::SetConstantDW(asDWORD value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + dwordValue = value; +} + +void asCExprValue::SetConstantW(asWORD value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 2); + wordValue = value; +} + +void asCExprValue::SetConstantB(asBYTE value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 1); + byteValue = value; +} + +void asCExprValue::SetConstantF(float value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + floatValue = value; +} + +void asCExprValue::SetConstantD(double value) +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + doubleValue = value; +} + +asQWORD asCExprValue::GetConstantQW() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + return qwordValue; +} + +asDWORD asCExprValue::GetConstantDW() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + return dwordValue; +} + +asWORD asCExprValue::GetConstantW() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 2); + return wordValue; +} + +asBYTE asCExprValue::GetConstantB() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 1); + return byteValue; +} + +float asCExprValue::GetConstantF() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 4); + return floatValue; +} + +double asCExprValue::GetConstantD() +{ + asASSERT(dataType.GetSizeInMemoryBytes() == 8); + return doubleValue; +} + +void asCExprValue::SetConstantData(const asCDataType &dt, asQWORD qw) +{ + Set(dt); + + isConstant = true; + + // This code is necessary to guarantee that the code + // works on both big endian and little endian CPUs. + if (dataType.GetSizeInMemoryBytes() == 1) + byteValue = (asBYTE)qw; + if (dataType.GetSizeInMemoryBytes() == 2) + wordValue = (asWORD)qw; + if (dataType.GetSizeInMemoryBytes() == 4) + dwordValue = (asDWORD)qw; + else + qwordValue = qw; +} + +asQWORD asCExprValue::GetConstantData() +{ + asQWORD qw = 0; + // This code is necessary to guarantee that the code + // works on both big endian and little endian CPUs. + if (dataType.GetSizeInMemoryBytes() == 1) + qw = byteValue; + if (dataType.GetSizeInMemoryBytes() == 2) + qw = wordValue; + if (dataType.GetSizeInMemoryBytes() == 4) + qw = dwordValue; + else + qw = qwordValue; + return qw; +} + +void asCExprValue::SetUndefinedFuncHandle(asCScriptEngine *engine) +{ + // This is used for when the expression evaluates to a + // function, but it is not yet known exactly which. The + // owner expression will hold the name of the function + // to determine the exact function when the signature is + // known. + Set(asCDataType::CreateObjectHandle(&engine->functionBehaviours, true)); + isConstant = true; + isExplicitHandle = false; + qwordValue = 1; // Set to a different value than 0 to differentiate from null constant + isLValue = false; +} + +bool asCExprValue::IsUndefinedFuncHandle() const +{ + if (isConstant == false) return false; + if (qwordValue == 0) return false; + if (isLValue) return false; + if (dataType.GetTypeInfo() == 0) return false; + if (dataType.GetTypeInfo()->name != "$func") return false; + if (dataType.IsFuncdef()) return false; + + return true; +} + +void asCExprValue::SetNullConstant() +{ + Set(asCDataType::CreateNullHandle()); + isConstant = true; + isExplicitHandle = false; + qwordValue = 0; + isLValue = false; +} + +bool asCExprValue::IsNullConstant() const +{ + // We can't check the actual object type, because the null constant may have been cast to another type + if (isConstant && dataType.IsObjectHandle() && qwordValue == 0) + return true; + + return false; +} + +void asCExprValue::SetVoid() +{ + Set(asCDataType::CreatePrimitive(ttVoid, false)); + isLValue = false; + isConstant = true; +} + +bool asCExprValue::IsVoid() const +{ + if (dataType.GetTokenType() == ttVoid) + return true; + + return false; +} + +void asCExprValue::SetDummy() +{ + SetConstantDW(asCDataType::CreatePrimitive(ttInt, true), 0); +} + +//////////////////////////////////////////////////////////////////////////////////////////////// + +asCExprContext::asCExprContext(asCScriptEngine *engine) : bc(engine) +{ + property_arg = 0; + + Clear(); +} + +asCExprContext::~asCExprContext() +{ + if (property_arg) + asDELETE(property_arg, asCExprContext); +} + +void asCExprContext::Clear() +{ + bc.ClearAll(); + type.Set(asCDataType()); + deferredParams.SetLength(0); + if (property_arg) + asDELETE(property_arg, asCExprContext); + property_arg = 0; + exprNode = 0; + origExpr = 0; + property_get = 0; + property_set = 0; + property_const = false; + property_handle = false; + property_ref = false; + methodName = ""; + enumValue = ""; + symbolNamespace = 0; + isVoidExpression = false; + isCleanArg = false; + isAnonymousInitList = false; + origCode = 0; +} + +bool asCExprContext::IsClassMethod() const +{ + if (type.dataType.GetTypeInfo() == 0) return false; + if (methodName == "") return false; + if (type.dataType.GetTypeInfo() == &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; + if (isAnonymousInitList) return false; + return true; +} + +bool asCExprContext::IsGlobalFunc() const +{ + if (type.dataType.GetTypeInfo() == 0) return false; + if (methodName == "") return false; + if (type.dataType.GetTypeInfo() != &type.dataType.GetTypeInfo()->engine->functionBehaviours) return false; + if (isAnonymousInitList) return false; + return true; +} + +void asCExprContext::SetLambda(asCScriptNode *funcDecl) +{ + asASSERT(funcDecl && funcDecl->nodeType == snFunction); + asASSERT(bc.GetLastInstr() == -1); + + Clear(); + type.SetUndefinedFuncHandle(bc.GetEngine()); + exprNode = funcDecl; +} + +bool asCExprContext::IsLambda() const +{ + if (type.IsUndefinedFuncHandle() && exprNode && exprNode->nodeType == snFunction) + return true; + + return false; +} + +void asCExprContext::SetVoidExpression() +{ + Clear(); + type.SetVoid(); + isVoidExpression = true; +} + +bool asCExprContext::IsVoidExpression() const +{ + if (isVoidExpression && type.IsVoid() && exprNode == 0) + return true; + + return false; +} + +void asCExprContext::SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script) +{ + Clear(); + exprNode = initList; + origCode = script; + isAnonymousInitList = true; +} + +bool asCExprContext::IsAnonymousInitList() const +{ + if (isAnonymousInitList && exprNode && exprNode->nodeType == snInitList) + return true; + + return false; +} + +void asCExprContext::Copy(asCExprContext *other) +{ + type = other->type; + property_get = other->property_get; + property_set = other->property_set; + property_const = other->property_const; + property_handle = other->property_handle; + property_ref = other->property_ref; + property_arg = other->property_arg; + exprNode = other->exprNode; + methodName = other->methodName; + enumValue = other->enumValue; + isVoidExpression = other->isVoidExpression; + isCleanArg = other->isCleanArg; + isAnonymousInitList = other->isAnonymousInitList; + origCode = other->origCode; + + // Do not copy the origExpr member +} + +void asCExprContext::Merge(asCExprContext *after) +{ + // Overwrite properties with the expression that comes after + Copy(after); + + // Clean the properties in 'after' that have now moved into + // this structure so they are not cleaned up accidentally + after->property_arg = 0; +} + + + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + + + diff --git a/angelscript/source/as_compiler.h b/angelscript/source/as_compiler.h new file mode 100644 index 0000000..ae4bff4 --- /dev/null +++ b/angelscript/source/as_compiler.h @@ -0,0 +1,439 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_compiler.h +// +// The class that does the actual compilation of the functions +// + + + +#ifndef AS_COMPILER_H +#define AS_COMPILER_H + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_builder.h" +#include "as_scriptfunction.h" +#include "as_variablescope.h" +#include "as_bytecode.h" +#include "as_array.h" +#include "as_datatype.h" + +BEGIN_AS_NAMESPACE + +// This class represents the value of an expression as evaluated by the compiler. +// It holds information such as the type of the value, stack offset for a local +// variable, value of constants, whether the value can be modified (i.e. lvalue), etc. +struct asCExprValue +{ + asCExprValue(); + void Set(const asCDataType &dataType); + + void SetVariable(const asCDataType &dataType, int stackOffset, bool isTemporary); + void SetConstantB(const asCDataType &dataType, asBYTE value); + void SetConstantQW(const asCDataType &dataType, asQWORD value); + void SetConstantDW(const asCDataType &dataType, asDWORD value); + void SetConstantW(const asCDataType &dataType, asWORD value); + void SetConstantF(const asCDataType &dataType, float value); + void SetConstantD(const asCDataType &dataType, double value); + void SetConstantB(asBYTE value); + void SetConstantW(asWORD value); + void SetConstantQW(asQWORD value); + void SetConstantDW(asDWORD value); + void SetConstantF(float value); + void SetConstantD(double value); + asBYTE GetConstantB(); + asWORD GetConstantW(); + asQWORD GetConstantQW(); + asDWORD GetConstantDW(); + float GetConstantF(); + double GetConstantD(); + + void SetConstantData(const asCDataType &dataType, asQWORD value); + asQWORD GetConstantData(); + + void SetNullConstant(); + void SetUndefinedFuncHandle(asCScriptEngine *engine); + void SetVoid(); + void SetDummy(); + + bool IsUndefinedFuncHandle() const; + bool IsNullConstant() const; + bool IsVoid() const; + + asCDataType dataType; + bool isLValue : 1; // Can this value be updated in assignment, or increment operators, etc + bool isTemporary : 1; + bool isConstant : 1; + bool isVariable : 1; + bool isExplicitHandle : 1; + bool isRefToLocal : 1; // The reference may be to a local variable + bool isRefSafe : 1; // the life-time of the ref is guaranteed for the duration of the access + short dummy : 9; + short stackOffset; + +private: + // These values must not be accessed directly in order to avoid problems with endianess. + // Use the appropriate accessor methods instead + union + { + asQWORD qwordValue; + double doubleValue; + asDWORD dwordValue; + float floatValue; + asWORD wordValue; + asBYTE byteValue; + }; +}; + +struct asCExprContext; + +// This class holds information for arguments that needs to be +// cleaned up after the result of a function has been evaluated. +struct asSDeferredParam +{ + asSDeferredParam() {argNode = 0; origExpr = 0;} + + asCScriptNode *argNode; + asCExprValue argType; + int argInOutFlags; + asCExprContext *origExpr; +}; + +// TODO: refactor: asCExprContext should have indicators to inform where the value is, +// i.e. if the reference to an object is pushed on the stack or not, etc + +// This class holds information about an expression that is being evaluated, e.g. +// the current bytecode, ambiguous symbol names, property accessors, etc. +struct asCExprContext +{ + asCExprContext(asCScriptEngine *engine); + ~asCExprContext(); + void Clear(); + bool IsClassMethod() const; + bool IsGlobalFunc() const; + void SetLambda(asCScriptNode *funcDecl); + bool IsLambda() const; + void SetVoidExpression(); + bool IsVoidExpression() const; + void Merge(asCExprContext *after); + void Copy(asCExprContext *other); + void SetAnonymousInitList(asCScriptNode *initList, asCScriptCode *script); + bool IsAnonymousInitList() const; + + asCByteCode bc; + asCExprValue type; + int property_get; + int property_set; + bool property_const; // If the object that is being accessed through property accessor is read-only + bool property_handle; // If the property accessor is called on an object stored in a handle + bool property_ref; // If the property accessor is called on a reference + bool isVoidExpression; // Set to true if the expression is an explicit 'void', e.g. used to ignore out parameters in func calls + bool isCleanArg; // Set to true if the expression has only been initialized with default constructor + asCExprContext *property_arg; + asCArray deferredParams; + asCScriptNode *exprNode; + asCExprContext *origExpr; + asCScriptCode *origCode; + // TODO: cleanup: use ambiguousName and an enum to say if it is a method, global func, or enum value + asCString methodName; + asCString enumValue; + asSNameSpace *symbolNamespace; // The namespace in which the ambiguous symbol was found + bool isAnonymousInitList; // Set to true if the expression is an init list for which the type has not yet been determined +}; + +struct asSOverloadCandidate +{ + asSOverloadCandidate() : funcId(0), cost(0) {} + asSOverloadCandidate(int _id, asUINT _cost) : funcId(_id), cost(_cost) {} + int funcId; + asUINT cost; +}; + +struct asSNamedArgument +{ + asCString name; + asCExprContext *ctx; + asUINT match; +}; + +enum EImplicitConv +{ + asIC_IMPLICIT_CONV, + asIC_EXPLICIT_REF_CAST, + asIC_EXPLICIT_VAL_CAST +}; + +enum EConvCost +{ + asCC_NO_CONV = 0, + asCC_CONST_CONV = 1, + asCC_ENUM_SAME_SIZE_CONV = 2, + asCC_ENUM_DIFF_SIZE_CONV = 3, + asCC_PRIMITIVE_SIZE_CONV = 4, + asCC_SIGNED_CONV = 5, + asCC_INT_FLOAT_CONV = 6, + asCC_REF_CONV = 7, + asCC_OBJ_TO_PRIMITIVE_CONV = 8, + asCC_TO_OBJECT_CONV = 9, + asCC_VARIABLE_CONV = 10 +}; + +class asCCompiler +{ +public: + asCCompiler(asCScriptEngine *engine); + ~asCCompiler(); + + int CompileFunction(asCBuilder *builder, asCScriptCode *script, asCArray ¶meterNames, asCScriptNode *func, asCScriptFunction *outFunc, sClassDeclaration *classDecl); + int CompileDefaultConstructor(asCBuilder *builder, asCScriptCode *script, asCScriptNode *node, asCScriptFunction *outFunc, sClassDeclaration *classDecl); + int CompileFactory(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); + int CompileGlobalVariable(asCBuilder *builder, asCScriptCode *script, asCScriptNode *expr, sGlobalVariableDescription *gvar, asCScriptFunction *outFunc); + +protected: + friend class asCBuilder; + + void Reset(asCBuilder *builder, asCScriptCode *script, asCScriptFunction *outFunc); + + // Statements + void CompileStatementBlock(asCScriptNode *block, bool ownVariableScope, bool *hasReturn, asCByteCode *bc); + void CompileDeclaration(asCScriptNode *decl, asCByteCode *bc); + void CompileStatement(asCScriptNode *statement, bool *hasReturn, asCByteCode *bc); + void CompileIfStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); + void CompileSwitchStatement(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); + void CompileCase(asCScriptNode *node, asCByteCode *bc); + void CompileForStatement(asCScriptNode *node, asCByteCode *bc); + void CompileWhileStatement(asCScriptNode *node, asCByteCode *bc); + void CompileDoWhileStatement(asCScriptNode *node, asCByteCode *bc); + void CompileBreakStatement(asCScriptNode *node, asCByteCode *bc); + void CompileContinueStatement(asCScriptNode *node, asCByteCode *bc); + void CompileReturnStatement(asCScriptNode *node, asCByteCode *bc); + void CompileExpressionStatement(asCScriptNode *node, asCByteCode *bc); + void CompileTryCatch(asCScriptNode *node, bool *hasReturn, asCByteCode *bc); + + // Expressions + int CompileAssignment(asCScriptNode *expr, asCExprContext *out); + int CompileCondition(asCScriptNode *expr, asCExprContext *out); + int CompileExpression(asCScriptNode *expr, asCExprContext *out); + int CompilePostFixExpression(asCArray *postfix, asCExprContext *out); + int CompileExpressionTerm(asCScriptNode *node, asCExprContext *out); + int CompileExpressionPreOp(asCScriptNode *node, asCExprContext *out); + int CompileExpressionPostOp(asCScriptNode *node, asCExprContext *out); + int CompileExpressionValue(asCScriptNode *node, asCExprContext *out); + int CompileFunctionCall(asCScriptNode *node, asCExprContext *out, asCObjectType *objectType, bool objIsConst, const asCString &scope = ""); + int CompileConstructCall(asCScriptNode *node, asCExprContext *out); + int CompileConversion(asCScriptNode *node, asCExprContext *out); + int CompileOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken, bool leftToRight = true); + void CompileOperatorOnHandles(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileMathOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileBitwiseOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileComparisonOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + void CompileBooleanOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, asCExprContext *out, eTokenType opToken = ttUnrecognizedToken); + bool CompileOverloadedDualOperator(asCScriptNode *node, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool isHandle = false, eTokenType opToken = ttUnrecognizedToken); + int CompileOverloadedDualOperator2(asCScriptNode *node, const char *methodName, asCExprContext *l, asCExprContext *r, bool leftToRight, asCExprContext *out, bool specificReturn = false, const asCDataType &returnType = asCDataType::CreatePrimitive(ttVoid, false)); + + void CompileInitList(asCExprValue *var, asCScriptNode *node, asCByteCode *bc, int isVarGlobOrMem); + int CompileInitListElement(asSListPatternNode *&patternNode, asCScriptNode *&valueNode, int bufferTypeId, short bufferVar, asUINT &bufferSize, asCByteCode &byteCode, int &elementsInSubList); + int CompileAnonymousInitList(asCScriptNode *listNode, asCExprContext *ctx, const asCDataType &dt); + + int CallDefaultConstructor(const asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCScriptNode *node, int isVarGlobOrMem = 0, bool derefDest = false); + int CallCopyConstructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool isGlobalVar = false, bool derefDestination = false); + void CallDestructor(asCDataType &type, int offset, bool isObjectOnHeap, asCByteCode *bc); + int CompileArgumentList(asCScriptNode *node, asCArray &args, asCArray &namedArgs); + int CompileDefaultAndNamedArgs(asCScriptNode *node, asCArray &args, int funcId, asCObjectType *type, asCArray *namedArgs = 0); + asUINT MatchFunctions(asCArray &funcs, asCArray &args, asCScriptNode *node, const char *name, asCArray *namedArgs = NULL, asCObjectType *objectType = NULL, bool isConstMethod = false, bool silent = false, bool allowObjectConstruct = true, const asCString &scope = ""); + int CompileVariableAccess(const asCString &name, const asCString &scope, asCExprContext *ctx, asCScriptNode *errNode, bool isOptional = false, asCObjectType *objType = 0); + void CompileMemberInitialization(asCByteCode *bc, bool onlyDefaults); + bool CompileAutoType(asCDataType &autoType, asCExprContext &compiledCtx, asCScriptNode *exprNode, asCScriptNode *errNode); + bool CompileInitialization(asCScriptNode *node, asCByteCode *bc, const asCDataType &type, asCScriptNode *errNode, int offset, asQWORD *constantValue, int isVarGlobOrMem, asCExprContext *preCompiled = 0); + void CompileInitAsCopy(asCDataType &type, int offset, asCByteCode *bc, asCExprContext *arg, asCScriptNode *node, bool derefDestination); + + // Helper functions + void ConvertToPostFix(asCScriptNode *expr, asCArray &postfix); + int ProcessPropertyGetAccessor(asCExprContext *ctx, asCScriptNode *node); + int ProcessPropertySetAccessor(asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node); + int ProcessPropertyGetSetAccessor(asCExprContext *ctx, asCExprContext *lctx, asCExprContext *rctx, eTokenType op, asCScriptNode *errNode); + int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); + int FindPropertyAccessor(const asCString &name, asCExprContext *ctx, asCExprContext *arg, asCScriptNode *node, asSNameSpace *ns, bool isThisAccess = false); + void PrepareTemporaryVariable(asCScriptNode *node, asCExprContext *ctx, bool forceOnHeap = false); + void PrepareOperand(asCExprContext *ctx, asCScriptNode *node); + void PrepareForAssignment(asCDataType *lvalue, asCExprContext *rvalue, asCScriptNode *node, bool toTemporary, asCExprContext *lvalueExpr = 0); + int PerformAssignment(asCExprValue *lvalue, asCExprValue *rvalue, asCByteCode *bc, asCScriptNode *node); + bool IsVariableInitialized(asCExprValue *type, asCScriptNode *node); + void Dereference(asCExprContext *ctx, bool generateCode); + bool CompileRefCast(asCExprContext *ctx, const asCDataType &to, bool isExplicit, asCScriptNode *node, bool generateCode = true); + asUINT MatchArgument(asCArray &funcs, asCArray &matches, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); + int MatchArgument(asCScriptFunction *desc, const asCExprContext *argExpr, int paramNum, bool allowObjectConstruct = true); + void PerformFunctionCall(int funcId, asCExprContext *out, bool isConstructor = false, asCArray *args = 0, asCObjectType *objTypeForConstruct = 0, bool useVariable = false, int varOffset = 0, int funcPtrVar = 0); + void MoveArgsToStack(int funcId, asCByteCode *bc, asCArray &args, bool addOneToOffset); + int MakeFunctionCall(asCExprContext *ctx, int funcId, asCObjectType *objectType, asCArray &args, asCScriptNode *node, bool useVariable = false, int stackOffset = 0, int funcPtrVar = 0); + int PrepareFunctionCall(int funcId, asCByteCode *bc, asCArray &args); + void AfterFunctionCall(int funcId, asCArray &args, asCExprContext *ctx, bool deferAll); + void ProcessDeferredParams(asCExprContext *ctx); + int PrepareArgument(asCDataType *paramType, asCExprContext *ctx, asCScriptNode *node, bool isFunction = false, int refType = 0, bool isMakingCopy = false); + int PrepareArgument2(asCExprContext *ctx, asCExprContext *arg, asCDataType *paramType, bool isFunction = false, int refType = 0, bool isMakingCopy = false); + bool IsLValue(asCExprValue &type); + int DoAssignment(asCExprContext *out, asCExprContext *lctx, asCExprContext *rctx, asCScriptNode *lexpr, asCScriptNode *rexpr, eTokenType op, asCScriptNode *opNode); + void MergeExprBytecode(asCExprContext *before, asCExprContext *after); + void MergeExprBytecodeAndType(asCExprContext *before, asCExprContext *after); + void FilterConst(asCArray &funcs, bool removeConst = true); + void ConvertToVariable(asCExprContext *ctx); + void ConvertToVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); + void ConvertToTempVariable(asCExprContext *ctx); + void ConvertToTempVariableNotIn(asCExprContext *ctx, asCExprContext *exclude); + void ConvertToReference(asCExprContext *ctx); + void PushVariableOnStack(asCExprContext *ctx, bool asReference); + void DestroyVariables(asCByteCode *bc); + asSNameSpace *DetermineNameSpace(const asCString &scope); + int SetupParametersAndReturnVariable(asCArray ¶meterNames, asCScriptNode *func); + + enum SYMBOLTYPE + { + SL_NOMATCH, + SL_LOCALCONST, + SL_LOCALVAR, + SL_THISPTR, + SL_CLASSPROPACCESS, + SL_CLASSPROP, + SL_CLASSMETHOD, + SL_CLASSTYPE, + SL_GLOBALPROPACCESS, + SL_GLOBALCONST, + SL_GLOBALVAR, + SL_GLOBALFUNC, + SL_GLOBALTYPE, + SL_ENUMVAL, + SL_ERROR = -1 + }; + + SYMBOLTYPE SymbolLookup(const asCString &name, const asCString &scope, asCObjectType *objType, asCExprContext *outResult); + SYMBOLTYPE SymbolLookupLocalVar(const asCString &name, asCExprContext *outResult); + SYMBOLTYPE SymbolLookupMember(const asCString &name, asCObjectType *objType, asCExprContext *outResult); + + void DetermineSingleFunc(asCExprContext *ctx, asCScriptNode *node); + + // Returns the cost of the conversion (the sum of the EConvCost performed) + asUINT ImplicitConversion(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvPrimitiveToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + asUINT ImplicitConvObjectToPrimitive(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + asUINT ImplicitConvPrimitiveToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvObjectToObject(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true, bool allowObjectConstruct = true); + asUINT ImplicitConvObjectRef(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); + asUINT ImplicitConvObjectValue(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode); + void ImplicitConversionConstant(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType); + void ImplicitConvObjectToBestMathType(asCExprContext *ctx, asCScriptNode *node); + asUINT ImplicitConvLambdaToFunc(asCExprContext *ctx, const asCDataType &to, asCScriptNode *node, EImplicitConv convType, bool generateCode = true); + + void LineInstr(asCByteCode *bc, size_t pos); + + asUINT ProcessStringConstant(asCString &str, asCScriptNode *node, bool processEscapeSequences = true); + void ProcessHeredocStringConstant(asCString &str, asCScriptNode *node); + int GetPrecedence(asCScriptNode *op); + void Error(const asCString &msg, asCScriptNode *node); + void Warning(const asCString &msg, asCScriptNode *node); + void Information(const asCString &msg, asCScriptNode *node); + void PrintMatchingFuncs(asCArray &funcs, asCScriptNode *node, asCObjectType *inType = 0); + void AddVariableScope(bool isBreakScope = false, bool isContinueScope = false); + void RemoveVariableScope(); + void FinalizeFunction(); + + asCByteCode byteCode; + + bool hasCompileErrors; + + int nextLabel; + int numLambdas; + + asCVariableScope *variables; + asCBuilder *builder; + asCScriptEngine *engine; + asCScriptCode *script; + asCScriptFunction *outFunc; + + bool m_isConstructor; + bool m_isConstructorCalled; + sClassDeclaration *m_classDecl; + sGlobalVariableDescription *m_globalVar; + + asCArray breakLabels; + asCArray continueLabels; + + int AllocateVariable(const asCDataType &type, bool isTemporary, bool forceOnHeap = false, bool asReference = false); + int AllocateVariableNotIn(const asCDataType &type, bool isTemporary, bool forceOnHeap, asCExprContext *ctx); + int GetVariableOffset(int varIndex); + int GetVariableSlot(int varOffset); + void DeallocateVariable(int pos); + void ReleaseTemporaryVariable(asCExprValue &t, asCByteCode *bc); + void ReleaseTemporaryVariable(int offset, asCByteCode *bc); + bool IsVariableOnHeap(int offset); + + // This ordered array indicates the type of each variable + asCArray variableAllocations; + + // This ordered array indicates which variables are temporaries or not + asCArray variableIsTemporary; + + // This unordered array gives the offsets of all temporary variables, whether currently allocated or not + asCArray tempVariableOffsets; + + // This ordered array indicated if the variable is on the heap or not + asCArray variableIsOnHeap; + + // This unordered array gives the indexes of the currently unused variables + asCArray freeVariables; + + // This array holds the offsets of the currently allocated temporary variables + asCArray tempVariables; + + // This array holds the indices of variables that must not be used in an allocation + asCArray reservedVariables; + + // This array holds the string constants that were allocated during the compilation, + // so they can be released upon completion, whether the compilation was successful or not. + asCArray usedStringConstants; + + // This array holds the nodes that have been allocated temporarily + asCArray nodesToFreeUponComplete; + + bool isCompilingDefaultArg; + bool isProcessingDeferredParams; + int noCodeOutput; +}; + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + +#endif diff --git a/angelscript/source/as_config.h b/angelscript/source/as_config.h new file mode 100644 index 0000000..8af33a2 --- /dev/null +++ b/angelscript/source/as_config.h @@ -0,0 +1,1327 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_config.h +// +// this file is used for configuring the compilation of the library +// + +#ifndef AS_CONFIG_H +#define AS_CONFIG_H + + + +// +// Features +//----------------------------------------- + +// AS_NO_THREADS +// Turns off support for multithreading. By turning off +// this when it's not needed a bit of performance is gained. + +// AS_WINDOWS_THREADS +// If the library should be compiled using windows threads. + +// AS_POSIX_THREADS +// If the library should be compiled using posix threads. + +// AS_NO_ATOMIC +// If the compiler/platform doesn't support atomic instructions +// then this should be defined to use critical sections instead. + +// AS_DEBUG +// This flag can be defined to make the library write some extra output when +// compiling and executing scripts. + +// AS_DEPRECATED +// If this flag is defined then some backwards compatibility is maintained. +// There is no guarantee for how well deprecated functionality will work though +// so it is best to exchange it for the new functionality as soon as possible. + +// AS_NO_CLASS_METHODS +// Disables the possibility to add class methods. Can increase the +// portability of the library. + +// AS_MAX_PORTABILITY +// Disables all platform specific code. Only the asCALL_GENERIC calling +// convention will be available in with this flag set. + +// AS_DOUBLEBYTE_CHARSET +// When this flag is defined, the parser will treat all characters in strings +// that are greater than 127 as lead characters and automatically include the +// next character in the script without checking its value. This should be +// compatible with common encoding schemes, e.g. Big5. Shift-JIS is not compatible +// though as it encodes some single byte characters above 127. +// +// If support for international text is desired, it is recommended that UTF-8 +// is used as this is supported natively by the compiler without the use for this +// preprocessor flag. + +// AS_NO_COMPILER +// Compiles the library without support for compiling scripts. This is intended +// for those applications that will load pre-compiled bytecode and wants to decrease +// the size of the executable. + +// AS_NO_EXCEPTIONS +// Define this if exception handling is turned off or not available on the target platform. + +// AS_NO_MEMBER_INIT +// Disable the support for initialization of class members directly in the declaration. +// This was as a form to maintain backwards compatibility with versions before 2.26.0 +// if the new order of the member initialization caused null pointer exceptions in older +// scripts (e.g. if a base class accessed members of a derived class through a virtual method). + +// AS_USE_NAMESPACE +// Adds the AngelScript namespace on the declarations. + + + +// +// Library usage +//------------------------------------------ + +// ANGELSCRIPT_EXPORT +// This flag should be defined when compiling the library as a lib or dll. + +// ANGELSCRIPT_DLL_LIBRARY_IMPORT +// This flag should be defined when using AngelScript as a dll with automatic +// library import. + +// ANGELSCRIPT_DLL_MANUAL_IMPORT +// This flag should be defined when using AngelScript as a dll with manual +// loading of the library. + + + + +// +// Compiler differences +//----------------------------------------- + +// asVSNPRINTF(a,b,c,d) +// Some compilers use different names for this function. You must +// define this macro to map to the proper function. + +// ASM_AT_N_T or ASM_INTEL +// You should choose what inline assembly syntax to use when compiling. + +// VALUE_OF_BOOLEAN_TRUE +// This flag allows to customize the exact value of boolean true. + +// AS_SIZEOF_BOOL +// On some target platforms the sizeof(bool) is 4, but on most it is 1. + +// STDCALL +// This is used to declare a function to use the stdcall calling convention. + +// AS_NO_MEMORY_H +// Some compilers don't come with the memory.h header file. + +// AS_NO_THISCALL_FUNCTOR_METHOD +// Defined if the support for functor methods hasn't been implemented on the platform. + + + +// +// How to identify different compilers +//----------------------------------------- +// Ref: http://nadeausoftware.com/articles/2012/10/c_c_tip_how_detect_compiler_name_and_version_using_compiler_predefined_macros + +// MS Visual C++ +// _MSC_VER is defined +// __MWERKS__ is not defined + +// Metrowerks +// _MSC_VER is defined +// __MWERKS__ is defined + +// GNU C based compilers +// __GNUC__ is defined + +// CLang/LLVM +// __clang__ is defined + +// Embarcadero C++Builder +// __BORLANDC__ is defined + +// Oracle Solaris Studio (previously known as Sun CC compiler) +// __SUNPRO_CC is defined + +// Local (or Little) C Compiler +// __LCC__ is defined +// __e2k__ is not defined + +// MCST eLbrus C Compiler +// __LCC__ is defined +// __e2k__ is defined + + + +// +// CPU differences +//--------------------------------------- + +// AS_USE_DOUBLE_AS_FLOAT +// If there is no 64 bit floating point type, then this constant can be defined +// to treat double like normal floats. + +// AS_X86 +// Use assembler code for the x86 CPU family + +// AS_SH4 +// Use assembler code for the SH4 CPU family + +// AS_MIPS +// Use assembler code for the MIPS CPU family + +// AS_PPC +// Use assembler code for the 32bit PowerPC CPU family + +// AS_PPC_64 +// Use assembler code for the 64bit PowerPC CPU family + +// AS_XENON +// Use assembler code for the Xenon (XBOX360) CPU family + +// AS_ARM +// Use assembler code for the ARM CPU family + +// AS_ARM64 +// Use assembler code for the ARM64/AArch64 CPU family + +// AS_SOFTFP +// Use to tell compiler that ARM soft-float ABI +// should be used instead of ARM hard-float ABI + +// AS_X64_GCC +// Use GCC assembler code for the X64 AMD/Intel CPU family + +// AS_X64_MSVC +// Use MSVC assembler code for the X64 AMD/Intel CPU family + +// AS_64BIT_PTR +// Define this to make the engine store all pointers in 64bit words. + +// AS_BIG_ENDIAN +// Define this for CPUs that use big endian memory layout, e.g. PPC + +// AS_SPARC +// Define this for SPARC CPU family + +// AS_E2K +// Define this for MCST Elbrus 2000 CPU family + + + + +// +// Target systems +//-------------------------------- +// This group shows a few of the flags used to identify different target systems. +// Sometimes there are differences on different target systems, while both CPU and +// compiler is the same for both, when this is so these flags are used to produce the +// right code. + +// AS_WIN - Microsoft Windows +// AS_LINUX - Linux +// AS_MAC - Apple Macintosh +// AS_BSD - BSD based OS (FreeBSD, DragonFly, OpenBSD, etc) +// AS_XBOX - Microsoft XBox +// AS_XBOX360 - Microsoft XBox 360 +// AS_PSP - Sony Playstation Portable +// AS_PSVITA - Sony Playstation Vita +// AS_PS2 - Sony Playstation 2 +// AS_PS3 - Sony Playstation 3 +// AS_DC - Sega Dreamcast +// AS_GC - Nintendo GameCube +// AS_WII - Nintendo Wii +// AS_WIIU - Nintendo Wii U +// AS_IPHONE - Apple IPhone +// AS_ANDROID - Android +// AS_HAIKU - Haiku +// AS_ILLUMOS - Illumos like (OpenSolaris, OpenIndiana, NCP, etc) +// AS_MARMALADE - Marmalade cross platform SDK (a layer on top of the OS) +// AS_SUN - Sun UNIX + + + + +// +// Calling conventions +//----------------------------------------- + +// GNU_STYLE_VIRTUAL_METHOD +// This constant should be defined if method pointers store index for virtual +// functions in the same location as the function pointer. In such cases the method +// is identified as virtual if the least significant bit is set. + +// MULTI_BASE_OFFSET(x) +// This macro is used to retrieve the offset added to the object pointer in order to +// implicitly cast the object to the base object. x is the method pointer received by +// the register function. + +// HAVE_VIRTUAL_BASE_OFFSET +// Define this constant if the compiler stores the virtual base offset in the method +// pointers. If it is not stored in the pointers then AngelScript have no way of +// identifying a method as coming from a class with virtual inheritance. + +// VIRTUAL_BASE_OFFSET(x) +// This macro is used to retrieve the offset added to the object pointer in order to +// find the virtual base object. x is the method pointer received by the register +// function; + +// COMPLEX_RETURN_MASK +// This constant shows what attributes determine if an object is returned in memory +// or in the registers as normal structures + +// COMPLEX_MASK +// This constant shows what attributes determine if an object is implicitly passed +// by reference or not, even if the argument is declared by value + +// THISCALL_RETURN_SIMPLE_IN_MEMORY +// CDECL_RETURN_SIMPLE_IN_MEMORY +// STDCALL_RETURN_SIMPLE_IN_MEMORY +// When these constants are defined then the corresponding calling convention always +// return classes/structs in memory regardless of size or complexity. + +// THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE +// STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE +// CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE +// Specifies the minimum size in dwords a class/struct needs to be to be passed in memory + +// CALLEE_POPS_HIDDEN_RETURN_POINTER +// This constant should be defined if the callee pops the hidden return pointer, +// used when returning an object in memory. + +// THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER +// This constant should be defined if the callee pops the hidden return pointer +// for thiscall functions; used when returning an object in memory. + +// THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK +// With this constant defined AngelScript will pass the object pointer on the stack + +// THISCALL_CALLEE_POPS_ARGUMENTS +// If the callee pops arguments for class methods then define this constant + +// COMPLEX_OBJS_PASSED_BY_REF +// Some compilers always pass certain objects by reference. GNUC for example does +// this if the the class has a defined destructor. + +// AS_LARGE_OBJS_PASSED_BY_REF +// If this is defined large objects are passed by reference, whether they are complex or not + +// AS_LARGE_OBJ_MIN_SIZE +// This is the size of objects determined as large ones + +// AS_CALLEE_DESTROY_OBJ_BY_VAL +// When an object is passed by value the called function is the one responsible +// for calling the destructor before returning. + +// HAS_128_BIT_PRIMITIVES +// 64bit processors often support 128bit primitives. These may require special +// treatment when passed in function arguments or returned by functions. + +// SPLIT_OBJS_BY_MEMBER_TYPES +// On some platforms objects with primitive members are split over different +// register types when passed by value to functions. + + + + + +// +// Detect compiler +//------------------------------------------------ + + +#define VALUE_OF_BOOLEAN_TRUE 1 +#define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 +#define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 +#define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 +#define THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER + +// Not implemented by default. Undefined with tested platforms. +#define AS_NO_THISCALL_FUNCTOR_METHOD + + +// Emscripten compiler toolchain +// ref: https://emscripten.org/ +#if defined(__EMSCRIPTEN__) + #define AS_MAX_PORTABILITY +#endif + + + +// Embarcadero C++Builder +#if defined(__BORLANDC__) + #ifndef _Windows + #error "Configuration doesn't yet support BCC for Linux or Mac OS." + #endif + #if defined(_M_X64) + #error "Configuration doesn't yet support BCC for AMD64." + #endif + + #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) + #define HAVE_VIRTUAL_BASE_OFFSET + #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+2)) + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #define COMPLEX_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR) + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR) + #define STDCALL __stdcall + #define AS_SIZEOF_BOOL 1 + #define AS_WINDOWS_THREADS + #undef THISCALL_CALLEE_POPS_HIDDEN_RETURN_POINTER + + #define AS_WIN + #define AS_X86 + #define ASM_INTEL + + #define asVSNPRINTF(a, b, c, d) _vsnprintf(a, b, c, d) + + #define fmodf(a,b) fmod(a,b) + + #define UNREACHABLE_RETURN +#endif + +// Microsoft Visual C++ +// Ref: http://msdn.microsoft.com/en-us/library/b0084kay.aspx +#if defined(_MSC_VER) && !defined(__MWERKS__) + + #if _MSC_VER <= 1200 // MSVC6 + // Disable the useless warnings about truncated symbol names for template instances + #pragma warning( disable : 4786 ) + #endif + + #ifdef _M_X64 + #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+2)) + #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+4)) + #else + #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) + #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+3)) + #endif + #define HAVE_VIRTUAL_BASE_OFFSET + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_PASS_OBJECT_POINTER_IN_ECX + + // http://www.madewithmarmalade.com/ + #if defined(__S3E__) + #ifndef AS_MARMALADE + // From now on we'll use the below define + #define AS_MARMALADE + #endif + + // Marmalade doesn't use the Windows libraries + #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) + + // Marmalade doesn't seem to have proper support for + // atomic instructions or read/write locks, so we turn off + // multithread support + //#define AS_POSIX_THREADS + #define AS_NO_THREADS + #define AS_NO_ATOMIC + + // Marmalade has it's own way of identifying the CPU target + // Note, when building for ARM, the gnuc compiler will always + // be used so we don't need to check for it here + #if defined(I3D_ARCH_X86) + #define AS_X86 + #endif + #else + #if _MSC_VER < 1500 // MSVC++ 9 (aka MSVC++ .NET 2008) + #define asVSNPRINTF(a, b, c, d) _vsnprintf(a, b, c, d) + #else + #define asVSNPRINTF(a, b, c, d) vsnprintf_s(a, b, _TRUNCATE, c, d) + #endif + + #define AS_WINDOWS_THREADS + #endif + + #define THISCALL_CALLEE_POPS_ARGUMENTS + #define STDCALL __stdcall + #define AS_SIZEOF_BOOL 1 + #define COMPLEX_OBJS_PASSED_BY_REF + + #define ASM_INTEL // Intel style for inline assembly on microsoft compilers + + #if defined(WIN32) || defined(_WIN32) || defined(_WIN64) + #define AS_WIN + #endif + + #if _XBOX_VER >= 200 + // 360 uses a Xenon processor (which is a modified 64bit PPC) + #define AS_XBOX360 + #define AS_XENON + #define AS_BIG_ENDIAN + #else + #if defined(_XBOX) || (defined(_M_IX86) && !defined(__LP64__)) + #define AS_X86 + #ifndef _XBOX + // Not tested with xbox (only enabled if is Windows) + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #endif + #elif defined(_M_X64) + #define AS_X64_MSVC + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #define AS_CALLEE_DESTROY_OBJ_BY_VAL + #define AS_LARGE_OBJS_PASSED_BY_REF + #define AS_LARGE_OBJ_MIN_SIZE 3 + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY | asOBJ_APP_CLASS_MORE_CONSTRUCTORS) + #define COMPLEX_MASK (asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #endif + #endif + + #if defined(_ARM_) || defined(_M_ARM) + #define AS_ARM + #define AS_CALLEE_DESTROY_OBJ_BY_VAL + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define COMPLEX_MASK (asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY) + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY) + + // Windows CE uses softfp calling convention, while Windows RT uses hardfp calling convention + // ref: http://stackoverflow.com/questions/16375355/what-is-the-windows-rt-on-arm-native-code-calling-convention + #if defined(_WIN32_WCE) + #define AS_SOFTFP + #endif + #endif + + #if defined(_M_ARM64) + #define AS_ARM64 + + // TODO: MORE HERE + #endif + + #ifndef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_ARRAY) + #endif + + #ifndef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_ARRAY | asOBJ_APP_CLASS_MORE_CONSTRUCTORS) + #endif + + #define UNREACHABLE_RETURN +#endif + +// Metrowerks CodeWarrior (experimental, let me know if something isn't working) +#if defined(__MWERKS__) && !defined(EPPC) // JWC -- If Wii DO NOT use this even when using Metrowerks Compiler. Even though they are called Freescale... + #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) + #define HAVE_VIRTUAL_BASE_OFFSET + #define VIRTUAL_BASE_OFFSET(x) (*((asDWORD*)(&x)+3)) + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_PASS_OBJECT_POINTER_IN_ECX + #define asVSNPRINTF(a, b, c, d) _vsnprintf(a, b, c, d) + #define THISCALL_CALLEE_POPS_ARGUMENTS + #define COMPLEX_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT) + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT) + #define AS_SIZEOF_BOOL 1 + #define AS_WINDOWS_THREADS + #define STDCALL __stdcall + + // Support native calling conventions on x86, but not 64bit yet + #if defined(_M_IX86) && !defined(__LP64__) + #define AS_X86 + #define ASM_INTEL // Intel style for inline assembly + #endif + + #define UNREACHABLE_RETURN +#endif + +// SN Systems ProDG +#if defined(__SNC__) || defined(SNSYS) + #define MULTI_BASE_OFFSET(x) (*((asDWORD*)(&x)+1)) + #define CALLEE_POPS_HIDDEN_RETURN_POINTER + #define COMPLEX_OBJS_PASSED_BY_REF + + #ifdef __psp2__ + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR) + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR) + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #else + #define GNU_STYLE_VIRTUAL_METHOD + #define ASM_AT_N_T // AT&T style inline assembly + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR) + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR) + #endif + + #define AS_SIZEOF_BOOL 1 + #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) + + // SN doesnt seem to like STDCALL. + // Maybe it can work with some fiddling, but I can't imagine linking to + // any STDCALL functions with a console anyway... + #define STDCALL + + // Linux specific + #ifdef __linux__ + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #endif + + // Support native calling conventions on x86, but not 64bit yet + #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + #define AS_X86 + // PS3 + #elif (defined(__PPC__) || defined(__ppc__)) && defined(__PPU__) + // Support native calling conventions on PS3 + #define AS_PS3 + #define AS_PPC_64 + #define AS_NO_MEMORY_H + #define AS_NO_EXCEPTIONS + #include + // PSP + #elif defined(__psp__) + #define AS_NO_MEMORY_H + #define AS_MIPS + #define AS_PSP + #define AS_USE_DOUBLE_AS_FLOAT + // PSVita + #elif defined(__psp2__) + #define AS_PSVITA + #define AS_ARM + #define AS_NO_MEMORY_H + #define AS_NO_EXCEPTIONS + #define AS_CALLEE_DESTROY_OBJ_BY_VAL + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #endif + + #define UNREACHABLE_RETURN +#endif + +// GNU C (and MinGW or Cygwin on Windows) +// Use the following command to determine predefined macros: echo . | g++ -dM -E - +// MSVC2015 can now use CLang too, but it shouldn't go in here +#if (defined(__GNUC__) && !defined(__SNC__) && !defined(_MSC_VER)) || defined(EPPC) || defined(__CYGWIN__) // JWC -- use this instead for Wii + #define GNU_STYLE_VIRTUAL_METHOD + #define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1)) + #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) + #define CALLEE_POPS_HIDDEN_RETURN_POINTER + #define COMPLEX_OBJS_PASSED_BY_REF + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_ARRAY) + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_ARRAY) + #define AS_NO_MEMORY_H + #define AS_SIZEOF_BOOL 1 + #define STDCALL __attribute__((stdcall)) + #define ASM_AT_N_T + + // WII U + #if defined(__ghs__) + #define AS_WIIU + + // Native calling conventions are not yet supported + #define AS_MAX_PORTABILITY + + // Marmalade is a cross platform SDK. It uses g++ to compile for iOS and Android + #elif defined(__S3E__) + #ifndef AS_MARMALADE + // From now on we'll use the below define + #define AS_MARMALADE + #endif + + // STDCALL is not available on Marmalade when compiled for iOS or Android + #undef STDCALL + #define STDCALL + + // Marmalade doesn't seem to have proper support for + // atomic instructions or read/write locks + #define AS_NO_THREADS + #define AS_NO_ATOMIC + + // Identify for which CPU the library is being built + #if defined(I3D_ARCH_X86) + #define AS_X86 + #elif defined(I3D_ARCH_ARM) + #define AS_ARM + + #define AS_SOFTFP + + // Marmalade appear to use the same ABI as Android when built for ARM + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + + #undef GNU_STYLE_VIRTUAL_METHOD + + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + + #define AS_CALLEE_DESTROY_OBJ_BY_VAL + #endif + + // MacOSX and IPhone + #elif defined(__APPLE__) + + #include + + // Is this a Mac or an IPhone (or other iOS device)? + #if defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE == 1 + #define AS_IPHONE + #else + #define AS_MAC + #endif + + // The sizeof bool is different depending on the target CPU + #undef AS_SIZEOF_BOOL + #if defined(__ppc__) + #define AS_SIZEOF_BOOL 4 + // STDCALL is not available on PPC + #undef STDCALL + #define STDCALL + #else + #define AS_SIZEOF_BOOL 1 + #endif + + #if (defined(_ARM_) || defined(__arm__)) + // iOS use ARM processor + #define AS_ARM + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + + #undef GNU_STYLE_VIRTUAL_METHOD + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define COMPLEX_OBJS_PASSED_BY_REF + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + + // iOS uses soft-float ABI + #define AS_SOFTFP + + // STDCALL is not available on ARM + #undef STDCALL + #define STDCALL + + #elif (defined(__arm64__)) + // The IPhone 5S+ uses an ARM64 processor + + // AngelScript currently doesn't support native calling + // for 64bit ARM processors so it's necessary to turn on + // portability mode + #define AS_MAX_PORTABILITY + + // STDCALL is not available on ARM + #undef STDCALL + #define STDCALL + + #elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + // Support native calling conventions on Mac OS X + Intel 32bit CPU + #define AS_X86 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + + #elif defined(__LP64__) && !defined(__ppc__) && !defined(__PPC__) && !defined(__arm64__) + // http://developer.apple.com/library/mac/#documentation/DeveloperTools/Conceptual/LowLevelABI/140-x86-64_Function_Calling_Conventions/x86_64.html#//apple_ref/doc/uid/TP40005035-SW1 + #define AS_X64_GCC + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #define HAS_128_BIT_PRIMITIVES + #define SPLIT_OBJS_BY_MEMBER_TYPES + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #define AS_LARGE_OBJS_PASSED_BY_REF + #define AS_LARGE_OBJ_MIN_SIZE 5 + // STDCALL is not available on 64bit Mac + #undef STDCALL + #define STDCALL + + #elif (defined(__ppc__) || defined(__PPC__)) && !defined(__LP64__) + // Support native calling conventions on Mac OS X + PPC 32bit CPU + #define AS_PPC + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + + #elif (defined(__ppc__) || defined(__PPC__)) && defined(__LP64__) + #define AS_PPC_64 + #else + // Unknown CPU type + #define AS_MAX_PORTABILITY + #endif + #define AS_POSIX_THREADS + + // Windows + #elif defined(WIN32) || defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__) + // On Windows the simple classes are returned in the EAX:EDX registers + //#define THISCALL_RETURN_SIMPLE_IN_MEMORY + //#define CDECL_RETURN_SIMPLE_IN_MEMORY + //#define STDCALL_RETURN_SIMPLE_IN_MEMORY + + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + + #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + // Support native calling conventions on Intel 32bit CPU + #define AS_X86 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + + // As of version 4.7 MinGW changed the ABI, presumably + // to be better aligned with how MSVC works + #if (__GNUC__ == 4 && __GNUC_MINOR__ >= 7) || __GNUC__ > 4 + #define AS_MINGW47 + #endif + + #if (__clang_major__ == 3 && __clang_minor__ > 4) || __clang_major > 3 + #define AS_MINGW47 + #endif + + #ifdef AS_MINGW47 + #undef CALLEE_POPS_HIDDEN_RETURN_POINTER + #define THISCALL_CALLEE_POPS_ARGUMENTS + #else + // Earlier versions than 4.7 + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #endif + + #elif defined(__x86_64__) + #define AS_X64_MINGW + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #define AS_LARGE_OBJS_PASSED_BY_REF + #define AS_LARGE_OBJ_MIN_SIZE 3 + #define COMPLEX_OBJS_PASSED_BY_REF + #else + #define AS_MAX_PORTABILITY + #endif + #define AS_WIN + #define AS_WINDOWS_THREADS + + // Linux + #elif defined(__linux__) && !defined(ANDROID) && !defined(__ANDROID__) + + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + + #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + // x86 32bit + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + + // Support native calling conventions on Intel 32bit CPU + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #define AS_X86 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #elif defined(__x86_64__) + // x86 64bit + #define AS_X64_GCC + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #define HAS_128_BIT_PRIMITIVES + #define SPLIT_OBJS_BY_MEMBER_TYPES + #define AS_LARGE_OBJS_PASSED_BY_REF + #define AS_LARGE_OBJ_MIN_SIZE 5 + // STDCALL is not available on 64bit Linux + #undef STDCALL + #define STDCALL + #elif defined(__ARMEL__) || defined(__arm__) || defined(__aarch64__) || defined(__AARCH64EL__) + // arm + + // The assembler code currently doesn't support arm v4 + #if !defined(__ARM_ARCH_4__) && !defined(__ARM_ARCH_4T__) && !defined(__LP64__) + #define AS_ARM + + // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S + #define AS_NO_EXCEPTIONS + + #undef STDCALL + #define STDCALL + + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + + #ifndef AS_MAX_PORTABILITY + // Make a few checks against incompatible ABI combinations + #if defined(__FAST_MATH__) && __FAST_MATH__ == 1 + #error -ffast-math is not supported with native calling conventions + #endif + #endif + + // Verify if soft-float or hard-float ABI is used + #if (defined(__SOFTFP__) && __SOFTFP__ == 1) || defined(__ARM_PCS) + // -ffloat-abi=softfp or -ffloat-abi=soft + #define AS_SOFTFP + #endif + + // Tested with both hard float and soft float abi + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #elif defined(__LP64__) || defined(__aarch64__) + #define AS_ARM64 + + #undef STDCALL + #define STDCALL + + #undef GNU_STYLE_VIRTUAL_METHOD + #undef AS_NO_THISCALL_FUNCTOR_METHOD + + #define HAS_128_BIT_PRIMITIVES + + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 5 + #endif + + #elif defined(__mips__) + // mips + #define AS_MIPS + #undef STDCALL + #define STDCALL + + #ifdef _ABIO32 + // 32bit O32 ABI + #define AS_MIPS + + // All structures are returned in memory regardless of size or complexity + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #else + // For other ABIs the native calling convention is not available (yet) + #define AS_MAX_PORTABILITY + #endif + #elif defined(__PPC64__) + // PPC 64bit + + // The code in as_callfunc_ppc_64.cpp was built for PS3 and XBox 360, that + // although use 64bit PPC only uses 32bit pointers. + // TODO: Add support for native calling conventions on Linux with PPC 64bit + #define AS_MAX_PORTABILITY + #elif defined(__e2k__) + // 64bit MCST Elbrus 2000 + // ref: https://en.wikipedia.org/wiki/Elbrus_2000 + #define AS_E2K + // AngelScript currently doesn't support native calling + // for MCST Elbrus 2000 processor so it's necessary to turn on + // portability mode + #define AS_MAX_PORTABILITY + // STDCALL is not available on 64bit Linux + #undef STDCALL + #define STDCALL + #else + #define AS_MAX_PORTABILITY + #endif + #define AS_LINUX + #define AS_POSIX_THREADS + + #if !( ( (__GNUC__ == 4) && (__GNUC_MINOR__ >= 1) || __GNUC__ > 4) ) + // Only with GCC 4.1 was the atomic instructions available + #define AS_NO_ATOMIC + #endif + + // Free BSD + #elif defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) + #define AS_BSD + #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #define AS_X86 + #elif defined(__x86_64__) + #define AS_X64_GCC + #define HAS_128_BIT_PRIMITIVES + #define SPLIT_OBJS_BY_MEMBER_TYPES + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #define AS_LARGE_OBJS_PASSED_BY_REF + #define AS_LARGE_OBJ_MIN_SIZE 5 + #undef STDCALL + #define STDCALL + #else + #define AS_MAX_PORTABILITY + #endif + #define AS_POSIX_THREADS + #if !( ( (__GNUC__ == 4) && (__GNUC_MINOR__ >= 1) || __GNUC__ > 4) ) + // Only with GCC 4.1 was the atomic instructions available + #define AS_NO_ATOMIC + #endif + + // PSP and PS2 + #elif defined(__PSP__) || defined(__psp__) || defined(_EE_) || defined(_PSP) || defined(_PS2) + // Support native calling conventions on MIPS architecture + #if (defined(_MIPS_ARCH) || defined(_mips) || defined(__MIPSEL__)) && !defined(__LP64__) + #define AS_MIPS + #define AS_USE_DOUBLE_AS_FLOAT + #else + #define AS_MAX_PORTABILITY + #endif + + // PS3 + #elif (defined(__PPC__) || defined(__ppc__)) && defined(__PPU__) + // Support native calling conventions on PS3 + #define AS_PS3 + #define AS_PPC_64 + #define SPLIT_OBJS_BY_MEMBER_TYPES + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + // PS3 doesn't have STDCALL + #undef STDCALL + #define STDCALL + + // Dreamcast + #elif __SH4_SINGLE_ONLY__ + // Support native calling conventions on Dreamcast + #define AS_DC + #define AS_SH4 + + // Wii JWC - Close to PS3 just no PPC_64 and AS_PS3 + #elif defined(EPPC) + #define AS_WII + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #undef STDCALL + #define STDCALL + + // Android + #elif defined(ANDROID) || defined(__ANDROID__) + #define AS_ANDROID + + // Android 2.3+ supports posix threads + #define AS_POSIX_THREADS + + // Common configuration with Android arm and x86 + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + + #if (defined(_ARM_) || defined(__arm__)) + // Android ARM + + // TODO: The stack unwind on exceptions currently fails due to the assembler code in as_callfunc_arm_gcc.S + #define AS_NO_EXCEPTIONS + + #undef THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + #undef STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE + + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 2 + + // The stdcall calling convention is not used on the arm cpu + #undef STDCALL + #define STDCALL + + #undef GNU_STYLE_VIRTUAL_METHOD + + #define AS_ARM + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #define AS_SOFTFP + #define AS_CALLEE_DESTROY_OBJ_BY_VAL + #elif (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + // Android Intel x86 (same config as Linux x86). Tested with Intel x86 Atom System Image. + + // Support native calling conventions on Intel 32bit CPU + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #define AS_X86 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #elif defined(__mips__) + #define AS_MIPS + #undef STDCALL + #define STDCALL + + #ifdef _ABIO32 + #define AS_MIPS + + // All structures are returned in memory regardless of size or complexity + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define THISCALL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY_MIN_SIZE 0 + #undef AS_NO_THISCALL_FUNCTOR_METHOD + #else + // For other ABIs the native calling convention is not available (yet) + #define AS_MAX_PORTABILITY + #endif + #endif + + // Haiku OS + #elif __HAIKU__ + #define AS_HAIKU + #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + #define AS_X86 + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + #elif defined(__x86_64__) + #define AS_X64_GCC + #define HAS_128_BIT_PRIMITIVES + #define SPLIT_OBJS_BY_MEMBER_TYPES + #undef COMPLEX_MASK + #define COMPLEX_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #undef COMPLEX_RETURN_MASK + #define COMPLEX_RETURN_MASK (asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_COPY_CONSTRUCTOR | asOBJ_APP_ARRAY) + #define AS_LARGE_OBJS_PASSED_BY_REF + #define AS_LARGE_OBJ_MIN_SIZE 5 + #undef STDCALL + #define STDCALL + #else + #define AS_MAX_PORTABILITY + #endif + + // Illumos + #elif defined(__sun) + #if (defined(i386) || defined(__i386) || defined(__i386__)) && !defined(__LP64__) + #define THISCALL_RETURN_SIMPLE_IN_MEMORY + #define CDECL_RETURN_SIMPLE_IN_MEMORY + #define STDCALL_RETURN_SIMPLE_IN_MEMORY + + // Support native calling conventions on Intel 32bit CPU + #define THISCALL_PASS_OBJECT_POINTER_ON_THE_STACK + #define AS_X86 + #elif defined(__x86_64__) + #define AS_X64_GCC + #define HAS_128_BIT_PRIMITIVES + #define SPLIT_OBJS_BY_MEMBER_TYPES + // STDCALL is not available on 64bit Linux + #undef STDCALL + #define STDCALL + #else + #define AS_MAX_PORTABILITY + #endif + #define AS_ILLUMOS + #define AS_POSIX_THREADS + + #if !( ( (__GNUC__ == 4) && (__GNUC_MINOR__ >= 1) || __GNUC__ > 4) ) + // Only with GCC 4.1 was the atomic instructions available + #define AS_NO_ATOMIC + #endif + #endif + + #define UNREACHABLE_RETURN +#endif + +// Sun CC +// Initial information provided by Andrey Bergman +#if defined(__SUNPRO_CC) + #if defined(__sparc) + #define AS_SPARC + #endif + + #if defined(__sun) + #define AS_SUN + #endif + + // Native calling conventions is not yet supported for Sun CC + #if !defined(AS_MAX_PORTABILITY) + #define AS_MAX_PORTABILITY + #endif + + // I presume Sun CC uses a similar structure of method pointers as gnuc + #define MULTI_BASE_OFFSET(x) (*((asPWORD*)(&x)+1)) + + #if !defined(AS_SIZEOF_BOOL) + #define AS_SIZEOF_BOOL 1 // sizeof(bool) == 1 + #endif + #if !defined(UNREACHABLE_RETURN) + #define UNREACHABLE_RETURN + #endif + #if !defined(STDCALL) + #define STDCALL // There is no stdcall on Solaris/SunPro/SPARC + #endif + #if !defined(asVSNPRINTF) + #define asVSNPRINTF(a, b, c, d) vsnprintf(a, b, c, d) + #endif +#endif + + +// +// Detect target hardware +//------------------------------------------------ + +// Big endian CPU target? +// see: http://sourceforge.net/p/predef/wiki/Endianness/ +#if !defined(AS_BIG_ENDIAN) && \ + defined(__BYTE_ORDER) && __BYTE_ORDER == __BIG_ENDIAN || \ + defined(__BIG_ENDIAN__) || \ + defined(__ARMEB__) || \ + defined(__THUMBEB__) || \ + defined(__AARCH64EB__) || \ + defined(_MIBSEB) || defined(__MIBSEB) || defined(__MIBSEB__) + #define AS_BIG_ENDIAN +#endif + +// Dreamcast and Gamecube use only 32bit floats, so treat doubles as floats +#if defined(__SH4_SINGLE_ONLY__) || defined(_GC) + #define AS_USE_DOUBLE_AS_FLOAT // use 32bit floats instead of doubles +#endif + +// If there are no current support for native calling +// conventions, then compile with AS_MAX_PORTABILITY +#if (!defined(AS_X86) && !defined(AS_SH4) && !defined(AS_MIPS) && !defined(AS_PPC) && !defined(AS_PPC_64) && !defined(AS_XENON) && !defined(AS_X64_GCC) && !defined(AS_X64_MSVC) && !defined(AS_ARM) && !defined(AS_ARM64) && !defined(AS_X64_MINGW)) + #ifndef AS_MAX_PORTABILITY + #define AS_MAX_PORTABILITY + #endif +#endif + +// If the platform doesn't support atomic instructions we can't allow +// multithreading as the reference counters won't be threadsafe +#if defined(AS_NO_ATOMIC) && !defined(AS_NO_THREADS) + #define AS_NO_THREADS +#endif + +// If the form of threads to use hasn't been chosen +// then the library will be compiled without support +// for multithreading +#if !defined(AS_POSIX_THREADS) && !defined(AS_WINDOWS_THREADS) + #define AS_NO_THREADS +#endif + + +// The assert macro +#if defined(ANDROID) + #if defined(AS_DEBUG) + #include + #include + #define asASSERT(x) \ + do { \ + if (!(x)) { \ + __android_log_print(ANDROID_LOG_ERROR, "AngelScript", "Assert failed at %s:%d - %s", __FILE__, __LINE__, #x); \ + exit(1); \ + } \ + } while (0) + #else + #define asASSERT(x) + #endif +#else + #include + #define asASSERT(x) assert(x) +#endif + + + +// +// Internal defines (do not change these) +//---------------------------------------------------------------- + +#define ARG_W(b) ((asWORD*)&b) +#define ARG_DW(b) ((asDWORD*)&b) +#define ARG_QW(b) ((asQWORD*)&b) +#define ARG_PTR(b) ((asPWORD*)&b) +#define BCARG_W(b) ((asWORD*)&(b)[1]) +#define BCARG_DW(b) ((asDWORD*)&(b)[1]) +#define BCARG_QW(b) ((asQWORD*)&(b)[1]) +#define BCARG_PTR(b) ((asPWORD*)&(b)[1]) + +// This macro is used to avoid warnings about unused variables. +// Usually where the variables are only used in debug mode. +#define UNUSED_VAR(x) (void)(x) + +#include "../include/angelscript.h" +#include "as_memory.h" + +#ifdef AS_USE_NAMESPACE +using namespace AngelScript; +#endif + +#endif diff --git a/angelscript/source/as_configgroup.cpp b/angelscript/source/as_configgroup.cpp new file mode 100644 index 0000000..a29bc93 --- /dev/null +++ b/angelscript/source/as_configgroup.cpp @@ -0,0 +1,209 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_configgroup.cpp +// +// This class holds configuration groups for the engine +// + + + +#include "as_config.h" +#include "as_configgroup.h" +#include "as_scriptengine.h" +#include "as_texts.h" + +BEGIN_AS_NAMESPACE + +asCConfigGroup::asCConfigGroup() +{ + refCount = 0; +} + +asCConfigGroup::~asCConfigGroup() +{ +} + +int asCConfigGroup::AddRef() +{ + refCount++; + return refCount; +} + +int asCConfigGroup::Release() +{ + // Don't delete the object here, the engine will delete the object when ready + refCount--; + return refCount; +} + +asCTypeInfo *asCConfigGroup::FindType(const char *obj) +{ + for( asUINT n = 0; n < types.GetLength(); n++ ) + if( types[n]->name == obj ) + return types[n]; + + return 0; +} + +void asCConfigGroup::RefConfigGroup(asCConfigGroup *group) +{ + if( group == this || group == 0 ) return; + + // Verify if the group is already referenced + for( asUINT n = 0; n < referencedConfigGroups.GetLength(); n++ ) + if( referencedConfigGroups[n] == group ) + return; + + referencedConfigGroups.PushLast(group); + group->AddRef(); +} + +void asCConfigGroup::AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func) +{ + AddReferencesForType(engine, func->returnType.GetTypeInfo()); + for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) + AddReferencesForType(engine, func->parameterTypes[n].GetTypeInfo()); +} + +void asCConfigGroup::AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type) +{ + if( type == 0 ) return; + + // Keep reference to other groups + RefConfigGroup(engine->FindConfigGroupForTypeInfo(type)); + + // Keep track of which generated template instances the config group uses + if( type->flags & asOBJ_TEMPLATE && engine->generatedTemplateTypes.Exists(CastToObjectType(type)) && !generatedTemplateInstances.Exists(CastToObjectType(type)) ) + generatedTemplateInstances.PushLast(CastToObjectType(type)); +} + +bool asCConfigGroup::HasLiveObjects() +{ + for( asUINT n = 0; n < types.GetLength(); n++ ) + if( types[n]->externalRefCount.get() != 0 ) + return true; + + return false; +} + +void asCConfigGroup::RemoveConfiguration(asCScriptEngine *engine, bool notUsed) +{ + asASSERT( refCount == 0 ); + + asUINT n; + + // Remove global variables + for( n = 0; n < globalProps.GetLength(); n++ ) + { + int index = engine->registeredGlobalProps.GetIndex(globalProps[n]); + if( index >= 0 ) + { + globalProps[n]->Release(); + + engine->registeredGlobalProps.Erase(index); + } + } + globalProps.SetLength(0); + + // Remove global functions + for( n = 0; n < scriptFunctions.GetLength(); n++ ) + { + int index = engine->registeredGlobalFuncs.GetIndex(scriptFunctions[n]); + if( index >= 0 ) + engine->registeredGlobalFuncs.Erase(index); + scriptFunctions[n]->ReleaseInternal(); + } + scriptFunctions.SetLength(0); + + // Remove behaviours and members of object types + for( n = 0; n < types.GetLength(); n++ ) + { + asCObjectType *obj = CastToObjectType(types[n]); + if( obj ) + obj->ReleaseAllFunctions(); + } + + // Remove object types (skip this if it is possible other groups are still using the types) + if( !notUsed ) + { + for( n = asUINT(types.GetLength()); n-- > 0; ) + { + asCTypeInfo *t = types[n]; + asSMapNode *cursor; + if( engine->allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(t->nameSpace, t->name)) && + cursor->value == t ) + { + engine->allRegisteredTypes.Erase(cursor); + + if( engine->defaultArrayObjectType == t ) + engine->defaultArrayObjectType = 0; + + if( t->flags & asOBJ_TYPEDEF ) + engine->registeredTypeDefs.RemoveValue(CastToTypedefType(t)); + else if( t->flags & asOBJ_ENUM ) + engine->registeredEnums.RemoveValue(CastToEnumType(t)); + else if (t->flags & asOBJ_TEMPLATE) + engine->registeredTemplateTypes.RemoveValue(CastToObjectType(t)); + else if (t->flags & asOBJ_FUNCDEF) + { + engine->registeredFuncDefs.RemoveValue(CastToFuncdefType(t)); + engine->RemoveFuncdef(CastToFuncdefType(t)); + } + else + engine->registeredObjTypes.RemoveValue(CastToObjectType(t)); + + t->DestroyInternal(); + t->ReleaseInternal(); + } + else + { + int idx = engine->templateInstanceTypes.IndexOf(CastToObjectType(t)); + if( idx >= 0 ) + { + engine->templateInstanceTypes.RemoveIndexUnordered(idx); + asCObjectType *ot = CastToObjectType(t); + ot->DestroyInternal(); + ot->ReleaseInternal(); + } + } + } + types.SetLength(0); + } + + // Release other config groups + for( n = 0; n < referencedConfigGroups.GetLength(); n++ ) + referencedConfigGroups[n]->refCount--; + referencedConfigGroups.SetLength(0); +} + +END_AS_NAMESPACE diff --git a/angelscript/source/as_configgroup.h b/angelscript/source/as_configgroup.h new file mode 100644 index 0000000..4872030 --- /dev/null +++ b/angelscript/source/as_configgroup.h @@ -0,0 +1,84 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_configgroup.h +// +// This class holds configuration groups for the engine +// + + + +#ifndef AS_CONFIGGROUP_H +#define AS_CONFIGGROUP_H + +#include "as_config.h" +#include "as_string.h" +#include "as_array.h" +#include "as_objecttype.h" + +BEGIN_AS_NAMESPACE + +class asCConfigGroup +{ +public: + asCConfigGroup(); + ~asCConfigGroup(); + + // Memory management + int AddRef(); + int Release(); + + asCTypeInfo *FindType(const char *name); + void RefConfigGroup(asCConfigGroup *group); + + bool HasLiveObjects(); + void RemoveConfiguration(asCScriptEngine *engine, bool notUsed = false); + + void AddReferencesForFunc(asCScriptEngine *engine, asCScriptFunction *func); + void AddReferencesForType(asCScriptEngine *engine, asCTypeInfo *type); + + asCString groupName; + int refCount; + + asCArray types; + asCArray scriptFunctions; + asCArray globalProps; + asCArray referencedConfigGroups; + + // This array holds the generated template instances that are used + // by the config group as part of function signature or property + asCArray generatedTemplateInstances; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_context.cpp b/angelscript/source/as_context.cpp new file mode 100644 index 0000000..d578c3f --- /dev/null +++ b/angelscript/source/as_context.cpp @@ -0,0 +1,5997 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_context.cpp +// +// This class handles the execution of the byte code +// + +#include // fmodf() pow() + +#include "as_config.h" +#include "as_context.h" +#include "as_scriptengine.h" +#include "as_tokendef.h" +#include "as_texts.h" +#include "as_callfunc.h" +#include "as_generic.h" +#include "as_debug.h" // mkdir() +#include "as_bytecode.h" +#include "as_scriptobject.h" + +#ifdef _MSC_VER +#pragma warning(disable:4702) // unreachable code +#endif + +BEGIN_AS_NAMESPACE + +// We need at least 2 PTRs reserved for exception handling +// We need at least 1 PTR reserved for calling system functions +const int RESERVE_STACK = 2*AS_PTR_SIZE; + +// For each script function call we push 9 PTRs on the call stack +const int CALLSTACK_FRAME_SIZE = 9; + +#if defined(AS_DEBUG) + +class asCDebugStats +{ +public: + asCDebugStats() + { + memset(instrCount, 0, sizeof(instrCount)); + memset(instrCount2, 0, sizeof(instrCount2)); + lastBC = 255; + } + + ~asCDebugStats() + { + // This code writes out some statistics for the VM. + // It's useful for determining what needs to be optimized. + +#ifndef __MINGW32__ + // _mkdir is broken on mingw + _mkdir("AS_DEBUG"); +#endif + #if _MSC_VER >= 1500 && !defined(AS_MARMALADE) + FILE *f; + fopen_s(&f, "AS_DEBUG/stats.txt", "wt"); + #else + FILE *f = fopen("AS_DEBUG/stats.txt", "wt"); + #endif + if( f ) + { + // Output instruction statistics + fprintf(f, "\nTotal count\n"); + int n; + for( n = 0; n < asBC_MAXBYTECODE; n++ ) + { + if( asBCInfo[n].name && instrCount[n] > 0 ) + fprintf(f, "%-10.10s : %.0f\n", asBCInfo[n].name, instrCount[n]); + } + + fprintf(f, "\nNever executed\n"); + for( n = 0; n < asBC_MAXBYTECODE; n++ ) + { + if( asBCInfo[n].name && instrCount[n] == 0 ) + fprintf(f, "%-10.10s\n", asBCInfo[n].name); + } + + fprintf(f, "\nSequences\n"); + for( n = 0; n < 256; n++ ) + { + if( asBCInfo[n].name ) + { + for( int m = 0; m < 256; m++ ) + { + if( instrCount2[n][m] ) + fprintf(f, "%-10.10s, %-10.10s : %.0f\n", asBCInfo[n].name, asBCInfo[m].name, instrCount2[n][m]); + } + } + } + fclose(f); + } + } + + void Instr(asBYTE bc) + { + ++instrCount[bc]; + ++instrCount2[lastBC][bc]; + lastBC = bc; + } + + // Instruction statistics + double instrCount[256]; + double instrCount2[256][256]; + int lastBC; +} stats; + +#endif + +// interface +AS_API asIScriptContext *asGetActiveContext() +{ + asCThreadLocalData *tld = asCThreadManager::GetLocalData(); + + // tld can be 0 if asGetActiveContext is called before any engine has been created. + + // Observe! I've seen a case where an application linked with the library twice + // and thus ended up with two separate instances of the code and global variables. + // The application somehow mixed the two instances so that a function called from + // a script ended up calling asGetActiveContext from the other instance that had + // never been initialized. + + if( tld == 0 || tld->activeContexts.GetLength() == 0 ) + return 0; + return tld->activeContexts[tld->activeContexts.GetLength()-1]; +} + +// internal +asCThreadLocalData *asPushActiveContext(asIScriptContext *ctx) +{ + asCThreadLocalData *tld = asCThreadManager::GetLocalData(); + asASSERT( tld ); + if( tld == 0 ) + return 0; + tld->activeContexts.PushLast(ctx); + return tld; +} + +// internal +void asPopActiveContext(asCThreadLocalData *tld, asIScriptContext *ctx) +{ + UNUSED_VAR(ctx); + asASSERT(tld && tld->activeContexts[tld->activeContexts.GetLength() - 1] == ctx); + if (tld) + tld->activeContexts.PopLast(); +} + +asCContext::asCContext(asCScriptEngine *engine, bool holdRef) +{ + m_refCount.set(1); + + m_holdEngineRef = holdRef; + if( holdRef ) + engine->AddRef(); + + m_engine = engine; + m_status = asEXECUTION_UNINITIALIZED; + m_stackBlockSize = 0; + m_originalStackPointer = 0; + m_inExceptionHandler = false; + m_isStackMemoryNotAllocated = false; + m_needToCleanupArgs = false; + m_currentFunction = 0; + m_callingSystemFunction = 0; + m_regs.objectRegister = 0; + m_initialFunction = 0; + m_lineCallback = false; + m_exceptionCallback = false; + m_regs.doProcessSuspend = false; + m_doSuspend = false; + m_userData = 0; + m_regs.ctx = this; + m_exceptionWillBeCaught = false; +} + +asCContext::~asCContext() +{ + DetachEngine(); +} + +// interface +bool asCContext::IsNested(asUINT *nestCount) const +{ + if( nestCount ) + *nestCount = 0; + + asUINT c = GetCallstackSize(); + if( c == 0 ) + return false; + + // Search for a marker on the call stack + // This loop starts at 2 because the 0th entry is not stored in m_callStack, + // and then we need to subtract one more to get the base of each frame + for( asUINT n = 2; n <= c; n++ ) + { + const asPWORD *s = m_callStack.AddressOf() + (c - n)*CALLSTACK_FRAME_SIZE; + if( s && s[0] == 0 ) + { + if( nestCount ) + (*nestCount)++; + else + return true; + } + } + + if( nestCount && *nestCount > 0 ) + return true; + + return false; +} + +// interface +int asCContext::AddRef() const +{ + return m_refCount.atomicInc(); +} + +// interface +int asCContext::Release() const +{ + int r = m_refCount.atomicDec(); + + if( r == 0 ) + { + asDELETE(const_cast(this),asCContext); + return 0; + } + + return r; +} + +// internal +void asCContext::DetachEngine() +{ + if( m_engine == 0 ) return; + + // Clean up all calls, included nested ones + do + { + // Abort any execution + Abort(); + + // Free all resources + Unprepare(); + } + while( IsNested() ); + + // Free the stack blocks + for( asUINT n = 0; n < m_stackBlocks.GetLength(); n++ ) + { + if( m_stackBlocks[n] ) + { +#ifndef WIP_16BYTE_ALIGN + asDELETEARRAY(m_stackBlocks[n]); +#else + asDELETEARRAYALIGNED(m_stackBlocks[n]); +#endif + } + } + m_stackBlocks.SetLength(0); + m_stackBlockSize = 0; + + // Clean the user data + for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) + { + if( m_userData[n+1] ) + { + for( asUINT c = 0; c < m_engine->cleanContextFuncs.GetLength(); c++ ) + if( m_engine->cleanContextFuncs[c].type == m_userData[n] ) + m_engine->cleanContextFuncs[c].cleanFunc(this); + } + } + m_userData.SetLength(0); + + // Clear engine pointer + if( m_holdEngineRef ) + m_engine->Release(); + m_engine = 0; +} + +// interface +asIScriptEngine *asCContext::GetEngine() const +{ + return m_engine; +} + +// interface +void *asCContext::SetUserData(void *data, asPWORD type) +{ + // As a thread might add a new new user data at the same time as another + // it is necessary to protect both read and write access to the userData member + ACQUIREEXCLUSIVE(m_engine->engineRWLock); + + // It is not intended to store a lot of different types of userdata, + // so a more complex structure like a associative map would just have + // more overhead than a simple array. + for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) + { + if( m_userData[n] == type ) + { + void *oldData = reinterpret_cast(m_userData[n+1]); + m_userData[n+1] = reinterpret_cast(data); + + RELEASEEXCLUSIVE(m_engine->engineRWLock); + + return oldData; + } + } + + m_userData.PushLast(type); + m_userData.PushLast(reinterpret_cast(data)); + + RELEASEEXCLUSIVE(m_engine->engineRWLock); + + return 0; +} + +// interface +void *asCContext::GetUserData(asPWORD type) const +{ + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + ACQUIRESHARED(m_engine->engineRWLock); + + for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) + { + if( m_userData[n] == type ) + { + RELEASESHARED(m_engine->engineRWLock); + return reinterpret_cast(m_userData[n+1]); + } + } + + RELEASESHARED(m_engine->engineRWLock); + + return 0; +} + +// interface +asIScriptFunction *asCContext::GetSystemFunction() +{ + return m_callingSystemFunction; +} + +// interface +int asCContext::Prepare(asIScriptFunction *func) +{ + if( func == 0 ) + { + asCString str; + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", "null", errorNames[-asNO_FUNCTION], asNO_FUNCTION); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return asNO_FUNCTION; + } + + if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED ) + { + asCString str; + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asCONTEXT_ACTIVE], asCONTEXT_ACTIVE); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return asCONTEXT_ACTIVE; + } + + // Clean the stack if not done before + if( m_status != asEXECUTION_FINISHED && m_status != asEXECUTION_UNINITIALIZED ) + CleanStack(); + + // Release the returned object (if any) + CleanReturnObject(); + + // Release the object if it is a script object + if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) + { + asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0]; + if( obj ) + obj->Release(); + + *(asPWORD*)&m_regs.stackFramePointer[0] = 0; + } + + if( m_initialFunction && m_initialFunction == func ) + { + // If the same function is executed again, we can skip a lot of the setup + m_currentFunction = m_initialFunction; + + // Reset stack pointer + m_regs.stackPointer = m_originalStackPointer; + + // Make sure the stack pointer is pointing to the original position, + // otherwise something is wrong with the way it is being updated + asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) ); + } + else + { + asASSERT( m_engine ); + + // Make sure the function is from the same engine as the context to avoid mixups + if( m_engine != func->GetEngine() ) + { + asCString str; + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, "Prepare", func->GetDeclaration(true, true), errorNames[-asINVALID_ARG], asINVALID_ARG); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return asINVALID_ARG; + } + + if( m_initialFunction ) + { + m_initialFunction->Release(); + + // Reset stack pointer + m_regs.stackPointer = m_originalStackPointer; + + // Make sure the stack pointer is pointing to the original position, + // otherwise something is wrong with the way it is being updated + asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) ); + } + + // We trust the application not to pass anything else but a asCScriptFunction + m_initialFunction = reinterpret_cast(func); + m_initialFunction->AddRef(); + m_currentFunction = m_initialFunction; + + // TODO: runtime optimize: GetSpaceNeededForArguments() should be precomputed + m_argumentsSize = m_currentFunction->GetSpaceNeededForArguments() + (m_currentFunction->objectType ? AS_PTR_SIZE : 0); + + // Reserve space for the arguments and return value + if( m_currentFunction->DoesReturnOnStack() ) + { + m_returnValueSize = m_currentFunction->returnType.GetSizeInMemoryDWords(); + m_argumentsSize += AS_PTR_SIZE; + } + else + m_returnValueSize = 0; + + // Determine the minimum stack size needed + int stackSize = m_argumentsSize + m_returnValueSize; + if( m_currentFunction->scriptData ) + stackSize += m_currentFunction->scriptData->stackNeeded; + + // Make sure there is enough space on the stack for the arguments and return value + if( !ReserveStackSpace(stackSize) ) + return asOUT_OF_MEMORY; + + // Set up the call stack too + if (m_callStack.GetCapacity() < m_engine->ep.initCallStackSize) + m_callStack.AllocateNoConstruct(m_engine->ep.initCallStackSize * CALLSTACK_FRAME_SIZE, true); + } + + // Reset state + // Most of the time the previous state will be asEXECUTION_FINISHED, in which case the values are already initialized + if( m_status != asEXECUTION_FINISHED ) + { + m_exceptionLine = -1; + m_exceptionFunction = 0; + m_doAbort = false; + m_doSuspend = false; + m_regs.doProcessSuspend = m_lineCallback; + m_externalSuspendRequest = false; + } + m_status = asEXECUTION_PREPARED; + m_regs.programPointer = 0; + + // Reserve space for the arguments and return value + m_regs.stackFramePointer = m_regs.stackPointer - m_argumentsSize - m_returnValueSize; + m_originalStackPointer = m_regs.stackPointer; + m_regs.stackPointer = m_regs.stackFramePointer; + + // Set arguments to 0 + memset(m_regs.stackPointer, 0, 4*m_argumentsSize); + + if( m_returnValueSize ) + { + // Set the address of the location where the return value should be put + asDWORD *ptr = m_regs.stackFramePointer; + if( m_currentFunction->objectType ) + ptr += AS_PTR_SIZE; + + *(void**)ptr = (void*)(m_regs.stackFramePointer + m_argumentsSize); + } + + return asSUCCESS; +} + +// Free all resources +int asCContext::Unprepare() +{ + if( m_status == asEXECUTION_ACTIVE || m_status == asEXECUTION_SUSPENDED ) + return asCONTEXT_ACTIVE; + + // Set the context as active so that any clean up code can use access it if desired + asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this); + asDWORD count = m_refCount.get(); + UNUSED_VAR(count); + + // Only clean the stack if the context was prepared but not executed until the end + if( m_status != asEXECUTION_UNINITIALIZED && + m_status != asEXECUTION_FINISHED ) + CleanStack(); + + asASSERT( m_needToCleanupArgs == false ); + + // Release the returned object (if any) + CleanReturnObject(); + + // TODO: Unprepare is called during destruction, so nobody + // must be allowed to keep an extra reference + asASSERT(m_refCount.get() == count); + asPopActiveContext(tld, this); + + // Release the object if it is a script object + if( m_initialFunction && m_initialFunction->objectType && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) + { + asCScriptObject *obj = *(asCScriptObject**)&m_regs.stackFramePointer[0]; + if( obj ) + obj->Release(); + } + + // Release the initial function + if( m_initialFunction ) + { + m_initialFunction->Release(); + + // Reset stack pointer + m_regs.stackPointer = m_originalStackPointer; + + // Make sure the stack pointer is pointing to the original position, + // otherwise something is wrong with the way it is being updated + asASSERT( IsNested() || m_stackIndex > 0 || (m_regs.stackPointer == m_stackBlocks[0] + m_stackBlockSize) ); + } + + // Clear function pointers + m_initialFunction = 0; + m_currentFunction = 0; + m_exceptionFunction = 0; + m_regs.programPointer = 0; + + // Reset status + m_status = asEXECUTION_UNINITIALIZED; + + m_regs.stackFramePointer = 0; + + return 0; +} + +asBYTE asCContext::GetReturnByte() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + + return *(asBYTE*)&m_regs.valueRegister; +} + +asWORD asCContext::GetReturnWord() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + + return *(asWORD*)&m_regs.valueRegister; +} + +asDWORD asCContext::GetReturnDWord() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + + return *(asDWORD*)&m_regs.valueRegister; +} + +asQWORD asCContext::GetReturnQWord() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + + return m_regs.valueRegister; +} + +float asCContext::GetReturnFloat() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + + return *(float*)&m_regs.valueRegister; +} + +double asCContext::GetReturnDouble() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) return 0; + + return *(double*)&m_regs.valueRegister; +} + +void *asCContext::GetReturnAddress() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( dt->IsReference() ) + return *(void**)&m_regs.valueRegister; + else if( dt->IsObject() || dt->IsFuncdef() ) + { + if( m_initialFunction->DoesReturnOnStack() ) + { + // The address of the return value was passed as the first argument, after the object pointer + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + return *(void**)(&m_regs.stackFramePointer[offset]); + } + + return m_regs.objectRegister; + } + + return 0; +} + +void *asCContext::GetReturnObject() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + if( !dt->IsObject() && !dt->IsFuncdef() ) return 0; + + if( dt->IsReference() ) + return *(void**)(asPWORD)m_regs.valueRegister; + else + { + if( m_initialFunction->DoesReturnOnStack() ) + { + // The address of the return value was passed as the first argument, after the object pointer + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + return *(void**)(&m_regs.stackFramePointer[offset]); + } + + return m_regs.objectRegister; + } +} + +void *asCContext::GetAddressOfReturnValue() +{ + if( m_status != asEXECUTION_FINISHED ) return 0; + + asCDataType *dt = &m_initialFunction->returnType; + + // An object is stored in the objectRegister + if( !dt->IsReference() && (dt->IsObject() || dt->IsFuncdef()) ) + { + // Need to dereference objects + if( !dt->IsObjectHandle() ) + { + if( m_initialFunction->DoesReturnOnStack() ) + { + // The address of the return value was passed as the first argument, after the object pointer + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + return *(void**)(&m_regs.stackFramePointer[offset]); + } + + return *(void**)&m_regs.objectRegister; + } + return &m_regs.objectRegister; + } + + // Primitives and references are stored in valueRegister + return &m_regs.valueRegister; +} + +int asCContext::SetObject(void *obj) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( !m_initialFunction->objectType ) + { + m_status = asEXECUTION_ERROR; + return asERROR; + } + + asASSERT( *(asPWORD*)&m_regs.stackFramePointer[0] == 0 ); + + *(asPWORD*)&m_regs.stackFramePointer[0] = (asPWORD)obj; + + // TODO: This should be optional by having a flag where the application can chose whether it should be done or not + // The flag could be named something like takeOwnership and have default value of true + if( obj && (m_initialFunction->objectType->flags & asOBJ_SCRIPT_OBJECT) ) + reinterpret_cast(obj)->AddRef(); + + return 0; +} + +int asCContext::SetArgByte(asUINT arg, asBYTE value) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + if( dt->GetSizeInMemoryBytes() != 1 ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(asBYTE*)&m_regs.stackFramePointer[offset] = value; + + return 0; +} + +int asCContext::SetArgWord(asUINT arg, asWORD value) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + if( dt->GetSizeInMemoryBytes() != 2 ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(asWORD*)&m_regs.stackFramePointer[offset] = value; + + return 0; +} + +int asCContext::SetArgDWord(asUINT arg, asDWORD value) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + if( dt->GetSizeInMemoryBytes() != 4 ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(asDWORD*)&m_regs.stackFramePointer[offset] = value; + + return 0; +} + +int asCContext::SetArgQWord(asUINT arg, asQWORD value) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + if( dt->GetSizeOnStackDWords() != 2 ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(asQWORD*)(&m_regs.stackFramePointer[offset]) = value; + + return 0; +} + +int asCContext::SetArgFloat(asUINT arg, float value) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + if( dt->GetSizeOnStackDWords() != 1 ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(float*)(&m_regs.stackFramePointer[offset]) = value; + + return 0; +} + +int asCContext::SetArgDouble(asUINT arg, double value) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( dt->IsObject() || dt->IsFuncdef() || dt->IsReference() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + if( dt->GetSizeOnStackDWords() != 2 ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(double*)(&m_regs.stackFramePointer[offset]) = value; + + return 0; +} + +int asCContext::SetArgAddress(asUINT arg, void *value) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( !dt->IsReference() && !dt->IsObjectHandle() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)value; + + return 0; +} + +int asCContext::SetArgObject(asUINT arg, void *obj) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( !dt->IsObject() && !dt->IsFuncdef() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // If the object should be sent by value we must make a copy of it + if( !dt->IsReference() ) + { + if( dt->IsObjectHandle() ) + { + // Increase the reference counter + if (obj && dt->IsFuncdef()) + ((asIScriptFunction*)obj)->AddRef(); + else + { + asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; + if (obj && beh->addref) + m_engine->CallObjectMethod(obj, beh->addref); + } + } + else + { + obj = m_engine->CreateScriptObjectCopy(obj, dt->GetTypeInfo()); + } + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the value + *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)obj; + + return 0; +} + +int asCContext::SetArgVarType(asUINT arg, void *ptr, int typeId) +{ + if( m_status != asEXECUTION_PREPARED ) + return asCONTEXT_NOT_PREPARED; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_ARG; + } + + // Verify the type of the argument + asCDataType *dt = &m_initialFunction->parameterTypes[arg]; + if( dt->GetTokenType() != ttQuestion ) + { + m_status = asEXECUTION_ERROR; + return asINVALID_TYPE; + } + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Set the typeId and pointer + *(asPWORD*)(&m_regs.stackFramePointer[offset]) = (asPWORD)ptr; + offset += AS_PTR_SIZE; + *(int*)(&m_regs.stackFramePointer[offset]) = typeId; + + return 0; +} + +// TODO: Instead of GetAddressOfArg, maybe we need a SetArgValue(int arg, void *value, bool takeOwnership) instead. + +// interface +void *asCContext::GetAddressOfArg(asUINT arg) +{ + if( m_status != asEXECUTION_PREPARED ) + return 0; + + if( arg >= (unsigned)m_initialFunction->parameterTypes.GetLength() ) + return 0; + + // Determine the position of the argument + int offset = 0; + if( m_initialFunction->objectType ) + offset += AS_PTR_SIZE; + + // If function returns object by value an extra pointer is pushed on the stack + if( m_returnValueSize ) + offset += AS_PTR_SIZE; + + for( asUINT n = 0; n < arg; n++ ) + offset += m_initialFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // We should return the address of the location where the argument value will be placed + + // All registered types are always sent by reference, even if + // the function is declared to receive the argument by value. + return &m_regs.stackFramePointer[offset]; +} + + +int asCContext::Abort() +{ + if( m_engine == 0 ) return asERROR; + + // TODO: multithread: Make thread safe. There is a chance that the status + // changes to something else after being set to ABORTED here. + if( m_status == asEXECUTION_SUSPENDED ) + m_status = asEXECUTION_ABORTED; + + m_doSuspend = true; + m_regs.doProcessSuspend = true; + m_externalSuspendRequest = true; + m_doAbort = true; + + return 0; +} + +// interface +int asCContext::Suspend() +{ + // This function just sets some internal flags and is safe + // to call from a secondary thread, even if the library has + // been built without multi-thread support. + + if( m_engine == 0 ) return asERROR; + + m_doSuspend = true; + m_externalSuspendRequest = true; + m_regs.doProcessSuspend = true; + + return 0; +} + +// interface +int asCContext::Execute() +{ + asASSERT( m_engine != 0 ); + + if( m_status != asEXECUTION_SUSPENDED && m_status != asEXECUTION_PREPARED ) + { + asCString str; + str.Format(TXT_FAILED_IN_FUNC_s_s_d, "Execute", errorNames[-asCONTEXT_NOT_PREPARED], asCONTEXT_NOT_PREPARED); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return asCONTEXT_NOT_PREPARED; + } + + m_status = asEXECUTION_ACTIVE; + + asCThreadLocalData *tld = asPushActiveContext((asIScriptContext *)this); + + // Make sure there are not too many nested calls, as it could crash the application + // by filling up the thread call stack + if (tld->activeContexts.GetLength() > m_engine->ep.maxNestedCalls) + SetInternalException(TXT_TOO_MANY_NESTED_CALLS); + else if( m_regs.programPointer == 0 ) + { + if( m_currentFunction->funcType == asFUNC_DELEGATE ) + { + // Push the object pointer onto the stack + asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); + m_regs.stackPointer -= AS_PTR_SIZE; + m_regs.stackFramePointer -= AS_PTR_SIZE; + *(asPWORD*)m_regs.stackPointer = asPWORD(m_currentFunction->objForDelegate); + + // Make the call to the delegated object method + m_currentFunction = m_currentFunction->funcForDelegate; + } + + if( m_currentFunction->funcType == asFUNC_VIRTUAL || + m_currentFunction->funcType == asFUNC_INTERFACE ) + { + // The currentFunction is a virtual method + + // Determine the true function from the object + asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackFramePointer; + if( obj == 0 ) + { + SetInternalException(TXT_NULL_POINTER_ACCESS); + } + else + { + asCObjectType *objType = obj->objType; + asCScriptFunction *realFunc = 0; + + if( m_currentFunction->funcType == asFUNC_VIRTUAL ) + { + if( objType->virtualFunctionTable.GetLength() > (asUINT)m_currentFunction->vfTableIdx ) + { + realFunc = objType->virtualFunctionTable[m_currentFunction->vfTableIdx]; + } + } + else + { + // Search the object type for a function that matches the interface function + for( asUINT n = 0; n < objType->methods.GetLength(); n++ ) + { + asCScriptFunction *f2 = m_engine->scriptFunctions[objType->methods[n]]; + if( f2->signatureId == m_currentFunction->signatureId ) + { + if( f2->funcType == asFUNC_VIRTUAL ) + realFunc = objType->virtualFunctionTable[f2->vfTableIdx]; + else + realFunc = f2; + break; + } + } + } + + if( realFunc && realFunc->signatureId == m_currentFunction->signatureId ) + m_currentFunction = realFunc; + else + SetInternalException(TXT_NULL_POINTER_ACCESS); + } + } + else if( m_currentFunction->funcType == asFUNC_IMPORTED ) + { + int funcId = m_engine->importedFunctions[m_currentFunction->id & ~FUNC_IMPORTED]->boundFunctionId; + if( funcId > 0 ) + m_currentFunction = m_engine->scriptFunctions[funcId]; + else + SetInternalException(TXT_UNBOUND_FUNCTION); + } + + if( m_currentFunction->funcType == asFUNC_SCRIPT ) + { + m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf(); + + // Set up the internal registers for executing the script function + PrepareScriptFunction(); + } + else if( m_currentFunction->funcType == asFUNC_SYSTEM ) + { + // The current function is an application registered function + + // Call the function directly + CallSystemFunction(m_currentFunction->id, this); + + // Was the call successful? + if( m_status == asEXECUTION_ACTIVE ) + { + m_status = asEXECUTION_FINISHED; + } + } + else + { + // This shouldn't happen unless there was an error in which + // case an exception should have been raised already + asASSERT( m_status == asEXECUTION_EXCEPTION ); + } + } + + asUINT gcPreObjects = 0; + if( m_engine->ep.autoGarbageCollect ) + m_engine->gc.GetStatistics(&gcPreObjects, 0, 0, 0, 0); + + while (m_status == asEXECUTION_ACTIVE) + { + ExecuteNext(); + + // If an exception was raised that will be caught, then unwind the stack + // and move the program pointer to the catch block before proceeding + if (m_status == asEXECUTION_EXCEPTION && m_exceptionWillBeCaught) + CleanStack(true); + } + + if( m_lineCallback ) + { + // Call the line callback one last time before leaving + // so anyone listening can catch the state change + CallLineCallback(); + m_regs.doProcessSuspend = true; + } + else + m_regs.doProcessSuspend = false; + + m_doSuspend = false; + + if( m_engine->ep.autoGarbageCollect ) + { + asUINT gcPosObjects = 0; + m_engine->gc.GetStatistics(&gcPosObjects, 0, 0, 0, 0); + if( gcPosObjects > gcPreObjects ) + { + // Execute as many steps as there were new objects created + m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, gcPosObjects - gcPreObjects); + } + else if( gcPosObjects > 0 ) + { + // Execute at least one step, even if no new objects were created + m_engine->GarbageCollect(asGC_ONE_STEP | asGC_DESTROY_GARBAGE | asGC_DETECT_GARBAGE, 1); + } + } + + // Pop the active context + asPopActiveContext(tld, this); + + if( m_status == asEXECUTION_FINISHED ) + { + m_regs.objectType = m_initialFunction->returnType.GetTypeInfo(); + return asEXECUTION_FINISHED; + } + + if( m_doAbort ) + { + m_doAbort = false; + + m_status = asEXECUTION_ABORTED; + return asEXECUTION_ABORTED; + } + + if( m_status == asEXECUTION_SUSPENDED ) + return asEXECUTION_SUSPENDED; + + if( m_status == asEXECUTION_EXCEPTION ) + return asEXECUTION_EXCEPTION; + + return asERROR; +} + +int asCContext::PushState() +{ + // Only allow the state to be pushed when active + // TODO: Can we support a suspended state too? So the reuse of + // the context can be done outside the Execute() call? + if( m_status != asEXECUTION_ACTIVE ) + { + // TODO: Write message. Wrong usage + return asERROR; + } + + // Allocate space on the callstack for at least two states + if (m_callStack.GetLength() >= m_callStack.GetCapacity() - 2*CALLSTACK_FRAME_SIZE) + { + if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE) + { + // The call stack is too big to grow further + // If an error occurs, no change to the context should be done + return asOUT_OF_MEMORY; + } + + // Allocate space for 10 call states at a time to save time + m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10 * CALLSTACK_FRAME_SIZE, true); + } + + // Push the current script function that is calling the system function + // This cannot fail, since the memory was already allocated above + PushCallState(); + + // Push the system function too, which will serve both as a marker and + // informing which system function that created the nested call + m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE); + + // Need to push m_initialFunction as it must be restored later + asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; + tmp[0] = 0; + tmp[1] = (asPWORD)m_callingSystemFunction; + tmp[2] = (asPWORD)m_initialFunction; + tmp[3] = (asPWORD)m_originalStackPointer; + tmp[4] = (asPWORD)m_argumentsSize; + + // Need to push the value of registers so they can be restored + tmp[5] = (asPWORD)asDWORD(m_regs.valueRegister); + tmp[6] = (asPWORD)asDWORD(m_regs.valueRegister>>32); + tmp[7] = (asPWORD)m_regs.objectRegister; + tmp[8] = (asPWORD)m_regs.objectType; + + // Decrease stackpointer to prevent the top value from being overwritten + m_regs.stackPointer -= 2; + + // Clear the initial function so that Prepare() knows it must do all validations + m_initialFunction = 0; + + // After this the state should appear as if uninitialized + m_callingSystemFunction = 0; + + m_regs.objectRegister = 0; + m_regs.objectType = 0; + + // Set the status to uninitialized as application + // should call Prepare() after this to reuse the context + m_status = asEXECUTION_UNINITIALIZED; + + return asSUCCESS; +} + +int asCContext::PopState() +{ + if( !IsNested() ) + return asERROR; + + // Clean up the current execution + Unprepare(); + + // The topmost state must be a marker for nested call + asASSERT( m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 ); + + // Restore the previous state + asPWORD *tmp = &m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE]; + m_callingSystemFunction = reinterpret_cast(tmp[1]); + m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE); + + // Restore the previous initial function and the associated values + m_initialFunction = reinterpret_cast(tmp[2]); + m_originalStackPointer = (asDWORD*)tmp[3]; + m_argumentsSize = (int)tmp[4]; + + m_regs.valueRegister = asQWORD(asDWORD(tmp[5])); + m_regs.valueRegister |= asQWORD(tmp[6])<<32; + m_regs.objectRegister = (void*)tmp[7]; + m_regs.objectType = (asITypeInfo*)tmp[8]; + + // Calculate the returnValueSize + if( m_initialFunction->DoesReturnOnStack() ) + m_returnValueSize = m_initialFunction->returnType.GetSizeInMemoryDWords(); + else + m_returnValueSize = 0; + + // Pop the current script function. This will also restore the previous stack pointer + PopCallState(); + + m_status = asEXECUTION_ACTIVE; + + return asSUCCESS; +} + +int asCContext::PushCallState() +{ + if( m_callStack.GetLength() == m_callStack.GetCapacity() ) + { + if (m_engine->ep.maxCallStackSize > 0 && m_callStack.GetLength() >= m_engine->ep.maxCallStackSize*CALLSTACK_FRAME_SIZE) + { + // The call stack is too big to grow further + SetInternalException(TXT_STACK_OVERFLOW); + return asERROR; + } + + // Allocate space for 10 call states at a time to save time + m_callStack.AllocateNoConstruct(m_callStack.GetLength() + 10*CALLSTACK_FRAME_SIZE, true); + } + m_callStack.SetLengthNoConstruct(m_callStack.GetLength() + CALLSTACK_FRAME_SIZE); + + // Separating the loads and stores limits data cache trash, and with a smart compiler + // could turn into SIMD style loading/storing if available. + // The compiler can't do this itself due to potential pointer aliasing between the pointers, + // ie writing to tmp could overwrite the data contained in registers.stackFramePointer for example + // for all the compiler knows. So introducing the local variable s, which is never referred to by + // its address we avoid this issue. + + asPWORD s[5]; + s[0] = (asPWORD)m_regs.stackFramePointer; + s[1] = (asPWORD)m_currentFunction; + s[2] = (asPWORD)m_regs.programPointer; + s[3] = (asPWORD)m_regs.stackPointer; + s[4] = m_stackIndex; + + asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; + tmp[0] = s[0]; + tmp[1] = s[1]; + tmp[2] = s[2]; + tmp[3] = s[3]; + tmp[4] = s[4]; + + return asSUCCESS; +} + +void asCContext::PopCallState() +{ + // See comments in PushCallState about pointer aliasing and data cache trashing + asPWORD *tmp = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; + asPWORD s[5]; + s[0] = tmp[0]; + s[1] = tmp[1]; + s[2] = tmp[2]; + s[3] = tmp[3]; + s[4] = tmp[4]; + + m_regs.stackFramePointer = (asDWORD*)s[0]; + m_currentFunction = (asCScriptFunction*)s[1]; + m_regs.programPointer = (asDWORD*)s[2]; + m_regs.stackPointer = (asDWORD*)s[3]; + m_stackIndex = (int)s[4]; + + m_callStack.SetLength(m_callStack.GetLength() - CALLSTACK_FRAME_SIZE); +} + +// interface +asUINT asCContext::GetCallstackSize() const +{ + if( m_currentFunction == 0 ) return 0; + + // The current function is accessed at stackLevel 0 + return asUINT(1 + m_callStack.GetLength() / CALLSTACK_FRAME_SIZE); +} + +// interface +asIScriptFunction *asCContext::GetFunction(asUINT stackLevel) +{ + if( stackLevel >= GetCallstackSize() ) return 0; + + if( stackLevel == 0 ) return m_currentFunction; + + asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize() - stackLevel - 1)*CALLSTACK_FRAME_SIZE; + asCScriptFunction *func = (asCScriptFunction*)s[1]; + + return func; +} + +// interface +int asCContext::GetLineNumber(asUINT stackLevel, int *column, const char **sectionName) +{ + if( stackLevel >= GetCallstackSize() ) return asINVALID_ARG; + + asCScriptFunction *func; + asDWORD *bytePos; + if( stackLevel == 0 ) + { + func = m_currentFunction; + if( func->scriptData == 0 ) return 0; + bytePos = m_regs.programPointer; + } + else + { + asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; + func = (asCScriptFunction*)s[1]; + if( func->scriptData == 0 ) return 0; + bytePos = (asDWORD*)s[2]; + + // Subract 1 from the bytePos, because we want the line where + // the call was made, and not the instruction after the call + bytePos -= 1; + } + + // For nested calls it is possible that func is null + if( func == 0 ) + { + if( column ) *column = 0; + if( sectionName ) *sectionName = 0; + return 0; + } + + int sectionIdx; + asDWORD line = func->GetLineNumber(int(bytePos - func->scriptData->byteCode.AddressOf()), §ionIdx); + if( column ) *column = (line >> 20); + if( sectionName ) + { + asASSERT( sectionIdx < int(m_engine->scriptSectionNames.GetLength()) ); + if( sectionIdx >= 0 && asUINT(sectionIdx) < m_engine->scriptSectionNames.GetLength() ) + *sectionName = m_engine->scriptSectionNames[sectionIdx]->AddressOf(); + else + *sectionName = 0; + } + return (line & 0xFFFFF); +} + +// internal +bool asCContext::ReserveStackSpace(asUINT size) +{ +#ifdef WIP_16BYTE_ALIGN + // Pad size to a multiple of MAX_TYPE_ALIGNMENT. + const asUINT remainder = size % MAX_TYPE_ALIGNMENT; + if(remainder != 0) + { + size = size + (MAX_TYPE_ALIGNMENT - (size % MAX_TYPE_ALIGNMENT)); + } +#endif + + // Make sure the first stack block is allocated + if( m_stackBlocks.GetLength() == 0 ) + { + m_stackBlockSize = m_engine->ep.initContextStackSize; + asASSERT( m_stackBlockSize > 0 ); + +#ifndef WIP_16BYTE_ALIGN + asDWORD *stack = asNEWARRAY(asDWORD,m_stackBlockSize); +#else + asDWORD *stack = asNEWARRAYALIGNED(asDWORD, m_stackBlockSize, MAX_TYPE_ALIGNMENT); +#endif + if( stack == 0 ) + { + // Out of memory + return false; + } + +#ifdef WIP_16BYTE_ALIGN + asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); +#endif + + m_stackBlocks.PushLast(stack); + m_stackIndex = 0; + m_regs.stackPointer = m_stackBlocks[0] + m_stackBlockSize; + +#ifdef WIP_16BYTE_ALIGN + // Align the stack pointer. This is necessary as the m_stackBlockSize is not necessarily evenly divisable with the max alignment + ((asPWORD&)m_regs.stackPointer) &= ~(MAX_TYPE_ALIGNMENT-1); + + asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) ); +#endif + } + + // Check if there is enough space on the current stack block, otherwise move + // to the next one. New and larger blocks will be allocated as necessary + while( m_regs.stackPointer - (size + RESERVE_STACK) < m_stackBlocks[m_stackIndex] ) + { + // Make sure we don't allocate more space than allowed + if( m_engine->ep.maximumContextStackSize ) + { + // This test will only stop growth once it is on or already crossed the limit + if( m_stackBlockSize * ((1 << (m_stackIndex+1)) - 1) >= m_engine->ep.maximumContextStackSize ) + { + m_isStackMemoryNotAllocated = true; + + // Set the stackFramePointer, even though the stackPointer wasn't updated + m_regs.stackFramePointer = m_regs.stackPointer; + + SetInternalException(TXT_STACK_OVERFLOW); + return false; + } + } + + m_stackIndex++; + if( m_stackBlocks.GetLength() == m_stackIndex ) + { + // Allocate the new stack block, with twice the size of the previous +#ifndef WIP_16BYTE_ALIGN + asDWORD *stack = asNEWARRAY(asDWORD, (m_stackBlockSize << m_stackIndex)); +#else + asDWORD *stack = asNEWARRAYALIGNED(asDWORD, (m_stackBlockSize << m_stackIndex), MAX_TYPE_ALIGNMENT); +#endif + if( stack == 0 ) + { + // Out of memory + m_isStackMemoryNotAllocated = true; + + // Set the stackFramePointer, even though the stackPointer wasn't updated + m_regs.stackFramePointer = m_regs.stackPointer; + + SetInternalException(TXT_STACK_OVERFLOW); + return false; + } + +#ifdef WIP_16BYTE_ALIGN + asASSERT( isAligned(stack, MAX_TYPE_ALIGNMENT) ); +#endif + + m_stackBlocks.PushLast(stack); + } + + // Update the stack pointer to point to the new block. + // Leave enough room above the stackpointer to copy the arguments from the previous stackblock + m_regs.stackPointer = m_stackBlocks[m_stackIndex] + + (m_stackBlockSize<GetSpaceNeededForArguments() - + (m_currentFunction->objectType ? AS_PTR_SIZE : 0) - + (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0); + +#ifdef WIP_16BYTE_ALIGN + // Align the stack pointer + (asPWORD&)m_regs.stackPointer &= ~(MAX_TYPE_ALIGNMENT-1); + + asASSERT( isAligned(m_regs.stackPointer, MAX_TYPE_ALIGNMENT) ); +#endif + } + + return true; +} + +// internal +void asCContext::CallScriptFunction(asCScriptFunction *func) +{ + asASSERT( func->scriptData ); + + // Push the framepointer, function id and programCounter on the stack + if (PushCallState() < 0) + return; + + // Update the current function and program position before increasing the stack + // so the exception handler will know what to do if there is a stack overflow + m_currentFunction = func; + m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf(); + + PrepareScriptFunction(); +} + +void asCContext::PrepareScriptFunction() +{ + asASSERT( m_currentFunction->scriptData ); + + // Make sure there is space on the stack to execute the function + asDWORD *oldStackPointer = m_regs.stackPointer; + if( !ReserveStackSpace(m_currentFunction->scriptData->stackNeeded) ) + return; + + // If a new stack block was allocated then we'll need to move + // over the function arguments to the new block. + if( m_regs.stackPointer != oldStackPointer ) + { + int numDwords = m_currentFunction->GetSpaceNeededForArguments() + + (m_currentFunction->objectType ? AS_PTR_SIZE : 0) + + (m_currentFunction->DoesReturnOnStack() ? AS_PTR_SIZE : 0); + memcpy(m_regs.stackPointer, oldStackPointer, sizeof(asDWORD)*numDwords); + } + + // Update framepointer + m_regs.stackFramePointer = m_regs.stackPointer; + + // Set all object variables to 0 to guarantee that they are null before they are used + // Only variables on the heap should be cleared. The rest will be cleared by calling the constructor + asUINT n = m_currentFunction->scriptData->objVariablesOnHeap; + while( n-- > 0 ) + { + int pos = m_currentFunction->scriptData->objVariablePos[n]; + *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; + } + + // Initialize the stack pointer with the space needed for local variables + m_regs.stackPointer -= m_currentFunction->scriptData->variableSpace; + + // Call the line callback for each script function, to guarantee that infinitely recursive scripts can + // be interrupted, even if the scripts have been compiled with asEP_BUILD_WITHOUT_LINE_CUES + if( m_regs.doProcessSuspend ) + { + if( m_lineCallback ) + CallLineCallback(); + if( m_doSuspend ) + m_status = asEXECUTION_SUSPENDED; + } +} + +void asCContext::CallInterfaceMethod(asCScriptFunction *func) +{ + // Resolve the interface method using the current script type + asCScriptObject *obj = *(asCScriptObject**)(asPWORD*)m_regs.stackPointer; + if( obj == 0 ) + { + // Tell the exception handler to clean up the arguments to this method + m_needToCleanupArgs = true; + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + + asCObjectType *objType = obj->objType; + + // Search the object type for a function that matches the interface function + asCScriptFunction *realFunc = 0; + if( func->funcType == asFUNC_INTERFACE ) + { + // Find the offset for the interface's virtual function table chunk + asUINT offset = 0; + bool found = false; + asCObjectType *findInterface = func->objectType; + + // TODO: runtime optimize: The list of interfaces should be ordered by the address + // Then a binary search pattern can be used. + asUINT intfCount = asUINT(objType->interfaces.GetLength()); + for( asUINT n = 0; n < intfCount; n++ ) + { + if( objType->interfaces[n] == findInterface ) + { + offset = objType->interfaceVFTOffsets[n]; + found = true; + break; + } + } + + if( !found ) + { + // Tell the exception handler to clean up the arguments to this method + m_needToCleanupArgs = true; + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + + // Find the real function in the virtual table chunk with the found offset + realFunc = objType->virtualFunctionTable[func->vfTableIdx + offset]; + + // Since the interface was implemented by the class, it shouldn't + // be possible that the real function isn't found + asASSERT( realFunc ); + + asASSERT( realFunc->signatureId == func->signatureId ); + } + else // if( func->funcType == asFUNC_VIRTUAL ) + { + realFunc = objType->virtualFunctionTable[func->vfTableIdx]; + } + + // Then call the true script function + CallScriptFunction(realFunc); +} + +void asCContext::ExecuteNext() +{ + asDWORD *l_bc = m_regs.programPointer; + asDWORD *l_sp = m_regs.stackPointer; + asDWORD *l_fp = m_regs.stackFramePointer; + + for(;;) + { + +#ifdef AS_DEBUG + // Gather statistics on executed bytecode + stats.Instr(*(asBYTE*)l_bc); + + // Used to verify that the size of the instructions are correct + asDWORD *old = l_bc; +#endif + + + // Remember to keep the cases in order and without + // gaps, because that will make the switch faster. + // It will be faster since only one lookup will be + // made to find the correct jump destination. If not + // in order, the switch will make two lookups. + switch( *(asBYTE*)l_bc ) + { +//-------------- +// memory access functions + + case asBC_PopPtr: + // Pop a pointer from the stack + l_sp += AS_PTR_SIZE; + l_bc++; + break; + + case asBC_PshGPtr: + // Replaces PGA + RDSPtr + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = *(asPWORD*)asBC_PTRARG(l_bc); + l_bc += 1 + AS_PTR_SIZE; + break; + + // Push a dword value on the stack + case asBC_PshC4: + --l_sp; + *l_sp = asBC_DWORDARG(l_bc); + l_bc += 2; + break; + + // Push the dword value of a variable on the stack + case asBC_PshV4: + --l_sp; + *l_sp = *(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + // Push the address of a variable on the stack + case asBC_PSF: + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = asPWORD(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + // Swap the top 2 pointers on the stack + case asBC_SwapPtr: + { + asPWORD p = *(asPWORD*)l_sp; + *(asPWORD*)l_sp = *(asPWORD*)(l_sp+AS_PTR_SIZE); + *(asPWORD*)(l_sp+AS_PTR_SIZE) = p; + l_bc++; + } + break; + + // Do a boolean not operation, modifying the value of the variable + case asBC_NOT: +#if AS_SIZEOF_BOOL == 1 + { + // Set the value to true if it is equal to 0 + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on the pointer. + + volatile asBYTE *ptr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); + asBYTE val = (ptr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0; + ptr[0] = val; // The result is stored in the lower byte + ptr[1] = 0; // Make sure the rest of the DWORD is 0 + ptr[2] = 0; + ptr[3] = 0; + } +#else + *(l_fp - asBC_SWORDARG0(l_bc)) = (*(l_fp - asBC_SWORDARG0(l_bc)) == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); +#endif + l_bc++; + break; + + // Push the dword value of a global variable on the stack + case asBC_PshG4: + --l_sp; + *l_sp = *(asDWORD*)asBC_PTRARG(l_bc); + l_bc += 1 + AS_PTR_SIZE; + break; + + // Load the address of a global variable in the register, then + // copy the value of the global variable into a local variable + case asBC_LdGRdR4: + *(void**)&m_regs.valueRegister = (void*)asBC_PTRARG(l_bc); + *(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister; + l_bc += 1+AS_PTR_SIZE; + break; + +//---------------- +// path control instructions + + // Begin execution of a script function + case asBC_CALL: + { + int i = asBC_INTARG(l_bc); + l_bc += 2; + + asASSERT( i >= 0 ); + asASSERT( (i & FUNC_IMPORTED) == 0 ); + + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + CallScriptFunction(m_engine->scriptFunctions[i]); + + // Extract the values from the context again + l_bc = m_regs.programPointer; + l_sp = m_regs.stackPointer; + l_fp = m_regs.stackFramePointer; + + // If status isn't active anymore then we must stop + if( m_status != asEXECUTION_ACTIVE ) + return; + } + break; + + // Return to the caller, and remove the arguments from the stack + case asBC_RET: + { + // Return if this was the first function, or a nested execution + if( m_callStack.GetLength() == 0 || + m_callStack[m_callStack.GetLength() - CALLSTACK_FRAME_SIZE] == 0 ) + { + m_status = asEXECUTION_FINISHED; + return; + } + + asWORD w = asBC_WORDARG0(l_bc); + + // Read the old framepointer, functionid, and programCounter from the call stack + PopCallState(); + + // Extract the values from the context again + l_bc = m_regs.programPointer; + l_sp = m_regs.stackPointer; + l_fp = m_regs.stackFramePointer; + + // Pop arguments from stack + l_sp += w; + } + break; + + // Jump to a relative position + case asBC_JMP: + l_bc += 2 + asBC_INTARG(l_bc); + break; + +//---------------- +// Conditional jumps + + // Jump to a relative position if the value in the register is 0 + case asBC_JZ: + if( *(int*)&m_regs.valueRegister == 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; + + // Jump to a relative position if the value in the register is not 0 + case asBC_JNZ: + if( *(int*)&m_regs.valueRegister != 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; + + // Jump to a relative position if the value in the register is negative + case asBC_JS: + if( *(int*)&m_regs.valueRegister < 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; + + // Jump to a relative position if the value in the register it not negative + case asBC_JNS: + if( *(int*)&m_regs.valueRegister >= 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; + + // Jump to a relative position if the value in the register is greater than 0 + case asBC_JP: + if( *(int*)&m_regs.valueRegister > 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; + + // Jump to a relative position if the value in the register is not greater than 0 + case asBC_JNP: + if( *(int*)&m_regs.valueRegister <= 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; +//-------------------- +// test instructions + + // If the value in the register is 0, then set the register to 1, else to 0 + case asBC_TZ: +#if AS_SIZEOF_BOOL == 1 + { + // Set the value to true if it is equal to 0 + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on valueRegister. + + volatile int *regPtr = (int*)&m_regs.valueRegister; + volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; + asBYTE val = (regPtr[0] == 0) ? VALUE_OF_BOOLEAN_TRUE : 0; + regBptr[0] = val; // The result is stored in the lower byte + regBptr[1] = 0; // Make sure the rest of the register is 0 + regBptr[2] = 0; + regBptr[3] = 0; + regBptr[4] = 0; + regBptr[5] = 0; + regBptr[6] = 0; + regBptr[7] = 0; + } +#else + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? VALUE_OF_BOOLEAN_TRUE : 0); +#endif + l_bc++; + break; + + // If the value in the register is not 0, then set the register to 1, else to 0 + case asBC_TNZ: +#if AS_SIZEOF_BOOL == 1 + { + // Set the value to true if it is not equal to 0 + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on valueRegister. + + volatile int *regPtr = (int*)&m_regs.valueRegister; + volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; + asBYTE val = (regPtr[0] == 0) ? 0 : VALUE_OF_BOOLEAN_TRUE; + regBptr[0] = val; // The result is stored in the lower byte + regBptr[1] = 0; // Make sure the rest of the register is 0 + regBptr[2] = 0; + regBptr[3] = 0; + regBptr[4] = 0; + regBptr[5] = 0; + regBptr[6] = 0; + regBptr[7] = 0; + } +#else + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister == 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); +#endif + l_bc++; + break; + + // If the value in the register is negative, then set the register to 1, else to 0 + case asBC_TS: +#if AS_SIZEOF_BOOL == 1 + { + // Set the value to true if it is less than 0 + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on valueRegister. + + volatile int *regPtr = (int*)&m_regs.valueRegister; + volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; + asBYTE val = (regPtr[0] < 0) ? VALUE_OF_BOOLEAN_TRUE : 0; + regBptr[0] = val; // The result is stored in the lower byte + regBptr[1] = 0; // Make sure the rest of the register is 0 + regBptr[2] = 0; + regBptr[3] = 0; + regBptr[4] = 0; + regBptr[5] = 0; + regBptr[6] = 0; + regBptr[7] = 0; + } +#else + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? VALUE_OF_BOOLEAN_TRUE : 0); +#endif + l_bc++; + break; + + // If the value in the register is not negative, then set the register to 1, else to 0 + case asBC_TNS: +#if AS_SIZEOF_BOOL == 1 + { + // Set the value to true if it is not less than 0 + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on valueRegister. + + volatile int *regPtr = (int*)&m_regs.valueRegister; + volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; + asBYTE val = (regPtr[0] >= 0) ? VALUE_OF_BOOLEAN_TRUE : 0; + regBptr[0] = val; // The result is stored in the lower byte + regBptr[1] = 0; // Make sure the rest of the register is 0 + regBptr[2] = 0; + regBptr[3] = 0; + regBptr[4] = 0; + regBptr[5] = 0; + regBptr[6] = 0; + regBptr[7] = 0; + } +#else + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister < 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); +#endif + l_bc++; + break; + + // If the value in the register is greater than 0, then set the register to 1, else to 0 + case asBC_TP: +#if AS_SIZEOF_BOOL == 1 + { + // Set the value to true if it is greater than 0 + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on valueRegister. + + volatile int *regPtr = (int*)&m_regs.valueRegister; + volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; + asBYTE val = (regPtr[0] > 0) ? VALUE_OF_BOOLEAN_TRUE : 0; + regBptr[0] = val; // The result is stored in the lower byte + regBptr[1] = 0; // Make sure the rest of the register is 0 + regBptr[2] = 0; + regBptr[3] = 0; + regBptr[4] = 0; + regBptr[5] = 0; + regBptr[6] = 0; + regBptr[7] = 0; + } +#else + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? VALUE_OF_BOOLEAN_TRUE : 0); +#endif + l_bc++; + break; + + // If the value in the register is not greater than 0, then set the register to 1, else to 0 + case asBC_TNP: +#if AS_SIZEOF_BOOL == 1 + { + // Set the value to true if it is not greater than 0 + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on valueRegister. + + volatile int *regPtr = (int*)&m_regs.valueRegister; + volatile asBYTE *regBptr = (asBYTE*)&m_regs.valueRegister; + asBYTE val = (regPtr[0] <= 0) ? VALUE_OF_BOOLEAN_TRUE : 0; + regBptr[0] = val; // The result is stored in the lower byte + regBptr[1] = 0; // Make sure the rest of the register is 0 + regBptr[2] = 0; + regBptr[3] = 0; + regBptr[4] = 0; + regBptr[5] = 0; + regBptr[6] = 0; + regBptr[7] = 0; + } +#else + *(int*)&m_regs.valueRegister = (*(int*)&m_regs.valueRegister > 0 ? 0 : VALUE_OF_BOOLEAN_TRUE); +#endif + l_bc++; + break; + +//-------------------- +// negate value + + // Negate the integer value in the variable + case asBC_NEGi: + *(l_fp - asBC_SWORDARG0(l_bc)) = asDWORD(-int(*(l_fp - asBC_SWORDARG0(l_bc)))); + l_bc++; + break; + + // Negate the float value in the variable + case asBC_NEGf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(float*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + // Negate the double value in the variable + case asBC_NEGd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(double*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + +//------------------------- +// Increment value pointed to by address in register + + // Increment the short value pointed to by the register + case asBC_INCi16: + (**(short**)&m_regs.valueRegister)++; + l_bc++; + break; + + // Increment the byte value pointed to by the register + case asBC_INCi8: + (**(char**)&m_regs.valueRegister)++; + l_bc++; + break; + + // Decrement the short value pointed to by the register + case asBC_DECi16: + (**(short**)&m_regs.valueRegister)--; + l_bc++; + break; + + // Decrement the byte value pointed to by the register + case asBC_DECi8: + (**(char**)&m_regs.valueRegister)--; + l_bc++; + break; + + // Increment the integer value pointed to by the register + case asBC_INCi: + ++(**(int**)&m_regs.valueRegister); + l_bc++; + break; + + // Decrement the integer value pointed to by the register + case asBC_DECi: + --(**(int**)&m_regs.valueRegister); + l_bc++; + break; + + // Increment the float value pointed to by the register + case asBC_INCf: + ++(**(float**)&m_regs.valueRegister); + l_bc++; + break; + + // Decrement the float value pointed to by the register + case asBC_DECf: + --(**(float**)&m_regs.valueRegister); + l_bc++; + break; + + // Increment the double value pointed to by the register + case asBC_INCd: + ++(**(double**)&m_regs.valueRegister); + l_bc++; + break; + + // Decrement the double value pointed to by the register + case asBC_DECd: + --(**(double**)&m_regs.valueRegister); + l_bc++; + break; + + // Increment the local integer variable + case asBC_IncVi: + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))++; + l_bc++; + break; + + // Decrement the local integer variable + case asBC_DecVi: + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))--; + l_bc++; + break; + +//-------------------- +// bits instructions + + // Do a bitwise not on the value in the variable + case asBC_BNOT: + *(l_fp - asBC_SWORDARG0(l_bc)) = ~*(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + // Do a bitwise and of two variables and store the result in a third variable + case asBC_BAND: + *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) & *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + // Do a bitwise or of two variables and store the result in a third variable + case asBC_BOR: + *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) | *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + // Do a bitwise xor of two variables and store the result in a third variable + case asBC_BXOR: + *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) ^ *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + // Do a logical shift left of two variables and store the result in a third variable + case asBC_BSLL: + *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + // Do a logical shift right of two variables and store the result in a third variable + case asBC_BSRL: + *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + // Do an arithmetic shift right of two variables and store the result in a third variable + case asBC_BSRA: + *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(l_fp - asBC_SWORDARG1(l_bc))) >> *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_COPY: + { + void *d = (void*)*(asPWORD*)l_sp; l_sp += AS_PTR_SIZE; + void *s = (void*)*(asPWORD*)l_sp; + if( s == 0 || d == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + memcpy(d, s, asBC_WORDARG0(l_bc)*4); + + // replace the pointer on the stack with the lvalue + *(asPWORD**)l_sp = (asPWORD*)d; + } + l_bc += 2; + break; + + case asBC_PshC8: + l_sp -= 2; + *(asQWORD*)l_sp = asBC_QWORDARG(l_bc); + l_bc += 3; + break; + + case asBC_PshVPtr: + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_RDSPtr: + { + // The pointer must not be null + asPWORD a = *(asPWORD*)l_sp; + if( a == 0 ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + // Pop an address from the stack, read a pointer from that address and push it on the stack + *(asPWORD*)l_sp = *(asPWORD*)a; + } + l_bc++; + break; + + //---------------------------- + // Comparisons + case asBC_CMPd: + { + // Do a comparison of the values, rather than a subtraction + // in order to get proper behaviour for infinity values. + double dbl1 = *(double*)(l_fp - asBC_SWORDARG0(l_bc)); + double dbl2 = *(double*)(l_fp - asBC_SWORDARG1(l_bc)); + if( dbl1 == dbl2 ) *(int*)&m_regs.valueRegister = 0; + else if( dbl1 < dbl2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_CMPu: + { + asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + asDWORD d2 = *(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc)); + if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0; + else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_CMPf: + { + // Do a comparison of the values, rather than a subtraction + // in order to get proper behaviour for infinity values. + float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc)); + float f2 = *(float*)(l_fp - asBC_SWORDARG1(l_bc)); + if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0; + else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_CMPi: + { + int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc)); + int i2 = *(int*)(l_fp - asBC_SWORDARG1(l_bc)); + if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0; + else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + //---------------------------- + // Comparisons with constant value + case asBC_CMPIi: + { + int i1 = *(int*)(l_fp - asBC_SWORDARG0(l_bc)); + int i2 = asBC_INTARG(l_bc); + if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0; + else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_CMPIf: + { + // Do a comparison of the values, rather than a subtraction + // in order to get proper behaviour for infinity values. + float f1 = *(float*)(l_fp - asBC_SWORDARG0(l_bc)); + float f2 = asBC_FLOATARG(l_bc); + if( f1 == f2 ) *(int*)&m_regs.valueRegister = 0; + else if( f1 < f2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_CMPIu: + { + asDWORD d1 = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + asDWORD d2 = asBC_DWORDARG(l_bc); + if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0; + else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_JMPP: + l_bc += 1 + (*(int*)(l_fp - asBC_SWORDARG0(l_bc)))*2; + break; + + case asBC_PopRPtr: + *(asPWORD*)&m_regs.valueRegister = *(asPWORD*)l_sp; + l_sp += AS_PTR_SIZE; + l_bc++; + break; + + case asBC_PshRPtr: + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = *(asPWORD*)&m_regs.valueRegister; + l_bc++; + break; + + case asBC_STR: + // TODO: NEWSTRING: Deprecate this instruction + asASSERT(false); + l_bc++; + break; + + case asBC_CALLSYS: + { + // Get function ID from the argument + int i = asBC_INTARG(l_bc); + + // Need to move the values back to the context as the called functions + // may use the debug interface to inspect the registers + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + l_sp += CallSystemFunction(i, this); + + // Update the program position after the call so that line number is correct + l_bc += 2; + + if( m_regs.doProcessSuspend ) + { + // Should the execution be suspended? + if( m_doSuspend ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + m_status = asEXECUTION_SUSPENDED; + return; + } + // An exception might have been raised + if( m_status != asEXECUTION_ACTIVE ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + return; + } + } + } + break; + + case asBC_CALLBND: + { + // TODO: Clean-up: This code is very similar to asBC_CallPtr. Create a shared method for them + // Get the function ID from the stack + int i = asBC_INTARG(l_bc); + + asASSERT( i >= 0 ); + asASSERT( i & FUNC_IMPORTED ); + + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + int funcId = m_engine->importedFunctions[i & ~FUNC_IMPORTED]->boundFunctionId; + if( funcId == -1 ) + { + // Need to update the program pointer for the exception handler + m_regs.programPointer += 2; + + // Tell the exception handler to clean up the arguments to this function + m_needToCleanupArgs = true; + SetInternalException(TXT_UNBOUND_FUNCTION); + return; + } + else + { + asCScriptFunction *func = m_engine->GetScriptFunction(funcId); + if( func->funcType == asFUNC_SCRIPT ) + { + m_regs.programPointer += 2; + CallScriptFunction(func); + } + else if( func->funcType == asFUNC_DELEGATE ) + { + // Push the object pointer on the stack. There is always a reserved space for this so + // we don't don't need to worry about overflowing the allocated memory buffer + asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); + m_regs.stackPointer -= AS_PTR_SIZE; + *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate); + + // Call the delegated method + if( func->funcForDelegate->funcType == asFUNC_SYSTEM ) + { + m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this); + + // Update program position after the call so the line number + // is correct in case the system function queries it + m_regs.programPointer += 2; + } + else + { + m_regs.programPointer += 2; + + // TODO: run-time optimize: The true method could be figured out when creating the delegate + CallInterfaceMethod(func->funcForDelegate); + } + } + else + { + asASSERT( func->funcType == asFUNC_SYSTEM ); + + m_regs.stackPointer += CallSystemFunction(func->id, this); + + // Update program position after the call so the line number + // is correct in case the system function queries it + m_regs.programPointer += 2; + } + } + + // Extract the values from the context again + l_bc = m_regs.programPointer; + l_sp = m_regs.stackPointer; + l_fp = m_regs.stackFramePointer; + + // If status isn't active anymore then we must stop + if( m_status != asEXECUTION_ACTIVE ) + return; + } + break; + + case asBC_SUSPEND: + if( m_regs.doProcessSuspend ) + { + if( m_lineCallback ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + CallLineCallback(); + } + if( m_doSuspend ) + { + l_bc++; + + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + m_status = asEXECUTION_SUSPENDED; + return; + } + } + + l_bc++; + break; + + case asBC_ALLOC: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); + int func = asBC_INTARG(l_bc+AS_PTR_SIZE); + + if( objType->flags & asOBJ_SCRIPT_OBJECT ) + { + // Need to move the values back to the context as the construction + // of the script object may reuse the context for nested calls. + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Pre-allocate the memory + asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType); + + // Pre-initialize the memory by calling the constructor for asCScriptObject + ScriptObject_Construct(objType, (asCScriptObject*)mem); + + // Call the constructor to initalize the memory + asCScriptFunction *f = m_engine->scriptFunctions[func]; + + asDWORD **a = (asDWORD**)*(asPWORD*)(m_regs.stackPointer + f->GetSpaceNeededForArguments()); + if( a ) *a = mem; + + // Push the object pointer on the stack + m_regs.stackPointer -= AS_PTR_SIZE; + *(asPWORD*)m_regs.stackPointer = (asPWORD)mem; + + m_regs.programPointer += 2+AS_PTR_SIZE; + + CallScriptFunction(f); + + // Extract the values from the context again + l_bc = m_regs.programPointer; + l_sp = m_regs.stackPointer; + l_fp = m_regs.stackFramePointer; + + // If status isn't active anymore then we must stop + if( m_status != asEXECUTION_ACTIVE ) + return; + } + else + { + // Pre-allocate the memory + asDWORD *mem = (asDWORD*)m_engine->CallAlloc(objType); + + if( func ) + { + // Push the object pointer on the stack (it will be popped by the function) + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = (asPWORD)mem; + + // Need to move the values back to the context as the called functions + // may use the debug interface to inspect the registers + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + l_sp += CallSystemFunction(func, this); + } + + // Pop the variable address from the stack + asDWORD **a = (asDWORD**)*(asPWORD*)l_sp; + l_sp += AS_PTR_SIZE; + if( a ) *a = mem; + + l_bc += 2+AS_PTR_SIZE; + + if( m_regs.doProcessSuspend ) + { + // Should the execution be suspended? + if( m_doSuspend ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + m_status = asEXECUTION_SUSPENDED; + return; + } + // An exception might have been raised + if( m_status != asEXECUTION_ACTIVE ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + m_engine->CallFree(mem); + *a = 0; + + return; + } + } + } + } + break; + + case asBC_FREE: + { + // Get the variable that holds the object handle/reference + asPWORD *a = (asPWORD*)asPWORD(l_fp - asBC_SWORDARG0(l_bc)); + if( *a ) + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); + asSTypeBehaviour *beh = &objType->beh; + + // Need to move the values back to the context as the called functions + // may use the debug interface to inspect the registers + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + if( objType->flags & asOBJ_REF ) + { + asASSERT( (objType->flags & asOBJ_NOCOUNT) || beh->release ); + if( beh->release ) + m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->release); + } + else + { + if( beh->destruct ) + m_engine->CallObjectMethod((void*)(asPWORD)*a, beh->destruct); + else if( objType->flags & asOBJ_LIST_PATTERN ) + m_engine->DestroyList((asBYTE*)(asPWORD)*a, objType); + + m_engine->CallFree((void*)(asPWORD)*a); + } + + // Clear the variable + *a = 0; + } + } + l_bc += 1+AS_PTR_SIZE; + break; + + case asBC_LOADOBJ: + { + // Move the object pointer from the object variable into the object register + void **a = (void**)(l_fp - asBC_SWORDARG0(l_bc)); + m_regs.objectType = 0; + m_regs.objectRegister = *a; + *a = 0; + } + l_bc++; + break; + + case asBC_STOREOBJ: + // Move the object pointer from the object register to the object variable + *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asPWORD(m_regs.objectRegister); + m_regs.objectRegister = 0; + l_bc++; + break; + + case asBC_GETOBJ: + { + // Read variable index from location on stack + asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); + asPWORD offset = *a; + // Move pointer from variable to the same location on the stack + asPWORD *v = (asPWORD*)(l_fp - offset); + *a = *v; + // Clear variable + *v = 0; + } + l_bc++; + break; + + case asBC_REFCPY: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); + asSTypeBehaviour *beh = &objType->beh; + + // Pop address of destination pointer from the stack + void **d = (void**)*(asPWORD*)l_sp; + l_sp += AS_PTR_SIZE; + + // Read wanted pointer from the stack + void *s = (void*)*(asPWORD*)l_sp; + + // Need to move the values back to the context as the called functions + // may use the debug interface to inspect the registers + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + if( !(objType->flags & asOBJ_NOCOUNT) ) + { + // Release previous object held by destination pointer + if( *d != 0 && beh->release ) + m_engine->CallObjectMethod(*d, beh->release); + // Increase ref counter of wanted object + if( s != 0 && beh->addref ) + m_engine->CallObjectMethod(s, beh->addref); + } + + // Set the new object in the destination + *d = s; + } + l_bc += 1+AS_PTR_SIZE; + break; + + case asBC_CHKREF: + { + // Verify if the pointer on the stack is null + // This is used when validating a pointer that an operator will work on + asPWORD a = *(asPWORD*)l_sp; + if( a == 0 ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + } + l_bc++; + break; + + case asBC_GETOBJREF: + { + // Get the location on the stack where the reference will be placed + asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); + + // Replace the variable index with the object handle held in the variable + *(asPWORD**)a = *(asPWORD**)(l_fp - *a); + } + l_bc++; + break; + + case asBC_GETREF: + { + // Get the location on the stack where the reference will be placed + asPWORD *a = (asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); + + // Replace the variable index with the address of the variable + *(asPWORD**)a = (asPWORD*)(l_fp - (int)*a); + } + l_bc++; + break; + + case asBC_PshNull: + // Push a null pointer on the stack + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = 0; + l_bc++; + break; + + case asBC_ClrVPtr: + // TODO: runtime optimize: Is this instruction really necessary? + // CallScriptFunction() can clear the null handles upon entry, just as is done for + // all other object variables + // Clear pointer variable + *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = 0; + l_bc++; + break; + + case asBC_OBJTYPE: + // Push the object type on the stack + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = asBC_PTRARG(l_bc); + l_bc += 1+AS_PTR_SIZE; + break; + + case asBC_TYPEID: + // Equivalent to PshC4, but kept as separate instruction for bytecode serialization + --l_sp; + *l_sp = asBC_DWORDARG(l_bc); + l_bc += 2; + break; + + case asBC_SetV4: + *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc); + l_bc += 2; + break; + + case asBC_SetV8: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asBC_QWORDARG(l_bc); + l_bc += 3; + break; + + case asBC_ADDSi: + { + // The pointer must not be null + asPWORD a = *(asPWORD*)l_sp; + if( a == 0 ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + // Add an offset to the pointer + *(asPWORD*)l_sp = a + asBC_SWORDARG0(l_bc); + } + l_bc += 2; + break; + + case asBC_CpyVtoV4: + *(l_fp - asBC_SWORDARG0(l_bc)) = *(l_fp - asBC_SWORDARG1(l_bc)); + l_bc += 2; + break; + + case asBC_CpyVtoV8: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)); + l_bc += 2; + break; + + case asBC_CpyVtoR4: + *(asDWORD*)&m_regs.valueRegister = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_CpyVtoR8: + *(asQWORD*)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_CpyVtoG4: + *(asDWORD*)asBC_PTRARG(l_bc) = *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc += 1 + AS_PTR_SIZE; + break; + + case asBC_CpyRtoV4: + *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)&m_regs.valueRegister; + l_bc++; + break; + + case asBC_CpyRtoV8: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = m_regs.valueRegister; + l_bc++; + break; + + case asBC_CpyGtoV4: + *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asDWORD*)asBC_PTRARG(l_bc); + l_bc += 1 + AS_PTR_SIZE; + break; + + case asBC_WRTV1: + // The pointer in the register points to a byte, and *(l_fp - offset) too + **(asBYTE**)&m_regs.valueRegister = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_WRTV2: + // The pointer in the register points to a word, and *(l_fp - offset) too + **(asWORD**)&m_regs.valueRegister = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_WRTV4: + **(asDWORD**)&m_regs.valueRegister = *(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_WRTV8: + **(asQWORD**)&m_regs.valueRegister = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_RDR1: + { + // The pointer in the register points to a byte, and *(l_fp - offset) will also point to a byte + asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); + bPtr[0] = **(asBYTE**)&m_regs.valueRegister; // read the byte + bPtr[1] = 0; // 0 the rest of the DWORD + bPtr[2] = 0; + bPtr[3] = 0; + } + l_bc++; + break; + + case asBC_RDR2: + { + // The pointer in the register points to a word, and *(l_fp - offset) will also point to a word + asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + wPtr[0] = **(asWORD**)&m_regs.valueRegister; // read the word + wPtr[1] = 0; // 0 the rest of the DWORD + } + l_bc++; + break; + + case asBC_RDR4: + *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asDWORD**)&m_regs.valueRegister; + l_bc++; + break; + + case asBC_RDR8: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = **(asQWORD**)&m_regs.valueRegister; + l_bc++; + break; + + case asBC_LDG: + *(asPWORD*)&m_regs.valueRegister = asBC_PTRARG(l_bc); + l_bc += 1+AS_PTR_SIZE; + break; + + case asBC_LDV: + *(asDWORD**)&m_regs.valueRegister = (l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_PGA: + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = asBC_PTRARG(l_bc); + l_bc += 1+AS_PTR_SIZE; + break; + + case asBC_CmpPtr: + { + // TODO: runtime optimize: This instruction should really just be an equals, and return true or false. + // The instruction is only used for is and !is tests anyway. + asPWORD p1 = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + asPWORD p2 = *(asPWORD*)(l_fp - asBC_SWORDARG1(l_bc)); + if( p1 == p2 ) *(int*)&m_regs.valueRegister = 0; + else if( p1 < p2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_VAR: + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = (asPWORD)asBC_SWORDARG0(l_bc); + l_bc++; + break; + + //---------------------------- + // Type conversions + case asBC_iTOf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(int*)(l_fp - asBC_SWORDARG0(l_bc))); + l_bc++; + break; + + case asBC_fTOi: + *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(float*)(l_fp - asBC_SWORDARG0(l_bc))); + l_bc++; + break; + + case asBC_uTOf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(l_fp - asBC_SWORDARG0(l_bc))); + l_bc++; + break; + + case asBC_fTOu: + // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0 + *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(float*)(l_fp - asBC_SWORDARG0(l_bc)))); + l_bc++; + break; + + case asBC_sbTOi: + // *(l_fp - offset) points to a char, and will point to an int afterwards + *(l_fp - asBC_SWORDARG0(l_bc)) = *(signed char*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_swTOi: + // *(l_fp - offset) points to a short, and will point to an int afterwards + *(l_fp - asBC_SWORDARG0(l_bc)) = *(short*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_ubTOi: + // (l_fp - offset) points to a byte, and will point to an int afterwards + *(l_fp - asBC_SWORDARG0(l_bc)) = *(asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_uwTOi: + // *(l_fp - offset) points to a word, and will point to an int afterwards + *(l_fp - asBC_SWORDARG0(l_bc)) = *(asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_dTOi: + *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(double*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_dTOu: + // We must cast to int first, because on some compilers the cast of a negative float value to uint result in 0 + *(l_fp - asBC_SWORDARG0(l_bc)) = asUINT(int(*(double*)(l_fp - asBC_SWORDARG1(l_bc)))); + l_bc += 2; + break; + + case asBC_dTOf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(double*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_iTOd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(int*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_uTOd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_fTOd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(float*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + //------------------------------ + // Math operations + case asBC_ADDi: + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + *(int*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_SUBi: + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - *(int*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_MULi: + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * *(int*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_DIVi: + { + int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + else if( divider == -1 ) + { + // Need to check if the value that is divided is 0x80000000 + // as dividing it with -1 will cause an overflow exception + if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_OVERFLOW); + return; + } + } + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; + } + l_bc += 2; + break; + + case asBC_MODi: + { + int divider = *(int*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + else if( divider == -1 ) + { + // Need to check if the value that is divided is 0x80000000 + // as dividing it with -1 will cause an overflow exception + if( *(int*)(l_fp - asBC_SWORDARG1(l_bc)) == int(0x80000000) ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_OVERFLOW); + return; + } + } + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; + } + l_bc += 2; + break; + + case asBC_ADDf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + *(float*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_SUBf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - *(float*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_MULf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * *(float*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_DIVf: + { + float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; + } + l_bc += 2; + break; + + case asBC_MODf: + { + float divider = *(float*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = fmodf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), divider); + } + l_bc += 2; + break; + + case asBC_ADDd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) + *(double*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_SUBd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) - *(double*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_MULd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) * *(double*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_DIVd: + { + double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = *(double*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; + l_bc += 2; + } + break; + + case asBC_MODd: + { + double divider = *(double*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = fmod(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), divider); + l_bc += 2; + } + break; + + //------------------------------ + // Math operations with constant value + case asBC_ADDIi: + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_INTARG(l_bc+1); + l_bc += 3; + break; + + case asBC_SUBIi: + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_INTARG(l_bc+1); + l_bc += 3; + break; + + case asBC_MULIi: + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = *(int*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_INTARG(l_bc+1); + l_bc += 3; + break; + + case asBC_ADDIf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) + asBC_FLOATARG(l_bc+1); + l_bc += 3; + break; + + case asBC_SUBIf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) - asBC_FLOATARG(l_bc+1); + l_bc += 3; + break; + + case asBC_MULIf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = *(float*)(l_fp - asBC_SWORDARG1(l_bc)) * asBC_FLOATARG(l_bc+1); + l_bc += 3; + break; + + //----------------------------------- + case asBC_SetG4: + *(asDWORD*)asBC_PTRARG(l_bc) = asBC_DWORDARG(l_bc+AS_PTR_SIZE); + l_bc += 2 + AS_PTR_SIZE; + break; + + case asBC_ChkRefS: + { + // Verify if the pointer on the stack refers to a non-null value + // This is used to validate a reference to a handle + asPWORD *a = (asPWORD*)*(asPWORD*)l_sp; + if( *a == 0 ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + } + l_bc++; + break; + + case asBC_ChkNullV: + { + // Verify if variable (on the stack) is not null + asDWORD *a = *(asDWORD**)(l_fp - asBC_SWORDARG0(l_bc)); + if( a == 0 ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + } + l_bc++; + break; + + case asBC_CALLINTF: + { + int i = asBC_INTARG(l_bc); + l_bc += 2; + + asASSERT( i >= 0 ); + asASSERT( (i & FUNC_IMPORTED) == 0 ); + + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + CallInterfaceMethod(m_engine->GetScriptFunction(i)); + + // Extract the values from the context again + l_bc = m_regs.programPointer; + l_sp = m_regs.stackPointer; + l_fp = m_regs.stackFramePointer; + + // If status isn't active anymore then we must stop + if( m_status != asEXECUTION_ACTIVE ) + return; + } + break; + + case asBC_iTOb: + { + // *(l_fp - offset) points to an int, and will point to a byte afterwards + + // We need to use volatile here to tell the compiler not to rearrange + // read and write operations during optimizations. + volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc)); + volatile asBYTE *bPtr = (asBYTE*)(l_fp - asBC_SWORDARG0(l_bc)); + bPtr[0] = (asBYTE)val; // write the byte + bPtr[1] = 0; // 0 the rest of the DWORD + bPtr[2] = 0; + bPtr[3] = 0; + } + l_bc++; + break; + + case asBC_iTOw: + { + // *(l_fp - offset) points to an int, and will point to word afterwards + + // We need to use volatile here to tell the compiler not to rearrange + // read and write operations during optimizations. + volatile asDWORD val = *(l_fp - asBC_SWORDARG0(l_bc)); + volatile asWORD *wPtr = (asWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + wPtr[0] = (asWORD)val; // write the word + wPtr[1] = 0; // 0 the rest of the DWORD + } + l_bc++; + break; + + case asBC_SetV1: + // TODO: This is exactly the same as SetV4. This is a left over from the time + // when the bytecode instructions were more tightly packed. It can now + // be removed. When removing it, make sure the value is correctly converted + // on big-endian CPUs. + + // The byte is already stored correctly in the argument + *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc); + l_bc += 2; + break; + + case asBC_SetV2: + // TODO: This is exactly the same as SetV4. This is a left over from the time + // when the bytecode instructions were more tightly packed. It can now + // be removed. When removing it, make sure the value is correctly converted + // on big-endian CPUs. + + // The word is already stored correctly in the argument + *(l_fp - asBC_SWORDARG0(l_bc)) = asBC_DWORDARG(l_bc); + l_bc += 2; + break; + + case asBC_Cast: + // Cast the handle at the top of the stack to the type in the argument + { + asDWORD **a = (asDWORD**)*(asPWORD*)l_sp; + if( a && *a ) + { + asDWORD typeId = asBC_DWORDARG(l_bc); + + asCScriptObject *obj = (asCScriptObject *)* a; + asCObjectType *objType = obj->objType; + asCObjectType *to = m_engine->GetObjectTypeFromTypeId(typeId); + + // This instruction can only be used with script classes and interfaces + asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT ); + asASSERT( to->flags & asOBJ_SCRIPT_OBJECT ); + + if( objType->Implements(to) || objType->DerivesFrom(to) ) + { + m_regs.objectType = 0; + m_regs.objectRegister = obj; + obj->AddRef(); + } + else + { + // The object register should already be null, so there + // is no need to clear it if the cast is unsuccessful + asASSERT( m_regs.objectRegister == 0 ); + } + } + l_sp += AS_PTR_SIZE; + } + l_bc += 2; + break; + + case asBC_i64TOi: + *(l_fp - asBC_SWORDARG0(l_bc)) = int(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_uTOi64: + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(asUINT*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_iTOi64: + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(int*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_fTOi64: + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_dTOi64: + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc))); + l_bc++; + break; + + case asBC_fTOu64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(float*)(l_fp - asBC_SWORDARG1(l_bc)))); + l_bc += 2; + break; + + case asBC_dTOu64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = asQWORD(asINT64(*(double*)(l_fp - asBC_SWORDARG0(l_bc)))); + l_bc++; + break; + + case asBC_i64TOf: + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc))); + l_bc += 2; + break; + + case asBC_u64TOf: +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6 + { + // MSVC6 doesn't permit UINT64 to double + asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)); + if( v < 0 ) + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0f+float(v); + else + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(v); + } +#else + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = float(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc))); +#endif + l_bc += 2; + break; + + case asBC_i64TOd: + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc))); + l_bc++; + break; + + case asBC_u64TOd: +#if defined(_MSC_VER) && _MSC_VER <= 1200 // MSVC6 + { + // MSVC6 doesn't permit UINT64 to double + asINT64 v = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)); + if( v < 0 ) + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = 18446744073709551615.0+double(v); + else + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(v); + } +#else + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = double(*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc))); +#endif + l_bc++; + break; + + case asBC_NEGi64: + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = -*(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_INCi64: + ++(**(asQWORD**)&m_regs.valueRegister); + l_bc++; + break; + + case asBC_DECi64: + --(**(asQWORD**)&m_regs.valueRegister); + l_bc++; + break; + + case asBC_BNOT64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = ~*(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_ADDi64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) + *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_SUBi64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) - *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_MULi64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) * *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_DIVi64: + { + asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + else if( divider == -1 ) + { + // Need to check if the value that is divided is 1<<63 + // as dividing it with -1 will cause an overflow exception + if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_OVERFLOW); + return; + } + } + + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; + } + l_bc += 2; + break; + + case asBC_MODi64: + { + asINT64 divider = *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + else if( divider == -1 ) + { + // Need to check if the value that is divided is 1<<63 + // as dividing it with -1 will cause an overflow exception + if( *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) == (asINT64(1)<<63) ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_OVERFLOW); + return; + } + } + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; + } + l_bc += 2; + break; + + case asBC_BAND64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) & *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_BOR64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) | *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_BXOR64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) ^ *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_BSLL64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) << *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_BSRL64: + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_BSRA64: + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)) >> *(l_fp - asBC_SWORDARG2(l_bc)); + l_bc += 2; + break; + + case asBC_CMPi64: + { + asINT64 i1 = *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)); + asINT64 i2 = *(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)); + if( i1 == i2 ) *(int*)&m_regs.valueRegister = 0; + else if( i1 < i2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_CMPu64: + { + asQWORD d1 = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + asQWORD d2 = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)); + if( d1 == d2 ) *(int*)&m_regs.valueRegister = 0; + else if( d1 < d2 ) *(int*)&m_regs.valueRegister = -1; + else *(int*)&m_regs.valueRegister = 1; + l_bc += 2; + } + break; + + case asBC_ChkNullS: + { + // Verify if the pointer on the stack is null + // This is used for example when validating handles passed as function arguments + asPWORD a = *(asPWORD*)(l_sp + asBC_WORDARG0(l_bc)); + if( a == 0 ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + } + l_bc++; + break; + + case asBC_ClrHi: +#if AS_SIZEOF_BOOL == 1 + { + // Clear the upper bytes, so that trash data don't interfere with boolean operations + + // We need to use volatile here to tell the compiler it cannot + // change the order of read and write operations on the pointer. + + volatile asBYTE *ptr = (asBYTE*)&m_regs.valueRegister; + ptr[1] = 0; // The boolean value is stored in the lower byte, so we clear the rest + ptr[2] = 0; + ptr[3] = 0; + } +#else + // We don't have anything to do here +#endif + l_bc++; + break; + + case asBC_JitEntry: + { + if( m_currentFunction->scriptData->jitFunction ) + { + asPWORD jitArg = asBC_PTRARG(l_bc); + + if( jitArg ) + { + // Resume JIT operation + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + (m_currentFunction->scriptData->jitFunction)(&m_regs, jitArg); + + l_bc = m_regs.programPointer; + l_sp = m_regs.stackPointer; + l_fp = m_regs.stackFramePointer; + + // If status isn't active anymore then we must stop + if( m_status != asEXECUTION_ACTIVE ) + return; + + break; + } + } + + // Not a JIT resume point, treat as nop + l_bc += 1+AS_PTR_SIZE; + } + break; + + case asBC_CallPtr: + { + // Get the function pointer from the local variable + asCScriptFunction *func = *(asCScriptFunction**)(l_fp - asBC_SWORDARG0(l_bc)); + + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + if( func == 0 ) + { + // Need to update the program pointer anyway for the exception handler + m_regs.programPointer++; + + // Tell the exception handler to clean up the arguments to this method + m_needToCleanupArgs = true; + + // TODO: funcdef: Should we have a different exception string? + SetInternalException(TXT_UNBOUND_FUNCTION); + return; + } + else + { + if( func->funcType == asFUNC_SCRIPT ) + { + m_regs.programPointer++; + CallScriptFunction(func); + } + else if( func->funcType == asFUNC_DELEGATE ) + { + // Push the object pointer on the stack. There is always a reserved space for this so + // we don't don't need to worry about overflowing the allocated memory buffer + asASSERT( m_regs.stackPointer - AS_PTR_SIZE >= m_stackBlocks[m_stackIndex] ); + m_regs.stackPointer -= AS_PTR_SIZE; + *(asPWORD*)m_regs.stackPointer = asPWORD(func->objForDelegate); + + // Call the delegated method + if( func->funcForDelegate->funcType == asFUNC_SYSTEM ) + { + m_regs.stackPointer += CallSystemFunction(func->funcForDelegate->id, this); + + // Update program position after the call so the line number + // is correct in case the system function queries it + m_regs.programPointer++; + } + else + { + m_regs.programPointer++; + + // TODO: run-time optimize: The true method could be figured out when creating the delegate + CallInterfaceMethod(func->funcForDelegate); + } + } + else + { + asASSERT( func->funcType == asFUNC_SYSTEM ); + + m_regs.stackPointer += CallSystemFunction(func->id, this); + + // Update program position after the call so the line number + // is correct in case the system function queries it + m_regs.programPointer++; + } + } + + // Extract the values from the context again + l_bc = m_regs.programPointer; + l_sp = m_regs.stackPointer; + l_fp = m_regs.stackFramePointer; + + // If status isn't active anymore then we must stop + if( m_status != asEXECUTION_ACTIVE ) + return; + } + break; + + case asBC_FuncPtr: + // Push the function pointer on the stack. The pointer is in the argument + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = asBC_PTRARG(l_bc); + l_bc += 1+AS_PTR_SIZE; + break; + + case asBC_LoadThisR: + { + // PshVPtr 0 + asPWORD tmp = *(asPWORD*)l_fp; + + // Make sure the pointer is not null + if( tmp == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + + // ADDSi + tmp = tmp + asBC_SWORDARG0(l_bc); + + // PopRPtr + *(asPWORD*)&m_regs.valueRegister = tmp; + l_bc += 2; + } + break; + + // Push the qword value of a variable on the stack + case asBC_PshV8: + l_sp -= 2; + *(asQWORD*)l_sp = *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + l_bc++; + break; + + case asBC_DIVu: + { + asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; + } + l_bc += 2; + break; + + case asBC_MODu: + { + asUINT divider = *(asUINT*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + *(asUINT*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asUINT*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; + } + l_bc += 2; + break; + + case asBC_DIVu64: + { + asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) / divider; + } + l_bc += 2; + break; + + case asBC_MODu64: + { + asQWORD divider = *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)); + if( divider == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_DIVIDE_BY_ZERO); + return; + } + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = *(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)) % divider; + } + l_bc += 2; + break; + + case asBC_LoadRObjR: + { + // PshVPtr x + asPWORD tmp = *(asPWORD*)(l_fp - asBC_SWORDARG0(l_bc)); + + // Make sure the pointer is not null + if( tmp == 0 ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_NULL_POINTER_ACCESS); + return; + } + + // ADDSi y + tmp = tmp + asBC_SWORDARG1(l_bc); + + // PopRPtr + *(asPWORD*)&m_regs.valueRegister = tmp; + l_bc += 3; + } + break; + + case asBC_LoadVObjR: + { + // PSF x + asPWORD tmp = (asPWORD)(l_fp - asBC_SWORDARG0(l_bc)); + + // ADDSi y + tmp = tmp + asBC_SWORDARG1(l_bc); + + // PopRPtr + *(asPWORD*)&m_regs.valueRegister = tmp; + l_bc += 3; + } + break; + + case asBC_RefCpyV: + // Same as PSF v, REFCPY + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(l_bc); + asSTypeBehaviour *beh = &objType->beh; + + // Determine destination from argument + void **d = (void**)asPWORD(l_fp - asBC_SWORDARG0(l_bc)); + + // Read wanted pointer from the stack + void *s = (void*)*(asPWORD*)l_sp; + + // Need to move the values back to the context as the called functions + // may use the debug interface to inspect the registers + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + if( !(objType->flags & asOBJ_NOCOUNT) ) + { + // Release previous object held by destination pointer + if( *d != 0 && beh->release ) + m_engine->CallObjectMethod(*d, beh->release); + // Increase ref counter of wanted object + if( s != 0 && beh->addref ) + m_engine->CallObjectMethod(s, beh->addref); + } + + // Set the new object in the destination + *d = s; + } + l_bc += 1+AS_PTR_SIZE; + break; + + case asBC_JLowZ: + if( *(asBYTE*)&m_regs.valueRegister == 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; + + case asBC_JLowNZ: + if( *(asBYTE*)&m_regs.valueRegister != 0 ) + l_bc += asBC_INTARG(l_bc) + 2; + else + l_bc += 2; + break; + + case asBC_AllocMem: + // Allocate a buffer and store the pointer in the local variable + { + // TODO: runtime optimize: As the list buffers are going to be short lived, it may be interesting + // to use a memory pool to avoid reallocating the memory all the time + + asUINT size = asBC_DWORDARG(l_bc); + asBYTE **var = (asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); +#ifndef WIP_16BYTE_ALIGN + *var = asNEWARRAY(asBYTE, size); +#else + *var = asNEWARRAYALIGNED(asBYTE, size, MAX_TYPE_ALIGNMENT); +#endif + + // Clear the buffer for the pointers that will be placed in it + memset(*var, 0, size); + } + l_bc += 2; + break; + + case asBC_SetListSize: + { + // Set the size element in the buffer + asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); + asUINT off = asBC_DWORDARG(l_bc); + asUINT size = asBC_DWORDARG(l_bc+1); + + asASSERT( var ); + + *(asUINT*)(var+off) = size; + } + l_bc += 3; + break; + + case asBC_PshListElmnt: + { + // Push the pointer to the list element on the stack + // In essence it does the same as PSF, RDSPtr, ADDSi + asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); + asUINT off = asBC_DWORDARG(l_bc); + + asASSERT( var ); + + l_sp -= AS_PTR_SIZE; + *(asPWORD*)l_sp = asPWORD(var+off); + } + l_bc += 2; + break; + + case asBC_SetListType: + { + // Set the type id in the buffer + asBYTE *var = *(asBYTE**)(l_fp - asBC_SWORDARG0(l_bc)); + asUINT off = asBC_DWORDARG(l_bc); + asUINT type = asBC_DWORDARG(l_bc+1); + + asASSERT( var ); + + *(asUINT*)(var+off) = type; + } + l_bc += 3; + break; + + //------------------------------ + // Exponent operations + case asBC_POWi: + { + bool isOverflow; + *(int*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi(*(int*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); + if( isOverflow ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_POW_OVERFLOW); + return; + } + } + l_bc += 2; + break; + + case asBC_POWu: + { + bool isOverflow; + *(asDWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu(*(asDWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asDWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); + if( isOverflow ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_POW_OVERFLOW); + return; + } + } + l_bc += 2; + break; + + case asBC_POWf: + { + float r = powf(*(float*)(l_fp - asBC_SWORDARG1(l_bc)), *(float*)(l_fp - asBC_SWORDARG2(l_bc))); + *(float*)(l_fp - asBC_SWORDARG0(l_bc)) = r; + if( r == float(HUGE_VAL) ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_POW_OVERFLOW); + return; + } + } + l_bc += 2; + break; + + case asBC_POWd: + { + double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(double*)(l_fp - asBC_SWORDARG2(l_bc))); + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r; + if( r == HUGE_VAL ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_POW_OVERFLOW); + return; + } + } + l_bc += 2; + break; + + case asBC_POWdi: + { + double r = pow(*(double*)(l_fp - asBC_SWORDARG1(l_bc)), *(int*)(l_fp - asBC_SWORDARG2(l_bc))); + *(double*)(l_fp - asBC_SWORDARG0(l_bc)) = r; + if( r == HUGE_VAL ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_POW_OVERFLOW); + return; + } + l_bc += 2; + } + break; + + case asBC_POWi64: + { + bool isOverflow; + *(asINT64*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powi64(*(asINT64*)(l_fp - asBC_SWORDARG1(l_bc)), *(asINT64*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); + if( isOverflow ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_POW_OVERFLOW); + return; + } + } + l_bc += 2; + break; + + case asBC_POWu64: + { + bool isOverflow; + *(asQWORD*)(l_fp - asBC_SWORDARG0(l_bc)) = as_powu64(*(asQWORD*)(l_fp - asBC_SWORDARG1(l_bc)), *(asQWORD*)(l_fp - asBC_SWORDARG2(l_bc)), isOverflow); + if( isOverflow ) + { + // Need to move the values back to the context + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Raise exception + SetInternalException(TXT_POW_OVERFLOW); + return; + } + } + l_bc += 2; + break; + case asBC_Thiscall1: + // This instruction is a faster version of asBC_CALLSYS. It is faster because + // it has much less runtime overhead with determining the calling convention + // and no dynamic code for loading the parameters. The instruction can only + // be used to call functions with the following signatures: + // + // type &obj::func(int) + // type &obj::func(uint) + // void obj::func(int) + // void obj::func(uint) + { + // Get function ID from the argument + int i = asBC_INTARG(l_bc); + + // Need to move the values back to the context as the called functions + // may use the debug interface to inspect the registers + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + // Pop the thispointer from the stack + void *obj = *(void**)l_sp; + if (obj == 0) + SetInternalException(TXT_NULL_POINTER_ACCESS); + else + { + // Only update the stack pointer if all is OK so the + // exception handler can properly clean up the stack + l_sp += AS_PTR_SIZE; + + // Pop the int arg from the stack + int arg = *(int*)l_sp; + l_sp++; + + // Call the method + m_callingSystemFunction = m_engine->scriptFunctions[i]; + void *ptr = 0; +#ifdef AS_NO_EXCEPTIONS + ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); +#else + // This try/catch block is to catch potential exception that may + // be thrown by the registered function. + try + { + ptr = m_engine->CallObjectMethodRetPtr(obj, arg, m_callingSystemFunction); + } + catch (...) + { + // Convert the exception to a script exception so the VM can + // properly report the error to the application and then clean up + HandleAppException(); + } +#endif + m_callingSystemFunction = 0; + *(asPWORD*)&m_regs.valueRegister = (asPWORD)ptr; + } + + // Update the program position after the call so that line number is correct + l_bc += 2; + + if( m_regs.doProcessSuspend ) + { + // Should the execution be suspended? + if( m_doSuspend ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + m_status = asEXECUTION_SUSPENDED; + return; + } + // An exception might have been raised + if( m_status != asEXECUTION_ACTIVE ) + { + m_regs.programPointer = l_bc; + m_regs.stackPointer = l_sp; + m_regs.stackFramePointer = l_fp; + + return; + } + } + } + break; + + // Don't let the optimizer optimize for size, + // since it requires extra conditions and jumps + case 201: l_bc = (asDWORD*)201; break; + case 202: l_bc = (asDWORD*)202; break; + case 203: l_bc = (asDWORD*)203; break; + case 204: l_bc = (asDWORD*)204; break; + case 205: l_bc = (asDWORD*)205; break; + case 206: l_bc = (asDWORD*)206; break; + case 207: l_bc = (asDWORD*)207; break; + case 208: l_bc = (asDWORD*)208; break; + case 209: l_bc = (asDWORD*)209; break; + case 210: l_bc = (asDWORD*)210; break; + case 211: l_bc = (asDWORD*)211; break; + case 212: l_bc = (asDWORD*)212; break; + case 213: l_bc = (asDWORD*)213; break; + case 214: l_bc = (asDWORD*)214; break; + case 215: l_bc = (asDWORD*)215; break; + case 216: l_bc = (asDWORD*)216; break; + case 217: l_bc = (asDWORD*)217; break; + case 218: l_bc = (asDWORD*)218; break; + case 219: l_bc = (asDWORD*)219; break; + case 220: l_bc = (asDWORD*)220; break; + case 221: l_bc = (asDWORD*)221; break; + case 222: l_bc = (asDWORD*)222; break; + case 223: l_bc = (asDWORD*)223; break; + case 224: l_bc = (asDWORD*)224; break; + case 225: l_bc = (asDWORD*)225; break; + case 226: l_bc = (asDWORD*)226; break; + case 227: l_bc = (asDWORD*)227; break; + case 228: l_bc = (asDWORD*)228; break; + case 229: l_bc = (asDWORD*)229; break; + case 230: l_bc = (asDWORD*)230; break; + case 231: l_bc = (asDWORD*)231; break; + case 232: l_bc = (asDWORD*)232; break; + case 233: l_bc = (asDWORD*)233; break; + case 234: l_bc = (asDWORD*)234; break; + case 235: l_bc = (asDWORD*)235; break; + case 236: l_bc = (asDWORD*)236; break; + case 237: l_bc = (asDWORD*)237; break; + case 238: l_bc = (asDWORD*)238; break; + case 239: l_bc = (asDWORD*)239; break; + case 240: l_bc = (asDWORD*)240; break; + case 241: l_bc = (asDWORD*)241; break; + case 242: l_bc = (asDWORD*)242; break; + case 243: l_bc = (asDWORD*)243; break; + case 244: l_bc = (asDWORD*)244; break; + case 245: l_bc = (asDWORD*)245; break; + case 246: l_bc = (asDWORD*)246; break; + case 247: l_bc = (asDWORD*)247; break; + case 248: l_bc = (asDWORD*)248; break; + case 249: l_bc = (asDWORD*)249; break; + case 250: l_bc = (asDWORD*)250; break; + case 251: l_bc = (asDWORD*)251; break; + case 252: l_bc = (asDWORD*)252; break; + case 253: l_bc = (asDWORD*)253; break; + case 254: l_bc = (asDWORD*)254; break; + case 255: l_bc = (asDWORD*)255; break; + +#ifdef AS_DEBUG + default: + asASSERT(false); + SetInternalException(TXT_UNRECOGNIZED_BYTE_CODE); +#endif +#if defined(_MSC_VER) && !defined(AS_DEBUG) + default: + // This Microsoft specific code allows the + // compiler to optimize the switch case as + // it will know that the code will never + // reach this point + __assume(0); +#endif + } + +#ifdef AS_DEBUG + asDWORD instr = *(asBYTE*)old; + if( instr != asBC_JMP && instr != asBC_JMPP && (instr < asBC_JZ || instr > asBC_JNP) && instr != asBC_JLowZ && instr != asBC_JLowNZ && + instr != asBC_CALL && instr != asBC_CALLBND && instr != asBC_CALLINTF && instr != asBC_RET && instr != asBC_ALLOC && instr != asBC_CallPtr && + instr != asBC_JitEntry ) + { + asASSERT( (l_bc - old) == asBCTypeSize[asBCInfo[instr].type] ); + } +#endif + } +} + +// interface +int asCContext::SetException(const char *descr, bool allowCatch) +{ + // Only allow this if we're executing a CALL byte code + if( m_callingSystemFunction == 0 ) return asERROR; + + SetInternalException(descr, allowCatch); + + return 0; +} + +void asCContext::SetInternalException(const char *descr, bool allowCatch) +{ + if( m_inExceptionHandler ) + { + asASSERT(false); // Shouldn't happen + return; // but if it does, at least this will not crash the application + } + + m_status = asEXECUTION_EXCEPTION; + m_regs.doProcessSuspend = true; + + m_exceptionString = descr; + m_exceptionFunction = m_currentFunction->id; + + if( m_currentFunction->scriptData ) + { + m_exceptionLine = m_currentFunction->GetLineNumber(int(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()), &m_exceptionSectionIdx); + m_exceptionColumn = m_exceptionLine >> 20; + m_exceptionLine &= 0xFFFFF; + } + else + { + m_exceptionSectionIdx = 0; + m_exceptionLine = 0; + m_exceptionColumn = 0; + } + + // Recursively search the callstack for try/catch blocks + m_exceptionWillBeCaught = allowCatch && FindExceptionTryCatch(); + + if( m_exceptionCallback ) + CallExceptionCallback(); +} + +// interface +bool asCContext::WillExceptionBeCaught() +{ + return m_exceptionWillBeCaught; +} + +void asCContext::CleanReturnObject() +{ + if( m_initialFunction && m_initialFunction->DoesReturnOnStack() && m_status == asEXECUTION_FINISHED ) + { + // If function returns on stack we need to call the destructor on the returned object + if(CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct ) + m_engine->CallObjectMethod(GetReturnObject(), CastToObjectType(m_initialFunction->returnType.GetTypeInfo())->beh.destruct); + + return; + } + + if( m_regs.objectRegister == 0 ) return; + + asASSERT( m_regs.objectType != 0 ); + + if( m_regs.objectType ) + { + if (m_regs.objectType->GetFlags() & asOBJ_FUNCDEF) + { + // Release the function pointer + reinterpret_cast(m_regs.objectRegister)->Release(); + m_regs.objectRegister = 0; + } + else + { + // Call the destructor on the object + asSTypeBehaviour *beh = &(CastToObjectType(reinterpret_cast(m_regs.objectType))->beh); + if (m_regs.objectType->GetFlags() & asOBJ_REF) + { + asASSERT(beh->release || (m_regs.objectType->GetFlags() & asOBJ_NOCOUNT)); + + if (beh->release) + m_engine->CallObjectMethod(m_regs.objectRegister, beh->release); + + m_regs.objectRegister = 0; + } + else + { + if (beh->destruct) + m_engine->CallObjectMethod(m_regs.objectRegister, beh->destruct); + + // Free the memory + m_engine->CallFree(m_regs.objectRegister); + m_regs.objectRegister = 0; + } + } + } +} + +void asCContext::CleanStack(bool catchException) +{ + m_inExceptionHandler = true; + + // Run the clean up code and move to catch block + bool caught = CleanStackFrame(catchException); + if( !caught ) + { + // Set the status to exception so that the stack unwind is done correctly. + // This shouldn't be done for the current function, which is why we only + // do this after the first CleanStackFrame() is done. + m_status = asEXECUTION_EXCEPTION; + + while (!caught && m_callStack.GetLength() > 0) + { + // Only clean up until the top most marker for a nested call + asPWORD *s = m_callStack.AddressOf() + m_callStack.GetLength() - CALLSTACK_FRAME_SIZE; + if (s[0] == 0) + break; + + PopCallState(); + + caught = CleanStackFrame(catchException); + } + } + + // If the exception was caught, then move the status to + // active as is now possible to resume the execution + if (caught) + m_status = asEXECUTION_ACTIVE; + + m_inExceptionHandler = false; +} + +// Interface +bool asCContext::IsVarInScope(asUINT varIndex, asUINT stackLevel) +{ + // Don't return anything if there is no bytecode, e.g. before calling Execute() + if( m_regs.programPointer == 0 ) return false; + + if( stackLevel >= GetCallstackSize() ) return false; + + asCScriptFunction *func; + asUINT pos; + + if( stackLevel == 0 ) + { + func = m_currentFunction; + if( func->scriptData == 0 ) return false; + pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf()); + } + else + { + asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; + func = (asCScriptFunction*)s[1]; + if( func->scriptData == 0 ) return false; + pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf()); + } + + // First determine if the program position is after the variable declaration + if( func->scriptData->variables.GetLength() <= varIndex ) return false; + if( func->scriptData->variables[varIndex]->declaredAtProgramPos > pos ) return false; + + asUINT declaredAt = func->scriptData->variables[varIndex]->declaredAtProgramPos; + + // If the program position is after the variable declaration it is necessary + // determine if the program position is still inside the statement block where + // the variable was delcared. + for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ ) + { + if( func->scriptData->objVariableInfo[n].programPos >= declaredAt ) + { + // If the current block ends between the declaredAt and current + // program position, then we know the variable is no longer visible + int level = 0; + for( ; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ ) + { + if( func->scriptData->objVariableInfo[n].programPos > pos ) + break; + + if( func->scriptData->objVariableInfo[n].option == asBLOCK_BEGIN ) level++; + if( func->scriptData->objVariableInfo[n].option == asBLOCK_END && --level < 0 ) + return false; + } + + break; + } + } + + // Variable is visible + return true; +} + +// Internal +void asCContext::DetermineLiveObjects(asCArray &liveObjects, asUINT stackLevel) +{ + asASSERT( stackLevel < GetCallstackSize() ); + + asCScriptFunction *func; + asUINT pos; + + if( stackLevel == 0 ) + { + func = m_currentFunction; + if( func->scriptData == 0 ) + return; + + pos = asUINT(m_regs.programPointer - func->scriptData->byteCode.AddressOf()); + + if( m_status == asEXECUTION_EXCEPTION ) + { + // Don't consider the last instruction as executed, as it failed with an exception + // It's not actually necessary to decrease the exact size of the instruction. Just + // before the current position is enough to disconsider it. + pos--; + } + } + else + { + asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; + func = (asCScriptFunction*)s[1]; + if( func->scriptData == 0 ) + return; + + pos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf()); + + // Don't consider the last instruction as executed, as the function that was called by it + // is still being executed. If we consider it as executed already, then a value object + // returned by value would be considered alive, which it is not. + pos--; + } + + // Determine which object variables that are really live ones + liveObjects.SetLength(func->scriptData->objVariablePos.GetLength()); + memset(liveObjects.AddressOf(), 0, sizeof(int)*liveObjects.GetLength()); + for( int n = 0; n < (int)func->scriptData->objVariableInfo.GetLength(); n++ ) + { + // Find the first variable info with a larger position than the current + // As the variable info are always placed on the instruction right after the + // one that initialized or freed the object, the current position needs to be + // considered as valid. + if( func->scriptData->objVariableInfo[n].programPos > pos ) + { + // We've determined how far the execution ran, now determine which variables are alive + for( --n; n >= 0; n-- ) + { + switch( func->scriptData->objVariableInfo[n].option ) + { + case asOBJ_UNINIT: // Object was destroyed + { + // TODO: optimize: This should have been done by the compiler already + // Which variable is this? + asUINT var = 0; + for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) + if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset ) + { + var = v; + break; + } + liveObjects[var] -= 1; + } + break; + case asOBJ_INIT: // Object was created + { + // Which variable is this? + asUINT var = 0; + for( asUINT v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) + if( func->scriptData->objVariablePos[v] == func->scriptData->objVariableInfo[n].variableOffset ) + { + var = v; + break; + } + liveObjects[var] += 1; + } + break; + case asBLOCK_BEGIN: // Start block + // We should ignore start blocks, since it just means the + // program was within the block when the exception occurred + break; + case asBLOCK_END: // End block + // We need to skip the entire block, as the objects created + // and destroyed inside this block are already out of scope + { + int nested = 1; + while( nested > 0 ) + { + int option = func->scriptData->objVariableInfo[--n].option; + if( option == 3 ) + nested++; + if( option == 2 ) + nested--; + } + } + break; + case asOBJ_VARDECL: // A variable was declared + // We don't really care about the variable declarations at this moment + break; + } + } + + // We're done with the investigation + break; + } + } +} + +void asCContext::CleanArgsOnStack() +{ + if( !m_needToCleanupArgs ) + return; + + asASSERT( m_currentFunction->scriptData ); + + // Find the instruction just before the current program pointer + asDWORD *instr = m_currentFunction->scriptData->byteCode.AddressOf(); + asDWORD *prevInstr = 0; + while( instr < m_regs.programPointer ) + { + prevInstr = instr; + instr += asBCTypeSize[asBCInfo[*(asBYTE*)(instr)].type]; + } + + // Determine what function was being called + asCScriptFunction *func = 0; + asBYTE bc = *(asBYTE*)prevInstr; + if( bc == asBC_CALL || bc == asBC_CALLSYS || bc == asBC_CALLINTF ) + { + int funcId = asBC_INTARG(prevInstr); + func = m_engine->scriptFunctions[funcId]; + } + else if( bc == asBC_CALLBND ) + { + int funcId = asBC_INTARG(prevInstr); + func = m_engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature; + } + else if( bc == asBC_CallPtr ) + { + asUINT v; + int var = asBC_SWORDARG0(prevInstr); + + // Find the funcdef from the local variable + for( v = 0; v < m_currentFunction->scriptData->objVariablePos.GetLength(); v++ ) + if( m_currentFunction->scriptData->objVariablePos[v] == var ) + { + func = CastToFuncdefType(m_currentFunction->scriptData->objVariableTypes[v])->funcdef; + break; + } + + if( func == 0 ) + { + // Look in parameters + int paramPos = 0; + if( m_currentFunction->objectType ) + paramPos -= AS_PTR_SIZE; + if( m_currentFunction->DoesReturnOnStack() ) + paramPos -= AS_PTR_SIZE; + for( v = 0; v < m_currentFunction->parameterTypes.GetLength(); v++ ) + { + if( var == paramPos ) + { + if (m_currentFunction->parameterTypes[v].IsFuncdef()) + func = CastToFuncdefType(m_currentFunction->parameterTypes[v].GetTypeInfo())->funcdef; + break; + } + paramPos -= m_currentFunction->parameterTypes[v].GetSizeOnStackDWords(); + } + } + } + else + asASSERT( false ); + + asASSERT( func ); + + // Clean parameters + int offset = 0; + if( func->objectType ) + offset += AS_PTR_SIZE; + if( func->DoesReturnOnStack() ) + offset += AS_PTR_SIZE; + for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + if( (func->parameterTypes[n].IsObject() || func->parameterTypes[n].IsFuncdef()) && !func->parameterTypes[n].IsReference() ) + { + // TODO: cleanup: This logic is repeated twice in CleanStackFrame too. Should create a common function to share the code + if( *(asPWORD*)&m_regs.stackPointer[offset] ) + { + // Call the object's destructor + asSTypeBehaviour *beh = func->parameterTypes[n].GetBehaviour(); + if (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) + { + (*(asCScriptFunction**)&m_regs.stackPointer[offset])->Release(); + } + else if( func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) + { + asASSERT( (func->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); + + if( beh->release ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->release); + } + else + { + if( beh->destruct ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackPointer[offset], beh->destruct); + + // Free the memory + m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackPointer[offset]); + } + *(asPWORD*)&m_regs.stackPointer[offset] = 0; + } + } + + offset += func->parameterTypes[n].GetSizeOnStackDWords(); + } + + m_needToCleanupArgs = false; +} + +bool asCContext::FindExceptionTryCatch() +{ + // Check each of the script functions on the callstack to see if + // the current program position is within a try/catch block + if (m_currentFunction && m_currentFunction->scriptData) + { + asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()); + for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++) + { + if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos && + currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos) + return true; + } + } + + int stackSize = GetCallstackSize(); + for (int level = 1; level < stackSize; level++) + { + asPWORD *s = m_callStack.AddressOf() + (stackSize - level - 1)*CALLSTACK_FRAME_SIZE; + asCScriptFunction *func = (asCScriptFunction*)s[1]; + if (func && func->scriptData) + { + asUINT currPos = asUINT((asDWORD*)s[2] - func->scriptData->byteCode.AddressOf()); + for (asUINT n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++) + { + if (currPos >= func->scriptData->tryCatchInfo[n].tryPos && + currPos < func->scriptData->tryCatchInfo[n].catchPos) + return true; + } + } + } + + return false; +} + +bool asCContext::CleanStackFrame(bool catchException) +{ + bool exceptionCaught = false; + asSTryCatchInfo *tryCatchInfo = 0; + + // Clean object variables on the stack + // If the stack memory is not allocated or the program pointer + // is not set, then there is nothing to clean up on the stack frame + if( !m_isStackMemoryNotAllocated && m_regs.programPointer ) + { + // If the exception occurred while calling a function it is necessary + // to clean up the arguments that were put on the stack. + CleanArgsOnStack(); + + // Check if this function will catch the exception + // Try blocks can be nested, so use the innermost block + asASSERT(m_currentFunction->scriptData); + if (catchException && m_currentFunction->scriptData) + { + asUINT currPos = asUINT(m_regs.programPointer - m_currentFunction->scriptData->byteCode.AddressOf()); + + for (asUINT n = 0; n < m_currentFunction->scriptData->tryCatchInfo.GetLength(); n++) + { + if (currPos >= m_currentFunction->scriptData->tryCatchInfo[n].tryPos && + currPos < m_currentFunction->scriptData->tryCatchInfo[n].catchPos) + { + tryCatchInfo = &m_currentFunction->scriptData->tryCatchInfo[n]; + exceptionCaught = true; + } + if (currPos < m_currentFunction->scriptData->tryCatchInfo[n].tryPos) + break; + } + } + + // Restore the stack pointer + if( !exceptionCaught ) + m_regs.stackPointer += m_currentFunction->scriptData->variableSpace; + + // Determine which object variables that are really live ones + asCArray liveObjects; + DetermineLiveObjects(liveObjects, 0); + + for( asUINT n = 0; n < m_currentFunction->scriptData->objVariablePos.GetLength(); n++ ) + { + int pos = m_currentFunction->scriptData->objVariablePos[n]; + + // If the exception was caught, then only clean up objects within the try block + if (exceptionCaught) + { + // Find out where the variable was declared, and skip cleaning of those that were declared before the try catch + // Multiple variables in different scopes may occupy the same slot on the stack so it is necessary to search + // the entire list to determine which variable occupies the slot now. + int skipClean = 0; + for( asUINT p = 0; p < m_currentFunction->scriptData->objVariableInfo.GetLength(); p++ ) + { + asSObjectVariableInfo &info = m_currentFunction->scriptData->objVariableInfo[p]; + if (info.variableOffset == pos && + info.option == asOBJ_VARDECL ) + { + asUINT progPos = info.programPos; + if (progPos < tryCatchInfo->tryPos ) + { + if( skipClean >= 0 ) + skipClean = 1; + break; + } + else if( progPos < tryCatchInfo->catchPos ) + { + skipClean = -1; + break; + } + } + } + + // Skip only variables that have been declared before the try block. Variables declared + // within the try block and variables whose declaration was not identified (temporary objects) + // will not be skipped. + // TODO: What if a temporary variable reuses a slot from a declared variable that is no longer in scope? + if (skipClean > 0) + continue; + } + + if( n < m_currentFunction->scriptData->objVariablesOnHeap ) + { + // Check if the pointer is initialized + if( *(asPWORD*)&m_regs.stackFramePointer[-pos] ) + { + // Call the object's destructor + if (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_FUNCDEF) + { + (*(asCScriptFunction**)&m_regs.stackFramePointer[-pos])->Release(); + } + else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_REF ) + { + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; + asASSERT( (m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_NOCOUNT) || beh->release ); + if( beh->release ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->release); + } + else + { + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; + if( beh->destruct ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); + else if( m_currentFunction->scriptData->objVariableTypes[n]->flags & asOBJ_LIST_PATTERN ) + m_engine->DestroyList((asBYTE*)*(asPWORD*)&m_regs.stackFramePointer[-pos], CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])); + + // Free the memory + m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[-pos]); + } + *(asPWORD*)&m_regs.stackFramePointer[-pos] = 0; + } + } + else + { + asASSERT( m_currentFunction->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE ); + + // Only destroy the object if it is truly alive + if( liveObjects[n] > 0 ) + { + asSTypeBehaviour *beh = &CastToObjectType(m_currentFunction->scriptData->objVariableTypes[n])->beh; + if( beh->destruct ) + m_engine->CallObjectMethod((void*)(asPWORD*)&m_regs.stackFramePointer[-pos], beh->destruct); + } + } + } + } + else + m_isStackMemoryNotAllocated = false; + + // If the exception was caught then move the program position to the catch block then stop the unwinding + if (exceptionCaught) + { + m_regs.programPointer = m_currentFunction->scriptData->byteCode.AddressOf() + tryCatchInfo->catchPos; + return exceptionCaught; + } + + // Functions that do not own the object and parameters shouldn't do any clean up + if( m_currentFunction->dontCleanUpOnException ) + return exceptionCaught; + + // Clean object and parameters + int offset = 0; + if( m_currentFunction->objectType ) + offset += AS_PTR_SIZE; + if( m_currentFunction->DoesReturnOnStack() ) + offset += AS_PTR_SIZE; + for( asUINT n = 0; n < m_currentFunction->parameterTypes.GetLength(); n++ ) + { + if( (m_currentFunction->parameterTypes[n].IsObject() ||m_currentFunction->parameterTypes[n].IsFuncdef()) && !m_currentFunction->parameterTypes[n].IsReference() ) + { + if( *(asPWORD*)&m_regs.stackFramePointer[offset] ) + { + // Call the object's destructor + asSTypeBehaviour *beh = m_currentFunction->parameterTypes[n].GetBehaviour(); + if (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_FUNCDEF) + { + (*(asCScriptFunction**)&m_regs.stackFramePointer[offset])->Release(); + } + else if( m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_REF ) + { + asASSERT( (m_currentFunction->parameterTypes[n].GetTypeInfo()->flags & asOBJ_NOCOUNT) || beh->release ); + + if( beh->release ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->release); + } + else + { + if( beh->destruct ) + m_engine->CallObjectMethod((void*)*(asPWORD*)&m_regs.stackFramePointer[offset], beh->destruct); + + // Free the memory + m_engine->CallFree((void*)*(asPWORD*)&m_regs.stackFramePointer[offset]); + } + *(asPWORD*)&m_regs.stackFramePointer[offset] = 0; + } + } + + offset += m_currentFunction->parameterTypes[n].GetSizeOnStackDWords(); + } + + return exceptionCaught; +} + +// interface +int asCContext::GetExceptionLineNumber(int *column, const char **sectionName) +{ + // Return the last exception even if the context is no longer in the exception state + // if( GetState() != asEXECUTION_EXCEPTION ) return asERROR; + + if( column ) *column = m_exceptionColumn; + + if( sectionName ) + { + // The section index can be -1 if the exception was raised in a generated function, e.g. $fact for templates + if( m_exceptionSectionIdx >= 0 ) + *sectionName = m_engine->scriptSectionNames[m_exceptionSectionIdx]->AddressOf(); + else + *sectionName = 0; + } + + return m_exceptionLine; +} + +// interface +asIScriptFunction *asCContext::GetExceptionFunction() +{ + // Return the last exception even if the context is no longer in the exception state + // if( GetState() != asEXECUTION_EXCEPTION ) return 0; + + return m_engine->scriptFunctions[m_exceptionFunction]; +} + +// interface +const char *asCContext::GetExceptionString() +{ + // Return the last exception even if the context is no longer in the exception state + // if( GetState() != asEXECUTION_EXCEPTION ) return 0; + + return m_exceptionString.AddressOf(); +} + +// interface +asEContextState asCContext::GetState() const +{ + return m_status; +} + +// interface +int asCContext::SetLineCallback(asSFuncPtr callback, void *obj, int callConv) +{ + // First turn off the line callback to avoid a second thread + // attempting to call it while the new one is still being set + m_lineCallback = false; + + m_lineCallbackObj = obj; + bool isObj = false; + if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) + { + m_regs.doProcessSuspend = m_doSuspend; + return asNOT_SUPPORTED; + } + if( (unsigned)callConv >= asCALL_THISCALL ) + { + isObj = true; + if( obj == 0 ) + { + m_regs.doProcessSuspend = m_doSuspend; + return asINVALID_ARG; + } + } + + int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_lineCallbackFunc); + + // Turn on the line callback after setting both the function pointer and object pointer + if( r >= 0 ) m_lineCallback = true; + + // The BC_SUSPEND instruction should be processed if either line + // callback is set or if the application has requested a suspension + m_regs.doProcessSuspend = m_doSuspend || m_lineCallback; + + return r; +} + +void asCContext::CallLineCallback() +{ + if( m_lineCallbackFunc.callConv < ICC_THISCALL ) + m_engine->CallGlobalFunction(this, m_lineCallbackObj, &m_lineCallbackFunc, 0); + else + m_engine->CallObjectMethod(m_lineCallbackObj, this, &m_lineCallbackFunc, 0); +} + +// interface +int asCContext::SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv) +{ + m_exceptionCallback = true; + m_exceptionCallbackObj = obj; + bool isObj = false; + if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) + return asNOT_SUPPORTED; + if( (unsigned)callConv >= asCALL_THISCALL ) + { + isObj = true; + if( obj == 0 ) + { + m_exceptionCallback = false; + return asINVALID_ARG; + } + } + int r = DetectCallingConvention(isObj, callback, callConv, 0, &m_exceptionCallbackFunc); + if( r < 0 ) m_exceptionCallback = false; + return r; +} + +void asCContext::CallExceptionCallback() +{ + if( m_exceptionCallbackFunc.callConv < ICC_THISCALL ) + m_engine->CallGlobalFunction(this, m_exceptionCallbackObj, &m_exceptionCallbackFunc, 0); + else + m_engine->CallObjectMethod(m_exceptionCallbackObj, this, &m_exceptionCallbackFunc, 0); +} + +#ifndef AS_NO_EXCEPTIONS +// internal +void asCContext::HandleAppException() +{ + // This method is called from within a catch(...) block + if (m_engine->translateExceptionCallback) + { + // Allow the application to translate the application exception to a proper exception string + if (m_engine->translateExceptionCallbackFunc.callConv < ICC_THISCALL) + m_engine->CallGlobalFunction(this, m_engine->translateExceptionCallbackObj, &m_engine->translateExceptionCallbackFunc, 0); + else + m_engine->CallObjectMethod(m_engine->translateExceptionCallbackObj, this, &m_engine->translateExceptionCallbackFunc, 0); + } + + // Make sure an exception is set even if the application decides not to do any specific translation + if( m_status != asEXECUTION_EXCEPTION ) + SetException(TXT_EXCEPTION_CAUGHT); +} +#endif + +// interface +void asCContext::ClearLineCallback() +{ + m_lineCallback = false; + m_regs.doProcessSuspend = m_doSuspend; +} + +// interface +void asCContext::ClearExceptionCallback() +{ + m_exceptionCallback = false; +} + +int asCContext::CallGeneric(asCScriptFunction *descr) +{ + asSSystemFunctionInterface *sysFunc = descr->sysFuncIntf; + void (*func)(asIScriptGeneric*) = (void (*)(asIScriptGeneric*))sysFunc->func; + int popSize = sysFunc->paramSize; + asDWORD *args = m_regs.stackPointer; + + // Verify the object pointer if it is a class method + void *currentObject = 0; + asASSERT( sysFunc->callConv == ICC_GENERIC_FUNC || sysFunc->callConv == ICC_GENERIC_METHOD ); + if( sysFunc->callConv == ICC_GENERIC_METHOD ) + { + // The object pointer should be popped from the context stack + popSize += AS_PTR_SIZE; + + // Check for null pointer + currentObject = (void*)*(asPWORD*)(args); + if( currentObject == 0 ) + { + SetInternalException(TXT_NULL_POINTER_ACCESS); + return 0; + } + + asASSERT( sysFunc->baseOffset == 0 ); + + // Skip object pointer + args += AS_PTR_SIZE; + } + + if( descr->DoesReturnOnStack() ) + { + // Skip the address where the return value will be stored + args += AS_PTR_SIZE; + popSize += AS_PTR_SIZE; + } + + asCGeneric gen(m_engine, descr, currentObject, args); + + m_callingSystemFunction = descr; +#ifdef AS_NO_EXCEPTIONS + func(&gen); +#else + // This try/catch block is to catch potential exception that may + // be thrown by the registered function. + try + { + func(&gen); + } + catch (...) + { + // Convert the exception to a script exception so the VM can + // properly report the error to the application and then clean up + HandleAppException(); + } +#endif + m_callingSystemFunction = 0; + + m_regs.valueRegister = gen.returnVal; + m_regs.objectRegister = gen.objectRegister; + m_regs.objectType = descr->returnType.GetTypeInfo(); + + // Increase the returned handle if the function has been declared with autohandles + // and the engine is not set to use the old mode for the generic calling convention + if (sysFunc->returnAutoHandle && m_engine->ep.genericCallMode == 1 && m_regs.objectRegister) + { + asASSERT(!(descr->returnType.GetTypeInfo()->flags & asOBJ_NOCOUNT)); + m_engine->CallObjectMethod(m_regs.objectRegister, CastToObjectType(descr->returnType.GetTypeInfo())->beh.addref); + } + + // Clean up arguments + const asUINT cleanCount = sysFunc->cleanArgs.GetLength(); + if( cleanCount ) + { + asSSystemFunctionInterface::SClean *clean = sysFunc->cleanArgs.AddressOf(); + for( asUINT n = 0; n < cleanCount; n++, clean++ ) + { + void **addr = (void**)&args[clean->off]; + if( clean->op == 0 ) + { + if( *addr != 0 ) + { + m_engine->CallObjectMethod(*addr, clean->ot->beh.release); + *addr = 0; + } + } + else + { + asASSERT( clean->op == 1 || clean->op == 2 ); + asASSERT( *addr ); + + if( clean->op == 2 ) + m_engine->CallObjectMethod(*addr, clean->ot->beh.destruct); + + m_engine->CallFree(*addr); + } + } + } + + // Return how much should be popped from the stack + return popSize; +} + +// interface +int asCContext::GetVarCount(asUINT stackLevel) +{ + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return asINVALID_ARG; + + return func->GetVarCount(); +} + +// interface +const char *asCContext::GetVarName(asUINT varIndex, asUINT stackLevel) +{ + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return 0; + + const char *name = 0; + int r = func->GetVar(varIndex, &name); + return r >= 0 ? name : 0; +} + +// interface +const char *asCContext::GetVarDeclaration(asUINT varIndex, asUINT stackLevel, bool includeNamespace) +{ + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return 0; + + return func->GetVarDecl(varIndex, includeNamespace); +} + +// interface +int asCContext::GetVarTypeId(asUINT varIndex, asUINT stackLevel) +{ + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return asINVALID_ARG; + + int typeId; + int r = func->GetVar(varIndex, 0, &typeId); + return r < 0 ? r : typeId; +} + +// interface +void *asCContext::GetAddressOfVar(asUINT varIndex, asUINT stackLevel) +{ + // Don't return anything if there is no bytecode, e.g. before calling Execute() + if( m_regs.programPointer == 0 ) return 0; + + if( stackLevel >= GetCallstackSize() ) return 0; + + asCScriptFunction *func; + asDWORD *sf; + if( stackLevel == 0 ) + { + func = m_currentFunction; + sf = m_regs.stackFramePointer; + } + else + { + asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; + func = (asCScriptFunction*)s[1]; + sf = (asDWORD*)s[0]; + } + + if( func == 0 ) + return 0; + + if( func->scriptData == 0 ) + return 0; + + if( varIndex >= func->scriptData->variables.GetLength() ) + return 0; + + // For object variables it's necessary to dereference the pointer to get the address of the value + // Reference parameters must also be dereferenced to give the address of the value + int pos = func->scriptData->variables[varIndex]->stackOffset; + if( (func->scriptData->variables[varIndex]->type.IsObject() && !func->scriptData->variables[varIndex]->type.IsObjectHandle()) || (pos <= 0) ) + { + // Determine if the object is really on the heap + bool onHeap = false; + if( func->scriptData->variables[varIndex]->type.IsObject() && + !func->scriptData->variables[varIndex]->type.IsObjectHandle() ) + { + onHeap = true; + if( func->scriptData->variables[varIndex]->type.GetTypeInfo()->GetFlags() & asOBJ_VALUE ) + { + for( asUINT n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) + { + if( func->scriptData->objVariablePos[n] == pos ) + { + onHeap = n < func->scriptData->objVariablesOnHeap; + + if( !onHeap ) + { + // If the object on the stack is not initialized return a null pointer instead + asCArray liveObjects; + DetermineLiveObjects(liveObjects, stackLevel); + + if( liveObjects[n] <= 0 ) + return 0; + } + + break; + } + } + } + } + + // If it wasn't an object on the heap, then check if it is a reference parameter + if( !onHeap && pos <= 0 ) + { + // Determine what function argument this position matches + int stackPos = 0; + if( func->objectType ) + stackPos -= AS_PTR_SIZE; + + if( func->DoesReturnOnStack() ) + stackPos -= AS_PTR_SIZE; + + for( asUINT n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + if( stackPos == pos ) + { + // The right argument was found. Is this a reference parameter? + if( func->inOutFlags[n] != asTM_NONE ) + onHeap = true; + + break; + } + stackPos -= func->parameterTypes[n].GetSizeOnStackDWords(); + } + } + + if( onHeap ) + return *(void**)(sf - func->scriptData->variables[varIndex]->stackOffset); + } + + return sf - func->scriptData->variables[varIndex]->stackOffset; +} + +// interface +// returns the typeId of the 'this' object at the given call stack level (0 for current) +// returns 0 if the function call at the given stack level is not a method +int asCContext::GetThisTypeId(asUINT stackLevel) +{ + asIScriptFunction *func = GetFunction(stackLevel); + if( func == 0 ) return asINVALID_ARG; + + if( func->GetObjectType() == 0 ) + return 0; // not in a method + + // create a datatype + asCDataType dt = asCDataType::CreateType((asCObjectType*)func->GetObjectType(), false); + + // return a typeId from the data type + return m_engine->GetTypeIdFromDataType(dt); +} + +// interface +// returns the 'this' object pointer at the given call stack level (0 for current) +// returns 0 if the function call at the given stack level is not a method +void *asCContext::GetThisPointer(asUINT stackLevel) +{ + if( stackLevel >= GetCallstackSize() ) + return 0; + + asCScriptFunction *func; + asDWORD *sf; + if( stackLevel == 0 ) + { + func = m_currentFunction; + sf = m_regs.stackFramePointer; + } + else + { + asPWORD *s = m_callStack.AddressOf() + (GetCallstackSize()-stackLevel-1)*CALLSTACK_FRAME_SIZE; + func = (asCScriptFunction*)s[1]; + sf = (asDWORD*)s[0]; + } + + if( func == 0 ) + return 0; + + if( func->objectType == 0 ) + return 0; // not in a method + + void *thisPointer = (void*)*(asPWORD*)(sf); + if( thisPointer == 0 ) + { + return 0; + } + + // NOTE: this returns the pointer to the 'this' while the GetVarPointer functions return + // a pointer to a pointer. I can't imagine someone would want to change the 'this' + return thisPointer; +} + + + + + + + +// TODO: Move these to as_utils.cpp + +struct POW_INFO +{ + asQWORD MaxBaseu64; + asDWORD MaxBasei64; + asWORD MaxBaseu32; + asWORD MaxBasei32; + char HighBit; +}; + +const POW_INFO pow_info[] = +{ + { 0ULL, 0UL, 0, 0, 0 }, // 0 is a special case + { 0ULL, 0UL, 0, 0, 1 }, // 1 is a special case + { 3037000499ULL, 2147483647UL, 65535, 46340, 2 }, // 2 + { 2097152ULL, 1664510UL, 1625, 1290, 2 }, // 3 + { 55108ULL, 46340UL, 255, 215, 3 }, // 4 + { 6208ULL, 5404UL, 84, 73, 3 }, // 5 + { 1448ULL, 1290UL, 40, 35, 3 }, // 6 + { 511ULL, 463UL, 23, 21, 3 }, // 7 + { 234ULL, 215UL, 15, 14, 4 }, // 8 + { 128ULL, 118UL, 11, 10, 4 }, // 9 + { 78ULL, 73UL, 9, 8, 4 }, // 10 + { 52ULL, 49UL, 7, 7, 4 }, // 11 + { 38ULL, 35UL, 6, 5, 4 }, // 12 + { 28ULL, 27UL, 5, 5, 4 }, // 13 + { 22ULL, 21UL, 4, 4, 4 }, // 14 + { 18ULL, 17UL, 4, 4, 4 }, // 15 + { 15ULL, 14UL, 3, 3, 5 }, // 16 + { 13ULL, 12UL, 3, 3, 5 }, // 17 + { 11ULL, 10UL, 3, 3, 5 }, // 18 + { 9ULL, 9UL, 3, 3, 5 }, // 19 + { 8ULL, 8UL, 3, 2, 5 }, // 20 + { 8ULL, 7UL, 2, 2, 5 }, // 21 + { 7ULL, 7UL, 2, 2, 5 }, // 22 + { 6ULL, 6UL, 2, 2, 5 }, // 23 + { 6ULL, 5UL, 2, 2, 5 }, // 24 + { 5ULL, 5UL, 2, 2, 5 }, // 25 + { 5ULL, 5UL, 2, 2, 5 }, // 26 + { 5ULL, 4UL, 2, 2, 5 }, // 27 + { 4ULL, 4UL, 2, 2, 5 }, // 28 + { 4ULL, 4UL, 2, 2, 5 }, // 29 + { 4ULL, 4UL, 2, 2, 5 }, // 30 + { 4ULL, 4UL, 2, 1, 5 }, // 31 + { 3ULL, 3UL, 1, 1, 6 }, // 32 + { 3ULL, 3UL, 1, 1, 6 }, // 33 + { 3ULL, 3UL, 1, 1, 6 }, // 34 + { 3ULL, 3UL, 1, 1, 6 }, // 35 + { 3ULL, 3UL, 1, 1, 6 }, // 36 + { 3ULL, 3UL, 1, 1, 6 }, // 37 + { 3ULL, 3UL, 1, 1, 6 }, // 38 + { 3ULL, 3UL, 1, 1, 6 }, // 39 + { 2ULL, 2UL, 1, 1, 6 }, // 40 + { 2ULL, 2UL, 1, 1, 6 }, // 41 + { 2ULL, 2UL, 1, 1, 6 }, // 42 + { 2ULL, 2UL, 1, 1, 6 }, // 43 + { 2ULL, 2UL, 1, 1, 6 }, // 44 + { 2ULL, 2UL, 1, 1, 6 }, // 45 + { 2ULL, 2UL, 1, 1, 6 }, // 46 + { 2ULL, 2UL, 1, 1, 6 }, // 47 + { 2ULL, 2UL, 1, 1, 6 }, // 48 + { 2ULL, 2UL, 1, 1, 6 }, // 49 + { 2ULL, 2UL, 1, 1, 6 }, // 50 + { 2ULL, 2UL, 1, 1, 6 }, // 51 + { 2ULL, 2UL, 1, 1, 6 }, // 52 + { 2ULL, 2UL, 1, 1, 6 }, // 53 + { 2ULL, 2UL, 1, 1, 6 }, // 54 + { 2ULL, 2UL, 1, 1, 6 }, // 55 + { 2ULL, 2UL, 1, 1, 6 }, // 56 + { 2ULL, 2UL, 1, 1, 6 }, // 57 + { 2ULL, 2UL, 1, 1, 6 }, // 58 + { 2ULL, 2UL, 1, 1, 6 }, // 59 + { 2ULL, 2UL, 1, 1, 6 }, // 60 + { 2ULL, 2UL, 1, 1, 6 }, // 61 + { 2ULL, 2UL, 1, 1, 6 }, // 62 + { 2ULL, 1UL, 1, 1, 6 }, // 63 +}; + +int as_powi(int base, int exponent, bool& isOverflow) +{ + if( exponent < 0 ) + { + if( base == 0 ) + // Divide by zero + isOverflow = true; + else + // Result is less than 1, so it truncates to 0 + isOverflow = false; + + return 0; + } + else if( exponent == 0 && base == 0 ) + { + // Domain error + isOverflow = true; + return 0; + } + else if( exponent >= 31 ) + { + switch( base ) + { + case -1: + isOverflow = false; + return exponent & 1 ? -1 : 1; + case 0: + isOverflow = false; + break; + case 1: + isOverflow = false; + return 1; + default: + isOverflow = true; + break; + } + return 0; + } + else + { + const asWORD max_base = pow_info[exponent].MaxBasei32; + const char high_bit = pow_info[exponent].HighBit; + if( max_base != 0 && max_base < (base < 0 ? -base : base) ) + { + isOverflow = true; + return 0; // overflow + } + + int result = 1; + switch( high_bit ) + { + case 5: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 4: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 3: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 2: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 1: + if( exponent ) result *= base; + default: + isOverflow = false; + return result; + } + } +} + +asDWORD as_powu(asDWORD base, asDWORD exponent, bool& isOverflow) +{ + if( exponent == 0 && base == 0 ) + { + // Domain error + isOverflow = true; + return 0; + } + else if( exponent >= 32 ) + { + switch( base ) + { + case 0: + isOverflow = false; + break; + case 1: + isOverflow = false; + return 1; + default: + isOverflow = true; + break; + } + return 0; + } + else + { + const asWORD max_base = pow_info[exponent].MaxBaseu32; + const char high_bit = pow_info[exponent].HighBit; + if( max_base != 0 && max_base < base ) + { + isOverflow = true; + return 0; // overflow + } + + asDWORD result = 1; + switch( high_bit ) + { + case 5: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 4: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 3: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 2: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 1: + if( exponent ) result *= base; + default: + isOverflow = false; + return result; + } + } +} + +asINT64 as_powi64(asINT64 base, asINT64 exponent, bool& isOverflow) +{ + if( exponent < 0 ) + { + if( base == 0 ) + // Divide by zero + isOverflow = true; + else + // Result is less than 1, so it truncates to 0 + isOverflow = false; + + return 0; + } + else if( exponent == 0 && base == 0 ) + { + // Domain error + isOverflow = true; + return 0; + } + else if( exponent >= 63 ) + { + switch( base ) + { + case -1: + isOverflow = false; + return exponent & 1 ? -1 : 1; + case 0: + isOverflow = false; + break; + case 1: + isOverflow = false; + return 1; + default: + isOverflow = true; + break; + } + return 0; + } + else + { + const asDWORD max_base = pow_info[exponent].MaxBasei64; + const char high_bit = pow_info[exponent].HighBit; + if( max_base != 0 && max_base < (base < 0 ? -base : base) ) + { + isOverflow = true; + return 0; // overflow + } + + asINT64 result = 1; + switch( high_bit ) + { + case 6: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 5: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 4: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 3: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 2: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 1: + if( exponent ) result *= base; + default: + isOverflow = false; + return result; + } + } +} + +asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow) +{ + if( exponent == 0 && base == 0 ) + { + // Domain error + isOverflow = true; + return 0; + } + else if( exponent >= 64 ) + { + switch( base ) + { + case 0: + isOverflow = false; + break; + case 1: + isOverflow = false; + return 1; + default: + isOverflow = true; + break; + } + return 0; + } + else + { + const asQWORD max_base = pow_info[exponent].MaxBaseu64; + const char high_bit = pow_info[exponent].HighBit; + if( max_base != 0 && max_base < base ) + { + isOverflow = true; + return 0; // overflow + } + + asQWORD result = 1; + switch( high_bit ) + { + case 6: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 5: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 4: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 3: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 2: + if( exponent & 1 ) result *= base; + exponent >>= 1; + base *= base; + case 1: + if( exponent ) result *= base; + default: + isOverflow = false; + return result; + } + } +} + +END_AS_NAMESPACE + + + diff --git a/angelscript/source/as_context.h b/angelscript/source/as_context.h new file mode 100644 index 0000000..e564540 --- /dev/null +++ b/angelscript/source/as_context.h @@ -0,0 +1,250 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2018 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_context.h +// +// This class handles the execution of the byte code +// + + +#ifndef AS_CONTEXT_H +#define AS_CONTEXT_H + +#include "as_config.h" +#include "as_atomic.h" +#include "as_array.h" +#include "as_string.h" +#include "as_objecttype.h" +#include "as_callfunc.h" + +BEGIN_AS_NAMESPACE + +class asCScriptFunction; +class asCScriptEngine; + +class asCContext : public asIScriptContext +{ +public: + // Memory management + int AddRef() const; + int Release() const; + + // Miscellaneous + asIScriptEngine *GetEngine() const; + + // Execution + int Prepare(asIScriptFunction *func); + int Unprepare(); + int Execute(); + int Abort(); + int Suspend(); + asEContextState GetState() const; + int PushState(); + int PopState(); + bool IsNested(asUINT *nestCount = 0) const; + + // Object pointer for calling class methods + int SetObject(void *obj); + + // Arguments + int SetArgByte(asUINT arg, asBYTE value); + int SetArgWord(asUINT arg, asWORD value); + int SetArgDWord(asUINT arg, asDWORD value); + int SetArgQWord(asUINT arg, asQWORD value); + int SetArgFloat(asUINT arg, float value); + int SetArgDouble(asUINT arg, double value); + int SetArgAddress(asUINT arg, void *addr); + int SetArgObject(asUINT arg, void *obj); + int SetArgVarType(asUINT arg, void *ptr, int typeId); + void *GetAddressOfArg(asUINT arg); + + // Return value + asBYTE GetReturnByte(); + asWORD GetReturnWord(); + asDWORD GetReturnDWord(); + asQWORD GetReturnQWord(); + float GetReturnFloat(); + double GetReturnDouble(); + void *GetReturnAddress(); + void *GetReturnObject(); + void *GetAddressOfReturnValue(); + + // Exception handling + int SetException(const char *descr, bool allowCatch = true); + int GetExceptionLineNumber(int *column, const char **sectionName); + asIScriptFunction *GetExceptionFunction(); + const char * GetExceptionString(); + bool WillExceptionBeCaught(); + int SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv); + void ClearExceptionCallback(); + + // Debugging + int SetLineCallback(asSFuncPtr callback, void *obj, int callConv); + void ClearLineCallback(); + asUINT GetCallstackSize() const; + asIScriptFunction *GetFunction(asUINT stackLevel); + int GetLineNumber(asUINT stackLevel, int *column, const char **sectionName); + int GetVarCount(asUINT stackLevel); + const char *GetVarName(asUINT varIndex, asUINT stackLevel); + const char *GetVarDeclaration(asUINT varIndex, asUINT stackLevel, bool includeNamespace); + int GetVarTypeId(asUINT varIndex, asUINT stackLevel); + void *GetAddressOfVar(asUINT varIndex, asUINT stackLevel); + bool IsVarInScope(asUINT varIndex, asUINT stackLevel); + int GetThisTypeId(asUINT stackLevel); + void *GetThisPointer(asUINT stackLevel); + asIScriptFunction *GetSystemFunction(); + + // User data + void *SetUserData(void *data, asPWORD type); + void *GetUserData(asPWORD type) const; + +public: + // Internal public functions + asCContext(asCScriptEngine *engine, bool holdRef); + virtual ~asCContext(); + +//protected: + friend class asCScriptEngine; + + void CallLineCallback(); + void CallExceptionCallback(); + + int CallGeneric(asCScriptFunction *func); +#ifndef AS_NO_EXCEPTIONS + void HandleAppException(); +#endif + void DetachEngine(); + + void ExecuteNext(); + void CleanStack(bool catchException = false); + bool CleanStackFrame(bool catchException = false); + void CleanArgsOnStack(); + void CleanReturnObject(); + void DetermineLiveObjects(asCArray &liveObjects, asUINT stackLevel); + + int PushCallState(); + void PopCallState(); + void CallScriptFunction(asCScriptFunction *func); + void CallInterfaceMethod(asCScriptFunction *func); + void PrepareScriptFunction(); + + bool ReserveStackSpace(asUINT size); + + void SetInternalException(const char *descr, bool allowCatch = true); + bool FindExceptionTryCatch(); + + // Must be protected for multiple accesses + mutable asCAtomic m_refCount; + + bool m_holdEngineRef; + asCScriptEngine *m_engine; + + asEContextState m_status; + bool m_doSuspend; + bool m_doAbort; + bool m_externalSuspendRequest; + + asCScriptFunction *m_currentFunction; + asCScriptFunction *m_callingSystemFunction; + + // The call stack holds program pointer, stack pointer, etc for caller functions + asCArray m_callStack; + + // Dynamically growing local stack + asCArray m_stackBlocks; + asUINT m_stackBlockSize; + asUINT m_stackIndex; + asDWORD *m_originalStackPointer; + + // Exception handling + bool m_isStackMemoryNotAllocated; + bool m_needToCleanupArgs; + bool m_inExceptionHandler; + asCString m_exceptionString; + int m_exceptionFunction; + int m_exceptionSectionIdx; + int m_exceptionLine; + int m_exceptionColumn; + bool m_exceptionWillBeCaught; + + // The last prepared function, and some cached values related to it + asCScriptFunction *m_initialFunction; + int m_returnValueSize; + int m_argumentsSize; + + // callbacks + bool m_lineCallback; + asSSystemFunctionInterface m_lineCallbackFunc; + void * m_lineCallbackObj; + + bool m_exceptionCallback; + asSSystemFunctionInterface m_exceptionCallbackFunc; + void * m_exceptionCallbackObj; + + asCArray m_userData; + + // Registers available to JIT compiler functions + asSVMRegisters m_regs; +}; + +// TODO: Move these to as_utils.h +int as_powi(int base, int exponent, bool& isOverflow); +asDWORD as_powu(asDWORD base, asDWORD exponent, bool& isOverflow); +asINT64 as_powi64(asINT64 base, asINT64 exponent, bool& isOverflow); +asQWORD as_powu64(asQWORD base, asQWORD exponent, bool& isOverflow); + +// Optional template version of powi if overflow detection is not used. +#if 0 +template +T as_powi(T base, T exponent) +{ + // Test for sign bit (huge number is OK) + if( exponent & (T(1)<<(sizeof(T)*8-1)) ) + return 0; + else + { + int result = 1; + while( exponent ) + { + if( exponent & 1 ) + result *= base; + exponent >>= 1; + base *= base; + } + return result; + } +} +#endif + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_criticalsection.h b/angelscript/source/as_criticalsection.h new file mode 100644 index 0000000..2e15288 --- /dev/null +++ b/angelscript/source/as_criticalsection.h @@ -0,0 +1,189 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_criticalsection.h +// +// Classes for multi threading support +// + +#ifndef AS_CRITICALSECTION_H +#define AS_CRITICALSECTION_H + +#include "as_config.h" + +BEGIN_AS_NAMESPACE + +#ifdef AS_NO_THREADS + +#define DECLARECRITICALSECTION(x) +#define ENTERCRITICALSECTION(x) +#define LEAVECRITICALSECTION(x) + +inline bool tryEnter() { return true; } +#define TRYENTERCRITICALSECTION(x) tryEnter() + +#define DECLAREREADWRITELOCK(x) +#define ACQUIREEXCLUSIVE(x) +#define RELEASEEXCLUSIVE(x) +#define ACQUIRESHARED(x) +#define RELEASESHARED(x) + +#else + +#define DECLARECRITICALSECTION(x) asCThreadCriticalSection x; +#define ENTERCRITICALSECTION(x) x.Enter() +#define LEAVECRITICALSECTION(x) x.Leave() +#define TRYENTERCRITICALSECTION(x) x.TryEnter() + +#define DECLAREREADWRITELOCK(x) asCThreadReadWriteLock x; +#define ACQUIREEXCLUSIVE(x) x.AcquireExclusive() +#define RELEASEEXCLUSIVE(x) x.ReleaseExclusive() +#define ACQUIRESHARED(x) x.AcquireShared() +#define RELEASESHARED(x) x.ReleaseShared() + +#ifdef AS_POSIX_THREADS + +END_AS_NAMESPACE +#include +BEGIN_AS_NAMESPACE + +class asCThreadCriticalSection +{ +public: + asCThreadCriticalSection(); + ~asCThreadCriticalSection(); + + void Enter(); + void Leave(); + bool TryEnter(); + +protected: + pthread_mutex_t cs; +}; + +class asCThreadReadWriteLock +{ +public: + asCThreadReadWriteLock(); + ~asCThreadReadWriteLock(); + + void AcquireExclusive(); + void ReleaseExclusive(); + bool TryAcquireExclusive(); + + void AcquireShared(); + void ReleaseShared(); + bool TryAcquireShared(); + +protected: + pthread_rwlock_t lock; +}; + +#elif defined(AS_WINDOWS_THREADS) + +END_AS_NAMESPACE +#ifdef AS_XBOX360 +#include +#else +#ifndef WIN32_LEAN_AND_MEAN + #define WIN32_LEAN_AND_MEAN +#endif +#ifndef _WIN32_WINNT + #define _WIN32_WINNT 0x0600 // We need this to get the declaration for Windows Phone compatible Ex functions +#endif +#include +#endif +BEGIN_AS_NAMESPACE + +// Undefine macros that cause problems in our code +#undef GetObject +#undef RegisterClass + +class asCThreadCriticalSection +{ +public: + asCThreadCriticalSection(); + ~asCThreadCriticalSection(); + + void Enter(); + void Leave(); + bool TryEnter(); + +protected: + CRITICAL_SECTION cs; +}; + +class asCThreadReadWriteLock +{ +public: + asCThreadReadWriteLock(); + ~asCThreadReadWriteLock(); + + void AcquireExclusive(); + void ReleaseExclusive(); + + void AcquireShared(); + void ReleaseShared(); + +protected: + // The Slim Read Write Lock object, SRWLOCK, is more efficient + // but it is only available from Windows Vista so we cannot use it and + // maintain compatibility with olders versions of Windows. + + // Critical sections and semaphores are available on Windows XP and onwards. + // Windows XP is oldest version we support with multithreading. + + // The implementation is based on the following article, that shows + // how to implement a fair read/write lock that doesn't risk starving + // the writers: + + // http://doc.qt.nokia.com/qq/qq11-mutex.html + + // TODO: Allow use of SRWLOCK through configuration in as_config.h + + CRITICAL_SECTION writeLock; + HANDLE readLocks; +}; + +// This constant really should be a member of asCThreadReadWriteLock, +// but it gives a compiler error on MSVC6 so I'm leaving it outside +static const asUINT maxReaders = 10; + +#endif + +#endif + +END_AS_NAMESPACE + +#endif + diff --git a/angelscript/source/as_datatype.cpp b/angelscript/source/as_datatype.cpp new file mode 100644 index 0000000..0fcd75c --- /dev/null +++ b/angelscript/source/as_datatype.cpp @@ -0,0 +1,690 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_datatype.cpp +// +// This class describes the datatype for expressions during compilation +// + +#include "as_config.h" +#include "as_datatype.h" +#include "as_tokendef.h" +#include "as_typeinfo.h" +#include "as_objecttype.h" +#include "as_scriptengine.h" +#include "as_tokenizer.h" + +BEGIN_AS_NAMESPACE + +asCDataType::asCDataType() +{ + tokenType = ttUnrecognizedToken; + typeInfo = 0; + isReference = false; + isReadOnly = false; + isAuto = false; + isObjectHandle = false; + isConstHandle = false; + isHandleToAsHandleType = false; + ifHandleThenConst = false; +} + +asCDataType::asCDataType(const asCDataType &dt) +{ + tokenType = dt.tokenType; + typeInfo = dt.typeInfo; + isReference = dt.isReference; + isReadOnly = dt.isReadOnly; + isAuto = dt.isAuto; + isObjectHandle = dt.isObjectHandle; + isConstHandle = dt.isConstHandle; + isHandleToAsHandleType = dt.isHandleToAsHandleType; + ifHandleThenConst = dt.ifHandleThenConst; +} + +asCDataType::~asCDataType() +{ +} + +bool asCDataType::IsValid() const +{ + if( tokenType == ttUnrecognizedToken && + !isObjectHandle ) + return false; + + return true; +} + +asCDataType asCDataType::CreateType(asCTypeInfo *ti, bool isConst) +{ + asCDataType dt; + + dt.tokenType = ttIdentifier; + dt.typeInfo = ti; + dt.isReadOnly = isConst; + + return dt; +} + +asCDataType asCDataType::CreateAuto(bool isConst) +{ + asCDataType dt; + + dt.tokenType = ttIdentifier; + dt.isReadOnly = isConst; + dt.isAuto = true; + + return dt; +} + +asCDataType asCDataType::CreateObjectHandle(asCTypeInfo *ot, bool isConst) +{ + asCDataType dt; + + asASSERT(CastToObjectType(ot)); + + dt.tokenType = ttIdentifier; + dt.typeInfo = ot; + dt.isObjectHandle = true; + dt.isConstHandle = isConst; + + return dt; +} + +asCDataType asCDataType::CreatePrimitive(eTokenType tt, bool isConst) +{ + asCDataType dt; + + dt.tokenType = tt; + dt.isReadOnly = isConst; + + return dt; +} + +asCDataType asCDataType::CreateNullHandle() +{ + asCDataType dt; + + dt.tokenType = ttUnrecognizedToken; + dt.isReadOnly = true; + dt.isObjectHandle = true; + dt.isConstHandle = true; + + return dt; +} + +bool asCDataType::IsNullHandle() const +{ + if( tokenType == ttUnrecognizedToken && + typeInfo == 0 && + isObjectHandle ) + return true; + + return false; +} + +asCString asCDataType::Format(asSNameSpace *currNs, bool includeNamespace) const +{ + if( IsNullHandle() ) + return ""; + + asCString str; + + if( isReadOnly ) + str = "const "; + + // If the type is not declared in the current namespace, then the namespace + // must always be informed to guarantee that the correct type is informed + if (includeNamespace || (typeInfo && typeInfo->nameSpace != currNs)) + { + if (typeInfo && typeInfo->nameSpace && typeInfo->nameSpace->name != "") + str += typeInfo->nameSpace->name + "::"; + } + if (typeInfo && typeInfo->nameSpace == 0) + { + // If funcDef->nameSpace is null it means the funcDef was declared as member of + // another type, in which case the scope should be built with the name of that type + str += CastToFuncdefType(typeInfo)->parentClass->name + "::"; + } + + if( tokenType != ttIdentifier ) + { + str += asCTokenizer::GetDefinition(tokenType); + } + else if( IsArrayType() && typeInfo && !typeInfo->engine->ep.expandDefaultArrayToTemplate ) + { + asCObjectType *ot = CastToObjectType(typeInfo); + asASSERT( ot && ot->templateSubTypes.GetLength() == 1 ); + str += ot->templateSubTypes[0].Format(currNs, includeNamespace); + str += "[]"; + } + else if(typeInfo) + { + str += typeInfo->name; + asCObjectType *ot = CastToObjectType(typeInfo); + if( ot && ot->templateSubTypes.GetLength() > 0 ) + { + str += "<"; + for( asUINT subtypeIndex = 0; subtypeIndex < ot->templateSubTypes.GetLength(); subtypeIndex++ ) + { + str += ot->templateSubTypes[subtypeIndex].Format(currNs, includeNamespace); + if( subtypeIndex != ot->templateSubTypes.GetLength()-1 ) + str += ","; + } + str += ">"; + } + } + else if( isAuto ) + { + str += ""; + } + else + { + str = ""; + } + + if( isObjectHandle ) + { + str += "@"; + if( isConstHandle ) + str += "const"; + } + + if( isReference ) + str += "&"; + + return str; +} + +asCDataType &asCDataType::operator =(const asCDataType &dt) +{ + tokenType = dt.tokenType; + isReference = dt.isReference; + typeInfo = dt.typeInfo; + isReadOnly = dt.isReadOnly; + isObjectHandle = dt.isObjectHandle; + isConstHandle = dt.isConstHandle; + isAuto = dt.isAuto; + isHandleToAsHandleType = dt.isHandleToAsHandleType; + ifHandleThenConst = dt.ifHandleThenConst; + + return (asCDataType &)*this; +} + +int asCDataType::MakeHandle(bool b, bool acceptHandleForScope) +{ + if( !b ) + { + isObjectHandle = false; + isConstHandle = false; + isHandleToAsHandleType = false; + } + else + { + if( isAuto ) + { + isObjectHandle = true; + } + else if( !isObjectHandle ) + { + // Only reference types are allowed to be handles, + // but not nohandle reference types, and not scoped references + // (except when returned from registered function) + // funcdefs are special reference types and support handles + // value types with asOBJ_ASHANDLE are treated as a handle + if( (!typeInfo || + !((typeInfo->flags & asOBJ_REF) || (typeInfo->flags & asOBJ_TEMPLATE_SUBTYPE) || (typeInfo->flags & asOBJ_ASHANDLE) || (typeInfo->flags & asOBJ_FUNCDEF)) || + (typeInfo->flags & asOBJ_NOHANDLE) || + ((typeInfo->flags & asOBJ_SCOPED) && !acceptHandleForScope)) ) + return -1; + + isObjectHandle = b; + isConstHandle = false; + + // ASHANDLE supports being handle, but as it really is a value type it will not be marked as a handle + if( (typeInfo->flags & asOBJ_ASHANDLE) ) + { + isObjectHandle = false; + isHandleToAsHandleType = true; + } + } + } + + return 0; +} + +int asCDataType::MakeArray(asCScriptEngine *engine, asCModule *module) +{ + if( engine->defaultArrayObjectType == 0 ) + return asINVALID_TYPE; + + bool tmpIsReadOnly = isReadOnly; + isReadOnly = false; + asCArray subTypes; + subTypes.PushLast(*this); + asCObjectType *at = engine->GetTemplateInstanceType(engine->defaultArrayObjectType, subTypes, module); + isReadOnly = tmpIsReadOnly; + + isObjectHandle = false; + isConstHandle = false; + + typeInfo = at; + tokenType = ttIdentifier; + + return 0; +} + +int asCDataType::MakeReference(bool b) +{ + isReference = b; + + return 0; +} + +int asCDataType::MakeReadOnly(bool b) +{ + if( isObjectHandle ) + { + isConstHandle = b; + return 0; + } + + isReadOnly = b; + return 0; +} + +int asCDataType::MakeHandleToConst(bool b) +{ + if( !isObjectHandle ) return -1; + + isReadOnly = b; + return 0; +} + +bool asCDataType::SupportHandles() const +{ + if( typeInfo && + (typeInfo->flags & (asOBJ_REF | asOBJ_ASHANDLE | asOBJ_FUNCDEF)) && + !(typeInfo->flags & asOBJ_NOHANDLE) && + !isObjectHandle ) + return true; + + return false; +} + +bool asCDataType::CanBeInstantiated() const +{ + if( GetSizeOnStackDWords() == 0 ) // Void + return false; + + if( !IsObject() && !IsFuncdef() ) // Primitives + return true; + + if (IsNullHandle()) // null + return false; + + if( IsObjectHandle() && !(typeInfo->flags & asOBJ_NOHANDLE) ) // Handles + return true; + + // Funcdefs cannot be instantiated without being handles + // The exception being delegates, but these can only be created as temporary objects + if (IsFuncdef()) + return false; + + asCObjectType *ot = CastToObjectType(typeInfo); + if( ot && (ot->flags & asOBJ_REF) && ot->beh.factories.GetLength() == 0 ) // ref types without factories + return false; + + if( ot && (ot->flags & asOBJ_ABSTRACT) && !IsObjectHandle() ) // Can't instantiate abstract classes + return false; + + return true; +} + +bool asCDataType::IsAbstractClass() const +{ + return typeInfo && (typeInfo->flags & asOBJ_ABSTRACT) ? true : false; +} + +bool asCDataType::IsInterface() const +{ + if (typeInfo == 0) + return false; + + asCObjectType *ot = CastToObjectType(typeInfo); + return ot && ot->IsInterface(); +} + +bool asCDataType::CanBeCopied() const +{ + // All primitives can be copied + if( IsPrimitive() ) return true; + + // Plain-old-data structures can always be copied + if( typeInfo->flags & asOBJ_POD ) return true; + + // It must be possible to instantiate the type + if( !CanBeInstantiated() ) return false; + + // It must have a default constructor or factory and the opAssign + // Alternatively it must have the copy constructor + asCObjectType *ot = CastToObjectType(typeInfo); + if (ot && (((ot->beh.construct != 0 || ot->beh.factory != 0) && ot->beh.copy != 0) || + (ot->beh.copyconstruct != 0 || ot->beh.copyfactory != 0)) ) + return true; + + return false; +} + +bool asCDataType::IsReadOnly() const +{ + if( isObjectHandle ) + return isConstHandle; + + return isReadOnly; +} + +bool asCDataType::IsHandleToConst() const +{ + if( !isObjectHandle ) return false; + return isReadOnly; +} + +bool asCDataType::IsObjectConst() const +{ + if( IsObjectHandle() ) + return IsHandleToConst(); + + return IsReadOnly(); +} + +// TODO: 3.0.0: This should be removed +bool asCDataType::IsArrayType() const +{ + // This is only true if the type used is the default array type, i.e. the one used for the [] syntax form + if( typeInfo && typeInfo->engine->defaultArrayObjectType ) + return typeInfo->name == typeInfo->engine->defaultArrayObjectType->name; + + return false; +} + +bool asCDataType::IsTemplate() const +{ + if( typeInfo && (typeInfo->flags & asOBJ_TEMPLATE) ) + return true; + + return false; +} + +bool asCDataType::IsScriptObject() const +{ + if( typeInfo && (typeInfo->flags & asOBJ_SCRIPT_OBJECT) ) + return true; + + return false; +} + +asCDataType asCDataType::GetSubType(asUINT subtypeIndex) const +{ + asASSERT(typeInfo); + asCObjectType *ot = CastToObjectType(typeInfo); + return ot->templateSubTypes[subtypeIndex]; +} + + +bool asCDataType::operator !=(const asCDataType &dt) const +{ + return !(*this == dt); +} + +bool asCDataType::operator ==(const asCDataType &dt) const +{ + if( !IsEqualExceptRefAndConst(dt) ) return false; + if( isReference != dt.isReference ) return false; + if( isReadOnly != dt.isReadOnly ) return false; + if( isConstHandle != dt.isConstHandle ) return false; + + return true; +} + +bool asCDataType::IsEqualExceptRef(const asCDataType &dt) const +{ + if( !IsEqualExceptRefAndConst(dt) ) return false; + if( isReadOnly != dt.isReadOnly ) return false; + if( isConstHandle != dt.isConstHandle ) return false; + + return true; +} + +bool asCDataType::IsEqualExceptRefAndConst(const asCDataType &dt) const +{ + // Check base type + if( tokenType != dt.tokenType ) return false; + if( typeInfo != dt.typeInfo ) return false; + if( isObjectHandle != dt.isObjectHandle ) return false; + if( isObjectHandle ) + if( isReadOnly != dt.isReadOnly ) return false; + + return true; +} + +bool asCDataType::IsEqualExceptConst(const asCDataType &dt) const +{ + if( !IsEqualExceptRefAndConst(dt) ) return false; + if( isReference != dt.isReference ) return false; + + return true; +} + +bool asCDataType::IsPrimitive() const +{ + // Enumerations are primitives + if( IsEnumType() ) + return true; + + // A registered object is never a primitive neither is a pointer nor an array + if( typeInfo ) + return false; + + // Null handle doesn't have a typeInfo, but it is not a primitive + if( tokenType == ttUnrecognizedToken ) + return false; + + return true; +} + +bool asCDataType::IsMathType() const +{ + if( tokenType == ttInt || tokenType == ttInt8 || tokenType == ttInt16 || tokenType == ttInt64 || + tokenType == ttUInt || tokenType == ttUInt8 || tokenType == ttUInt16 || tokenType == ttUInt64 || + tokenType == ttFloat || tokenType == ttDouble ) + return true; + + return false; +} + +bool asCDataType::IsIntegerType() const +{ + if( tokenType == ttInt || + tokenType == ttInt8 || + tokenType == ttInt16 || + tokenType == ttInt64 ) + return true; + + // Enums are also integer types + return IsEnumType(); +} + +bool asCDataType::IsUnsignedType() const +{ + if( tokenType == ttUInt || + tokenType == ttUInt8 || + tokenType == ttUInt16 || + tokenType == ttUInt64 ) + return true; + + return false; +} + +bool asCDataType::IsFloatType() const +{ + if( tokenType == ttFloat ) + return true; + + return false; +} + +bool asCDataType::IsDoubleType() const +{ + if( tokenType == ttDouble ) + return true; + + return false; +} + +bool asCDataType::IsBooleanType() const +{ + if( tokenType == ttBool ) + return true; + + return false; +} + +bool asCDataType::IsObject() const +{ + if( IsPrimitive() ) + return false; + + // Null handle doesn't have an object type but should still be considered an object + if( typeInfo == 0 ) + return IsNullHandle(); + + // Template subtypes shouldn't be considered objects + return CastToObjectType(typeInfo) ? true : false; +} + +bool asCDataType::IsFuncdef() const +{ + if (typeInfo && (typeInfo->flags & asOBJ_FUNCDEF)) + return true; + + return false; +} + +int asCDataType::GetSizeInMemoryBytes() const +{ + if( typeInfo != 0 ) + return typeInfo->size; + + if( tokenType == ttVoid ) + return 0; + + if( tokenType == ttInt8 || + tokenType == ttUInt8 ) + return 1; + + if( tokenType == ttInt16 || + tokenType == ttUInt16 ) + return 2; + + if( tokenType == ttDouble || + tokenType == ttInt64 || + tokenType == ttUInt64 ) + return 8; + + if( tokenType == ttBool ) + return AS_SIZEOF_BOOL; + + // null handle + if( tokenType == ttUnrecognizedToken ) + return 4*AS_PTR_SIZE; + + return 4; +} + +int asCDataType::GetSizeInMemoryDWords() const +{ + int s = GetSizeInMemoryBytes(); + if( s == 0 ) return 0; + if( s <= 4 ) return 1; + + // Pad the size to 4 bytes + if( s & 0x3 ) + s += 4 - (s & 0x3); + + return s/4; +} + +int asCDataType::GetSizeOnStackDWords() const +{ + // If the type is the variable type then the typeid is stored on the stack too + int size = tokenType == ttQuestion ? 1 : 0; + + if( isReference ) return AS_PTR_SIZE + size; + if( typeInfo && !IsEnumType() ) return AS_PTR_SIZE + size; + + return GetSizeInMemoryDWords() + size; +} + +#ifdef WIP_16BYTE_ALIGN +int asCDataType::GetAlignment() const +{ + if( typeInfo == NULL ) + { + // TODO: Small primitives should not be aligned to 4 byte boundaries + return 4; //Default alignment + } + + return typeInfo->alignment; +} +#endif + +asSTypeBehaviour *asCDataType::GetBehaviour() const +{ + if (!typeInfo) return 0; + asCObjectType *ot = CastToObjectType(typeInfo); + return ot ? &ot->beh : 0; +} + +bool asCDataType::IsEnumType() const +{ + // Do a sanity check on the objectType, to verify that we aren't trying to access memory after it has been released + asASSERT(typeInfo == 0 || typeInfo->name.GetLength() < 100); + + if (typeInfo && (typeInfo->flags & asOBJ_ENUM)) + return true; + + return false; +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_datatype.h b/angelscript/source/as_datatype.h new file mode 100644 index 0000000..665f83a --- /dev/null +++ b/angelscript/source/as_datatype.h @@ -0,0 +1,161 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2016 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_datatype.h +// +// This class describes the datatype for expressions during compilation +// + + + +#ifndef AS_DATATYPE_H +#define AS_DATATYPE_H + +#include "as_tokendef.h" +#include "as_string.h" + +BEGIN_AS_NAMESPACE + +struct asSTypeBehaviour; +class asCScriptEngine; +class asCTypeInfo; +class asCScriptFunction; +class asCModule; +class asCObjectType; +class asCEnumType; +struct asSNameSpace; + +// TODO: refactor: Reference should not be part of the datatype. This should be stored separately, e.g. in asCExprValue +// MakeReference, MakeReadOnly, IsReference, IsReadOnly should be removed + +class asCDataType +{ +public: + asCDataType(); + asCDataType(const asCDataType &); + ~asCDataType(); + + bool IsValid() const; + + asCString Format(asSNameSpace *currNs, bool includeNamespace = false) const; + + static asCDataType CreatePrimitive(eTokenType tt, bool isConst); + static asCDataType CreateType(asCTypeInfo *ti, bool isConst); + static asCDataType CreateAuto(bool isConst); + static asCDataType CreateObjectHandle(asCTypeInfo *ot, bool isConst); + static asCDataType CreateNullHandle(); + + int MakeHandle(bool b, bool acceptHandleForScope = false); + int MakeArray(asCScriptEngine *engine, asCModule *requestingModule); + int MakeReference(bool b); + int MakeReadOnly(bool b); + int MakeHandleToConst(bool b); + void SetIfHandleThenConst(bool b) { ifHandleThenConst = b; } + bool HasIfHandleThenConst() const { return ifHandleThenConst; } + + bool IsTemplate() const; + bool IsScriptObject() const; + bool IsPrimitive() const; + bool IsMathType() const; + bool IsObject() const; + bool IsReference() const {return isReference;} + bool IsAuto() const {return isAuto;} + bool IsReadOnly() const; + bool IsIntegerType() const; + bool IsUnsignedType() const; + bool IsFloatType() const; + bool IsDoubleType() const; + bool IsBooleanType() const; + bool IsObjectHandle() const {return isObjectHandle;} + bool IsHandleToAuto() const {return isAuto && isObjectHandle;} + bool IsHandleToConst() const; + bool IsArrayType() const; + bool IsEnumType() const; + bool IsAnyType() const {return tokenType == ttQuestion;} + bool IsHandleToAsHandleType() const {return isHandleToAsHandleType;} + bool IsAbstractClass() const; + bool IsInterface() const; + bool IsFuncdef() const; + + bool IsObjectConst() const; + + bool IsEqualExceptRef(const asCDataType &) const; + bool IsEqualExceptRefAndConst(const asCDataType &) const; + bool IsEqualExceptConst(const asCDataType &) const; + bool IsNullHandle() const; + + bool SupportHandles() const; + bool CanBeInstantiated() const; + bool CanBeCopied() const; + + bool operator ==(const asCDataType &) const; + bool operator !=(const asCDataType &) const; + + asCDataType GetSubType(asUINT subtypeIndex = 0) const; + eTokenType GetTokenType() const {return tokenType;} + asCTypeInfo *GetTypeInfo() const { return typeInfo; } + + int GetSizeOnStackDWords() const; + int GetSizeInMemoryBytes() const; + int GetSizeInMemoryDWords() const; +#ifdef WIP_16BYTE_ALIGN + int GetAlignment() const; +#endif + + void SetTokenType(eTokenType tt) {tokenType = tt;} + void SetTypeInfo(asCTypeInfo *ti) {typeInfo = ti;} + + asCDataType &operator =(const asCDataType &); + + asSTypeBehaviour *GetBehaviour() const; + +protected: + // Base object type + eTokenType tokenType; + + // Behaviour type + asCTypeInfo *typeInfo; + + // Top level + bool isReference:1; + bool isReadOnly:1; + bool isObjectHandle:1; + bool isConstHandle:1; + bool isAuto:1; + bool isHandleToAsHandleType:1; // Used by the compiler to know how to initialize the object + bool ifHandleThenConst:1; // Used when creating template instances to determine if a handle should be const or not + char dummy:1; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_debug.h b/angelscript/source/as_debug.h new file mode 100644 index 0000000..e67d8b3 --- /dev/null +++ b/angelscript/source/as_debug.h @@ -0,0 +1,270 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2016 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_debug.h +// + +#ifndef AS_DEBUG_H +#define AS_DEBUG_H + +#include "as_config.h" + +#if defined(AS_DEBUG) + +#ifndef AS_WII +// The Wii SDK doesn't have these, we'll survive without AS_DEBUG + +#ifndef _WIN32_WCE +// Neither does WinCE + +#ifndef AS_PSVITA +// Possible on PSVita, but requires SDK access + +#if !defined(_MSC_VER) && (defined(__GNUC__) || defined(AS_MARMALADE)) + +#ifdef __ghs__ +// WIIU defines __GNUC__ but types are not defined here in 'conventional' way +#include +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef signed short int16_t; +typedef unsigned short uint16_t; +typedef signed int int32_t; +typedef unsigned int uint32_t; +typedef signed long long int64_t; +typedef unsigned long long uint64_t; +typedef float float32_t; +typedef double float64_t; +#else +// Define mkdir for GNUC +#include +#include +#define _mkdir(dirname) mkdir(dirname, S_IRWXU) +#endif +#else +#include +#endif + +#endif // AS_PSVITA +#endif // _WIN32_WCE +#endif // AS_WII + +#endif // !defined(AS_DEBUG) + + + +#if defined(_MSC_VER) && defined(AS_PROFILE) +// Currently only do profiling with MSVC++ + +#include +#include +#include "as_string.h" +#include "as_map.h" +#include "as_string_util.h" + +BEGIN_AS_NAMESPACE + +struct TimeCount +{ + double time; + int count; + double max; + double min; +}; + +class CProfiler +{ +public: + CProfiler() + { + // We need to know how often the clock is updated + __int64 tps; + if( !QueryPerformanceFrequency((LARGE_INTEGER *)&tps) ) + usePerformance = false; + else + { + usePerformance = true; + ticksPerSecond = double(tps); + } + + timeOffset = GetTime(); + } + + ~CProfiler() + { + WriteSummary(); + } + + double GetTime() + { + if( usePerformance ) + { + __int64 ticks; + QueryPerformanceCounter((LARGE_INTEGER *)&ticks); + + return double(ticks)/ticksPerSecond - timeOffset; + } + + return double(timeGetTime())/1000.0 - timeOffset; + } + + double Begin(const char *name) + { + double time = GetTime(); + + // Add the scope to the key + if( key.GetLength() ) + key += "|"; + key += name; + + // Compensate for the time spent writing to the file + timeOffset += GetTime() - time; + + return time; + } + + void End(const char * /*name*/, double beginTime) + { + double time = GetTime(); + + double elapsed = time - beginTime; + + // Update the profile info for this scope + asSMapNode *cursor; + if( map.MoveTo(&cursor, key) ) + { + cursor->value.time += elapsed; + cursor->value.count++; + if( cursor->value.max < elapsed ) + cursor->value.max = elapsed; + if( cursor->value.min > elapsed ) + cursor->value.min = elapsed; + } + else + { + TimeCount tc = {elapsed, 1, elapsed, elapsed}; + map.Insert(key, tc); + } + + // Remove the inner most scope from the key + int n = key.FindLast("|"); + if( n > 0 ) + key.SetLength(n); + else + key.SetLength(0); + + // Compensate for the time spent writing to the file + timeOffset += GetTime() - time; + } + +protected: + void WriteSummary() + { + // Write the analyzed info into a file for inspection + _mkdir("AS_DEBUG"); + FILE *fp; + #if _MSC_VER >= 1500 && !defined(AS_MARMALADE) + fopen_s(&fp, "AS_DEBUG/profiling_summary.txt", "wt"); + #else + fp = fopen("AS_DEBUG/profiling_summary.txt", "wt"); + #endif + if( fp == 0 ) + return; + + fprintf(fp, "%-60s %10s %15s %15s %15s %15s\n\n", "Scope", "Count", "Tot time", "Avg time", "Max time", "Min time"); + + asSMapNode *cursor; + map.MoveLast(&cursor); + while( cursor ) + { + asCString key = cursor->key; + int count; + int n = key.FindLast("|", &count); + if( count ) + { + key = asCString(" ", count) + key.SubString(n+1); + } + + fprintf(fp, "%-60s %10d %15.6f %15.6f %15.6f %15.6f\n", key.AddressOf(), cursor->value.count, cursor->value.time, cursor->value.time / cursor->value.count, cursor->value.max, cursor->value.min); + + map.MovePrev(&cursor, cursor); + } + + fclose(fp); + } + + double timeOffset; + double ticksPerSecond; + bool usePerformance; + + asCString key; + asCMap map; +}; + +extern CProfiler g_profiler; + +class CProfilerScope +{ +public: + CProfilerScope(const char *name) + { + this->name = name; + beginTime = g_profiler.Begin(name); + } + + ~CProfilerScope() + { + g_profiler.End(name, beginTime); + } + +protected: + const char *name; + double beginTime; +}; + +#define TimeIt(x) CProfilerScope profilescope(x) + +END_AS_NAMESPACE + +#else // !(_MSC_VER && AS_PROFILE) + +// Define it so nothing is done +#define TimeIt(x) + +#endif // !(_MSC_VER && AS_PROFILE) + + + + +#endif // defined(AS_DEBUG_H) + + diff --git a/angelscript/source/as_gc.cpp b/angelscript/source/as_gc.cpp new file mode 100644 index 0000000..d6004e3 --- /dev/null +++ b/angelscript/source/as_gc.cpp @@ -0,0 +1,997 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2018 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_gc.cpp +// +// The implementation of the garbage collector +// + + +#include + +#include "as_gc.h" +#include "as_scriptengine.h" +#include "as_scriptobject.h" +#include "as_texts.h" + +BEGIN_AS_NAMESPACE + +asCGarbageCollector::asCGarbageCollector() +{ + engine = 0; + detectState = clearCounters_init; + destroyNewState = destroyGarbage_init; + destroyOldState = destroyGarbage_init; + numDestroyed = 0; + numNewDestroyed = 0; + numDetected = 0; + numAdded = 0; + isProcessing = false; + + seqAtSweepStart[0] = 0; + seqAtSweepStart[1] = 0; + seqAtSweepStart[2] = 0; + + circularRefDetectCallbackFunc = 0; + circularRefDetectCallbackParam = 0; +} + +asCGarbageCollector::~asCGarbageCollector() +{ + // This local typedef is done to workaround a compiler error on + // MSVC6 when using the typedef declared in the class definition + typedef asSMapNode_t node_t; + for( asUINT n = 0; n < freeNodes.GetLength(); n++ ) + asDELETE(freeNodes[n], node_t); + freeNodes.SetLength(0); +} + +int asCGarbageCollector::AddScriptObjectToGC(void *obj, asCObjectType *objType) +{ + if( obj == 0 || objType == 0 ) + { + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GC_RECEIVED_NULL_PTR); + return asINVALID_ARG; + } + + engine->CallObjectMethod(obj, objType->beh.addref); + asSObjTypePair ot = {obj, objType, 0}; + + // Invoke the garbage collector to destroy a little garbage as new comes in + // This will maintain the number of objects in the GC at a maintainable level without + // halting the application, and without burdening the application with manually invoking the + // garbage collector. + if( engine->ep.autoGarbageCollect && gcNewObjects.GetLength() ) + { + // If the GC is already processing in another thread, then don't try this again + if( TRYENTERCRITICALSECTION(gcCollecting) ) + { + // Skip this if the GC is already running in this thread + if( !isProcessing ) + { + isProcessing = true; + + // TODO: The number of iterations should be dynamic, and increase + // if the number of objects in the garbage collector grows high + + // Run one step of DetectGarbage + if( gcOldObjects.GetLength() ) + { + IdentifyGarbageWithCyclicRefs(); + DestroyOldGarbage(); + } + + // Run a few steps of DestroyGarbage + int iter = (int)gcNewObjects.GetLength(); + if( iter > 10 ) iter = 10; + while( iter-- > 0 ) + DestroyNewGarbage(); + + isProcessing = false; + } + + LEAVECRITICALSECTION(gcCollecting); + } + } + + // Add the data to the gcObjects array in a critical section as + // another thread might be calling this method at the same time + ENTERCRITICALSECTION(gcCritical); + ot.seqNbr = numAdded++; + gcNewObjects.PushLast(ot); + LEAVECRITICALSECTION(gcCritical); + + return ot.seqNbr; +} + +int asCGarbageCollector::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type) +{ + if( seqNbr ) *seqNbr = 0; + if( obj ) *obj = 0; + if( type ) *type = 0; + + ENTERCRITICALSECTION(gcCritical); + asSObjTypePair *o = 0; + asUINT newObjs = asUINT(gcNewObjects.GetLength()); + if( idx < newObjs ) + o = &gcNewObjects[idx]; + else if( idx < gcOldObjects.GetLength() + newObjs ) + o = &gcOldObjects[idx-newObjs]; + else + { + LEAVECRITICALSECTION(gcCritical); + return asINVALID_ARG; + } + if( seqNbr ) *seqNbr = o->seqNbr; + if( obj ) *obj = o->obj; + if( type ) *type = o->type; + LEAVECRITICALSECTION(gcCritical); + + return asSUCCESS; +} + +// TODO: Should have a flag to tell the garbage collector to automatically determine how many iterations are needed +// It should then gather statistics such as how many objects has been created since last run, and how many objects +// are destroyed per iteration, and how many objects are detected as cyclic garbage per iteration. +// It should try to reach a stable number of objects, i.e. so that on average the number of objects added to +// the garbage collector is the same as the number of objects destroyed. And it should try to minimize the number +// of iterations of detections that must be executed per cycle while still identifying the cyclic garbage +// These variables should also be available for inspection through the gcstatistics. +int asCGarbageCollector::GarbageCollect(asDWORD flags, asUINT iterations) +{ + // If the GC is already processing in another thread, then don't enter here again + if( TRYENTERCRITICALSECTION(gcCollecting) ) + { + // If the GC is already processing in this thread, then don't enter here again + if( isProcessing ) + { + LEAVECRITICALSECTION(gcCollecting); + return 1; + } + + isProcessing = true; + + bool doDetect = (flags & asGC_DETECT_GARBAGE) || !(flags & asGC_DESTROY_GARBAGE); + bool doDestroy = (flags & asGC_DESTROY_GARBAGE) || !(flags & asGC_DETECT_GARBAGE); + + if( flags & asGC_FULL_CYCLE ) + { + // Reset the state + if( doDetect ) + { + // Move all new objects to the old list, so we guarantee that all is detected + MoveAllObjectsToOldList(); + detectState = clearCounters_init; + } + if( doDestroy ) + { + destroyNewState = destroyGarbage_init; + destroyOldState = destroyGarbage_init; + } + + // The full cycle only works with the objects in the old list so that the + // set of objects scanned for garbage is fixed even if new objects are added + // by other threads in parallel. + unsigned int count = (unsigned int)(gcOldObjects.GetLength()); + for(;;) + { + // Detect all garbage with cyclic references + if( doDetect ) + while( IdentifyGarbageWithCyclicRefs() == 1 ) {} + + // Now destroy all known garbage + if( doDestroy ) + { + if( !doDetect ) + while( DestroyNewGarbage() == 1 ) {} + while( DestroyOldGarbage() == 1 ) {} + } + + // Run another iteration if any garbage was destroyed + if( count != (unsigned int)(gcOldObjects.GetLength()) ) + count = (unsigned int)(gcOldObjects.GetLength()); + else + break; + } + + isProcessing = false; + LEAVECRITICALSECTION(gcCollecting); + return 0; + } + else + { + while( iterations-- > 0 ) + { + // Destroy the garbage that we know of + if( doDestroy ) + { + DestroyNewGarbage(); + DestroyOldGarbage(); + } + + // Run another incremental step of the identification of cyclic references + if( doDetect && gcOldObjects.GetLength() > 0 ) + IdentifyGarbageWithCyclicRefs(); + } + } + + isProcessing = false; + LEAVECRITICALSECTION(gcCollecting); + } + + // Return 1 to indicate that the cycle wasn't finished + return 1; +} + +// TODO: Additional statistics to gather +// +// - How many objects are added on average between each destroyed object +// - How many objects are added on average between each detected object +// - how many iterations are needed for each destroyed object +// - how many iterations are needed for each detected object +// +// The average must have a decay so that long running applications will not suffer +// from objects being created early on in the application and then never destroyed. +// +// This ought to be possible to accomplish by holding two buckets. +// Numbers will be accumulated in one bucket while the other is held fixed. +// When returning the average it should use a weighted average between the two buckets using the size as weight. +// When a bucket is filled up, the buckets are switched, and then new bucket is emptied to gather new statistics. +void asCGarbageCollector::GetStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const +{ + // It is not necessary to protect this with critical sections, however + // as it is not protected the variables can be filled in slightly different + // moments and might not match perfectly when inspected by the application + // afterwards. + + if( currentSize ) + *currentSize = (asUINT)(gcNewObjects.GetLength() + gcOldObjects.GetLength()); + + if( totalDestroyed ) + *totalDestroyed = numDestroyed; + + if( totalDetected ) + *totalDetected = numDetected; + + if( newObjects ) + *newObjects = (asUINT)gcNewObjects.GetLength(); + + if( totalNewDestroyed ) + *totalNewDestroyed = numNewDestroyed; +} + +asCGarbageCollector::asSObjTypePair asCGarbageCollector::GetNewObjectAtIdx(int idx) +{ + // We need to protect this access with a critical section as + // another thread might be appending an object at the same time + ENTERCRITICALSECTION(gcCritical); + asSObjTypePair gcObj = gcNewObjects[idx]; + LEAVECRITICALSECTION(gcCritical); + + return gcObj; +} + +asCGarbageCollector::asSObjTypePair asCGarbageCollector::GetOldObjectAtIdx(int idx) +{ + // We need to protect this access with a critical section as + // another thread might be appending an object at the same time + ENTERCRITICALSECTION(gcCritical); + asSObjTypePair gcObj = gcOldObjects[idx]; + LEAVECRITICALSECTION(gcCritical); + + return gcObj; +} + +void asCGarbageCollector::RemoveNewObjectAtIdx(int idx) +{ + // We need to protect this update with a critical section as + // another thread might be appending an object at the same time + ENTERCRITICALSECTION(gcCritical); + if( idx == (int)gcNewObjects.GetLength() - 1) + gcNewObjects.PopLast(); + else + gcNewObjects[idx] = gcNewObjects.PopLast(); + LEAVECRITICALSECTION(gcCritical); +} + +void asCGarbageCollector::RemoveOldObjectAtIdx(int idx) +{ + // We need to protect this update with a critical section as + // another thread might be appending an object at the same time + ENTERCRITICALSECTION(gcCritical); + if( idx == (int)gcOldObjects.GetLength() - 1) + gcOldObjects.PopLast(); + else + gcOldObjects[idx] = gcOldObjects.PopLast(); + LEAVECRITICALSECTION(gcCritical); +} + +void asCGarbageCollector::MoveObjectToOldList(int idx) +{ + // We need to protect this update with a critical section as + // another thread might be appending an object at the same time + ENTERCRITICALSECTION(gcCritical); + gcOldObjects.PushLast(gcNewObjects[idx]); + if( idx == (int)gcNewObjects.GetLength() - 1) + gcNewObjects.PopLast(); + else + gcNewObjects[idx] = gcNewObjects.PopLast(); + LEAVECRITICALSECTION(gcCritical); +} + +void asCGarbageCollector::MoveAllObjectsToOldList() +{ + // We need to protect this update with a critical section as + // another thread might be appending an object at the same time + ENTERCRITICALSECTION(gcCritical); + if( gcOldObjects.Concatenate(gcNewObjects) ) + gcNewObjects.SetLength(0); + LEAVECRITICALSECTION(gcCritical); +} + +int asCGarbageCollector::DestroyNewGarbage() +{ + // This function will only be called within the critical section gcCollecting + asASSERT(isProcessing); + + for(;;) + { + switch( destroyNewState ) + { + case destroyGarbage_init: + { + // If there are no objects to be freed then don't start + if( gcNewObjects.GetLength() == 0 ) + return 0; + + // Update the seqAtSweepStart which is used to determine when + // to move an object from the new set to the old set + seqAtSweepStart[0] = seqAtSweepStart[1]; + seqAtSweepStart[1] = seqAtSweepStart[2]; + seqAtSweepStart[2] = numAdded; + + destroyNewIdx = (asUINT)-1; + destroyNewState = destroyGarbage_loop; + } + break; + + case destroyGarbage_loop: + case destroyGarbage_haveMore: + { + // If the refCount has reached 1, then only the GC still holds a + // reference to the object, thus we don't need to worry about the + // application touching the objects during collection. + + // Destroy all objects that have refCount == 1. If any objects are + // destroyed, go over the list again, because it may have made more + // objects reach refCount == 1. + if( ++destroyNewIdx < gcNewObjects.GetLength() ) + { + asSObjTypePair gcObj = GetNewObjectAtIdx(destroyNewIdx); + if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 ) + { + // Release the object immediately + + // Make sure the refCount is really 0, because the + // destructor may have increased the refCount again. + bool addRef = false; + if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT ) + { + // Script objects may actually be resurrected in the destructor + int refCount = ((asCScriptObject*)gcObj.obj)->Release(); + if( refCount > 0 ) addRef = true; + } + else + engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); + + // Was the object really destroyed? + if( !addRef ) + { + numDestroyed++; + numNewDestroyed++; + RemoveNewObjectAtIdx(destroyNewIdx); + destroyNewIdx--; + } + else + { + // Since the object was resurrected in the + // destructor, we must add our reference again + engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); + } + + destroyNewState = destroyGarbage_haveMore; + } + // Check if this object has been inspected 3 times already, and if so move it to the + // set of old objects that are less likely to become garbage in a short time + // TODO: Is 3 really a good value? Should the number of times be dynamic? + else if( gcObj.seqNbr < seqAtSweepStart[0] ) + { + // We've already verified this object multiple times. It is likely + // to live for quite a long time so we'll move it to the list if old objects + MoveObjectToOldList(destroyNewIdx); + destroyNewIdx--; + } + + // Allow the application to work a little + return 1; + } + else + { + if( destroyNewState == destroyGarbage_haveMore ) + { + // Restart the cycle + destroyNewState = destroyGarbage_init; + } + else + { + // Restart the cycle + destroyNewState = destroyGarbage_init; + + // Return 0 to tell the application that there + // is no more garbage to destroy at the moment + return 0; + } + } + } + break; + } + } + + // Shouldn't reach this point + UNREACHABLE_RETURN; +} + +int asCGarbageCollector::ReportAndReleaseUndestroyedObjects() +{ + // This function will only be called as the engine is shutting down + + int items = 0; + for( asUINT n = 0; n < gcOldObjects.GetLength(); n++ ) + { + asSObjTypePair gcObj = GetOldObjectAtIdx(n); + + int refCount = 0; + if( gcObj.type->beh.gcGetRefCount && engine->scriptFunctions[gcObj.type->beh.gcGetRefCount] ) + refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount); + + // Report the object as not being properly destroyed + asCString msg; + msg.Format(TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d, gcObj.seqNbr, gcObj.type->name.AddressOf(), refCount - 1); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + + // Add additional info for builtin types + if( gcObj.type->name == "$func" ) + { + // Unfortunately we can't show the function declaration here, because the engine may have released the parameter list already so the declaration would only be misleading + // We need to show the function type too as for example delegates do not have a name + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, reinterpret_cast(gcObj.obj)->GetName(), reinterpret_cast(gcObj.obj)->GetFuncType()); + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + else if( gcObj.type->name == "$obj" ) + { + msg.Format(TXT_PREV_TYPE_IS_NAMED_s, reinterpret_cast(gcObj.obj)->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + + // Release the reference that the GC holds if the release functions is still available + if( gcObj.type->beh.release && engine->scriptFunctions[gcObj.type->beh.release] ) + engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); + + items++; + } + return items; +} + +int asCGarbageCollector::DestroyOldGarbage() +{ + // This function will only be called within the critical section gcCollecting + asASSERT(isProcessing); + + for(;;) + { + switch( destroyOldState ) + { + case destroyGarbage_init: + { + // If there are no objects to be freed then don't start + if( gcOldObjects.GetLength() == 0 ) + return 0; + + destroyOldIdx = (asUINT)-1; + destroyOldState = destroyGarbage_loop; + } + break; + + case destroyGarbage_loop: + case destroyGarbage_haveMore: + { + // If the refCount has reached 1, then only the GC still holds a + // reference to the object, thus we don't need to worry about the + // application touching the objects during collection. + + // Destroy all objects that have refCount == 1. If any objects are + // destroyed, go over the list again, because it may have made more + // objects reach refCount == 1. + if( ++destroyOldIdx < gcOldObjects.GetLength() ) + { + asSObjTypePair gcObj = GetOldObjectAtIdx(destroyOldIdx); + + if( gcObj.type->beh.gcGetRefCount == 0 ) + { + // If circular references are formed with registered types that hasn't + // registered the GC behaviours, then the engine may be forced to free + // the object type before the actual object instance. In this case we + // will be forced to skip the destruction of the objects, so as not to + // crash the application. + asCString msg; + msg.Format(TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s, gcObj.seqNbr, gcObj.type->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + + // Just remove the object, as we will not bother to destroy it + numDestroyed++; + RemoveOldObjectAtIdx(destroyOldIdx); + destroyOldIdx--; + } + else if( engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount) == 1 ) + { + // Release the object immediately + + // Make sure the refCount is really 0, because the + // destructor may have increased the refCount again. + bool addRef = false; + if( gcObj.type->flags & asOBJ_SCRIPT_OBJECT ) + { + // Script objects may actually be resurrected in the destructor + int refCount = ((asCScriptObject*)gcObj.obj)->Release(); + if( refCount > 0 ) addRef = true; + } + else + engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.release); + + // Was the object really destroyed? + if( !addRef ) + { + numDestroyed++; + RemoveOldObjectAtIdx(destroyOldIdx); + destroyOldIdx--; + } + else + { + // Since the object was resurrected in the + // destructor, we must add our reference again + engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); + } + + destroyOldState = destroyGarbage_haveMore; + } + + // Allow the application to work a little + return 1; + } + else + { + if( destroyOldState == destroyGarbage_haveMore ) + { + // Restart the cycle + destroyOldState = destroyGarbage_init; + } + else + { + // Restart the cycle + destroyOldState = destroyGarbage_init; + + // Return 0 to tell the application that there + // is no more garbage to destroy at the moment + return 0; + } + } + } + break; + } + } + + // Shouldn't reach this point + UNREACHABLE_RETURN; +} + +int asCGarbageCollector::IdentifyGarbageWithCyclicRefs() +{ + // This function will only be called within the critical section gcCollecting + asASSERT(isProcessing); + + for(;;) + { + switch( detectState ) + { + case clearCounters_init: + detectState = clearCounters_loop; + break; + + case clearCounters_loop: + { + // Decrease reference counter for all objects removed from the map + asSMapNode *cursor = 0; + gcMap.MoveFirst(&cursor); + if( cursor ) + { + void *obj = gcMap.GetKey(cursor); + asSIntTypePair it = gcMap.GetValue(cursor); + + engine->CallObjectMethod(obj, it.type->beh.release); + + ReturnNode(gcMap.Remove(cursor)); + + return 1; + } + + detectState = buildMap_init; + } + break; + + case buildMap_init: + detectIdx = 0; + detectState = buildMap_loop; + break; + + case buildMap_loop: + { + // Build a map of objects that will be checked, the map will + // hold the object pointer as key, and the gcCount and the + // object's type as value. As objects are added to the map the + // gcFlag must be set in the objects, so we can be verify if + // the object is accessed during the GC cycle. + + // If an object is removed from the gcObjects list during the + // iteration of this step, it is possible that an object won't + // be used during the analyzing for cyclic references. This + // isn't a problem, as the next time the GC cycle starts the + // object will be verified. + if( detectIdx < gcOldObjects.GetLength() ) + { + // Add the gc count for this object + asSObjTypePair gcObj = GetOldObjectAtIdx(detectIdx); + + int refCount = 0; + if( gcObj.type->beh.gcGetRefCount ) + refCount = engine->CallObjectMethodRetInt(gcObj.obj, gcObj.type->beh.gcGetRefCount); + + if( refCount > 1 ) + { + asSIntTypePair it = {refCount-1, gcObj.type}; + + gcMap.Insert(GetNode(gcObj.obj, it)); + + // Increment the object's reference counter when putting it in the map + engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.addref); + + // Mark the object so that we can + // see if it has changed since read + engine->CallObjectMethod(gcObj.obj, gcObj.type->beh.gcSetFlag); + } + + detectIdx++; + + // Let the application work a little + return 1; + } + else + detectState = countReferences_init; + } + break; + + case countReferences_init: + { + gcMap.MoveFirst(&gcMapCursor); + detectState = countReferences_loop; + } + break; + + case countReferences_loop: + { + // Call EnumReferences on all objects in the map to count the number + // of references reachable from between objects in the map. If all + // references for an object in the map is reachable from other objects + // in the map, then we know that no outside references are held for + // this object, thus it is a potential dead object in a circular reference. + + // If the gcFlag is cleared for an object we consider the object alive + // and referenced from outside the GC, thus we don't enumerate its references. + + // Any new objects created after this step in the GC cycle won't be + // in the map, and is thus automatically considered alive. + if( gcMapCursor ) + { + void *obj = gcMap.GetKey(gcMapCursor); + asCObjectType *type = gcMap.GetValue(gcMapCursor).type; + gcMap.MoveNext(&gcMapCursor, gcMapCursor); + + if( engine->CallObjectMethodRetBool(obj, type->beh.gcGetFlag) ) + { + engine->CallObjectMethod(obj, engine, type->beh.gcEnumReferences); + } + + // Allow the application to work a little + return 1; + } + else + detectState = detectGarbage_init; + } + break; + + case detectGarbage_init: + { + gcMap.MoveFirst(&gcMapCursor); + liveObjects.SetLength(0); + detectState = detectGarbage_loop1; + } + break; + + case detectGarbage_loop1: + { + // All objects that are known not to be dead must be removed from the map, + // along with all objects they reference. What remains in the map after + // this pass is sure to be dead objects in circular references. + + // An object is considered alive if its gcFlag is cleared, or all the + // references were not found in the map. + + // Add all alive objects from the map to the liveObjects array + if( gcMapCursor ) + { + asSMapNode *cursor = gcMapCursor; + gcMap.MoveNext(&gcMapCursor, gcMapCursor); + + void *obj = gcMap.GetKey(cursor); + asSIntTypePair it = gcMap.GetValue(cursor); + + bool gcFlag = engine->CallObjectMethodRetBool(obj, it.type->beh.gcGetFlag); + if( !gcFlag || it.i > 0 ) + { + liveObjects.PushLast(obj); + } + + // Allow the application to work a little + return 1; + } + else + detectState = detectGarbage_loop2; + } + break; + + case detectGarbage_loop2: + { + // In this step we are actually removing the alive objects from the map. + // As the object is removed, all the objects it references are added to the + // liveObjects list, by calling EnumReferences. Only objects still in the map + // will be added to the liveObjects list. + if( liveObjects.GetLength() ) + { + void *gcObj = liveObjects.PopLast(); + asCObjectType *type = 0; + + // Remove the object from the map to mark it as alive + asSMapNode *cursor = 0; + if( gcMap.MoveTo(&cursor, gcObj) ) + { + type = gcMap.GetValue(cursor).type; + ReturnNode(gcMap.Remove(cursor)); + + // We need to decrease the reference count again as we remove the object from the map + engine->CallObjectMethod(gcObj, type->beh.release); + + // Enumerate all the object's references so that they too can be marked as alive + engine->CallObjectMethod(gcObj, engine, type->beh.gcEnumReferences); + } + + // Allow the application to work a little + return 1; + } + else + detectState = verifyUnmarked_init; + } + break; + + case verifyUnmarked_init: + gcMap.MoveFirst(&gcMapCursor); + detectState = verifyUnmarked_loop; + break; + + case verifyUnmarked_loop: + { + // In this step we must make sure that none of the objects still in the map + // has been touched by the application. If they have then we must run the + // detectGarbage loop once more. + if( gcMapCursor ) + { + void *gcObj = gcMap.GetKey(gcMapCursor); + asCObjectType *type = gcMap.GetValue(gcMapCursor).type; + + bool gcFlag = engine->CallObjectMethodRetBool(gcObj, type->beh.gcGetFlag); + if( !gcFlag ) + { + // The unmarked object was touched, rerun the detectGarbage loop + detectState = detectGarbage_init; + } + else + gcMap.MoveNext(&gcMapCursor, gcMapCursor); + + // Allow the application to work a little + return 1; + } + else + { + // No unmarked object was touched, we can now be sure + // that objects that have gcCount == 0 really is garbage + detectState = breakCircles_init; + } + } + break; + + case breakCircles_init: + { + gcMap.MoveFirst(&gcMapCursor); + detectState = breakCircles_loop; + + // If the application has requested a callback for detected circular references, + // then make that callback now for all the objects in the list. This step is not + // done in incremental steps as it is only meant for debugging purposes and thus + // doesn't require interactivity + if (gcMapCursor && circularRefDetectCallbackFunc) + { + while (gcMapCursor) + { + void *gcObj = gcMap.GetKey(gcMapCursor); + asCObjectType *type = gcMap.GetValue(gcMapCursor).type; + circularRefDetectCallbackFunc(type, gcObj, circularRefDetectCallbackParam); + + gcMap.MoveNext(&gcMapCursor, gcMapCursor); + } + + // Reset iterator + gcMap.MoveFirst(&gcMapCursor); + } + } + break; + + case breakCircles_loop: + case breakCircles_haveGarbage: + { + // All objects in the map are now known to be dead objects + // kept alive through circular references. To be able to free + // these objects we need to force the breaking of the circle + // by having the objects release their references. + if( gcMapCursor ) + { + numDetected++; + void *gcObj = gcMap.GetKey(gcMapCursor); + asCObjectType *type = gcMap.GetValue(gcMapCursor).type; + if( type->flags & asOBJ_SCRIPT_OBJECT ) + { + // For script objects we must call the class destructor before + // releasing the references, otherwise the destructor may not + // be able to perform the necessary clean-up as the handles will + // be null. + reinterpret_cast(gcObj)->CallDestructor(); + } + engine->CallObjectMethod(gcObj, engine, type->beh.gcReleaseAllReferences); + + gcMap.MoveNext(&gcMapCursor, gcMapCursor); + + detectState = breakCircles_haveGarbage; + + // Allow the application to work a little + return 1; + } + else + { + // If no garbage was detected we can finish now + if( detectState != breakCircles_haveGarbage ) + { + // Restart the GC + detectState = clearCounters_init; + return 0; + } + else + { + // Restart the GC + detectState = clearCounters_init; + return 1; + } + } + } + } // switch + } + + // Shouldn't reach this point + UNREACHABLE_RETURN; +} + +asCGarbageCollector::asSMapNode_t *asCGarbageCollector::GetNode(void *obj, asSIntTypePair it) +{ + // This function will only be called within the critical section gcCollecting + asASSERT(isProcessing); + + asSMapNode_t *node; + if( freeNodes.GetLength() ) + node = freeNodes.PopLast(); + else + { + node = asNEW(asSMapNode_t); + if( !node ) + { + // Out of memory + return 0; + } + } + + node->Init(obj, it); + return node; +} + +void asCGarbageCollector::ReturnNode(asSMapNode_t *node) +{ + // This function will only be called within the critical section gcCollecting + asASSERT(isProcessing); + + if( node ) + freeNodes.PushLast(node); +} + +void asCGarbageCollector::GCEnumCallback(void *reference) +{ + // This function will only be called within the critical section gcCollecting + asASSERT(isProcessing); + + if( detectState == countReferences_loop ) + { + // Find the reference in the map + asSMapNode *cursor = 0; + if( gcMap.MoveTo(&cursor, reference) ) + { + // Decrease the counter in the map for the reference + gcMap.GetValue(cursor).i--; + } + } + else if( detectState == detectGarbage_loop2 ) + { + // Find the reference in the map + asSMapNode *cursor = 0; + if( gcMap.MoveTo(&cursor, reference) ) + { + // Add the object to the list of objects to mark as alive + liveObjects.PushLast(reference); + } + } +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_gc.h b/angelscript/source/as_gc.h new file mode 100644 index 0000000..76f2735 --- /dev/null +++ b/angelscript/source/as_gc.h @@ -0,0 +1,151 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2018 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_gc.h +// +// The garbage collector is used to resolve cyclic references +// + + + +#ifndef AS_GC_H +#define AS_GC_H + +#include "as_config.h" +#include "as_array.h" +#include "as_map.h" +#include "as_thread.h" + +BEGIN_AS_NAMESPACE + +class asCScriptEngine; +class asCObjectType; + +class asCGarbageCollector +{ +public: + asCGarbageCollector(); + ~asCGarbageCollector(); + + int GarbageCollect(asDWORD flags, asUINT iterations); + void GetStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const; + void GCEnumCallback(void *reference); + int AddScriptObjectToGC(void *obj, asCObjectType *objType); + int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type); + + int ReportAndReleaseUndestroyedObjects(); + + asCScriptEngine *engine; + + // Callback for when circular reference are detected + asCIRCULARREFFUNC_t circularRefDetectCallbackFunc; + void * circularRefDetectCallbackParam; + +protected: + struct asSObjTypePair {void *obj; asCObjectType *type; asUINT seqNbr;}; + struct asSIntTypePair {int i; asCObjectType *type;}; + typedef asSMapNode asSMapNode_t; + + enum egcDestroyState + { + destroyGarbage_init = 0, + destroyGarbage_loop, + destroyGarbage_haveMore + }; + + enum egcDetectState + { + clearCounters_init = 0, + clearCounters_loop, + buildMap_init, + buildMap_loop, + countReferences_init, + countReferences_loop, + detectGarbage_init, + detectGarbage_loop1, + detectGarbage_loop2, + verifyUnmarked_init, + verifyUnmarked_loop, + breakCircles_init, + breakCircles_loop, + breakCircles_haveGarbage + }; + + int DestroyNewGarbage(); + int DestroyOldGarbage(); + int IdentifyGarbageWithCyclicRefs(); + asSObjTypePair GetNewObjectAtIdx(int idx); + asSObjTypePair GetOldObjectAtIdx(int idx); + void RemoveNewObjectAtIdx(int idx); + void RemoveOldObjectAtIdx(int idx); + void MoveObjectToOldList(int idx); + void MoveAllObjectsToOldList(); + + // Holds all the objects known by the garbage collector + asCArray gcNewObjects; + asCArray gcOldObjects; + + // This array temporarily holds references to objects known to be live objects + asCArray liveObjects; + + // This map holds objects currently being searched for cyclic references, it also holds a + // counter that gives the number of references to the object that the GC can't reach + asCMap gcMap; + + // State variables + egcDestroyState destroyNewState; + egcDestroyState destroyOldState; + asUINT destroyNewIdx; + asUINT destroyOldIdx; + asUINT numDestroyed; + asUINT numNewDestroyed; + egcDetectState detectState; + asUINT detectIdx; + asUINT numDetected; + asUINT numAdded; + asUINT seqAtSweepStart[3]; + asSMapNode_t *gcMapCursor; + bool isProcessing; + + // We'll keep a pool of nodes to avoid allocating memory all the time + asSMapNode_t *GetNode(void *obj, asSIntTypePair it); + void ReturnNode(asSMapNode_t *node); + asCArray freeNodes; + + // Critical section for multithreaded access + DECLARECRITICALSECTION(gcCritical) // Used for adding/removing objects + DECLARECRITICALSECTION(gcCollecting) // Used for processing +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_generic.cpp b/angelscript/source/as_generic.cpp new file mode 100644 index 0000000..14dd9cb --- /dev/null +++ b/angelscript/source/as_generic.cpp @@ -0,0 +1,534 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2016 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_generic.cpp +// +// This class handles the call to a function registered with asCALL_GENERIC +// + +#include "as_generic.h" +#include "as_scriptfunction.h" +#include "as_objecttype.h" +#include "as_scriptengine.h" + +BEGIN_AS_NAMESPACE + +// TODO: runtime optimize: The access to the arguments should be optimized so that code +// doesn't have to count the position of the argument with every call + +// internal +asCGeneric::asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer) +{ + this->engine = engine; + this->sysFunction = sysFunction; + this->currentObject = currentObject; + this->stackPointer = stackPointer; + + objectRegister = 0; + returnVal = 0; +} + +// internal +asCGeneric::~asCGeneric() +{ +} + +// interface +void *asCGeneric::GetAuxiliary() const +{ + return sysFunction->GetAuxiliary(); +} + +// interface +asIScriptEngine *asCGeneric::GetEngine() const +{ + return (asIScriptEngine*)engine; +} + +// interface +asIScriptFunction *asCGeneric::GetFunction() const +{ + return sysFunction; +} + +// interface +void *asCGeneric::GetObject() +{ + return currentObject; +} + +// interface +int asCGeneric::GetObjectTypeId() const +{ + asCDataType dt = asCDataType::CreateType(sysFunction->objectType, false); + return engine->GetTypeIdFromDataType(dt); +} + +// interface +int asCGeneric::GetArgCount() const +{ + return (int)sysFunction->parameterTypes.GetLength(); +} + +// interface +asBYTE asCGeneric::GetArgByte(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; + + if( dt->GetSizeInMemoryBytes() != 1 ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return *(asBYTE*)&stackPointer[offset]; +} + +// interface +asWORD asCGeneric::GetArgWord(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; + + if( dt->GetSizeInMemoryBytes() != 2 ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return *(asWORD*)&stackPointer[offset]; +} + +// interface +asDWORD asCGeneric::GetArgDWord(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; + + if( dt->GetSizeInMemoryBytes() != 4 ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return *(asDWORD*)&stackPointer[offset]; +} + +// interface +asQWORD asCGeneric::GetArgQWord(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; + + if( dt->GetSizeInMemoryBytes() != 8 ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return *(asQWORD*)(&stackPointer[offset]); +} + +// interface +float asCGeneric::GetArgFloat(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; + + if( dt->GetSizeInMemoryBytes() != 4 ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return *(float*)(&stackPointer[offset]); +} + +// interface +double asCGeneric::GetArgDouble(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( (dt->IsObject() || dt->IsFuncdef()) || dt->IsReference() ) + return 0; + + if( dt->GetSizeInMemoryBytes() != 8 ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return *(double*)(&stackPointer[offset]); +} + +// interface +void *asCGeneric::GetArgAddress(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( !dt->IsReference() && !dt->IsObjectHandle() ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return (void*)*(asPWORD*)(&stackPointer[offset]); +} + +// interface +void *asCGeneric::GetArgObject(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Verify that the type is correct + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( !dt->IsObject() && !dt->IsFuncdef() ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Get the value + return *(void**)(&stackPointer[offset]); +} + +// interface +void *asCGeneric::GetAddressOfArg(asUINT arg) +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + // Determine the position of the argument + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // For object variables it's necessary to dereference the pointer to get the address of the value + if( !sysFunction->parameterTypes[arg].IsReference() && + sysFunction->parameterTypes[arg].IsObject() && + !sysFunction->parameterTypes[arg].IsObjectHandle() ) + return *(void**)&stackPointer[offset]; + + // Get the address of the value + return &stackPointer[offset]; +} + +// interface +int asCGeneric::GetArgTypeId(asUINT arg, asDWORD *flags) const +{ + if( arg >= (unsigned)sysFunction->parameterTypes.GetLength() ) + return 0; + + if( flags ) + { + *flags = sysFunction->inOutFlags[arg]; + *flags |= sysFunction->parameterTypes[arg].IsReadOnly() ? asTM_CONST : 0; + } + + asCDataType *dt = &sysFunction->parameterTypes[arg]; + if( dt->GetTokenType() != ttQuestion ) + return engine->GetTypeIdFromDataType(*dt); + else + { + int offset = 0; + for( asUINT n = 0; n < arg; n++ ) + offset += sysFunction->parameterTypes[n].GetSizeOnStackDWords(); + + // Skip the actual value to get to the type id + offset += AS_PTR_SIZE; + + // Get the value + return stackPointer[offset]; + } +} + +// interface +int asCGeneric::SetReturnByte(asBYTE val) +{ + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; + + if( sysFunction->returnType.GetSizeInMemoryBytes() != 1 ) + return asINVALID_TYPE; + + // Store the value + *(asBYTE*)&returnVal = val; + + return 0; +} + +// interface +int asCGeneric::SetReturnWord(asWORD val) +{ + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; + + if( sysFunction->returnType.GetSizeInMemoryBytes() != 2 ) + return asINVALID_TYPE; + + // Store the value + *(asWORD*)&returnVal = val; + + return 0; +} + +// interface +int asCGeneric::SetReturnDWord(asDWORD val) +{ + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; + + if( sysFunction->returnType.GetSizeInMemoryBytes() != 4 ) + return asINVALID_TYPE; + + // Store the value + *(asDWORD*)&returnVal = val; + + return 0; +} + +// interface +int asCGeneric::SetReturnQWord(asQWORD val) +{ + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; + + if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) + return asINVALID_TYPE; + + // Store the value + returnVal = val; + + return 0; +} + +// interface +int asCGeneric::SetReturnFloat(float val) +{ + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; + + if( sysFunction->returnType.GetSizeOnStackDWords() != 1 ) + return asINVALID_TYPE; + + // Store the value + *(float*)&returnVal = val; + + return 0; +} + +// interface +int asCGeneric::SetReturnDouble(double val) +{ + // Verify the type of the return value + if( (sysFunction->returnType.IsObject() || sysFunction->returnType.IsFuncdef()) || sysFunction->returnType.IsReference() ) + return asINVALID_TYPE; + + if( sysFunction->returnType.GetSizeOnStackDWords() != 2 ) + return asINVALID_TYPE; + + // Store the value + *(double*)&returnVal = val; + + return 0; +} + +// interface +int asCGeneric::SetReturnAddress(void *val) +{ + // Verify the type of the return value + if( sysFunction->returnType.IsReference() ) + { + // Store the value + *(void**)&returnVal = val; + return 0; + } + else if( sysFunction->returnType.IsObjectHandle() ) + { + // Store the handle without increasing reference + objectRegister = val; + return 0; + } + + return asINVALID_TYPE; +} + +// interface +int asCGeneric::SetReturnObject(void *obj) +{ + asCDataType *dt = &sysFunction->returnType; + if( !dt->IsObject() && !dt->IsFuncdef() ) + return asINVALID_TYPE; + + if( dt->IsReference() ) + { + *(void**)&returnVal = obj; + return 0; + } + + if( dt->IsObjectHandle() ) + { + // Increase the reference counter + if (dt->IsFuncdef()) + { + if (obj) + reinterpret_cast(obj)->AddRef(); + } + else + { + asSTypeBehaviour *beh = &CastToObjectType(dt->GetTypeInfo())->beh; + if (obj && beh && beh->addref) + engine->CallObjectMethod(obj, beh->addref); + } + } + else + { + // If function returns object by value the memory is already allocated. + // Here we should just initialize that memory by calling the copy constructor + // or the default constructor followed by the assignment operator + void *mem = (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE]; + engine->ConstructScriptObjectCopy(mem, obj, CastToObjectType(dt->GetTypeInfo())); + return 0; + } + + objectRegister = obj; + + return 0; +} + +// internal +void *asCGeneric::GetReturnPointer() +{ + asCDataType &dt = sysFunction->returnType; + + if( (dt.IsObject() ||dt.IsFuncdef()) && !dt.IsReference() ) + { + // This function doesn't support returning on the stack but the use of + // the function doesn't require it so we don't need to implement it here. + asASSERT( !sysFunction->DoesReturnOnStack() ); + + return &objectRegister; + } + + return &returnVal; +} + +// interface +void *asCGeneric::GetAddressOfReturnLocation() +{ + asCDataType &dt = sysFunction->returnType; + + if( (dt.IsObject() || dt.IsFuncdef()) && !dt.IsReference() ) + { + if( sysFunction->DoesReturnOnStack() ) + { + // The memory is already preallocated on the stack, + // and the pointer to the location is found before the first arg + return (void*)*(asPWORD*)&stackPointer[-AS_PTR_SIZE]; + } + + // Reference types store the handle in the objectReference + return &objectRegister; + } + + // Primitive types and references are stored in the returnVal property + return &returnVal; +} + +// interface +int asCGeneric::GetReturnTypeId(asDWORD *flags) const +{ + return sysFunction->GetReturnTypeId(flags); +} + +END_AS_NAMESPACE diff --git a/angelscript/source/as_generic.h b/angelscript/source/as_generic.h new file mode 100644 index 0000000..158d8f9 --- /dev/null +++ b/angelscript/source/as_generic.h @@ -0,0 +1,108 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_generic.h +// +// This class handles the call to a function registered with asCALL_GENERIC +// + + +#ifndef AS_GENERIC_H +#define AS_GENERIC_H + +#include "as_config.h" + +BEGIN_AS_NAMESPACE + +class asCScriptEngine; +class asCScriptFunction; + +class asCGeneric : public asIScriptGeneric +{ +public: +//------------------------------ +// asIScriptGeneric +//------------------------------ + // Miscellaneous + asIScriptEngine *GetEngine() const; + asIScriptFunction *GetFunction() const; + void *GetAuxiliary() const; + + // Object + void *GetObject(); + int GetObjectTypeId() const; + + // Arguments + int GetArgCount() const; + int GetArgTypeId(asUINT arg, asDWORD *flags = 0) const; + asBYTE GetArgByte(asUINT arg); + asWORD GetArgWord(asUINT arg); + asDWORD GetArgDWord(asUINT arg); + asQWORD GetArgQWord(asUINT arg); + float GetArgFloat(asUINT arg); + double GetArgDouble(asUINT arg); + void *GetArgAddress(asUINT arg); + void *GetArgObject(asUINT arg); + void *GetAddressOfArg(asUINT arg); + + // Return value + int GetReturnTypeId(asDWORD *flags = 0) const; + int SetReturnByte(asBYTE val); + int SetReturnWord(asWORD val); + int SetReturnDWord(asDWORD val); + int SetReturnQWord(asQWORD val); + int SetReturnFloat(float val); + int SetReturnDouble(double val); + int SetReturnAddress(void *addr); + int SetReturnObject(void *obj); + void *GetAddressOfReturnLocation(); + +//------------------------ +// internal +//------------------------- + asCGeneric(asCScriptEngine *engine, asCScriptFunction *sysFunction, void *currentObject, asDWORD *stackPointer); + virtual ~asCGeneric(); + + void *GetReturnPointer(); + + asCScriptEngine *engine; + asCScriptFunction *sysFunction; + void *currentObject; + asDWORD *stackPointer; + void *objectRegister; + + asQWORD returnVal; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_globalproperty.cpp b/angelscript/source/as_globalproperty.cpp new file mode 100644 index 0000000..3fe4627 --- /dev/null +++ b/angelscript/source/as_globalproperty.cpp @@ -0,0 +1,137 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + + +#include "as_config.h" +#include "as_property.h" +#include "as_scriptengine.h" + +BEGIN_AS_NAMESPACE + +asCGlobalProperty::asCGlobalProperty() +{ + memory = &storage; + memoryAllocated = false; + realAddress = 0; + initFunc = 0; + accessMask = 0xFFFFFFFF; + + refCount.set(1); +} + +asCGlobalProperty::~asCGlobalProperty() +{ +#ifndef WIP_16BYTE_ALIGNED + if( memoryAllocated ) { asDELETEARRAY(memory); } +#else + if( memoryAllocated ) { asDELETEARRAYALIGNED(memory); } +#endif + + if( initFunc ) + initFunc->ReleaseInternal(); +} + +void asCGlobalProperty::AddRef() +{ + refCount.atomicInc(); +} + +void asCGlobalProperty::Release() +{ + if( refCount.atomicDec() == 0 ) + asDELETE(this, asCGlobalProperty); +} + +void asCGlobalProperty::DestroyInternal() +{ + if( initFunc ) + { + initFunc->ReleaseInternal(); + initFunc = 0; + } +} + +void *asCGlobalProperty::GetAddressOfValue() +{ + return memory; +} + +// The global property structure is responsible for allocating the storage +// method for script declared variables. Each allocation is independent of +// other global properties, so that variables can be added and removed at +// any time. +void asCGlobalProperty::AllocateMemory() +{ + if( type.GetSizeOnStackDWords() > 2 ) + { +#ifndef WIP_16BYTE_ALIGNED + memory = asNEWARRAY(asDWORD, type.GetSizeOnStackDWords()); +#else + // TODO: Avoid aligned allocation if not needed to reduce the waste of memory for the alignment + memory = asNEWARRAYALIGNED(asDWORD, type.GetSizeOnStackDWords(), type.GetAlignment()); +#endif + memoryAllocated = true; + } +} + +void asCGlobalProperty::SetRegisteredAddress(void *p) +{ + realAddress = p; + if( type.IsObject() && !type.IsReference() && !type.IsObjectHandle() ) + { + // The global property is a pointer to a pointer + memory = &realAddress; + } + else + memory = p; +} + +void *asCGlobalProperty::GetRegisteredAddress() const +{ + return realAddress; +} + +void asCGlobalProperty::SetInitFunc(asCScriptFunction *in_initFunc) +{ + // This should only be done once + asASSERT( initFunc == 0 ); + + initFunc = in_initFunc; + initFunc->AddRefInternal(); +} + +asCScriptFunction *asCGlobalProperty::GetInitFunc() +{ + return initFunc; +} + +END_AS_NAMESPACE diff --git a/angelscript/source/as_map.h b/angelscript/source/as_map.h new file mode 100644 index 0000000..c21037b --- /dev/null +++ b/angelscript/source/as_map.h @@ -0,0 +1,786 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2013 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_map.h +// +// This class is used for mapping a value to another +// + + +#ifndef AS_MAP_H +#define AS_MAP_H + +template struct asSMapNode; + +template class asCMap +{ +public: + asCMap(); + ~asCMap(); + + int Insert(const KEY &key, const VAL &value); + int Insert(asSMapNode *node); + int GetCount() const; + + const KEY &GetKey(const asSMapNode *cursor) const; + const VAL &GetValue(const asSMapNode *cursor) const; + VAL &GetValue(asSMapNode *cursor); + + void Erase(asSMapNode *cursor); + asSMapNode *Remove(asSMapNode *cursor); + void EraseAll(); + + void SwapWith(asCMap &other); + + // Returns true as long as cursor is valid + + bool MoveTo(asSMapNode **out, const KEY &key) const; + bool MoveFirst(asSMapNode **out) const; + bool MoveLast(asSMapNode **out) const; + bool MoveNext(asSMapNode **out, asSMapNode *cursor) const; + bool MovePrev(asSMapNode **out, asSMapNode *cursor) const; + + // For debugging only + + int CheckIntegrity(asSMapNode *node) const; + +protected: + // Don't allow value assignment + asCMap &operator=(const asCMap &) { return *this; } + + void BalanceInsert(asSMapNode *node); + void BalanceErase(asSMapNode *child, asSMapNode *parent); + + int EraseAll(asSMapNode *node); + int RotateLeft(asSMapNode *node); + int RotateRight(asSMapNode *node); + + asSMapNode *root; + asSMapNode dummy; + + int count; +}; + +//--------------------------------------------------------------------------- +// Implementation + +// Properties of a Red-Black Tree +// +// 1. The root is always black +// 2. All single paths from the root to leafs +// contain the same amount of black nodes +// 3. No red node can have a red node as parent + +#define ISRED(x) ((x != 0) && (x)->isRed) +#define ISBLACK(x) (!ISRED(x)) + +template struct asSMapNode +{ + asSMapNode() {parent = 0; left = 0; right = 0; isRed = true;} + void Init(KEY k, VAL v) {key = k; value = v; parent = 0; left = 0; right = 0; isRed = true;} + + asSMapNode *parent; + asSMapNode *left; + asSMapNode *right; + bool isRed; + + KEY key; + VAL value; +}; + +template +asCMap::asCMap() +{ + root = 0; + count = 0; +} + +template +asCMap::~asCMap() +{ + EraseAll(); +} + +template +void asCMap::SwapWith(asCMap &other) +{ + asSMapNode *tmpRoot = root; + int tmpCount = count; + + root = other.root; + count = other.count; + + other.root = tmpRoot; + other.count = tmpCount; +} + +template +void asCMap::EraseAll() +{ + EraseAll(root); + root = 0; +} + +template +int asCMap::EraseAll(asSMapNode *p) +{ + if( p == 0 ) return -1; + + EraseAll( p->left ); + EraseAll( p->right ); + + typedef asSMapNode node_t; + asDELETE(p,node_t); + + count--; + + return 0; +} + +template +int asCMap::GetCount() const +{ + return count; +} + +template +int asCMap::Insert(const KEY &key, const VAL &value) +{ + typedef asSMapNode node_t; + asSMapNode *nnode = asNEW(node_t); + if( nnode == 0 ) + { + // Out of memory + return -1; + } + + nnode->key = key; + nnode->value = value; + + return Insert(nnode); +} + +template +int asCMap::Insert(asSMapNode *nnode) +{ + // Insert the node + if( root == 0 ) + root = nnode; + else + { + asSMapNode *p = root; + for(;;) + { + if( nnode->key < p->key ) + { + if( p->left == 0 ) + { + nnode->parent = p; + p->left = nnode; + break; + } + else + p = p->left; + } + else + { + if( p->right == 0 ) + { + nnode->parent = p; + p->right = nnode; + break; + } + else + p = p->right; + } + } + } + + BalanceInsert(nnode); + + count++; + + return 0; +} + +template +void asCMap::BalanceInsert(asSMapNode *node) +{ + // The node, that is red, can't have a red parent + while( node != root && node->parent->isRed ) + { + // Check color of uncle + if( node->parent == node->parent->parent->left ) + { + asSMapNode *uncle = node->parent->parent->right; + if( ISRED(uncle) ) + { + // B + // R R + // N + + // Change color on parent, uncle, and grand parent + node->parent->isRed = false; + uncle->isRed = false; + node->parent->parent->isRed = true; + + // Continue balancing from grand parent + node = node->parent->parent; + } + else + { + // B + // R B + // N + + if( node == node->parent->right ) + { + // Make the node a left child + node = node->parent; + RotateLeft(node); + } + + // Change color on parent and grand parent + // Then rotate grand parent to the right + node->parent->isRed = false; + node->parent->parent->isRed = true; + RotateRight(node->parent->parent); + } + } + else + { + asSMapNode *uncle = node->parent->parent->left; + if( ISRED(uncle) ) + { + // B + // R R + // N + + // Change color on parent, uncle, and grand parent + // Continue balancing from grand parent + node->parent->isRed = false; + uncle->isRed = false; + node = node->parent->parent; + node->isRed = true; + } + else + { + // B + // B R + // N + + if( node == node->parent->left ) + { + // Make the node a right child + node = node->parent; + RotateRight(node); + } + + // Change color on parent and grand parent + // Then rotate grand parent to the right + node->parent->isRed = false; + node->parent->parent->isRed = true; + RotateLeft(node->parent->parent); + } + } + } + + root->isRed = false; +} + +// For debugging purposes only +template +int asCMap::CheckIntegrity(asSMapNode *node) const +{ + if( node == 0 ) + { + if( root == 0 ) + return 0; + else if( ISRED(root) ) + return -1; + else + node = root; + } + + int left = 0, right = 0; + if( node->left ) + left = CheckIntegrity(node->left); + if( node->right ) + right = CheckIntegrity(node->right); + + if( left != right || left == -1 ) + return -1; + + if( ISBLACK(node) ) + return left+1; + + return left; +} + +// Returns true if successful +template +bool asCMap::MoveTo(asSMapNode **out, const KEY &key) const +{ + asSMapNode *p = root; + while( p ) + { + if( key < p->key ) + p = p->left; + else if( key == p->key ) + { + if( out ) *out = p; + return true; + } + else + p = p->right; + } + + if( out ) *out = 0; + return false; +} + +template +void asCMap::Erase(asSMapNode *cursor) +{ + asSMapNode *node = Remove(cursor); + asASSERT( node == cursor ); + + typedef asSMapNode node_t; + asDELETE(node,node_t); +} + +template +asSMapNode *asCMap::Remove(asSMapNode *cursor) +{ + if( cursor == 0 ) return 0; + + asSMapNode *node = cursor; + + //--------------------------------------------------- + // Choose the node that will replace the erased one + asSMapNode *remove; + if( node->left == 0 || node->right == 0 ) + remove = node; + else + { + remove = node->right; + while( remove->left ) remove = remove->left; + } + + //-------------------------------------------------- + // Remove the node + asSMapNode *child; + if( remove->left ) + child = remove->left; + else + child = remove->right; + + if( child ) child->parent = remove->parent; + if( remove->parent ) + { + if( remove == remove->parent->left ) + remove->parent->left = child; + else + remove->parent->right = child; + } + else + root = child; + + // If we remove a black node we must make sure the tree is balanced + if( ISBLACK(remove) ) + BalanceErase(child, remove->parent); + + //---------------------------------------- + // Replace the erased node with the removed one + if( remove != node ) + { + if( node->parent ) + { + if( node->parent->left == node ) + node->parent->left = remove; + else + node->parent->right = remove; + } + else + root = remove; + + remove->isRed = node->isRed; + remove->parent = node->parent; + + remove->left = node->left; + if( remove->left ) remove->left->parent = remove; + remove->right = node->right; + if( remove->right ) remove->right->parent = remove; + } + + count--; + + return node; +} + +// Call method only if removed node was black +// child is the child of the removed node +template +void asCMap::BalanceErase(asSMapNode *child, asSMapNode *parent) +{ + // If child is red + // Color child black + // Terminate + + // These tests assume brother is to the right. + + // 1. Brother is red + // Color parent red and brother black + // Rotate parent left + // Transforms to 2b + // 2a. Parent and brother is black, brother's children are black + // Color brother red + // Continue test with parent as child + // 2b. Parent is red, brother is black, brother's children are black + // Color parent black and brother red + // Terminate + // 3. Brother is black, and brother's left is red and brother's right is black + // Color brother red and brother's left black + // Rotate brother to right + // Transforms to 4. + // 4. Brother is black, brother's right is red + // Color brother's right black + // Color brother to color of parent + // Color parent black + // Rotate parent left + // Terminate + + while( child != root && ISBLACK(child) ) + { + if( child == parent->left ) + { + asSMapNode *brother = parent->right; + + // Case 1 + if( ISRED(brother) ) + { + brother->isRed = false; + parent->isRed = true; + RotateLeft(parent); + brother = parent->right; + } + + // Case 2 + if( brother == 0 ) break; + if( ISBLACK(brother->left) && ISBLACK(brother->right) ) + { + // Case 2b + if( ISRED(parent) ) + { + parent->isRed = false; + brother->isRed = true; + break; + } + + brother->isRed = true; + child = parent; + parent = child->parent; + } + else + { + // Case 3 + if( ISBLACK(brother->right) ) + { + brother->left->isRed = false; + brother->isRed = true; + RotateRight(brother); + brother = parent->right; + } + + // Case 4 + brother->isRed = parent->isRed; + parent->isRed = false; + brother->right->isRed = false; + RotateLeft(parent); + break; + } + } + else + { + asSMapNode *brother = parent->left; + + // Case 1 + if( ISRED(brother) ) + { + brother->isRed = false; + parent->isRed = true; + RotateRight(parent); + brother = parent->left; + } + + // Case 2 + if( brother == 0 ) break; + if( ISBLACK(brother->left) && ISBLACK(brother->right) ) + { + // Case 2b + if( ISRED(parent) ) + { + parent->isRed = false; + brother->isRed = true; + break; + } + + brother->isRed = true; + child = parent; + parent = child->parent; + } + else + { + // Case 3 + if( ISBLACK(brother->left) ) + { + brother->right->isRed = false; + brother->isRed = true; + RotateLeft(brother); + brother = parent->left; + } + + // Case 4 + brother->isRed = parent->isRed; + parent->isRed = false; + brother->left->isRed = false; + RotateRight(parent); + break; + } + } + } + + if( child ) + child->isRed = false; +} + +template +int asCMap::RotateRight(asSMapNode *node) +{ + // P L // + // / \ / \ // + // L R => Ll P // + // / \ / \ // + // Ll Lr Lr R // + + if( node->left == 0 ) return -1; + + asSMapNode *left = node->left; + + // Update parent + if( node->parent ) + { + asSMapNode *parent = node->parent; + if( parent->left == node ) + parent->left = left; + else + parent->right = left; + + left->parent = parent; + } + else + { + root = left; + left->parent = 0; + } + + // Move left's right child to node's left child + node->left = left->right; + if( node->left ) node->left->parent = node; + + // Put node as left's right child + left->right = node; + node->parent = left; + + return 0; +} + +template +int asCMap::RotateLeft(asSMapNode *node) +{ + // P R // + // / \ / \ // + // L R => P Rr // + // / \ / \ // + // Rl Rr L Rl // + + if( node->right == 0 ) return -1; + + asSMapNode *right = node->right; + + // Update parent + if( node->parent ) + { + asSMapNode *parent = node->parent; + if( parent->right == node ) + parent->right = right; + else + parent->left = right; + + right->parent = parent; + } + else + { + root = right; + right->parent = 0; + } + + // Move right's left child to node's right child + node->right = right->left; + if( node->right ) node->right->parent = node; + + // Put node as right's left child + right->left = node; + node->parent = right; + + return 0; +} + +template +const VAL &asCMap::GetValue(const asSMapNode *cursor) const +{ + if( cursor == 0 ) + return dummy.value; + + return cursor->value; +} + +template +VAL &asCMap::GetValue(asSMapNode *cursor) +{ + if( cursor == 0 ) + return dummy.value; + + return cursor->value; +} + +template +const KEY &asCMap::GetKey(const asSMapNode *cursor) const +{ + if( cursor == 0 ) + return dummy.key; + + return cursor->key; +} + +template +bool asCMap::MoveFirst(asSMapNode **out) const +{ + *out = root; + if( root == 0 ) return false; + + while( (*out)->left ) + *out = (*out)->left; + + return true; +} + +template +bool asCMap::MoveLast(asSMapNode **out) const +{ + *out = root; + if( root == 0 ) return false; + + while( (*out)->right ) + *out = (*out)->right; + + return true; +} + +template +bool asCMap::MoveNext(asSMapNode **out, asSMapNode *cursor) const +{ + if( cursor == 0 ) + { + *out = 0; + return false; + } + + if( cursor->right == 0 ) + { + // Move upwards until we find a parent node to the right + while( cursor->parent && cursor->parent->right == cursor ) + cursor = cursor->parent; + + cursor = cursor->parent; + *out = cursor; + if( cursor == 0 ) + return false; + + return true; + } + + cursor = cursor->right; + while( cursor->left ) + cursor = cursor->left; + + *out = cursor; + return true; +} + +template +bool asCMap::MovePrev(asSMapNode **out, asSMapNode *cursor) const +{ + if( cursor == 0 ) + { + *out = 0; + return false; + } + + if( cursor->left == 0 ) + { + // Move upwards until we find a parent node to the left + while( cursor->parent && cursor->parent->left == cursor ) + cursor = cursor->parent; + + cursor = cursor->parent; + + *out = cursor; + if( cursor == 0 ) + return false; + + return true; + } + + cursor = cursor->left; + while( cursor->right ) + cursor = cursor->right; + + *out = cursor; + return true; +} + + + + +#endif + diff --git a/angelscript/source/as_memory.cpp b/angelscript/source/as_memory.cpp new file mode 100644 index 0000000..5914658 --- /dev/null +++ b/angelscript/source/as_memory.cpp @@ -0,0 +1,288 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_memory.cpp +// +// Overload the default memory management functions so that we +// can let the application decide how to do it. +// + +#include + +#if !defined(__APPLE__) && !defined(__SNC__) && !defined(__ghs__) && !defined(__FreeBSD__) && !defined(__OpenBSD__) && !defined(__DragonFly__) +#include +#endif + +#include "as_config.h" +#include "as_memory.h" +#include "as_scriptnode.h" +#include "as_bytecode.h" + +BEGIN_AS_NAMESPACE + +#ifdef WIP_16BYTE_ALIGN + +// TODO: Add support for 16byte aligned application types (e.g. __m128). The following is a list of things that needs to be implemented: +// +// ok - The script context must make sure to always allocate the local stack memory buffer on 16byte aligned boundaries (asCContext::ReserveStackSpace) +// ok - The engine must make sure to always allocate the memory for the script objects on 16byte aligned boundaries (asCScriptEngine::CallAlloc) +// ok - The application needs to inform a new flag when registering types that require 16byte alignment, e.g. asOBJ_APP_ALIGN16 (asCScriptEngine::RegisterObjectType) +// ok - The script object type must make sure to align member properties of these types correctly (asCObjectType::AddPropertyToClass) +// ok - Script global properties must allocate memory on 16byte boundaries if holding these types (asCGlobalProperty::AllocateMemory) +// TODO - The script compiler must make sure to allocate the local variables on 16byte boundaries (asCCompiler::AllocateVariable) +// TODO - The script compiler must add pad bytes on the stack for all function calls to guarantee that the stack position is 16byte aligned on entry in the called function (asCCompiler) +// TODO - The bytecode serializer must be capable of adjusting these pad bytes to guarantee platform independent saved bytecode. Remember that the registered type may not be 16byte aligned on all platforms (asCWriter & asCReader) +// TODO - The bytecode serializer must also be prepared to adjust the position of the local variables according to the need fro 16byte alignment (asCWriter & asCReader) +// TODO - The code for the native calling conventions must be adjusted for all platforms that should support 16byte aligned types (as_callfunc...) +// ok - When the context needs to grow the local stack memory it must copy the function arguments so that the stack entry position is 16byte aligned (asCContext::CallScriptFunction) +// TODO - When the context is prepared for a new call, it must set the initial stack position so the stack entry position is 16byte aligned (asCContext::Prepare) +// +// http://www.gamedev.net/topic/650555-alignment-requirements/ + + +// TODO: Allow user to register its own aligned memory routines +// Wrappers for aligned allocations +void *debugAlignedMalloc(size_t size, size_t align, const char *file, int line) +{ + void *mem = ((asALLOCFUNCDEBUG_t)userAlloc)(size + (align-1) + sizeof(void*), file, line); + + char *amem = ((char*)mem) + sizeof(void*); + if( (uintptr_t)amem & (align - 1) ) + amem += align - ((uintptr_t)amem & (align - 1)); + + ((void**)amem)[-1] = mem; + return amem; +} + +void *alignedMalloc(size_t size, size_t align) +{ + void *mem = userAlloc(size + (align-1) + sizeof(void*)); + + char *amem = ((char*)mem) + sizeof(void*); + if( (uintptr_t)amem & (align - 1) ) + amem += align - ((uintptr_t)amem & (align - 1)); + + ((void**)amem)[-1] = mem; + return amem; +} + +void alignedFree(void *mem) +{ + userFree( ((void**)mem)[-1] ); +} + +bool isAligned(const void* const pointer, asUINT alignment) +{ + return (uintptr_t(pointer) % alignment) == 0; +} +#endif + +// By default we'll use the standard memory management functions + +// Make sure these globals are initialized first. Otherwise the +// library may crash in case the application initializes the engine +// as a global variable. + +#ifdef _MSC_VER +// MSVC let's us choose between a couple of different initialization orders. +#pragma warning(disable: 4073) +#pragma init_seg(lib) +asALLOCFUNC_t userAlloc = malloc; +asFREEFUNC_t userFree = free; +#ifdef WIP_16BYTE_ALIGN +#ifdef AS_DEBUG +asALLOCALIGNEDFUNC_t userAllocAligned = (asALLOCALIGNEDFUNC_t)debugAlignedMalloc; +#else +asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc; +#endif +asFREEALIGNEDFUNC_t userFreeAligned = alignedFree; +#endif +#else +// Other compilers will just have to rely on luck. +asALLOCFUNC_t userAlloc = malloc; +asFREEFUNC_t userFree = free; +#ifdef WIP_16BYTE_ALIGN +asALLOCALIGNEDFUNC_t userAllocAligned = alignedMalloc; +asFREEALIGNEDFUNC_t userFreeAligned = alignedFree; +#endif +#endif + +extern "C" +{ + +// interface +int asSetGlobalMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc) +{ + // Clean-up thread local memory before changing the allocation routines to avoid + // potential problem with trying to free memory using a different allocation + // routine than used when allocating it. + asThreadCleanup(); + + userAlloc = allocFunc; + userFree = freeFunc; + + return 0; +} + +// interface +int asResetGlobalMemoryFunctions() +{ + // Clean-up thread local memory before changing the allocation routines to avoid + // potential problem with trying to free memory using a different allocation + // routine than used when allocating it. + asThreadCleanup(); + + userAlloc = malloc; + userFree = free; + + return 0; +} + +// interface +void *asAllocMem(size_t size) +{ + return asNEWARRAY(asBYTE, size); +} + +// interface +void asFreeMem(void *mem) +{ + asDELETEARRAY(mem); +} + +} // extern "C" + +asCMemoryMgr::asCMemoryMgr() +{ +} + +asCMemoryMgr::~asCMemoryMgr() +{ + FreeUnusedMemory(); +} + +void asCMemoryMgr::FreeUnusedMemory() +{ + // It's necessary to protect the scriptNodePool from multiple + // simultaneous accesses, as the parser is used by several methods + // that can be executed simultaneously. + ENTERCRITICALSECTION(cs); + + int n; + for( n = 0; n < (signed)scriptNodePool.GetLength(); n++ ) + userFree(scriptNodePool[n]); + scriptNodePool.Allocate(0, false); + + LEAVECRITICALSECTION(cs); + + // The engine already protects against multiple threads + // compiling scripts simultaneously so this pool doesn't have + // to be protected again. + for( n = 0; n < (signed)byteInstructionPool.GetLength(); n++ ) + userFree(byteInstructionPool[n]); + byteInstructionPool.Allocate(0, false); +} + +void *asCMemoryMgr::AllocScriptNode() +{ + ENTERCRITICALSECTION(cs); + + if( scriptNodePool.GetLength() ) + { + void *tRet = scriptNodePool.PopLast(); + LEAVECRITICALSECTION(cs); + return tRet; + } + + LEAVECRITICALSECTION(cs); + +#if defined(AS_DEBUG) + return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCScriptNode), __FILE__, __LINE__); +#else + return userAlloc(sizeof(asCScriptNode)); +#endif +} + +void asCMemoryMgr::FreeScriptNode(void *ptr) +{ + ENTERCRITICALSECTION(cs); + + // Pre allocate memory for the array to avoid slow growth + if( scriptNodePool.GetLength() == 0 ) + scriptNodePool.Allocate(100, 0); + + scriptNodePool.PushLast(ptr); + +#ifdef AS_DEBUG + // clear the memory to facilitate identification of use after free + memset(ptr, 0xCDCDCDCD, sizeof(asCScriptNode)); +#endif + + LEAVECRITICALSECTION(cs); +} + +#ifndef AS_NO_COMPILER + +void *asCMemoryMgr::AllocByteInstruction() +{ + // This doesn't need a critical section because, only one compilation is allowed at a time + + if( byteInstructionPool.GetLength() ) + return byteInstructionPool.PopLast(); + +#if defined(AS_DEBUG) + return ((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(asCByteInstruction), __FILE__, __LINE__); +#else + return userAlloc(sizeof(asCByteInstruction)); +#endif +} + +void asCMemoryMgr::FreeByteInstruction(void *ptr) +{ + // Pre allocate memory for the array to avoid slow growth + if( byteInstructionPool.GetLength() == 0 ) + byteInstructionPool.Allocate(100, 0); + + byteInstructionPool.PushLast(ptr); + +#ifdef AS_DEBUG + // clear the memory to facilitate identification of use after free + memset(ptr, 0xCDCDCDCD, sizeof(asCByteInstruction)); +#endif +} + +#endif // AS_NO_COMPILER + +END_AS_NAMESPACE + + + diff --git a/angelscript/source/as_memory.h b/angelscript/source/as_memory.h new file mode 100644 index 0000000..369af64 --- /dev/null +++ b/angelscript/source/as_memory.h @@ -0,0 +1,135 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2014 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_memory.h +// +// Overload the default memory management functions so that we +// can let the application decide how to do it. +// + + + +#ifndef AS_MEMORY_H +#define AS_MEMORY_H + +#include "as_config.h" + +BEGIN_AS_NAMESPACE + +extern asALLOCFUNC_t userAlloc; +extern asFREEFUNC_t userFree; + +#ifdef WIP_16BYTE_ALIGN + +// TODO: This declaration should be in angelscript.h +// when the application can register it's own +// aligned memory routines +typedef void *(*asALLOCALIGNEDFUNC_t)(size_t, size_t); +typedef void (*asFREEALIGNEDFUNC_t)(void *); +extern asALLOCALIGNEDFUNC_t userAllocAligned; +extern asFREEALIGNEDFUNC_t userFreeAligned; +typedef void *(*asALLOCALIGNEDFUNCDEBUG_t)(size_t, size_t, const char *, unsigned int); + +// The maximum type alignment supported. +const int MAX_TYPE_ALIGNMENT = 16; + +// Utility function used for assertions. +bool isAligned(const void* const pointer, asUINT alignment); + +#endif // WIP_16BYTE_ALIGN + +// We don't overload the new operator as that would affect the application as well + +#ifndef AS_DEBUG + + #define asNEW(x) new(userAlloc(sizeof(x))) x + #define asDELETE(ptr,x) {void *tmp = ptr; (ptr)->~x(); userFree(tmp);} + + #define asNEWARRAY(x,cnt) (x*)userAlloc(sizeof(x)*cnt) + #define asDELETEARRAY(ptr) userFree(ptr) + +#ifdef WIP_16BYTE_ALIGN + #define asNEWARRAYALIGNED(x,cnt, alignment) (x*)userAllocAligned(sizeof(x)*cnt, alignment) + #define asDELETEARRAYALIGNED(ptr) userFreeAligned(ptr) +#endif + +#else + + typedef void *(*asALLOCFUNCDEBUG_t)(size_t, const char *, unsigned int); + + #define asNEW(x) new(((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(x), __FILE__, __LINE__)) x + #define asDELETE(ptr,x) {void *tmp = ptr; (ptr)->~x(); userFree(tmp);} + + #define asNEWARRAY(x,cnt) (x*)((asALLOCFUNCDEBUG_t)(userAlloc))(sizeof(x)*cnt, __FILE__, __LINE__) + #define asDELETEARRAY(ptr) userFree(ptr) + +#ifdef WIP_16BYTE_ALIGN + //TODO: Equivalent of debug allocation function with alignment? + #define asNEWARRAYALIGNED(x,cnt, alignment) (x*)userAllocAligned(sizeof(x)*cnt, alignment) + #define asDELETEARRAYALIGNED(ptr) userFreeAligned(ptr) +#endif + +#endif + +END_AS_NAMESPACE + +#include +#include "as_criticalsection.h" +#include "as_array.h" + +BEGIN_AS_NAMESPACE + +class asCMemoryMgr +{ +public: + asCMemoryMgr(); + ~asCMemoryMgr(); + + void FreeUnusedMemory(); + + void *AllocScriptNode(); + void FreeScriptNode(void *ptr); + +#ifndef AS_NO_COMPILER + void *AllocByteInstruction(); + void FreeByteInstruction(void *ptr); +#endif + +protected: + DECLARECRITICALSECTION(cs) + asCArray scriptNodePool; + asCArray byteInstructionPool; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_module.cpp b/angelscript/source/as_module.cpp new file mode 100644 index 0000000..5ec5542 --- /dev/null +++ b/angelscript/source/as_module.cpp @@ -0,0 +1,1877 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_module.cpp +// +// A class that holds a script module +// + +#include "as_config.h" +#include "as_module.h" +#include "as_builder.h" +#include "as_context.h" +#include "as_texts.h" +#include "as_debug.h" +#include "as_restore.h" + +BEGIN_AS_NAMESPACE + + +// internal +asCModule::asCModule(const char *name, asCScriptEngine *engine) +{ + m_name = name; + m_engine = engine; + + m_userData = 0; + m_builder = 0; + m_isGlobalVarInitialized = false; + + m_accessMask = 1; + + m_defaultNamespace = engine->nameSpaces[0]; +} + +// internal +asCModule::~asCModule() +{ + InternalReset(); + + // The builder is not removed by InternalReset because it holds the script + // sections that will be built, so we need to explictly remove it now if it exists + if( m_builder ) + { + asDELETE(m_builder,asCBuilder); + m_builder = 0; + } + + if( m_engine ) + { + // Clean the user data + for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) + { + if( m_userData[n+1] ) + { + for( asUINT c = 0; c < m_engine->cleanModuleFuncs.GetLength(); c++ ) + if( m_engine->cleanModuleFuncs[c].type == m_userData[n] ) + m_engine->cleanModuleFuncs[c].cleanFunc(this); + } + } + + // Remove the module from the engine + ACQUIREEXCLUSIVE(m_engine->engineRWLock); + // The module must have been discarded before it is deleted + asASSERT( !m_engine->scriptModules.Exists(this) ); + m_engine->discardedModules.RemoveValue(this); + RELEASEEXCLUSIVE(m_engine->engineRWLock); + } +} + +// interface +void asCModule::Discard() +{ + // Reset the global variables already so that no object in the global variables keep the module alive forever. + // If any live object tries to access the global variables during clean up they will fail with a script exception, + // so the application must keep that in mind before discarding a module. + CallExit(); + + // Keep a local copy of the engine pointer, because once the module is moved do the discarded + // pile, it is possible that another thread might discard it while we are still in here. So no + // further access to members may be done after that + asCScriptEngine *engine = m_engine; + + // Instead of deleting the module immediately, move it to the discarded pile + // This will turn it invisible to the application, yet keep it alive until all + // external references to its entities have been released. + ACQUIREEXCLUSIVE(engine->engineRWLock); + if( engine->lastModule == this ) + engine->lastModule = 0; + engine->scriptModules.RemoveValue(this); + engine->discardedModules.PushLast(this); + RELEASEEXCLUSIVE(engine->engineRWLock); + + // Allow the engine to go over the list of discarded modules to see what can be cleaned up at this moment. + // Don't do this if the engine is already shutting down, as it will be done explicitly by the engine itself with error reporting + if( !engine->shuttingDown ) + { + if( engine->ep.autoGarbageCollect ) + engine->GarbageCollect(); + else + { + // GarbageCollect calls DeleteDiscardedModules, so no need + // to call it again if we already called GarbageCollect + engine->DeleteDiscardedModules(); + } + } +} + +// interface +void *asCModule::SetUserData(void *data, asPWORD type) +{ + // As a thread might add a new new user data at the same time as another + // it is necessary to protect both read and write access to the userData member + ACQUIREEXCLUSIVE(m_engine->engineRWLock); + + // It is not intended to store a lot of different types of userdata, + // so a more complex structure like a associative map would just have + // more overhead than a simple array. + for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) + { + if( m_userData[n] == type ) + { + void *oldData = reinterpret_cast(m_userData[n+1]); + m_userData[n+1] = reinterpret_cast(data); + + RELEASEEXCLUSIVE(m_engine->engineRWLock); + + return oldData; + } + } + + m_userData.PushLast(type); + m_userData.PushLast(reinterpret_cast(data)); + + RELEASEEXCLUSIVE(m_engine->engineRWLock); + + return 0; +} + +// interface +void *asCModule::GetUserData(asPWORD type) const +{ + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + ACQUIRESHARED(m_engine->engineRWLock); + + for( asUINT n = 0; n < m_userData.GetLength(); n += 2 ) + { + if( m_userData[n] == type ) + { + void *ud = reinterpret_cast(m_userData[n+1]); + RELEASESHARED(m_engine->engineRWLock); + return ud; + } + } + + RELEASESHARED(m_engine->engineRWLock); + + return 0; +} + +// interface +asIScriptEngine *asCModule::GetEngine() const +{ + return m_engine; +} + +// interface +void asCModule::SetName(const char *in_name) +{ + m_name = in_name; +} + +// interface +const char *asCModule::GetName() const +{ + return m_name.AddressOf(); +} + +// interface +const char *asCModule::GetDefaultNamespace() const +{ + return m_defaultNamespace->name.AddressOf(); +} + +// interface +int asCModule::SetDefaultNamespace(const char *nameSpace) +{ + // TODO: cleanup: This function is similar to asCScriptEngine::SetDefaultNamespace. Can we reuse the code? + if( nameSpace == 0 ) + return asINVALID_ARG; + + asCString ns = nameSpace; + if( ns != "" ) + { + // Make sure the namespace is composed of alternating identifier and :: + size_t pos = 0; + bool expectIdentifier = true; + size_t len; + eTokenType t = ttIdentifier; + + for( ; pos < ns.GetLength(); pos += len ) + { + t = m_engine->tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len); + if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) ) + return asINVALID_DECLARATION; + + expectIdentifier = !expectIdentifier; + } + + // If the namespace ends with :: then strip it off + if( t == ttScope ) + ns.SetLength(ns.GetLength()-2); + } + + m_defaultNamespace = m_engine->AddNameSpace(ns.AddressOf()); + + return 0; +} + +// interface +int asCModule::AddScriptSection(const char *in_name, const char *in_code, size_t in_codeLength, int in_lineOffset) +{ +#ifdef AS_NO_COMPILER + UNUSED_VAR(in_name); + UNUSED_VAR(in_code); + UNUSED_VAR(in_codeLength); + UNUSED_VAR(in_lineOffset); + return asNOT_SUPPORTED; +#else + if( !m_builder ) + { + m_builder = asNEW(asCBuilder)(m_engine, this); + if( m_builder == 0 ) + return asOUT_OF_MEMORY; + } + + return m_builder->AddCode(in_name, in_code, (int)in_codeLength, in_lineOffset, (int)m_engine->GetScriptSectionNameIndex(in_name ? in_name : ""), m_engine->ep.copyScriptSections); +#endif +} + +// internal +void asCModule::JITCompile() +{ + asIJITCompiler *jit = m_engine->GetJITCompiler(); + if( !jit ) + return; + + for (unsigned int i = 0; i < m_scriptFunctions.GetLength(); i++) + m_scriptFunctions[i]->JITCompile(); +} + +// interface +int asCModule::Build() +{ +#ifdef AS_NO_COMPILER + return asNOT_SUPPORTED; +#else + TimeIt("asCModule::Build"); + + // Don't allow the module to be rebuilt if there are still + // external references that will need the previous code + // TODO: interface: The asIScriptModule must have a method for querying if the module is used + if( HasExternalReferences(false) ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE); + return asMODULE_IS_IN_USE; + } + + // Only one thread may build at one time + // TODO: It should be possible to have multiple threads perform compilations + int r = m_engine->RequestBuild(); + if( r < 0 ) + return r; + + m_engine->PrepareEngine(); + if( m_engine->configFailed ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); + m_engine->BuildCompleted(); + return asINVALID_CONFIGURATION; + } + + InternalReset(); + + if( !m_builder ) + { + m_engine->BuildCompleted(); + return asSUCCESS; + } + + // Compile the script + r = m_builder->Build(); + asDELETE(m_builder,asCBuilder); + m_builder = 0; + + if( r < 0 ) + { + // Reset module again + InternalReset(); + + m_engine->BuildCompleted(); + return r; + } + + JITCompile(); + + m_engine->PrepareEngine(); + +#ifdef AS_DEBUG + // Verify that there are no unwanted gaps in the scriptFunctions array. + for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ ) + { + int id = n; + if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) ) + asASSERT( false ); + } +#endif + + m_engine->BuildCompleted(); + + // Initialize global variables + if( r >= 0 && m_engine->ep.initGlobalVarsAfterBuild ) + r = ResetGlobalVars(0); + + return r; +#endif +} + +// interface +int asCModule::ResetGlobalVars(asIScriptContext *ctx) +{ + if( m_isGlobalVarInitialized ) + CallExit(); + + return CallInit(ctx); +} + +// interface +asIScriptFunction *asCModule::GetFunctionByIndex(asUINT index) const +{ + return const_cast(m_globalFunctions.Get(index)); +} + +// internal +int asCModule::CallInit(asIScriptContext *myCtx) +{ + if( m_isGlobalVarInitialized ) + return asERROR; + + // Each global variable needs to be cleared individually + asCSymbolTableIterator it = m_scriptGlobals.List(); + while( it ) + { + asCGlobalProperty *desc = *it; + memset(desc->GetAddressOfValue(), 0, sizeof(asDWORD)*desc->type.GetSizeOnStackDWords()); + it++; + } + + // Call the init function for each of the global variables + asIScriptContext *ctx = myCtx; + int r = asEXECUTION_FINISHED; + it = m_scriptGlobals.List(); + while( it && r == asEXECUTION_FINISHED ) + { + asCGlobalProperty *desc = *it; + it++; + if( desc->GetInitFunc() ) + { + if( ctx == 0 ) + { + ctx = m_engine->RequestContext(); + if( ctx == 0 ) + break; + } + + r = InitGlobalProp(desc, ctx); + } + } + + if( ctx && !myCtx ) + { + m_engine->ReturnContext(ctx); + ctx = 0; + } + + // Even if the initialization failed we need to set the + // flag that the variables have been initialized, otherwise + // the module won't free those variables that really were + // initialized. + m_isGlobalVarInitialized = true; + + if( r != asEXECUTION_FINISHED ) + return asINIT_GLOBAL_VARS_FAILED; + + return asSUCCESS; +} + +// internal +// This function assumes the memory for the global property is already cleared +int asCModule::InitGlobalProp(asCGlobalProperty *prop, asIScriptContext *myCtx) +{ + // Call the init function for each of the global variables + asIScriptContext *ctx = myCtx; + int r = asEXECUTION_FINISHED; + if( prop->GetInitFunc() ) + { + if( ctx == 0 ) + { + ctx = m_engine->RequestContext(); + if( ctx == 0 ) + return asERROR; + } + + r = ctx->Prepare(prop->GetInitFunc()); + if( r >= 0 ) + { + r = ctx->Execute(); + if( r != asEXECUTION_FINISHED ) + { + asCString msg; + msg.Format(TXT_FAILED_TO_INITIALIZE_s, prop->name.AddressOf()); + asCScriptFunction *func = prop->GetInitFunc(); + + m_engine->WriteMessage(func->scriptData->scriptSectionIdx >= 0 ? m_engine->scriptSectionNames[func->scriptData->scriptSectionIdx]->AddressOf() : "", + func->GetLineNumber(0, 0) & 0xFFFFF, + func->GetLineNumber(0, 0) >> 20, + asMSGTYPE_ERROR, + msg.AddressOf()); + + if( r == asEXECUTION_EXCEPTION ) + { + const asIScriptFunction *function = ctx->GetExceptionFunction(); + + msg.Format(TXT_EXCEPTION_s_IN_s, ctx->GetExceptionString(), function->GetDeclaration()); + + m_engine->WriteMessage(function->GetScriptSectionName(), + ctx->GetExceptionLineNumber(), + 0, + asMSGTYPE_INFORMATION, + msg.AddressOf()); + } + } + } + } + + if( ctx && !myCtx ) + { + m_engine->ReturnContext(ctx); + ctx = 0; + } + + // Even if the initialization failed we need to set the + // flag that the variables have been initialized, otherwise + // the module won't free those variables that really were + // initialized. + m_isGlobalVarInitialized = true; + + if( r != asEXECUTION_FINISHED ) + return asINIT_GLOBAL_VARS_FAILED; + + return asSUCCESS; +} + +// internal +void asCModule::UninitializeGlobalProp(asCGlobalProperty *prop) +{ + if (prop == 0) + return; + + if (prop->type.IsObject()) + { + void **obj = (void**)prop->GetAddressOfValue(); + if (*obj) + { + asCObjectType *ot = CastToObjectType(prop->type.GetTypeInfo()); + + if (ot->flags & asOBJ_REF) + { + asASSERT((ot->flags & asOBJ_NOCOUNT) || ot->beh.release); + if (ot->beh.release) + m_engine->CallObjectMethod(*obj, ot->beh.release); + } + else + { + if (ot->beh.destruct) + m_engine->CallObjectMethod(*obj, ot->beh.destruct); + + m_engine->CallFree(*obj); + } + + // Set the address to 0 as someone might try to access the variable afterwards + *obj = 0; + } + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **func = (asCScriptFunction**)prop->GetAddressOfValue(); + if (*func) + { + (*func)->Release(); + *func = 0; + } + } +} + +// internal +void asCModule::CallExit() +{ + if( !m_isGlobalVarInitialized ) return; + + asCSymbolTableIterator it = m_scriptGlobals.List(); + while( it ) + { + UninitializeGlobalProp(*it); + it++; + } + + m_isGlobalVarInitialized = false; +} + +// internal +bool asCModule::HasExternalReferences(bool shuttingDown) +{ + // Check all entities in the module for any external references. + // If there are any external references the module cannot be deleted yet. + + asCSymbolTableIterator it = m_scriptGlobals.List(); + while (it) + { + asCGlobalProperty *desc = *it; + if (desc->GetInitFunc() && desc->GetInitFunc()->externalRefCount.get()) + { + if( !shuttingDown ) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + // TODO: Use a better error message + asCString tmpName = "init " + desc->name; + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, tmpName.AddressOf(), desc->GetInitFunc()->GetFuncType()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + it++; + } + + for (asUINT n = 0; n < m_scriptFunctions.GetLength(); n++) + { + asCScriptFunction *func = m_scriptFunctions[n]; + if (func && func->externalRefCount.get()) + { + // If the func is shared and can be moved to another module then this is not a reason to keep the module alive + if (func->IsShared() && m_engine->FindNewOwnerForSharedFunc(func, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_scriptFunctions[n]->GetName(), m_scriptFunctions[n]->GetFuncType()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + for (asUINT n = 0; n < m_classTypes.GetLength(); n++) + { + asCObjectType *obj = m_classTypes[n]; + if (obj && obj->externalRefCount.get()) + { + // If the obj is shared and can be moved to another module then this is not a reason to keep the module alive + if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_classTypes[n]->GetName()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + for (asUINT n = 0; n < m_funcDefs.GetLength(); n++) + { + asCFuncdefType *func = m_funcDefs[n]; + if (func && func->externalRefCount.get()) + { + // If the funcdef is shared and can be moved to another module then this is not a reason to keep the module alive + if (func->IsShared() && m_engine->FindNewOwnerForSharedType(func, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d, m_funcDefs[n]->GetName(), m_funcDefs[n]->funcdef->GetFuncType()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + for (asUINT n = 0; n < m_templateInstances.GetLength(); n++) + { + asCObjectType *obj = m_templateInstances[n]; + if (obj && obj->externalRefCount.get()) + { + // If the template can be moved to another module then this is not a reason to keep the module alive + if (obj->IsShared() && m_engine->FindNewOwnerForSharedType(obj, this) != this) + continue; + + if (!shuttingDown) + return true; + else + { + asCString msg; + msg.Format(TXT_EXTRNL_REF_TO_MODULE_s, m_name.AddressOf()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + + msg.Format(TXT_PREV_TYPE_IS_NAMED_s, m_templateInstances[n]->GetName()); + m_engine->WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, msg.AddressOf()); + } + } + } + + return false; +} + +// internal +void asCModule::InternalReset() +{ + CallExit(); + + asUINT n; + + // Remove all global functions + m_globalFunctions.Clear(); + + // Destroy the internals of the global properties here, but do not yet remove them from the + // engine, because functions need the engine's varAddressMap to get to the property. If the + // property is removed already, it may leak as the refCount doesn't reach 0. + asCSymbolTableIterator globIt = m_scriptGlobals.List(); + while( globIt ) + { + (*globIt)->DestroyInternal(); + globIt++; + } + + UnbindAllImportedFunctions(); + + // Free bind information + for( n = 0; n < m_bindInformations.GetLength(); n++ ) + { + if( m_bindInformations[n] ) + { + m_bindInformations[n]->importedFunctionSignature->ReleaseInternal(); + + asDELETE(m_bindInformations[n], sBindInfo); + } + } + m_bindInformations.SetLength(0); + + // Free declared types, including classes, typedefs, and enums + for( n = 0; n < m_templateInstances.GetLength(); n++ ) + { + asCObjectType *type = m_templateInstances[n]; + if( m_engine->FindNewOwnerForSharedType(type, this) != this ) + { + // The type is owned by another module, just release our reference + type->ReleaseInternal(); + continue; + } + + // Orphan the template instance + type->module = 0; + + // No other module is holding the template type + m_engine->RemoveTemplateInstanceType(type); + type->ReleaseInternal(); + } + m_templateInstances.SetLength(0); + for( n = 0; n < m_classTypes.GetLength(); n++ ) + { + asCObjectType *type = m_classTypes[n]; + if( type->IsShared() ) + { + // The type is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedType(type, this) != this ) + { + // The type is owned by another module, just release our reference + type->ReleaseInternal(); + continue; + } + } + + // The type should be destroyed now + type->DestroyInternal(); + + // Remove the type from the engine + if( type->IsShared() ) + { + m_engine->sharedScriptTypes.RemoveValue(type); + type->ReleaseInternal(); + } + + // Release it from the module + type->module = 0; + type->ReleaseInternal(); + } + m_classTypes.SetLength(0); + for( n = 0; n < m_enumTypes.GetLength(); n++ ) + { + asCEnumType *type = m_enumTypes[n]; + if( type->IsShared() ) + { + // The type is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedType(type, this) != this ) + { + // The type is owned by another module, just release our reference + type->ReleaseInternal(); + continue; + } + } + + // Remove the type from the engine + if( type->IsShared() ) + { + m_engine->sharedScriptTypes.RemoveValue(type); + type->ReleaseInternal(); + } + + // Release it from the module + type->module = 0; + type->ReleaseInternal(); + } + m_enumTypes.SetLength(0); + for( n = 0; n < m_typeDefs.GetLength(); n++ ) + { + asCTypedefType *type = m_typeDefs[n]; + + // The type should be destroyed now + type->DestroyInternal(); + + // Release it from the module + type->module = 0; + type->ReleaseInternal(); + } + m_typeDefs.SetLength(0); + + // Free funcdefs + for( n = 0; n < m_funcDefs.GetLength(); n++ ) + { + asCFuncdefType *func = m_funcDefs[n]; + asASSERT(func); + if( func->funcdef && func->funcdef->IsShared() ) + { + // The funcdef is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedType(func, this) != this ) + { + // The funcdef is owned by another module, just release our reference + func->ReleaseInternal(); + continue; + } + } + + func->DestroyInternal(); + m_engine->RemoveFuncdef(func); + func->module = 0; + func->ReleaseInternal(); + } + m_funcDefs.SetLength(0); + + // Then release the functions + for( n = 0; n < m_scriptFunctions.GetLength(); n++ ) + { + asCScriptFunction *func = m_scriptFunctions[n]; + if( func->IsShared() ) + { + // The func is shared, so transfer ownership to another module that also uses it + if( m_engine->FindNewOwnerForSharedFunc(func, this) != this ) + { + // The func is owned by another module, just release our reference + func->ReleaseInternal(); + continue; + } + } + + func->DestroyInternal(); + func->module = 0; + func->ReleaseInternal(); + } + m_scriptFunctions.SetLength(0); + + // Now remove and release the global properties as there are no more references to them + globIt = m_scriptGlobals.List(); + while( globIt ) + { + m_engine->RemoveGlobalProperty(*globIt); + asASSERT( (*globIt)->refCount.get() == 1 ); + (*globIt)->Release(); + globIt++; + } + m_scriptGlobals.Clear(); + + // Clear the type lookup + // The references were already released as the types were removed from the respective arrays + m_typeLookup.EraseAll(); + + asASSERT( IsEmpty() ); +} + +// interface +asIScriptFunction *asCModule::GetFunctionByName(const char *in_name) const +{ + asCString name; + asSNameSpace *ns = 0; + if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) + return 0; + + // Search recursively in the given namespace, moving up to parent namespace until the function is found + while( ns ) + { + const asCArray &idxs = m_globalFunctions.GetIndexes(ns, name); + if( idxs.GetLength() != 1 ) + return 0; + + const asIScriptFunction *func = m_globalFunctions.Get(idxs[0]); + if( func ) + return const_cast(func); + + // Recursively search parent namespaces + ns = m_engine->GetParentNameSpace(ns); + } + + return 0; +} + +// interface +asUINT asCModule::GetImportedFunctionCount() const +{ + return (asUINT)m_bindInformations.GetLength(); +} + +// interface +int asCModule::GetImportedFunctionIndexByDecl(const char *decl) const +{ + asCBuilder bld(m_engine, const_cast(this)); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCScriptFunction func(m_engine, const_cast(this), asFUNC_DUMMY); + bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_defaultNamespace); + + // TODO: optimize: Improve linear search + // Search script functions for matching interface + int id = -1; + for( asUINT n = 0; n < m_bindInformations.GetLength(); ++n ) + { + if( func.name == m_bindInformations[n]->importedFunctionSignature->name && + func.returnType == m_bindInformations[n]->importedFunctionSignature->returnType && + func.parameterTypes.GetLength() == m_bindInformations[n]->importedFunctionSignature->parameterTypes.GetLength() ) + { + bool match = true; + for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p ) + { + if( func.parameterTypes[p] != m_bindInformations[n]->importedFunctionSignature->parameterTypes[p] ) + { + match = false; + break; + } + } + + if( match ) + { + if( id == -1 ) + id = n; + else + return asMULTIPLE_FUNCTIONS; + } + } + } + + if( id == -1 ) return asNO_FUNCTION; + + return id; +} + +// interface +asUINT asCModule::GetFunctionCount() const +{ + return (asUINT)m_globalFunctions.GetSize(); +} + +// interface +asIScriptFunction *asCModule::GetFunctionByDecl(const char *decl) const +{ + asCBuilder bld(m_engine, const_cast(this)); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCScriptFunction func(m_engine, const_cast(this), asFUNC_DUMMY); + int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, m_defaultNamespace); + if( r < 0 ) + { + // Invalid declaration + // TODO: Write error to message stream + return 0; + } + + // Use the defaultNamespace implicitly unless an explicit namespace has been provided + asSNameSpace *ns = func.nameSpace == m_engine->nameSpaces[0] ? m_defaultNamespace : func.nameSpace; + + // Search script functions for matching interface + while( ns ) + { + asIScriptFunction *f = 0; + const asCArray &idxs = m_globalFunctions.GetIndexes(ns, func.name); + for( unsigned int n = 0; n < idxs.GetLength(); n++ ) + { + const asCScriptFunction *funcPtr = m_globalFunctions.Get(idxs[n]); + if( funcPtr->objectType == 0 && + func.returnType == funcPtr->returnType && + func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength() + ) + { + bool match = true; + for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p ) + { + if( func.parameterTypes[p] != funcPtr->parameterTypes[p] ) + { + match = false; + break; + } + } + + if( match ) + { + if( f == 0 ) + f = const_cast(funcPtr); + else + // Multiple functions + return 0; + } + } + } + + if( f ) + return f; + else + { + // Search for matching functions in the parent namespace + ns = m_engine->GetParentNameSpace(ns); + } + } + + return 0; +} + +// interface +asUINT asCModule::GetGlobalVarCount() const +{ + return (asUINT)m_scriptGlobals.GetSize(); +} + +// interface +int asCModule::GetGlobalVarIndexByName(const char *in_name) const +{ + asCString name; + asSNameSpace *ns = 0; + if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) + return asINVALID_ARG; + + // Find the global var id + while( ns ) + { + int id = m_scriptGlobals.GetFirstIndex(ns, name); + if( id >= 0 ) return id; + + // Recursively search parent namespaces + ns = m_engine->GetParentNameSpace(ns); + } + + return asNO_GLOBAL_VAR; +} + +// interface +int asCModule::RemoveGlobalVar(asUINT index) +{ + asCGlobalProperty *prop = m_scriptGlobals.Get(index); + if( !prop ) + return asINVALID_ARG; + + // If the global variables have already been initialized + // then uninitialize the variable before it is removed + if (m_isGlobalVarInitialized) + UninitializeGlobalProp(prop); + + // Destroy the internal of the global variable (removes the initialization function) + prop->DestroyInternal(); + + // Check if the module is the only one referring to the property, if so remove it from the engine too + // If the property is not removed now, it will be removed later when the module is discarded + if( prop->refCount.get() == 2 ) + m_engine->RemoveGlobalProperty(prop); + + // Remove the global variable from the module + m_scriptGlobals.Erase(index); + prop->Release(); + + return 0; +} + +// interface +int asCModule::GetGlobalVarIndexByDecl(const char *decl) const +{ + asCBuilder bld(m_engine, const_cast(this)); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCString declName; + asSNameSpace *nameSpace; + asCDataType dt; + int r = bld.ParseVariableDeclaration(decl, m_defaultNamespace, declName, nameSpace, dt); + if( r < 0 ) + return r; + + // Search global variables for a match + while( nameSpace ) + { + int id = m_scriptGlobals.GetFirstIndex(nameSpace, declName, asCCompGlobPropType(dt)); + if( id != -1 ) + return id; + + // Recursively search parent namespace + nameSpace = m_engine->GetParentNameSpace(nameSpace); + } + + return asNO_GLOBAL_VAR; +} + +// interface +void *asCModule::GetAddressOfGlobalVar(asUINT index) +{ + asCGlobalProperty *prop = m_scriptGlobals.Get(index); + if( !prop ) + return 0; + + // For object variables it's necessary to dereference the pointer to get the address of the value + if( prop->type.IsObject() && + !prop->type.IsObjectHandle() ) + return *(void**)(prop->GetAddressOfValue()); + + return (void*)(prop->GetAddressOfValue()); +} + +// interface +const char *asCModule::GetGlobalVarDeclaration(asUINT index, bool includeNamespace) const +{ + const asCGlobalProperty *prop = m_scriptGlobals.Get(index); + if (!prop) return 0; + + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = prop->type.Format(m_defaultNamespace); + *tempString += " "; + if( includeNamespace && prop->nameSpace->name != "" ) + *tempString += prop->nameSpace->name + "::"; + *tempString += prop->name; + + return tempString->AddressOf(); +} + +// interface +int asCModule::GetGlobalVar(asUINT index, const char **out_name, const char **out_nameSpace, int *out_typeId, bool *out_isConst) const +{ + const asCGlobalProperty *prop = m_scriptGlobals.Get(index); + if (!prop) return asINVALID_ARG; + + if( out_name ) + *out_name = prop->name.AddressOf(); + if( out_nameSpace ) + *out_nameSpace = prop->nameSpace->name.AddressOf(); + if( out_typeId ) + *out_typeId = m_engine->GetTypeIdFromDataType(prop->type); + if( out_isConst ) + *out_isConst = prop->type.IsReadOnly(); + + return asSUCCESS; +} + +// interface +asUINT asCModule::GetObjectTypeCount() const +{ + return (asUINT)m_classTypes.GetLength(); +} + +// interface +asITypeInfo *asCModule::GetObjectTypeByIndex(asUINT index) const +{ + if( index >= m_classTypes.GetLength() ) + return 0; + + return m_classTypes[index]; +} + +// interface +asITypeInfo *asCModule::GetTypeInfoByName(const char *in_name) const +{ + asCString name; + asSNameSpace *ns = 0; + if( m_engine->DetermineNameAndNamespace(in_name, m_defaultNamespace, name, ns) < 0 ) + return 0; + + while (ns) + { + asITypeInfo* info = GetType(name, ns); + if(info) + { + return info; + } + + // Recursively search parent namespace + ns = m_engine->GetParentNameSpace(ns); + } + + return 0; +} + +// interface +int asCModule::GetTypeIdByDecl(const char *decl) const +{ + asCDataType dt; + + // This const cast is safe since we know the engine won't be modified + asCBuilder bld(m_engine, const_cast(this)); + + // Don't write parser errors to the message callback + bld.silent = true; + + int r = bld.ParseDataType(decl, &dt, m_defaultNamespace); + if( r < 0 ) + return asINVALID_TYPE; + + return m_engine->GetTypeIdFromDataType(dt); +} + +// interface +asITypeInfo *asCModule::GetTypeInfoByDecl(const char *decl) const +{ + asCDataType dt; + + // This const cast is safe since we know the engine won't be modified + asCBuilder bld(m_engine, const_cast(this)); + + // Don't write parser errors to the message callback + bld.silent = true; + + int r = bld.ParseDataType(decl, &dt, m_defaultNamespace); + if (r < 0) + return 0; + + return dt.GetTypeInfo(); +} + +// interface +asUINT asCModule::GetEnumCount() const +{ + return m_enumTypes.GetLength(); +} + +// interface +asITypeInfo *asCModule::GetEnumByIndex(asUINT index) const +{ + if( index >= m_enumTypes.GetLength() ) + return 0; + + return m_enumTypes[index]; +} + +// interface +asUINT asCModule::GetTypedefCount() const +{ + return (asUINT)m_typeDefs.GetLength(); +} + +// interface +asITypeInfo *asCModule::GetTypedefByIndex(asUINT index) const +{ + if( index >= m_typeDefs.GetLength() ) + return 0; + + return m_typeDefs[index]; +} + +// internal +int asCModule::GetNextImportedFunctionId() +{ + // TODO: multithread: This will break if one thread if freeing a module, while another is being compiled + if( m_engine->freeImportedFunctionIdxs.GetLength() ) + return FUNC_IMPORTED | (asUINT)m_engine->freeImportedFunctionIdxs[m_engine->freeImportedFunctionIdxs.GetLength()-1]; + + return FUNC_IMPORTED | (asUINT)m_engine->importedFunctions.GetLength(); +} + +#ifndef AS_NO_COMPILER +// internal +int asCModule::AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &funcName, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType, bool isGlobalFunction, asSFunctionTraits funcTraits, asSNameSpace *ns) +{ + asASSERT(id >= 0); + + // Store the function information + asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, this, isInterface ? asFUNC_INTERFACE : asFUNC_SCRIPT); + if( func == 0 ) + { + // Free the default args + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + return asOUT_OF_MEMORY; + } + + if( ns == 0 ) + ns = m_engine->nameSpaces[0]; + + // All methods of shared objects are also shared + if( objType && objType->IsShared() ) + funcTraits.SetTrait(asTRAIT_SHARED, true); + + func->name = funcName; + func->nameSpace = ns; + func->id = id; + func->returnType = returnType; + if( func->funcType == asFUNC_SCRIPT ) + { + func->scriptData->scriptSectionIdx = sectionIdx; + func->scriptData->declaredAt = declaredAt; + } + func->parameterTypes = params; + func->parameterNames = paramNames; + func->inOutFlags = inOutFlags; + func->defaultArgs = defaultArgs; + func->objectType = objType; + if( objType ) + objType->AddRefInternal(); + func->traits = funcTraits; + + asASSERT( params.GetLength() == inOutFlags.GetLength() && params.GetLength() == defaultArgs.GetLength() ); + + // Verify that we are not assigning either the final or override specifier(s) if we are registering a non-member function + asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_FINAL)) ); + asASSERT( !(!objType && funcTraits.GetTrait(asTRAIT_OVERRIDE)) ); + + // The internal ref count was already set by the constructor + m_scriptFunctions.PushLast(func); + m_engine->AddScriptFunction(func); + + // Compute the signature id + if( objType ) + func->ComputeSignatureId(); + + // Add reference + if( isGlobalFunction ) + m_globalFunctions.Put(func); + + return 0; +} + +// internal +int asCModule::AddScriptFunction(asCScriptFunction *func) +{ + m_scriptFunctions.PushLast(func); + func->AddRefInternal(); + m_engine->AddScriptFunction(func); + + // If the function that is being added is an already compiled shared function + // then it is necessary to look for anonymous functions that may be declared + // within it and add those as well + if( func->IsShared() && func->funcType == asFUNC_SCRIPT ) + { + // Loop through the byte code and check all the + // asBC_FuncPtr instructions for anonymous functions + asDWORD *bc = func->scriptData->byteCode.AddressOf(); + asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength(); + for( asUINT n = 0; n < bcLength; ) + { + int c = *(asBYTE*)&bc[n]; + if( c == asBC_FuncPtr ) + { + asCScriptFunction *f = reinterpret_cast(asBC_PTRARG(&bc[n])); + // Anonymous functions start with $ + // There are never two equal anonymous functions so it is not necessary to look for duplicates + if( f && f->name[0] == '$' ) + { + AddScriptFunction(f); + m_globalFunctions.Put(f); + } + } + n += asBCTypeSize[asBCInfo[c].type]; + } + } + + return 0; +} + +// internal +int asCModule::AddImportedFunction(int id, const asCString &funcName, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSFunctionTraits funcTraits, asSNameSpace *ns, const asCString &moduleName) +{ + asASSERT(id >= 0); + + // Store the function information + asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, this, asFUNC_IMPORTED); + if( func == 0 ) + { + // Free the default args + for( asUINT n = 0; n < defaultArgs.GetLength(); n++ ) + if( defaultArgs[n] ) + asDELETE(defaultArgs[n], asCString); + + return asOUT_OF_MEMORY; + } + + func->name = funcName; + func->id = id; + func->returnType = returnType; + func->nameSpace = ns; + func->parameterTypes = params; + func->inOutFlags = inOutFlags; + func->defaultArgs = defaultArgs; + func->objectType = 0; + func->traits = funcTraits; + + sBindInfo *info = asNEW(sBindInfo); + if( info == 0 ) + { + asDELETE(func, asCScriptFunction); + return asOUT_OF_MEMORY; + } + + info->importedFunctionSignature = func; + info->boundFunctionId = -1; + info->importFromModule = moduleName; + m_bindInformations.PushLast(info); + + // Add the info to the array in the engine + if( m_engine->freeImportedFunctionIdxs.GetLength() ) + m_engine->importedFunctions[m_engine->freeImportedFunctionIdxs.PopLast()] = info; + else + m_engine->importedFunctions.PushLast(info); + + return 0; +} +#endif + +// internal +asCScriptFunction *asCModule::GetImportedFunction(int index) const +{ + return m_bindInformations[index]->importedFunctionSignature; +} + +// interface +int asCModule::BindImportedFunction(asUINT index, asIScriptFunction *func) +{ + // First unbind the old function + int r = UnbindImportedFunction(index); + if( r < 0 ) return r; + + // Must verify that the interfaces are equal + asCScriptFunction *dst = GetImportedFunction(index); + if( dst == 0 ) return asNO_FUNCTION; + + if( func == 0 ) + return asINVALID_ARG; + + asCScriptFunction *src = m_engine->GetScriptFunction(func->GetId()); + if( src == 0 ) + return asNO_FUNCTION; + + // Verify return type + if( dst->returnType != src->returnType ) + return asINVALID_INTERFACE; + + if( dst->parameterTypes.GetLength() != src->parameterTypes.GetLength() ) + return asINVALID_INTERFACE; + + for( asUINT n = 0; n < dst->parameterTypes.GetLength(); ++n ) + { + if( dst->parameterTypes[n] != src->parameterTypes[n] ) + return asINVALID_INTERFACE; + } + + m_bindInformations[index]->boundFunctionId = src->GetId(); + src->AddRefInternal(); + + return asSUCCESS; +} + +// interface +int asCModule::UnbindImportedFunction(asUINT index) +{ + if( index >= m_bindInformations.GetLength() ) + return asINVALID_ARG; + + // Remove reference to old module + if( m_bindInformations[index] ) + { + int oldFuncID = m_bindInformations[index]->boundFunctionId; + if( oldFuncID != -1 ) + { + m_bindInformations[index]->boundFunctionId = -1; + m_engine->scriptFunctions[oldFuncID]->ReleaseInternal(); + } + } + + return asSUCCESS; +} + +// interface +const char *asCModule::GetImportedFunctionDeclaration(asUINT index) const +{ + asCScriptFunction *func = GetImportedFunction(index); + if( func == 0 ) return 0; + + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = func->GetDeclarationStr(); + + return tempString->AddressOf(); +} + +// interface +const char *asCModule::GetImportedFunctionSourceModule(asUINT index) const +{ + if( index >= m_bindInformations.GetLength() ) + return 0; + + return m_bindInformations[index]->importFromModule.AddressOf(); +} + +// inteface +int asCModule::BindAllImportedFunctions() +{ + bool notAllFunctionsWereBound = false; + + // Bind imported functions + int c = GetImportedFunctionCount(); + for( int n = 0; n < c; ++n ) + { + asCScriptFunction *importFunc = GetImportedFunction(n); + if( importFunc == 0 ) return asERROR; + + asCString str = importFunc->GetDeclarationStr(false, true); + + // Get module name from where the function should be imported + const char *moduleName = GetImportedFunctionSourceModule(n); + if( moduleName == 0 ) return asERROR; + + asCModule *srcMod = m_engine->GetModule(moduleName, false); + asIScriptFunction *func = 0; + if( srcMod ) + func = srcMod->GetFunctionByDecl(str.AddressOf()); + + if( func == 0 ) + notAllFunctionsWereBound = true; + else + { + if( BindImportedFunction(n, func) < 0 ) + notAllFunctionsWereBound = true; + } + } + + if( notAllFunctionsWereBound ) + return asCANT_BIND_ALL_FUNCTIONS; + + return asSUCCESS; +} + +// interface +int asCModule::UnbindAllImportedFunctions() +{ + asUINT c = GetImportedFunctionCount(); + for( asUINT n = 0; n < c; ++n ) + UnbindImportedFunction(n); + + return asSUCCESS; +} + +// internal +void asCModule::AddClassType(asCObjectType* type) +{ + m_classTypes.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); +} + +// internal +void asCModule::AddEnumType(asCEnumType* type) +{ + m_enumTypes.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); +} + +// internal +void asCModule::AddTypeDef(asCTypedefType* type) +{ + m_typeDefs.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); +} + +// internal +void asCModule::AddFuncDef(asCFuncdefType* type) +{ + m_funcDefs.PushLast(type); + m_typeLookup.Insert({type->nameSpace, type->name}, type); +} + +// internal +void asCModule::ReplaceFuncDef(asCFuncdefType* type, asCFuncdefType* newType) +{ + int i = m_funcDefs.IndexOf(type); + if( i >= 0 ) + { + m_funcDefs[i] = newType; + + // Replace it in the lookup map too + asSMapNode* result = nullptr; + if(m_typeLookup.MoveTo(&result, {type->nameSpace, type->name})) + { + asASSERT( result->value == type ); + result->value = newType; + } + } +} + +// internal +asCTypeInfo *asCModule::GetType(const asCString &type, asSNameSpace *ns) const +{ + asSMapNode* result = nullptr; + if(m_typeLookup.MoveTo(&result, {ns, type})) + { + return result->value; + } + return 0; +} + +// internal +asCObjectType *asCModule::GetObjectType(const char *type, asSNameSpace *ns) const +{ + asSMapNode* result = nullptr; + if(m_typeLookup.MoveTo(&result, {ns, type})) + { + return CastToObjectType(result->value); + } + + return 0; +} + +// internal +asCGlobalProperty *asCModule::AllocateGlobalProperty(const char *propName, const asCDataType &dt, asSNameSpace *ns) +{ + asCGlobalProperty *prop = m_engine->AllocateGlobalProperty(); + prop->name = propName; + prop->nameSpace = ns; + + // Allocate the memory for this property based on its type + prop->type = dt; + prop->AllocateMemory(); + + // Make an entry in the address to variable map + m_engine->varAddressMap.Insert(prop->GetAddressOfValue(), prop); + + // Store the variable in the module scope + m_scriptGlobals.Put(prop); + prop->AddRef(); + + return prop; +} + +// internal +bool asCModule::IsEmpty() const +{ + if( m_scriptFunctions.GetLength() ) return false; + if( m_globalFunctions.GetSize() ) return false; + if( m_bindInformations.GetLength() ) return false; + if( m_scriptGlobals.GetSize() ) return false; + if( m_classTypes.GetLength() ) return false; + if( m_enumTypes.GetLength() ) return false; + if( m_typeDefs.GetLength() ) return false; + if( m_funcDefs.GetLength() ) return false; + + return true; +} + +// interface +int asCModule::SaveByteCode(asIBinaryStream *out, bool stripDebugInfo) const +{ +#ifdef AS_NO_COMPILER + UNUSED_VAR(out); + UNUSED_VAR(stripDebugInfo); + return asNOT_SUPPORTED; +#else + if( out == 0 ) return asINVALID_ARG; + + // Make sure there is actually something to save + if( IsEmpty() ) + return asERROR; + + asCWriter write(const_cast(this), out, m_engine, stripDebugInfo); + return write.Write(); +#endif +} + +// interface +int asCModule::LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped) +{ + if( in == 0 ) return asINVALID_ARG; + + // Don't allow the module to be rebuilt if there are still + // external references that will need the previous code + if( HasExternalReferences(false) ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_MODULE_IS_IN_USE); + return asMODULE_IS_IN_USE; + } + + // Only permit loading bytecode if no other thread is currently compiling + // TODO: It should be possible to have multiple threads perform compilations + int r = m_engine->RequestBuild(); + if( r < 0 ) + return r; + + asCReader read(this, in, m_engine); + r = read.Read(wasDebugInfoStripped); + if (r < 0) + { + m_engine->BuildCompleted(); + return r; + } + + JITCompile(); + +#ifdef AS_DEBUG + // Verify that there are no unwanted gaps in the scriptFunctions array. + for( asUINT n = 1; n < m_engine->scriptFunctions.GetLength(); n++ ) + { + int id = n; + if( m_engine->scriptFunctions[n] == 0 && !m_engine->freeScriptFunctionIds.Exists(id) ) + asASSERT( false ); + } +#endif + + m_engine->BuildCompleted(); + + return r; +} + +// interface +int asCModule::CompileGlobalVar(const char *sectionName, const char *code, int lineOffset) +{ +#ifdef AS_NO_COMPILER + UNUSED_VAR(sectionName); + UNUSED_VAR(code); + UNUSED_VAR(lineOffset); + return asNOT_SUPPORTED; +#else + // Validate arguments + if( code == 0 ) + return asINVALID_ARG; + + // Only one thread may build at one time + // TODO: It should be possible to have multiple threads perform compilations + int r = m_engine->RequestBuild(); + if( r < 0 ) + return r; + + // Prepare the engine + m_engine->PrepareEngine(); + if( m_engine->configFailed ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); + m_engine->BuildCompleted(); + return asINVALID_CONFIGURATION; + } + + // Compile the global variable and add it to the module scope + asCBuilder varBuilder(m_engine, this); + asCString str = code; + r = varBuilder.CompileGlobalVar(sectionName, str.AddressOf(), lineOffset); + + m_engine->BuildCompleted(); + + // Initialize the variable + if( r >= 0 ) + { + // Clear the memory + asCGlobalProperty *prop = m_scriptGlobals.GetLast(); + if( prop ) + { + memset(prop->GetAddressOfValue(), 0, sizeof(asDWORD)*prop->type.GetSizeOnStackDWords()); + } + + if( prop && m_engine->ep.initGlobalVarsAfterBuild ) + { + // Flag that there are initialized global variables + m_isGlobalVarInitialized = true; + + r = InitGlobalProp(prop, 0); + } + } + + return r; +#endif +} + +// interface +int asCModule::CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc) +{ + // Make sure the outFunc is null if the function fails, so the + // application doesn't attempt to release a non-existent function + if( outFunc ) + *outFunc = 0; + +#ifdef AS_NO_COMPILER + UNUSED_VAR(sectionName); + UNUSED_VAR(code); + UNUSED_VAR(lineOffset); + UNUSED_VAR(compileFlags); + return asNOT_SUPPORTED; +#else + // Validate arguments + if( code == 0 || + (compileFlags != 0 && compileFlags != asCOMP_ADD_TO_MODULE) ) + return asINVALID_ARG; + + // Only one thread may build at one time + // TODO: It should be possible to have multiple threads perform compilations + int r = m_engine->RequestBuild(); + if( r < 0 ) + return r; + + // Prepare the engine + m_engine->PrepareEngine(); + if( m_engine->configFailed ) + { + m_engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_INVALID_CONFIGURATION); + m_engine->BuildCompleted(); + return asINVALID_CONFIGURATION; + } + + // Compile the single function + asCBuilder funcBuilder(m_engine, this); + asCString str = code; + asCScriptFunction *func = 0; + r = funcBuilder.CompileFunction(sectionName, str.AddressOf(), lineOffset, compileFlags, &func); + + m_engine->BuildCompleted(); + + if( r >= 0 && outFunc && func ) + { + // Return the function to the caller and add an external reference + *outFunc = func; + func->AddRef(); + } + + // Release our reference to the function + if( func ) + func->ReleaseInternal(); + + return r; +#endif +} + +// interface +int asCModule::RemoveFunction(asIScriptFunction *func) +{ + // Find the global function + asCScriptFunction *f = static_cast(func); + int idx = m_globalFunctions.GetIndex(f); + if( idx >= 0 ) + { + m_globalFunctions.Erase(idx); + m_scriptFunctions.RemoveValue(f); + f->ReleaseInternal(); + return 0; + } + + return asNO_FUNCTION; +} + +#ifndef AS_NO_COMPILER +// internal +int asCModule::AddFuncDef(const asCString &funcName, asSNameSpace *ns, asCObjectType *parent) +{ + // namespace and parent are mutually exclusive + asASSERT((ns == 0 && parent) || (ns && parent == 0)); + + asCScriptFunction *func = asNEW(asCScriptFunction)(m_engine, 0, asFUNC_FUNCDEF); + if (func == 0) + return asOUT_OF_MEMORY; + + func->name = funcName; + func->nameSpace = ns; + func->module = this; + + asCFuncdefType *fdt = asNEW(asCFuncdefType)(m_engine, func); + AddFuncDef(fdt); // The constructor set the refcount to 1 + + m_engine->funcDefs.PushLast(fdt); // doesn't increase refcount + func->id = m_engine->GetNextScriptFunctionId(); + m_engine->AddScriptFunction(func); + + if (parent) + { + parent->childFuncDefs.PushLast(fdt); + fdt->parentClass = parent; + } + + return (int)m_funcDefs.GetLength()-1; +} +#endif + +// interface +asDWORD asCModule::SetAccessMask(asDWORD mask) +{ + asDWORD old = m_accessMask; + m_accessMask = mask; + return old; +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_module.h b/angelscript/source/as_module.h new file mode 100644 index 0000000..04a0af3 --- /dev/null +++ b/angelscript/source/as_module.h @@ -0,0 +1,257 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_module.h +// +// A class that holds a script module +// + +#ifndef AS_MODULE_H +#define AS_MODULE_H + +#include "as_config.h" +#include "as_symboltable.h" +#include "as_atomic.h" +#include "as_string.h" +#include "as_array.h" +#include "as_datatype.h" +#include "as_scriptfunction.h" +#include "as_property.h" + +BEGIN_AS_NAMESPACE + +// TODO: import: Remove this when the imported functions are removed +const int FUNC_IMPORTED = 0x40000000; + +class asCScriptEngine; +class asCCompiler; +class asCBuilder; +class asCContext; +class asCConfigGroup; +class asCTypedefType; +class asCFuncdefType; +struct asSNameSpace; + +struct sBindInfo +{ + asCScriptFunction *importedFunctionSignature; + asCString importFromModule; + int boundFunctionId; +}; + +struct sObjectTypePair +{ + asCObjectType *a; + asCObjectType *b; +}; + + +// TODO: import: Remove function imports. When I have implemented function +// pointers the function imports should be deprecated. + +// TODO: Need a separate interface for compiling scripts. The asIScriptCompiler +// will have a target module, and will allow the compilation of an entire +// script or just individual functions within the scope of the module +// +// With this separation it will be possible to compile the library without +// the compiler, thus giving a much smaller binary executable. + +// TODO: There should be a special compile option that will let the application +// recompile an already compiled script. The compiler should check if no +// destructive changes have been made (changing function signatures, etc) +// then it should simply replace the bytecode within the functions without +// changing the values of existing global properties, etc. + +class asCModule : public asIScriptModule +{ +//------------------------------------------- +// Public interface +//-------------------------------------------- +public: + virtual asIScriptEngine *GetEngine() const; + virtual void SetName(const char *name); + virtual const char *GetName() const; + virtual void Discard(); + + // Compilation + virtual int AddScriptSection(const char *name, const char *code, size_t codeLength, int lineOffset); + virtual int Build(); + virtual int CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD reserved, asIScriptFunction **outFunc); + virtual int CompileGlobalVar(const char *sectionName, const char *code, int lineOffset); + virtual asDWORD SetAccessMask(asDWORD accessMask); + virtual int SetDefaultNamespace(const char *nameSpace); + virtual const char *GetDefaultNamespace() const; + + // Script functions + virtual asUINT GetFunctionCount() const; + virtual asIScriptFunction *GetFunctionByIndex(asUINT index) const; + virtual asIScriptFunction *GetFunctionByDecl(const char *decl) const; + virtual asIScriptFunction *GetFunctionByName(const char *name) const; + virtual int RemoveFunction(asIScriptFunction *func); + + // Script global variables + // TODO: interface: Should be called InitGlobalVars, and should have a bool to reset in case already initialized + virtual int ResetGlobalVars(asIScriptContext *ctx); + virtual asUINT GetGlobalVarCount() const; + virtual int GetGlobalVarIndexByName(const char *name) const; + virtual int GetGlobalVarIndexByDecl(const char *decl) const; + virtual const char *GetGlobalVarDeclaration(asUINT index, bool includeNamespace) const; + virtual int GetGlobalVar(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst) const; + virtual void *GetAddressOfGlobalVar(asUINT index); + virtual int RemoveGlobalVar(asUINT index); + + // Type identification + virtual asUINT GetObjectTypeCount() const; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const; + virtual int GetTypeIdByDecl(const char *decl) const; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; + + // Enums + virtual asUINT GetEnumCount() const; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const; + + // Typedefs + virtual asUINT GetTypedefCount() const; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const; + + // Dynamic binding between modules + virtual asUINT GetImportedFunctionCount() const; + virtual int GetImportedFunctionIndexByDecl(const char *decl) const; + virtual const char *GetImportedFunctionDeclaration(asUINT importIndex) const; + virtual const char *GetImportedFunctionSourceModule(asUINT importIndex) const; + virtual int BindImportedFunction(asUINT index, asIScriptFunction *func); + virtual int UnbindImportedFunction(asUINT importIndex); + virtual int BindAllImportedFunctions(); + virtual int UnbindAllImportedFunctions(); + + // Bytecode Saving/Loading + virtual int SaveByteCode(asIBinaryStream *out, bool stripDebugInfo) const; + virtual int LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped); + + // User data + virtual void *SetUserData(void *data, asPWORD type); + virtual void *GetUserData(asPWORD type) const; + +//----------------------------------------------- +// Internal +//----------------------------------------------- + asCModule(const char *name, asCScriptEngine *engine); + ~asCModule(); + +//protected: + friend class asCScriptEngine; + friend class asCBuilder; + friend class asCCompiler; + friend class asCContext; + friend class asCRestore; + + void InternalReset(); + bool IsEmpty() const; + bool HasExternalReferences(bool shuttingDown); + + int CallInit(asIScriptContext *ctx); + void CallExit(); + int InitGlobalProp(asCGlobalProperty *prop, asIScriptContext *ctx); + + void JITCompile(); + +#ifndef AS_NO_COMPILER + int AddScriptFunction(int sectionIdx, int declaredAt, int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray ¶mNames, const asCArray &inOutFlags, const asCArray &defaultArgs, bool isInterface, asCObjectType *objType = 0, bool isGlobalFunction = false, asSFunctionTraits funcTraits = asSFunctionTraits(), asSNameSpace *ns = 0); + int AddScriptFunction(asCScriptFunction *func); + int AddImportedFunction(int id, const asCString &name, const asCDataType &returnType, const asCArray ¶ms, const asCArray &inOutFlags, const asCArray &defaultArgs, asSFunctionTraits funcTraits, asSNameSpace *ns, const asCString &moduleName); + int AddFuncDef(const asCString &name, asSNameSpace *ns, asCObjectType *parent); +#endif + + int GetNextImportedFunctionId(); + asCScriptFunction *GetImportedFunction(int funcId) const; + asCTypeInfo *GetType(const asCString &type, asSNameSpace *ns) const; + asCObjectType *GetObjectType(const char *type, asSNameSpace *ns) const; + asCGlobalProperty *AllocateGlobalProperty(const char *name, const asCDataType &dt, asSNameSpace *ns); + void UninitializeGlobalProp(asCGlobalProperty *prop); + + // Adds the class type to the module. The module assumes ownership of the reference without increasing it + void AddClassType(asCObjectType*); + // Adds the enum type to the module. The module assumes ownership of the reference without increasing it + void AddEnumType(asCEnumType*); + // Adds the typedef to the module. The module assumes ownership of the reference without increasing it + void AddTypeDef(asCTypedefType*); + // Adds the funcdef to the module. The module assumes ownership of the reference without increasing it + void AddFuncDef(asCFuncdefType*); + // Replaces an existing funcdef with another (used for shared funcdefs). Doesn't add or release refCounts + void ReplaceFuncDef(asCFuncdefType *oldType, asCFuncdefType *newType); + + asCString m_name; + asCScriptEngine *m_engine; + asCBuilder *m_builder; + asCArray m_userData; + asDWORD m_accessMask; + asSNameSpace *m_defaultNamespace; + + // This array holds all functions, class members, factories, etc that were compiled with the module. + // These references hold an internal reference to the function object. + asCArray m_scriptFunctions; // increases ref count + // This array holds global functions declared in the module. These references are not counted, + // as the same pointer is always present in the scriptFunctions array too. + asCSymbolTable m_globalFunctions; // doesn't increase ref count + // This array holds imported functions in the module. + asCArray m_bindInformations; // increases ref count + // This array holds template instance types created for the module's object types + asCArray m_templateInstances; // increases ref count + + // This array holds the global variables declared in the script + asCSymbolTable m_scriptGlobals; // increases ref count + bool m_isGlobalVarInitialized; + + // This array holds class and interface types + asCArray m_classTypes; // increases ref count + // This array holds enum types + asCArray m_enumTypes; // increases ref count + // This array holds typedefs + asCArray m_typeDefs; // increases ref count + // This array holds the funcdefs declared in the module + asCArray m_funcDefs; // increases ref count + + // This map contains all the types (also contained in the arrays above) for quick lookup + // TODO: memory: Can we eliminate the arrays above? + asCMap m_typeLookup; // doesn't increase ref count + + // This array holds types that have been explicitly declared with 'external' + asCArray m_externalTypes; // doesn't increase ref count + // This array holds functions that have been explicitly declared with 'external' + asCArray m_externalFunctions; // doesn't increase ref count +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_namespace.h b/angelscript/source/as_namespace.h new file mode 100644 index 0000000..ae384e7 --- /dev/null +++ b/angelscript/source/as_namespace.h @@ -0,0 +1,77 @@ +/* + AngelCode Scripting Library + Copyright (c) 2013-2014 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +#ifndef AS_NAMESPACE_H +#define AS_NAMESPACE_H + +#include "as_string.h" + +BEGIN_AS_NAMESPACE + +struct asSNameSpace +{ + asCString name; + + // TODO: namespace: A namespace should have access masks. The application should be + // able to restrict specific namespaces from access to specific modules +}; + + +struct asSNameSpaceNamePair +{ + const asSNameSpace *ns; + asCString name; + + asSNameSpaceNamePair() : ns(0) {} + asSNameSpaceNamePair(const asSNameSpace *_ns, const asCString &_name) : ns(_ns), name(_name) {} + + asSNameSpaceNamePair &operator=(const asSNameSpaceNamePair &other) + { + ns = other.ns; + name = other.name; + return *this; + } + + bool operator==(const asSNameSpaceNamePair &other) const + { + return (ns == other.ns && name == other.name); + } + + bool operator<(const asSNameSpaceNamePair &other) const + { + return (ns < other.ns || (ns == other.ns && name < other.name)); + } +}; + +END_AS_NAMESPACE + +#endif + diff --git a/angelscript/source/as_objecttype.cpp b/angelscript/source/as_objecttype.cpp new file mode 100644 index 0000000..626cb11 --- /dev/null +++ b/angelscript/source/as_objecttype.cpp @@ -0,0 +1,707 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_objecttype.cpp +// +// A class for storing object type information +// + + +#include + +#include "as_config.h" +#include "as_objecttype.h" +#include "as_configgroup.h" +#include "as_scriptengine.h" + +BEGIN_AS_NAMESPACE + +asCObjectType::asCObjectType() : asCTypeInfo() +{ + derivedFrom = 0; + + acceptValueSubType = true; + acceptRefSubType = true; + +#ifdef WIP_16BYTE_ALIGN + alignment = 4; +#endif +} + +asCObjectType::asCObjectType(asCScriptEngine *in_engine) : asCTypeInfo(in_engine) +{ + derivedFrom = 0; + + acceptValueSubType = true; + acceptRefSubType = true; + +#ifdef WIP_16BYTE_ALIGN + alignment = 4; +#endif +} + +// interface +asUINT asCObjectType::GetChildFuncdefCount() const +{ + return childFuncDefs.GetLength(); +} + +// interface +asITypeInfo *asCObjectType::GetChildFuncdef(asUINT index) const +{ + if (index >= childFuncDefs.GetLength()) + return 0; + + return childFuncDefs[index]; +} + +// internal +void asCObjectType::DestroyInternal() +{ + if( engine == 0 ) return; + + // Skip this for list patterns as they do not increase the references + if( flags & asOBJ_LIST_PATTERN ) + { + // Clear the engine pointer to mark the object type as invalid + engine = 0; + return; + } + + // Release the object types held by the templateSubTypes + bool isTemplateInstance = templateSubTypes.GetLength() > 0; + for( asUINT subtypeIndex = 0; subtypeIndex < templateSubTypes.GetLength(); subtypeIndex++ ) + { + if( templateSubTypes[subtypeIndex].GetTypeInfo() ) + templateSubTypes[subtypeIndex].GetTypeInfo()->ReleaseInternal(); + } + templateSubTypes.SetLength(0); + + // Clear the child types + for (asUINT n = 0; n < childFuncDefs.GetLength(); n++) + { + asCFuncdefType *func = childFuncDefs[n]; + if (func) + { + func->parentClass = 0; + if (isTemplateInstance) + { + // Any child funcdefs that have been created as part of the template + // instantiation must be destroyed too + // TODO: Before destroying the funcdef, make sure no external references to it is held + if (func->externalRefCount.get() == 0) + { + func->DestroyInternal(); + engine->RemoveFuncdef(func); + func->module = 0; + func->ReleaseInternal(); + } + } + } + } + childFuncDefs.SetLength(0); + + if( derivedFrom ) + derivedFrom->ReleaseInternal(); + derivedFrom = 0; + + ReleaseAllProperties(); + + ReleaseAllFunctions(); + + CleanUserData(); + + // Remove the type from the engine + if( typeId != -1 ) + engine->RemoveFromTypeIdMap(this); + + // Clear the engine pointer to mark the object type as invalid + engine = 0; +} + +asCObjectType::~asCObjectType() +{ + DestroyInternal(); +} + +// interface +bool asCObjectType::Implements(const asITypeInfo *objType) const +{ + if( this == objType ) + return true; + + for( asUINT n = 0; n < interfaces.GetLength(); n++ ) + if( interfaces[n] == objType ) return true; + + return false; +} + +// interface +bool asCObjectType::DerivesFrom(const asITypeInfo *objType) const +{ + if( this == objType ) + return true; + + asCObjectType *base = derivedFrom; + while( base ) + { + if( base == objType ) + return true; + + base = base->derivedFrom; + } + + return false; +} + +// interface +int asCObjectType::GetSubTypeId(asUINT subtypeIndex) const +{ + // This method is only supported for templates and template specializations + if( templateSubTypes.GetLength() == 0 ) + return asERROR; + + if( subtypeIndex >= templateSubTypes.GetLength() ) + return asINVALID_ARG; + + return engine->GetTypeIdFromDataType(templateSubTypes[subtypeIndex]); +} + +// interface +asITypeInfo *asCObjectType::GetSubType(asUINT subtypeIndex) const +{ + if( subtypeIndex >= templateSubTypes.GetLength() ) + return 0; + + return templateSubTypes[subtypeIndex].GetTypeInfo(); +} + +asUINT asCObjectType::GetSubTypeCount() const +{ + return asUINT(templateSubTypes.GetLength()); +} + +asUINT asCObjectType::GetInterfaceCount() const +{ + return asUINT(interfaces.GetLength()); +} + +asITypeInfo *asCObjectType::GetInterface(asUINT index) const +{ + return interfaces[index]; +} + +// internal +bool asCObjectType::IsInterface() const +{ + if( (flags & asOBJ_SCRIPT_OBJECT) && size == 0 ) + return true; + + return false; +} + +// interface +asUINT asCObjectType::GetFactoryCount() const +{ + return (asUINT)beh.factories.GetLength(); +} + +// interface +asIScriptFunction *asCObjectType::GetFactoryByIndex(asUINT index) const +{ + if( index >= beh.factories.GetLength() ) + return 0; + + return engine->GetFunctionById(beh.factories[index]); +} + +// interface +asIScriptFunction *asCObjectType::GetFactoryByDecl(const char *decl) const +{ + if( beh.factories.GetLength() == 0 ) + return 0; + + // Let the engine parse the string and find the appropriate factory function + return engine->GetFunctionById(engine->GetFactoryIdByDecl(this, decl)); +} + +// interface +asUINT asCObjectType::GetMethodCount() const +{ + return (asUINT)methods.GetLength(); +} + +// interface +asIScriptFunction *asCObjectType::GetMethodByIndex(asUINT index, bool getVirtual) const +{ + if( index >= methods.GetLength() ) + return 0; + + asCScriptFunction *func = engine->scriptFunctions[methods[index]]; + if( !getVirtual ) + { + if( func && func->funcType == asFUNC_VIRTUAL ) + return virtualFunctionTable[func->vfTableIdx]; + } + + return func; +} + +// interface +asIScriptFunction *asCObjectType::GetMethodByName(const char *in_name, bool in_getVirtual) const +{ + int id = -1; + for( asUINT n = 0; n < methods.GetLength(); n++ ) + { + if( engine->scriptFunctions[methods[n]]->name == in_name ) + { + if( id == -1 ) + id = methods[n]; + else + return 0; + } + } + + if( id == -1 ) return 0; + + asCScriptFunction *func = engine->scriptFunctions[id]; + if( !in_getVirtual ) + { + if( func && func->funcType == asFUNC_VIRTUAL ) + return virtualFunctionTable[func->vfTableIdx]; + } + + return func; +} + +// interface +asIScriptFunction *asCObjectType::GetMethodByDecl(const char *decl, bool getVirtual) const +{ + if( methods.GetLength() == 0 ) + return 0; + + // Get the module from one of the methods, but it will only be + // used to allow the parsing of types not already known by the object. + // It is possible for object types to be orphaned, e.g. by discarding + // the module that created it. In this case it is still possible to + // find the methods, but any type not known by the object will result in + // an invalid declaration. + asCModule *mod = engine->scriptFunctions[methods[0]]->module; + int id = engine->GetMethodIdByDecl(this, decl, mod); + if( id <= 0 ) + return 0; + + if( !getVirtual ) + { + asCScriptFunction *func = engine->scriptFunctions[id]; + if( func && func->funcType == asFUNC_VIRTUAL ) + return virtualFunctionTable[func->vfTableIdx]; + } + + return engine->scriptFunctions[id]; +} + +// interface +asUINT asCObjectType::GetPropertyCount() const +{ + return (asUINT)properties.GetLength(); +} + +// interface +int asCObjectType::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const +{ + if( index >= properties.GetLength() ) + return asINVALID_ARG; + + asCObjectProperty *prop = properties[index]; + if( out_name ) + *out_name = prop->name.AddressOf(); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(prop->type); + if( out_isPrivate ) + *out_isPrivate = prop->isPrivate; + if( out_isProtected ) + *out_isProtected = prop->isProtected; + if( out_offset ) + *out_offset = prop->byteOffset; + if( out_isReference ) + *out_isReference = prop->type.IsReference(); + if( out_accessMask ) + *out_accessMask = prop->accessMask; + if (out_compositeOffset) + *out_compositeOffset = prop->compositeOffset; + if (out_isCompositeIndirect) + *out_isCompositeIndirect = prop->isCompositeIndirect; + + return 0; +} + +// interface +const char *asCObjectType::GetPropertyDeclaration(asUINT index, bool includeNamespace) const +{ + if( index >= properties.GetLength() ) + return 0; + + asCString *tempString = &asCThreadManager::GetLocalData()->string; + if( properties[index]->isPrivate ) + *tempString = "private "; + else if( properties[index]->isProtected ) + *tempString = "protected "; + else + *tempString = ""; + *tempString += properties[index]->type.Format(nameSpace, includeNamespace); + *tempString += " "; + *tempString += properties[index]->name; + + return tempString->AddressOf(); +} + +asITypeInfo *asCObjectType::GetBaseType() const +{ + return derivedFrom; +} + +asUINT asCObjectType::GetBehaviourCount() const +{ + // Count the number of behaviours (except factory functions) + asUINT count = 0; + + if( beh.destruct ) count++; + if( beh.addref ) count++; + if( beh.release ) count++; + if( beh.gcGetRefCount ) count++; + if( beh.gcSetFlag ) count++; + if( beh.gcGetFlag ) count++; + if( beh.gcEnumReferences ) count++; + if( beh.gcReleaseAllReferences ) count++; + if( beh.templateCallback ) count++; + if( beh.listFactory ) count++; + if( beh.getWeakRefFlag ) count++; + + // For reference types, the factories are also stored in the constructor + // list, so it is sufficient to enumerate only those + count += (asUINT)beh.constructors.GetLength(); + + return count; +} + +asIScriptFunction *asCObjectType::GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const +{ + // Find the correct behaviour + asUINT count = 0; + + if( beh.destruct && count++ == index ) // only increase count if the behaviour is registered + { + if( outBehaviour ) *outBehaviour = asBEHAVE_DESTRUCT; + return engine->scriptFunctions[beh.destruct]; + } + + if( beh.addref && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_ADDREF; + return engine->scriptFunctions[beh.addref]; + } + + if( beh.release && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_RELEASE; + return engine->scriptFunctions[beh.release]; + } + + if( beh.gcGetRefCount && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_GETREFCOUNT; + return engine->scriptFunctions[beh.gcGetRefCount]; + } + + if( beh.gcSetFlag && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_SETGCFLAG; + return engine->scriptFunctions[beh.gcSetFlag]; + } + + if( beh.gcGetFlag && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_GETGCFLAG; + return engine->scriptFunctions[beh.gcGetFlag]; + } + + if( beh.gcEnumReferences && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_ENUMREFS; + return engine->scriptFunctions[beh.gcEnumReferences]; + } + + if( beh.gcReleaseAllReferences && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_RELEASEREFS; + return engine->scriptFunctions[beh.gcReleaseAllReferences]; + } + + if( beh.templateCallback && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_TEMPLATE_CALLBACK; + return engine->scriptFunctions[beh.templateCallback]; + } + + if( beh.listFactory && count++ == index ) + { + if( outBehaviour ) + { + if( flags & asOBJ_VALUE ) + *outBehaviour = asBEHAVE_LIST_CONSTRUCT; + else + *outBehaviour = asBEHAVE_LIST_FACTORY; + } + + return engine->scriptFunctions[beh.listFactory]; + } + + if( beh.getWeakRefFlag && count++ == index ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_GET_WEAKREF_FLAG; + return engine->scriptFunctions[beh.getWeakRefFlag]; + } + + // For reference types, the factories are also stored in the constructor + // list, so it is sufficient to enumerate only those + if( index - count < beh.constructors.GetLength() ) + { + if( outBehaviour ) *outBehaviour = asBEHAVE_CONSTRUCT; + return engine->scriptFunctions[beh.constructors[index - count]]; + } + else + count += (asUINT)beh.constructors.GetLength(); + + return 0; +} + +// internal +asCObjectProperty *asCObjectType::AddPropertyToClass(const asCString &propName, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited) +{ + asASSERT( flags & asOBJ_SCRIPT_OBJECT ); + asASSERT( dt.CanBeInstantiated() ); + asASSERT( !IsInterface() ); + + // Store the properties in the object type descriptor + asCObjectProperty *prop = asNEW(asCObjectProperty); + if( prop == 0 ) + { + // Out of memory + return 0; + } + + prop->name = propName; + prop->type = dt; + prop->isPrivate = isPrivate; + prop->isProtected = isProtected; + prop->isInherited = isInherited; + + int propSize; + if( dt.IsObject() ) + { + // Non-POD value types can't be allocated inline, + // because there is a risk that the script might + // try to access the content without knowing that + // it hasn't been initialized yet. + if( dt.GetTypeInfo()->flags & asOBJ_POD ) + propSize = dt.GetSizeInMemoryBytes(); + else + { + propSize = dt.GetSizeOnStackDWords()*4; + if( !dt.IsObjectHandle() ) + prop->type.MakeReference(true); + } + } + else if (dt.IsFuncdef()) + { + // Funcdefs don't have a size, as they must always be stored as handles + asASSERT(dt.IsObjectHandle()); + propSize = AS_PTR_SIZE * 4; + } + else + propSize = dt.GetSizeInMemoryBytes(); + + // Add extra bytes so that the property will be properly aligned +#ifndef WIP_16BYTE_ALIGN + if( propSize == 2 && (size & 1) ) size += 1; + if( propSize > 2 && (size & 3) ) size += 4 - (size & 3); +#else + asUINT alignment = dt.GetAlignment(); + const asUINT propSizeAlignmentDifference = size & (alignment-1); + if( propSizeAlignmentDifference != 0 ) + { + size += (alignment - propSizeAlignmentDifference); + } + + asASSERT((size % alignment) == 0); +#endif + + prop->byteOffset = size; + size += propSize; + + properties.PushLast(prop); + + // Make sure the struct holds a reference to the config group where the object is registered + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(prop->type.GetTypeInfo()); + if( group != 0 ) group->AddRef(); + + // Add reference to object types + asCTypeInfo *type = prop->type.GetTypeInfo(); + if( type ) + type->AddRefInternal(); + + return prop; +} + +// internal +void asCObjectType::ReleaseAllProperties() +{ + for( asUINT n = 0; n < properties.GetLength(); n++ ) + { + if( properties[n] ) + { + if( flags & asOBJ_SCRIPT_OBJECT ) + { + // Release the config group for script classes that are being destroyed + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(properties[n]->type.GetTypeInfo()); + if( group != 0 ) group->Release(); + + // Release references to objects types + asCTypeInfo *type = properties[n]->type.GetTypeInfo(); + if( type ) + type->ReleaseInternal(); + } + else + { + // Release template instance types (ref increased by RegisterObjectProperty) + asCTypeInfo *type = properties[n]->type.GetTypeInfo(); + if( type ) + type->ReleaseInternal(); + } + + asDELETE(properties[n],asCObjectProperty); + } + } + + properties.SetLength(0); +} + +// internal +void asCObjectType::ReleaseAllFunctions() +{ + beh.factory = 0; + beh.copyfactory = 0; + for( asUINT a = 0; a < beh.factories.GetLength(); a++ ) + { + if( engine->scriptFunctions[beh.factories[a]] ) + engine->scriptFunctions[beh.factories[a]]->ReleaseInternal(); + } + beh.factories.SetLength(0); + + beh.construct = 0; + beh.copyconstruct = 0; + for( asUINT b = 0; b < beh.constructors.GetLength(); b++ ) + { + if( engine->scriptFunctions[beh.constructors[b]] ) + engine->scriptFunctions[beh.constructors[b]]->ReleaseInternal(); + } + beh.constructors.SetLength(0); + + if( beh.templateCallback ) + engine->scriptFunctions[beh.templateCallback]->ReleaseInternal(); + beh.templateCallback = 0; + + if( beh.listFactory ) + engine->scriptFunctions[beh.listFactory]->ReleaseInternal(); + beh.listFactory = 0; + + if( beh.destruct ) + engine->scriptFunctions[beh.destruct]->ReleaseInternal(); + beh.destruct = 0; + + if( beh.copy ) + engine->scriptFunctions[beh.copy]->ReleaseInternal(); + beh.copy = 0; + + for( asUINT c = 0; c < methods.GetLength(); c++ ) + { + if( engine->scriptFunctions[methods[c]] ) + engine->scriptFunctions[methods[c]]->ReleaseInternal(); + } + methods.SetLength(0); + + for( asUINT d = 0; d < virtualFunctionTable.GetLength(); d++ ) + { + if( virtualFunctionTable[d] ) + virtualFunctionTable[d]->ReleaseInternal(); + } + virtualFunctionTable.SetLength(0); + + // GC behaviours + if( beh.addref ) + engine->scriptFunctions[beh.addref]->ReleaseInternal(); + beh.addref = 0; + + if( beh.release ) + engine->scriptFunctions[beh.release]->ReleaseInternal(); + beh.release = 0; + + if( beh.gcEnumReferences ) + engine->scriptFunctions[beh.gcEnumReferences]->ReleaseInternal(); + beh.gcEnumReferences = 0; + + if( beh.gcGetFlag ) + engine->scriptFunctions[beh.gcGetFlag]->ReleaseInternal(); + beh.gcGetFlag = 0; + + if( beh.gcGetRefCount ) + engine->scriptFunctions[beh.gcGetRefCount]->ReleaseInternal(); + beh.gcGetRefCount = 0; + + if( beh.gcReleaseAllReferences ) + engine->scriptFunctions[beh.gcReleaseAllReferences]->ReleaseInternal(); + beh.gcReleaseAllReferences = 0; + + if( beh.gcSetFlag ) + engine->scriptFunctions[beh.gcSetFlag]->ReleaseInternal(); + beh.gcSetFlag = 0; + + if ( beh.getWeakRefFlag ) + engine->scriptFunctions[beh.getWeakRefFlag]->ReleaseInternal(); + beh.getWeakRefFlag = 0; +} + +END_AS_NAMESPACE + + + diff --git a/angelscript/source/as_objecttype.h b/angelscript/source/as_objecttype.h new file mode 100644 index 0000000..4b7bd5d --- /dev/null +++ b/angelscript/source/as_objecttype.h @@ -0,0 +1,171 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_objecttype.h +// +// A class for storing object type information +// + + + +#ifndef AS_OBJECTTYPE_H +#define AS_OBJECTTYPE_H + +#include "as_property.h" +#include "as_array.h" +#include "as_scriptfunction.h" +#include "as_typeinfo.h" + +BEGIN_AS_NAMESPACE + +struct asSTypeBehaviour +{ + asSTypeBehaviour() + { + factory = 0; + listFactory = 0; + copyfactory = 0; + construct = 0; + copyconstruct = 0; + destruct = 0; + copy = 0; + addref = 0; + release = 0; + gcGetRefCount = 0; + gcSetFlag = 0; + gcGetFlag = 0; + gcEnumReferences = 0; + gcReleaseAllReferences = 0; + templateCallback = 0; + getWeakRefFlag = 0; + } + + int factory; + int listFactory; // Used for initialization lists only + int copyfactory; + int construct; + int copyconstruct; + int destruct; + int copy; + int addref; + int release; + int templateCallback; + + // GC behaviours + int gcGetRefCount; + int gcSetFlag; + int gcGetFlag; + int gcEnumReferences; + int gcReleaseAllReferences; + + // Weakref behaviours + int getWeakRefFlag; + + asCArray factories; + asCArray constructors; +}; + +class asCScriptEngine; +struct asSNameSpace; + +class asCObjectType : public asCTypeInfo +{ +public: + asITypeInfo *GetBaseType() const; + bool DerivesFrom(const asITypeInfo *objType) const; + int GetSubTypeId(asUINT subtypeIndex = 0) const; + asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const; + asUINT GetSubTypeCount() const; + asUINT GetInterfaceCount() const; + asITypeInfo *GetInterface(asUINT index) const; + bool Implements(const asITypeInfo *objType) const; + asUINT GetFactoryCount() const; + asIScriptFunction *GetFactoryByIndex(asUINT index) const; + asIScriptFunction *GetFactoryByDecl(const char *decl) const; + asUINT GetMethodCount() const; + asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const; + asIScriptFunction *GetMethodByName(const char *name, bool getVirtual) const; + asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const; + asUINT GetPropertyCount() const; + int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; + const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const; + asUINT GetBehaviourCount() const; + asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const; + asUINT GetChildFuncdefCount() const; + asITypeInfo *GetChildFuncdef(asUINT index) const; + +public: + asCObjectType(asCScriptEngine *engine); + ~asCObjectType(); + void DestroyInternal(); + + void ReleaseAllFunctions(); + + bool IsInterface() const; + + asCObjectProperty *AddPropertyToClass(const asCString &name, const asCDataType &dt, bool isPrivate, bool isProtected, bool isInherited); + void ReleaseAllProperties(); + +#ifdef WIP_16BYTE_ALIGN + int alignment; +#endif + asCArray properties; + asCArray methods; + + // TODO: These are not used by template types. Should perhaps create a derived class to save memory on ordinary object types + asCArray interfaces; + asCArray interfaceVFTOffsets; + asCObjectType * derivedFrom; + asCArray virtualFunctionTable; + + // Used for funcdefs declared as members of class. + // TODO: child funcdef: Should be possible to enumerate these from application + asCArray childFuncDefs; + + asSTypeBehaviour beh; + + // Used for template types + asCArray templateSubTypes; // increases refCount for typeinfo held in datatype + bool acceptValueSubType; + bool acceptRefSubType; + +protected: + friend class asCScriptEngine; + friend class asCConfigGroup; + friend class asCModule; + asCObjectType(); +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_outputbuffer.cpp b/angelscript/source/as_outputbuffer.cpp new file mode 100644 index 0000000..433f820 --- /dev/null +++ b/angelscript/source/as_outputbuffer.cpp @@ -0,0 +1,109 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2012 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_outputbuffer.cpp +// +// This class appends strings to one large buffer that can later +// be sent to the real output stream +// + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_outputbuffer.h" +#include "as_scriptengine.h" + +BEGIN_AS_NAMESPACE + +asCOutputBuffer::~asCOutputBuffer() +{ + Clear(); +} + +void asCOutputBuffer::Clear() +{ + for( asUINT n = 0; n < messages.GetLength(); n++ ) + { + if( messages[n] ) + { + asDELETE(messages[n],message_t); + } + } + messages.SetLength(0); +} + +void asCOutputBuffer::Callback(asSMessageInfo *msg) +{ + message_t *msgInfo = asNEW(message_t); + if( msgInfo == 0 ) + return; + + msgInfo->section = msg->section; + msgInfo->row = msg->row; + msgInfo->col = msg->col; + msgInfo->type = msg->type; + msgInfo->msg = msg->message; + + messages.PushLast(msgInfo); +} + +void asCOutputBuffer::Append(asCOutputBuffer &in) +{ + for( asUINT n = 0; n < in.messages.GetLength(); n++ ) + messages.PushLast(in.messages[n]); + in.messages.SetLength(0); +} + +void asCOutputBuffer::SendToCallback(asCScriptEngine *engine, asSSystemFunctionInterface *func, void *obj) +{ + for( asUINT n = 0; n < messages.GetLength(); n++ ) + { + asSMessageInfo msg; + msg.section = messages[n]->section.AddressOf(); + msg.row = messages[n]->row; + msg.col = messages[n]->col; + msg.type = messages[n]->type; + msg.message = messages[n]->msg.AddressOf(); + + if( func->callConv < ICC_THISCALL ) + engine->CallGlobalFunction(&msg, obj, func, 0); + else + engine->CallObjectMethod(obj, &msg, func, 0); + } + Clear(); +} + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + diff --git a/angelscript/source/as_outputbuffer.h b/angelscript/source/as_outputbuffer.h new file mode 100644 index 0000000..500b162 --- /dev/null +++ b/angelscript/source/as_outputbuffer.h @@ -0,0 +1,80 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2012 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_outputbuffer.h +// +// This class appends strings to one large buffer that can later +// be sent to the real output stream +// + + +#ifndef AS_OUTPUTBUFFER_H +#define AS_OUTPUTBUFFER_H + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_string.h" +#include "as_array.h" + +BEGIN_AS_NAMESPACE + +struct asSSystemFunctionInterface; +class asCScriptEngine; + +class asCOutputBuffer +{ +public: + ~asCOutputBuffer (); + void Clear(); + void Callback(asSMessageInfo *msg); + void Append(asCOutputBuffer &in); + void SendToCallback(asCScriptEngine *engine, asSSystemFunctionInterface *func, void *obj); + + struct message_t + { + asCString section; + int row; + int col; + asEMsgType type; + asCString msg; + }; + + asCArray messages; +}; + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + +#endif diff --git a/angelscript/source/as_parser.cpp b/angelscript/source/as_parser.cpp new file mode 100644 index 0000000..2de81aa --- /dev/null +++ b/angelscript/source/as_parser.cpp @@ -0,0 +1,4539 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_parser.cpp +// +// This class parses the script code and builds a tree for compilation +// +// +// I've documented the syntax in Extended BNF. You'll find it by doing a search in +// this file by "BNF:". The starting point for the script language is SCRIPT ::=. +// +// Ref: http://matt.might.net/articles/grammars-bnf-ebnf/ +// +// ( ) - used for grouping +// { } - 0 or more repetitions +// [ ] - optional +// | - or +// ' ' - token +// + + + +#include "as_config.h" +#include "as_parser.h" +#include "as_tokendef.h" +#include "as_texts.h" +#include "as_debug.h" + +#ifdef _MSC_VER +#pragma warning(disable:4702) // unreachable code +#endif + +BEGIN_AS_NAMESPACE + +asCParser::asCParser(asCBuilder *builder) +{ + this->builder = builder; + this->engine = builder->engine; + + script = 0; + scriptNode = 0; + checkValidTypes = false; + isParsingAppInterface = false; +} + +asCParser::~asCParser() +{ + Reset(); +} + +void asCParser::Reset() +{ + errorWhileParsing = false; + isSyntaxError = false; + checkValidTypes = false; + isParsingAppInterface = false; + + sourcePos = 0; + + if( scriptNode ) + { + scriptNode->Destroy(engine); + } + + scriptNode = 0; + + script = 0; + + lastToken.pos = size_t(-1); +} + +asCScriptNode *asCParser::GetScriptNode() +{ + return scriptNode; +} + +int asCParser::ParseFunctionDefinition(asCScriptCode *in_script, bool in_expectListPattern) +{ + Reset(); + + // Set flag that permits ? as datatype for parameters + isParsingAppInterface = true; + + this->script = in_script; + + scriptNode = ParseFunctionDefinition(); + + if( in_expectListPattern ) + scriptNode->AddChildLast(ParseListPattern()); + + // The declaration should end after the definition + if( !isSyntaxError ) + { + sToken t; + GetToken(&t); + if( t.type != ttEnd ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); + Error(InsteadFound(t), &t); + return -1; + } + } + + if( errorWhileParsing ) + return -1; + + return 0; +} + +asCScriptNode *asCParser::CreateNode(eScriptNode type) +{ + void *ptr = engine->memoryMgr.AllocScriptNode(); + if( ptr == 0 ) + { + // Out of memory + errorWhileParsing = true; + return 0; + } + + return new(ptr) asCScriptNode(type); +} + +int asCParser::ParseDataType(asCScriptCode *in_script, bool in_isReturnType) +{ + Reset(); + + this->script = in_script; + + scriptNode = CreateNode(snDataType); + if( scriptNode == 0 ) return -1; + + scriptNode->AddChildLast(ParseType(true)); + if( isSyntaxError ) return -1; + + if( in_isReturnType ) + { + scriptNode->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return -1; + } + + // The declaration should end after the type + sToken t; + GetToken(&t); + if( t.type != ttEnd ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); + Error(InsteadFound(t), &t); + return -1; + } + + if( errorWhileParsing ) + return -1; + + return 0; +} + + +// Parse a template declaration: IDENTIFIER '<' 'class'? IDENTIFIER '>' +int asCParser::ParseTemplateDecl(asCScriptCode *in_script) +{ + Reset(); + + this->script = in_script; + scriptNode = CreateNode(snUndefined); + if( scriptNode == 0 ) return -1; + + scriptNode->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return -1; + + sToken t; + GetToken(&t); + if( t.type != ttLessThan ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); + Error(InsteadFound(t), &t); + return -1; + } + + // The class token is optional + GetToken(&t); + if( t.type != ttClass ) + RewindTo(&t); + + scriptNode->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return -1; + + // There can be multiple sub types + GetToken(&t); + + // Parse template types by list separator + while(t.type == ttListSeparator) + { + GetToken(&t); + if( t.type != ttClass ) + RewindTo(&t); + scriptNode->AddChildLast(ParseIdentifier()); + + if( isSyntaxError ) return -1; + GetToken(&t); + } + + if( t.type != ttGreaterThan ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); + Error(InsteadFound(t), &t); + return -1; + } + + GetToken(&t); + if( t.type != ttEnd ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); + Error(InsteadFound(t), &t); + return -1; + } + + if( errorWhileParsing ) + return -1; + + return 0; +} + +int asCParser::ParsePropertyDeclaration(asCScriptCode *in_script) +{ + Reset(); + + this->script = in_script; + + scriptNode = CreateNode(snDeclaration); + if( scriptNode == 0 ) return -1; + + scriptNode->AddChildLast(ParseType(true)); + if( isSyntaxError ) return -1; + + // Allow optional '&' to indicate that the property is indirect, i.e. stored as reference + sToken t; + GetToken(&t); + RewindTo(&t); + if( t.type == ttAmp ) + scriptNode->AddChildLast(ParseToken(ttAmp)); + + // Allow optional namespace to be defined before the identifier in case + // the declaration is to be used for searching for an existing property + ParseOptionalScope(scriptNode); + + scriptNode->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return -1; + + // The declaration should end after the identifier + GetToken(&t); + if( t.type != ttEnd ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnd)), &t); + Error(InsteadFound(t), &t); + return -1; + } + + return 0; +} + +// BNF:5: SCOPE ::= ['::'] {IDENTIFIER '::'} [IDENTIFIER ['<' TYPE {',' TYPE} '>'] '::'] +void asCParser::ParseOptionalScope(asCScriptNode *node) +{ + asCScriptNode *scope = CreateNode(snScope); + + sToken t1, t2; + GetToken(&t1); + GetToken(&t2); + if( t1.type == ttScope ) + { + RewindTo(&t1); + scope->AddChildLast(ParseToken(ttScope)); + GetToken(&t1); + GetToken(&t2); + } + while( t1.type == ttIdentifier && t2.type == ttScope ) + { + RewindTo(&t1); + scope->AddChildLast(ParseIdentifier()); + scope->AddChildLast(ParseToken(ttScope)); + GetToken(&t1); + GetToken(&t2); + } + + // The innermost scope may be a template type + if( t1.type == ttIdentifier && t2.type == ttLessThan ) + { + tempString.Assign(&script->code[t1.pos], t1.length); + if (engine->IsTemplateType(tempString.AddressOf())) + { + RewindTo(&t1); + asCScriptNode *restore = scope->lastChild; + scope->AddChildLast(ParseIdentifier()); + if (ParseTemplTypeList(scope, false)) + { + GetToken(&t2); + if (t2.type == ttScope) + { + // Template type is part of the scope + // Nothing more needs to be done + node->AddChildLast(scope); + return; + } + else + { + // The template type is not part of the scope + // Rewind to the template type and end the scope + RewindTo(&t1); + + // Restore the previously parsed node + while (scope->lastChild != restore) + { + asCScriptNode *last = scope->lastChild; + last->DisconnectParent(); + last->Destroy(engine); + } + if( scope->lastChild ) + node->AddChildLast(scope); + else + scope->Destroy(engine); + return; + } + } + } + } + + // The identifier is not part of the scope + RewindTo(&t1); + + if (scope->lastChild) + node->AddChildLast(scope); + else + scope->Destroy(engine); +} + +asCScriptNode *asCParser::ParseFunctionDefinition() +{ + asCScriptNode *node = CreateNode(snFunction); + if( node == 0 ) return 0; + + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; + + ParseOptionalScope(node); + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseParameterList()); + if( isSyntaxError ) return node; + + // Parse an optional 'const' after the function definition (used for object methods) + sToken t1; + GetToken(&t1); + RewindTo(&t1); + if( t1.type == ttConst ) + node->AddChildLast(ParseToken(ttConst)); + + // Parse optional attributes + ParseMethodAttributes(node); + + return node; +} + +// BNF:4: TYPEMOD ::= ['&' ['in' | 'out' | 'inout']] +asCScriptNode *asCParser::ParseTypeMod(bool isParam) +{ + asCScriptNode *node = CreateNode(snDataType); + if( node == 0 ) return 0; + + sToken t; + + // Parse possible & token + GetToken(&t); + RewindTo(&t); + if( t.type == ttAmp ) + { + node->AddChildLast(ParseToken(ttAmp)); + if( isSyntaxError ) return node; + + if( isParam ) + { + GetToken(&t); + RewindTo(&t); + + if( t.type == ttIn || t.type == ttOut || t.type == ttInOut ) + { + int tokens[3] = {ttIn, ttOut, ttInOut}; + node->AddChildLast(ParseOneOf(tokens, 3)); + } + } + } + + // Parse possible + token + GetToken(&t); + RewindTo(&t); + if( t.type == ttPlus ) + { + node->AddChildLast(ParseToken(ttPlus)); + if( isSyntaxError ) return node; + } + + // Parse possible if_handle_then_const token + GetToken(&t); + RewindTo(&t); + if (IdentifierIs(t, IF_HANDLE_TOKEN)) + { + node->AddChildLast(ParseToken(ttIdentifier)); + if (isSyntaxError) return node; + } + + return node; +} + +// BNF:4: TYPE ::= ['const'] SCOPE DATATYPE ['<' TYPE {',' TYPE} '>'] { ('[' ']') | ('@' ['const']) } +asCScriptNode *asCParser::ParseType(bool allowConst, bool allowVariableType, bool allowAuto) +{ + asCScriptNode *node = CreateNode(snDataType); + if( node == 0 ) return 0; + + sToken t; + + if( allowConst ) + { + GetToken(&t); + RewindTo(&t); + if( t.type == ttConst ) + { + node->AddChildLast(ParseToken(ttConst)); + if( isSyntaxError ) return node; + } + } + + // Parse scope prefix + ParseOptionalScope(node); + + // Parse the actual type + node->AddChildLast(ParseDataType(allowVariableType, allowAuto)); + if( isSyntaxError ) return node; + + // If the datatype is a template type, then parse the subtype within the < > + GetToken(&t); + RewindTo(&t); + asCScriptNode *type = node->lastChild; + tempString.Assign(&script->code[type->tokenPos], type->tokenLength); + if( engine->IsTemplateType(tempString.AddressOf()) && t.type == ttLessThan ) + { + ParseTemplTypeList(node); + if (isSyntaxError) return node; + } + + // Parse [] and @ + GetToken(&t); + RewindTo(&t); + while( t.type == ttOpenBracket || t.type == ttHandle) + { + if( t.type == ttOpenBracket ) + { + node->AddChildLast(ParseToken(ttOpenBracket)); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttCloseBracket ) + { + Error(ExpectedToken("]"), &t); + Error(InsteadFound(t), &t); + return node; + } + } + else + { + node->AddChildLast(ParseToken(ttHandle)); + if( isSyntaxError ) return node; + + GetToken(&t); + RewindTo(&t); + if( t.type == ttConst ) + { + node->AddChildLast(ParseToken(ttConst)); + if( isSyntaxError ) return node; + } + } + + GetToken(&t); + RewindTo(&t); + } + + return node; +} + +// This parses a template type list, e.g. +// If 'required' is false, and the template type list is not valid, +// then no change will be done and the function returns false. This +// can be used as do an optional parsing +bool asCParser::ParseTemplTypeList(asCScriptNode *node, bool required) +{ + sToken t; + bool isValid = true; + + // Remember the last child, so we can restore the state if needed + asCScriptNode *last = node->lastChild; + + // Starts with '<' + GetToken(&t); + if (t.type != ttLessThan) + { + if (required) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttLessThan)), &t); + Error(InsteadFound(t), &t); + } + return false; + } + + // At least one type + // TODO: child funcdef: Make this work with !required + node->AddChildLast(ParseType(true, false)); + if (isSyntaxError) return false; + + GetToken(&t); + + // Parse template types by list separator + while (t.type == ttListSeparator) + { + // TODO: child funcdef: Make this work with !required + node->AddChildLast(ParseType(true, false)); + if (isSyntaxError) return false; + GetToken(&t); + } + + // End with '>' + // Accept >> and >>> tokens too. But then force the tokenizer to move + // only 1 character ahead (thus splitting the token in two). + if (script->code[t.pos] != '>') + { + if (required) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttGreaterThan)), &t); + Error(InsteadFound(t), &t); + } + else + isValid = false; + } + else + { + // Break the token so that only the first > is parsed + SetPos(t.pos + 1); + } + + if (!required && !isValid) + { + // Restore the original state before returning + while (node->lastChild != last) + { + asCScriptNode *n = node->lastChild; + n->DisconnectParent(); + n->Destroy(engine); + } + + return false; + } + + // The template type list was parsed OK + return true; +} + +asCScriptNode *asCParser::ParseToken(int token) +{ + asCScriptNode *node = CreateNode(snUndefined); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( t1.type != token ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(token)), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +asCScriptNode *asCParser::ParseOneOf(int *tokens, int count) +{ + asCScriptNode *node = CreateNode(snUndefined); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + int n; + for( n = 0; n < count; n++ ) + { + if( tokens[n] == t1.type ) + break; + } + if( n == count ) + { + Error(ExpectedOneOf(tokens, count), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:5: DATATYPE ::= (IDENTIFIER | PRIMTYPE | '?' | 'auto') +asCScriptNode *asCParser::ParseDataType(bool allowVariableType, bool allowAuto) +{ + asCScriptNode *node = CreateNode(snDataType); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( !IsDataType(t1) && !(allowVariableType && t1.type == ttQuestion) && !(allowAuto && t1.type == ttAuto) ) + { + if( t1.type == ttIdentifier ) + { + asCString errMsg; + tempString.Assign(&script->code[t1.pos], t1.length); + errMsg.Format(TXT_IDENTIFIER_s_NOT_DATA_TYPE, tempString.AddressOf()); + Error(errMsg, &t1); + } + else if( t1.type == ttAuto ) + { + Error(TXT_AUTO_NOT_ALLOWED, &t1); + } + else + { + Error(TXT_EXPECTED_DATA_TYPE, &t1); + Error(InsteadFound(t1), &t1); + } + return node; + } + + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:6: PRIMTYPE ::= 'void' | 'int' | 'int8' | 'int16' | 'int32' | 'int64' | 'uint' | 'uint8' | 'uint16' | 'uint32' | 'uint64' | 'float' | 'double' | 'bool' +asCScriptNode *asCParser::ParseRealType() +{ + asCScriptNode *node = CreateNode(snDataType); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( !IsRealType(t1.type) ) + { + Error(TXT_EXPECTED_DATA_TYPE, &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:17: IDENTIFIER ::= single token: starts with letter or _, can include any letter and digit, same as in C++ +asCScriptNode *asCParser::ParseIdentifier() +{ + asCScriptNode *node = CreateNode(snIdentifier); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( t1.type != ttIdentifier ) + { + Error(TXT_EXPECTED_IDENTIFIER, &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->SetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:3: PARAMLIST ::= '(' ['void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]})] ')' +asCScriptNode *asCParser::ParseParameterList() +{ + asCScriptNode *node = CreateNode(snParameterList); + if( node == 0 ) return 0; + + sToken t1; + GetToken(&t1); + if( t1.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + GetToken(&t1); + if( t1.type == ttCloseParanthesis ) + { + node->UpdateSourcePos(t1.pos, t1.length); + + // Statement block is finished + return node; + } + else + { + // If the parameter list is just (void) then the void token should be ignored + if( t1.type == ttVoid ) + { + sToken t2; + GetToken(&t2); + if( t2.type == ttCloseParanthesis ) + { + node->UpdateSourcePos(t2.pos, t2.length); + return node; + } + } + + RewindTo(&t1); + + for(;;) + { + // Parse data type + node->AddChildLast(ParseType(true, isParsingAppInterface)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseTypeMod(true)); + if( isSyntaxError ) return node; + + // Parse optional identifier + GetToken(&t1); + if( t1.type == ttIdentifier ) + { + RewindTo(&t1); + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + GetToken(&t1); + } + + // Parse optional expression for the default arg + if( t1.type == ttAssignment ) + { + // Do a superficial parsing of the default argument + // The actual parsing will be done when the argument is compiled for a function call + node->AddChildLast(SuperficiallyParseExpression()); + if( isSyntaxError ) return node; + + GetToken(&t1); + } + + // Check if list continues + if( t1.type == ttCloseParanthesis ) + { + node->UpdateSourcePos(t1.pos, t1.length); + + return node; + } + else if( t1.type == ttListSeparator ) + continue; + else + { + Error(ExpectedTokens(")", ","), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + } + } + UNREACHABLE_RETURN; +} + +asCScriptNode *asCParser::SuperficiallyParseExpression() +{ + asCScriptNode *node = CreateNode(snExpression); + if( node == 0 ) return 0; + + // Simply parse everything until the first , or ), whichever comes first. + // Keeping in mind that () and {} can group expressions. + + sToken start; + GetToken(&start); + RewindTo(&start); + + asCString stack; + sToken t; + for(;;) + { + GetToken(&t); + + if( t.type == ttOpenParanthesis ) + stack += "("; + else if( t.type == ttCloseParanthesis ) + { + if( stack == "" ) + { + // Expression has ended. This token is not part of expression + RewindTo(&t); + break; + } + else if( stack[stack.GetLength()-1] == '(' ) + { + // Group has ended + stack.SetLength(stack.GetLength()-1); + } + else + { + // Wrong syntax + RewindTo(&t); + asCString str; + str.Format(TXT_UNEXPECTED_TOKEN_s, ")"); + Error(str, &t); + return node; + } + } + else if( t.type == ttListSeparator ) + { + if( stack == "" ) + { + // Expression has ended. This token is not part of expression + RewindTo(&t); + break; + } + } + else if( t.type == ttStartStatementBlock ) + stack += "{"; + else if( t.type == ttEndStatementBlock ) + { + if( stack == "" || stack[stack.GetLength()-1] != '{' ) + { + // Wrong syntax + RewindTo(&t); + asCString str; + str.Format(TXT_UNEXPECTED_TOKEN_s, "}"); + Error(str, &t); + return node; + } + else + { + // Group has ended + stack.SetLength(stack.GetLength()-1); + } + } + else if( t.type == ttEndStatement ) + { + // Wrong syntax (since we're parsing a default arg expression) + RewindTo(&t); + asCString str; + str.Format(TXT_UNEXPECTED_TOKEN_s, ";"); + Error(str, &t); + return node; + } + else if( t.type == ttNonTerminatedStringConstant ) + { + RewindTo(&t); + Error(TXT_NONTERMINATED_STRING, &t); + return node; + } + else if( t.type == ttEnd ) + { + // Wrong syntax + RewindTo(&t); + Error(TXT_UNEXPECTED_END_OF_FILE, &t); + Info(TXT_WHILE_PARSING_EXPRESSION, &start); + return node; + } + + // Include the token in the node + node->UpdateSourcePos(t.pos, t.length); + } + + return node; +} + +void asCParser::GetToken(sToken *token) +{ + // Check if the token has already been parsed + if( lastToken.pos == sourcePos ) + { + *token = lastToken; + sourcePos += token->length; + + if( token->type == ttWhiteSpace || + token->type == ttOnelineComment || + token->type == ttMultilineComment ) + GetToken(token); + + return; + } + + // Parse new token + size_t sourceLength = script->codeLength; + do + { + if( sourcePos >= sourceLength ) + { + token->type = ttEnd; + token->length = 0; + } + else + token->type = engine->tok.GetToken(&script->code[sourcePos], sourceLength - sourcePos, &token->length); + + token->pos = sourcePos; + + // Update state + sourcePos += token->length; + } + // Filter out whitespace and comments + while( token->type == ttWhiteSpace || + token->type == ttOnelineComment || + token->type == ttMultilineComment ); +} + +void asCParser::SetPos(size_t pos) +{ + lastToken.pos = size_t(-1); + sourcePos = pos; +} + +void asCParser::RewindTo(const sToken *token) +{ + // TODO: optimize: Perhaps we can optimize this further by having the parser + // set an explicit return point, after which each token will + // be stored. That way not just one token will be reused but + // no token will have to be tokenized more than once. + + // Store the token so it doesn't have to be tokenized again + lastToken = *token; + + sourcePos = token->pos; +} + +void asCParser::Error(const asCString &text, sToken *token) +{ + RewindTo(token); + + isSyntaxError = true; + errorWhileParsing = true; + + int row, col; + script->ConvertPosToRowCol(token->pos, &row, &col); + + if( builder ) + builder->WriteError(script->name, text, row, col); +} + +void asCParser::Warning(const asCString &text, sToken *token) +{ + int row, col; + script->ConvertPosToRowCol(token->pos, &row, &col); + + if( builder ) + builder->WriteWarning(script->name, text, row, col); +} + +void asCParser::Info(const asCString &text, sToken *token) +{ + RewindTo(token); + + isSyntaxError = true; + errorWhileParsing = true; + + int row, col; + script->ConvertPosToRowCol(token->pos, &row, &col); + + if( builder ) + builder->WriteInfo(script->name, text, row, col, false); +} + +bool asCParser::IsRealType(int tokenType) +{ + if( tokenType == ttVoid || + tokenType == ttInt || + tokenType == ttInt8 || + tokenType == ttInt16 || + tokenType == ttInt64 || + tokenType == ttUInt || + tokenType == ttUInt8 || + tokenType == ttUInt16 || + tokenType == ttUInt64 || + tokenType == ttFloat || + tokenType == ttBool || + tokenType == ttDouble ) + return true; + + return false; +} + +bool asCParser::IsDataType(const sToken &token) +{ + if( token.type == ttIdentifier ) + { +#ifndef AS_NO_COMPILER + if( checkValidTypes ) + { + // Check if this is an existing type, regardless of namespace + tempString.Assign(&script->code[token.pos], token.length); + if( !builder->DoesTypeExist(tempString.AddressOf()) ) + return false; + } +#endif + return true; + } + + if( IsRealType(token.type) ) + return true; + + return false; +} + +asCString asCParser::ExpectedToken(const char *token) +{ + asCString str; + + str.Format(TXT_EXPECTED_s, token); + + return str; +} + +asCString asCParser::ExpectedTokens(const char *t1, const char *t2) +{ + asCString str; + + str.Format(TXT_EXPECTED_s_OR_s, t1, t2); + + return str; +} + +asCString asCParser::ExpectedOneOf(int *tokens, int count) +{ + asCString str; + + str = TXT_EXPECTED_ONE_OF; + for( int n = 0; n < count; n++ ) + { + str += asCTokenizer::GetDefinition(tokens[n]); + if( n < count-1 ) + str += ", "; + } + + return str; +} + +asCString asCParser::ExpectedOneOf(const char **tokens, int count) +{ + asCString str; + + str = TXT_EXPECTED_ONE_OF; + for( int n = 0; n < count; n++ ) + { + str += tokens[n]; + if( n < count-1 ) + str += ", "; + } + + return str; +} + +asCString asCParser::InsteadFound(sToken &t) +{ + asCString str; + if( t.type == ttIdentifier ) + { + asCString id(&script->code[t.pos], t.length); + str.Format(TXT_INSTEAD_FOUND_IDENTIFIER_s, id.AddressOf()); + } + else if( t.type >= ttIf ) + str.Format(TXT_INSTEAD_FOUND_KEYWORD_s, asCTokenizer::GetDefinition(t.type)); + else + str.Format(TXT_INSTEAD_FOUND_s, asCTokenizer::GetDefinition(t.type)); + + return str; +} + +asCScriptNode *asCParser::ParseListPattern() +{ + asCScriptNode *node = CreateNode(snListPattern); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( t1.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + sToken start = t1; + + bool isBeginning = true; + bool afterType = false; + while( !isSyntaxError ) + { + GetToken(&t1); + if( t1.type == ttEndStatementBlock ) + { + if( !afterType ) + { + Error(TXT_EXPECTED_DATA_TYPE, &t1); + Error(InsteadFound(t1), &t1); + } + break; + } + else if( t1.type == ttStartStatementBlock ) + { + if( afterType ) + { + Error(ExpectedTokens(",","}"), &t1); + Error(InsteadFound(t1), &t1); + } + RewindTo(&t1); + node->AddChildLast(ParseListPattern()); + afterType = true; + } + else if( t1.type == ttIdentifier && (IdentifierIs(t1, "repeat") || IdentifierIs(t1, "repeat_same")) ) + { + if( !isBeginning ) + { + asCString msg; + asCString token(&script->code[t1.pos], t1.length); + msg.Format(TXT_UNEXPECTED_TOKEN_s, token.AddressOf()); + Error(msg.AddressOf(), &t1); + } + RewindTo(&t1); + node->AddChildLast(ParseIdentifier()); + } + else if( t1.type == ttEnd ) + { + Error(TXT_UNEXPECTED_END_OF_FILE, &t1); + Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start); + break; + } + else if( t1.type == ttListSeparator ) + { + if( !afterType ) + { + Error(TXT_EXPECTED_DATA_TYPE, &t1); + Error(InsteadFound(t1), &t1); + } + afterType = false; + } + else + { + if( afterType ) + { + Error(ExpectedTokens(",", "}"), &t1); + Error(InsteadFound(t1), &t1); + } + RewindTo(&t1); + node->AddChildLast(ParseType(true, true)); + afterType = true; + } + + isBeginning = false; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +bool asCParser::IdentifierIs(const sToken &t, const char *str) +{ + if( t.type != ttIdentifier ) + return false; + + return script->TokenEquals(t.pos, t.length, str); +} + +// BNF:6: FUNCATTR ::= {'override' | 'final' | 'explicit' | 'property'} +void asCParser::ParseMethodAttributes(asCScriptNode *funcNode) +{ + sToken t1; + + for(;;) + { + GetToken(&t1); + RewindTo(&t1); + + if( IdentifierIs(t1, FINAL_TOKEN) || + IdentifierIs(t1, OVERRIDE_TOKEN) || + IdentifierIs(t1, EXPLICIT_TOKEN) || + IdentifierIs(t1, PROPERTY_TOKEN) ) + funcNode->AddChildLast(ParseIdentifier()); + else + break; + } +} + +#ifndef AS_NO_COMPILER + +// nextToken is only modified if the current position can be interpreted as +// type, in this case it is set to the next token after the type tokens +bool asCParser::IsType(sToken &nextToken) +{ + // Set a rewind point + sToken t, t1; + GetToken(&t); + + // A type can start with a const + t1 = t; + if (t1.type == ttConst) + GetToken(&t1); + + sToken t2; + if (t1.type != ttAuto) + { + // The type may be initiated with the scope operator + if (t1.type == ttScope) + GetToken(&t1); + + // The type may be preceded with a multilevel scope + GetToken(&t2); + while (t1.type == ttIdentifier) + { + if (t2.type == ttScope) + { + GetToken(&t1); + GetToken(&t2); + continue; + } + else if (t2.type == ttLessThan) + { + // Template types can also be used as scope identifiers + RewindTo(&t2); + if (CheckTemplateType(t1)) + { + sToken t3; + GetToken(&t3); + if (t3.type == ttScope) + { + GetToken(&t1); + GetToken(&t2); + continue; + } + } + } + + break; + } + RewindTo(&t2); + } + + // We don't validate if the identifier is an actual declared type at this moment + // as it may wrongly identify the statement as a non-declaration if the user typed + // the name incorrectly. The real type is validated in ParseDeclaration where a + // proper error message can be given. + if (!IsRealType(t1.type) && t1.type != ttIdentifier && t1.type != ttAuto) + { + RewindTo(&t); + return false; + } + + if (!CheckTemplateType(t1)) + { + RewindTo(&t); + return false; + } + + // Object handles can be interleaved with the array brackets + // Even though declaring variables with & is invalid we'll accept + // it here to give an appropriate error message later + GetToken(&t2); + while (t2.type == ttHandle || t2.type == ttAmp || t2.type == ttOpenBracket) + { + if( t2.type == ttHandle ) + { + // A handle can optionally be read-only + sToken t3; + GetToken(&t3); + if(t3.type != ttConst ) + RewindTo(&t3); + } + else if (t2.type == ttOpenBracket) + { + GetToken(&t2); + if (t2.type != ttCloseBracket) + { + RewindTo(&t); + return false; + } + } + + GetToken(&t2); + } + + // Return the next token so the caller can jump directly to it if desired + nextToken = t2; + + // Rewind to start point + RewindTo(&t); + + return true; +} + +// This function will return true if the current token is not a template, or if it is and +// the following has a valid syntax for a template type. The source position will be left +// at the first token after the type in case of success +bool asCParser::CheckTemplateType(const sToken &t) +{ + // Is this a template type? + tempString.Assign(&script->code[t.pos], t.length); + if( engine->IsTemplateType(tempString.AddressOf()) ) + { + // If the next token is a < then parse the sub-type too + sToken t1; + GetToken(&t1); + if( t1.type != ttLessThan ) + { + RewindTo(&t1); + return true; + } + + for(;;) + { + // There might optionally be a 'const' + GetToken(&t1); + if( t1.type == ttConst ) + GetToken(&t1); + + // The type may be initiated with the scope operator + if( t1.type == ttScope ) + GetToken(&t1); + + // There may be multiple levels of scope operators + sToken t2; + GetToken(&t2); + while( t1.type == ttIdentifier && t2.type == ttScope ) + { + GetToken(&t1); + GetToken(&t2); + } + RewindTo(&t2); + + // Now there must be a data type + if( !IsDataType(t1) ) + return false; + + if( !CheckTemplateType(t1) ) + return false; + + GetToken(&t1); + + // Is it a handle or array? + while( t1.type == ttHandle || t1.type == ttOpenBracket ) + { + if( t1.type == ttOpenBracket ) + { + GetToken(&t1); + if( t1.type != ttCloseBracket ) + return false; + } + + GetToken(&t1); + } + + // Was this the last template subtype? + if( t1.type != ttListSeparator ) + break; + } + + // Accept >> and >>> tokens too. But then force the tokenizer to move + // only 1 character ahead (thus splitting the token in two). + if( script->code[t1.pos] != '>' ) + return false; + else if( t1.length != 1 ) + { + // We need to break the token, so that only the first character is parsed + SetPos(t1.pos + 1); + } + } + + return true; +} + +// BNF:12: CAST ::= 'cast' '<' TYPE '>' '(' ASSIGN ')' +asCScriptNode *asCParser::ParseCast() +{ + asCScriptNode *node = CreateNode(snCast); + if( node == 0 ) return 0; + + sToken t1; + GetToken(&t1); + if( t1.type != ttCast ) + { + Error(ExpectedToken("cast"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + GetToken(&t1); + if( t1.type != ttLessThan ) + { + Error(ExpectedToken("<"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + // Parse the data type + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; + + GetToken(&t1); + if( t1.type != ttGreaterThan ) + { + Error(ExpectedToken(">"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + GetToken(&t1); + if( t1.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t1); + if( t1.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:11: EXPRVALUE ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')' | LAMBDA +asCScriptNode *asCParser::ParseExprValue() +{ + asCScriptNode *node = CreateNode(snExprValue); + if( node == 0 ) return 0; + + sToken t1, t2; + GetToken(&t1); + GetToken(&t2); + RewindTo(&t1); + + // 'void' is a special expression that doesn't do anything (normally used for skipping output arguments) + if( t1.type == ttVoid ) + node->AddChildLast(ParseToken(ttVoid)); + else if( IsRealType(t1.type) ) + node->AddChildLast(ParseConstructCall()); + else if( t1.type == ttIdentifier || t1.type == ttScope ) + { + // Check if the expression is an anonymous function + if( IsLambda() ) + { + node->AddChildLast(ParseLambda()); + } + else + { + // Determine the last identifier in order to check if it is a type + sToken t; + if( t1.type == ttScope ) t = t2; else t = t1; + RewindTo(&t); + GetToken(&t2); + while( t.type == ttIdentifier ) + { + t2 = t; + GetToken(&t); + if( t.type == ttScope ) + GetToken(&t); + else + break; + } + + bool isDataType = IsDataType(t2); + bool isTemplateType = false; + if( isDataType ) + { + // Is this a template type? + tempString.Assign(&script->code[t2.pos], t2.length); + if( engine->IsTemplateType(tempString.AddressOf()) ) + isTemplateType = true; + } + + GetToken(&t2); + + // Rewind so the real parsing can be done, after deciding what to parse + RewindTo(&t1); + + // Check if this is a construct call + // Just 'type()' isn't considered a construct call, because type may just be a function/method name. + // The compiler will have to sort this out, since the parser doesn't have enough information. + if( isDataType && (t.type == ttOpenBracket && t2.type == ttCloseBracket) ) // type[]() + node->AddChildLast(ParseConstructCall()); + else if( isTemplateType && t.type == ttLessThan ) // type() + node->AddChildLast(ParseConstructCall()); + else if( IsFunctionCall() ) + node->AddChildLast(ParseFunctionCall()); + else + node->AddChildLast(ParseVariableAccess()); + } + } + else if( t1.type == ttCast ) + node->AddChildLast(ParseCast()); + else if( IsConstant(t1.type) ) + node->AddChildLast(ParseConstant()); + else if( t1.type == ttOpenParanthesis ) + { + GetToken(&t1); + node->UpdateSourcePos(t1.pos, t1.length); + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t1); + if( t1.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t1); + Error(InsteadFound(t1), &t1); + } + + node->UpdateSourcePos(t1.pos, t1.length); + } + else + { + Error(TXT_EXPECTED_EXPRESSION_VALUE, &t1); + Error(InsteadFound(t1), &t1); + } + + return node; +} + +// BNF:12: LITERAL ::= NUMBER | STRING | BITS | 'true' | 'false' | 'null' +// BNF:17: NUMBER ::= single token: includes integers and real numbers, same as C++ +// BNF:17: STRING ::= single token: single quoted ', double quoted ", or heredoc multi-line string """ +// BNF:17: BITS ::= single token: binary 0b or 0B, octal 0o or 0O, decimal 0d or 0D, hexadecimal 0x or 0X +asCScriptNode *asCParser::ParseConstant() +{ + asCScriptNode *node = CreateNode(snConstant); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( !IsConstant(t.type) ) + { + Error(TXT_EXPECTED_CONSTANT, &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + // We want to gather a list of string constants to concatenate as children + if( t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant ) + RewindTo(&t); + + while( t.type == ttStringConstant || t.type == ttMultilineStringConstant || t.type == ttHeredocStringConstant ) + { + node->AddChildLast(ParseStringConstant()); + + GetToken(&t); + RewindTo(&t); + } + + return node; +} + +bool asCParser::IsLambda() +{ + bool isLambda = false; + sToken t; + GetToken(&t); + if( t.type == ttIdentifier && IdentifierIs(t, FUNCTION_TOKEN) ) + { + sToken t2; + GetToken(&t2); + if( t2.type == ttOpenParanthesis ) + { + // Skip until ) + while( t2.type != ttCloseParanthesis && t2.type != ttEnd ) + GetToken(&t2); + + // The next token must be a { + GetToken(&t2); + if( t2.type == ttStartStatementBlock ) + isLambda = true; + } + } + + RewindTo(&t); + return isLambda; +} + +// BNF:12: LAMBDA ::= 'function' '(' [[TYPE TYPEMOD] IDENTIFIER {',' [TYPE TYPEMOD] IDENTIFIER}] ')' STATBLOCK +asCScriptNode *asCParser::ParseLambda() +{ + asCScriptNode *node = CreateNode(snFunction); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + + if( t.type != ttIdentifier || !IdentifierIs(t, FUNCTION_TOKEN) ) + { + Error(ExpectedToken("function"), &t); + return node; + } + + GetToken(&t); + if( t.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t); + return node; + } + + // Parse optional type before parameter name + if( IsType(t) && (t.type == ttAmp || t.type == ttIdentifier) ) + { + node->AddChildLast(ParseType(true)); + if (isSyntaxError) return node; + node->AddChildLast(ParseTypeMod(true)); + if (isSyntaxError) return node; + } + + GetToken(&t); + if( t.type == ttIdentifier ) + { + RewindTo(&t); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + + GetToken(&t); + while( t.type == ttListSeparator ) + { + // Parse optional type before parameter name + if (IsType(t) && (t.type == ttAmp || t.type == ttIdentifier)) + { + node->AddChildLast(ParseType(true)); + if (isSyntaxError) return node; + node->AddChildLast(ParseTypeMod(true)); + if (isSyntaxError) return node; + } + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + GetToken(&t); + } + } + + if( t.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t); + return node; + } + + // We should just find the end of the statement block here. The statements + // will be parsed on request by the compiler once it starts the compilation. + node->AddChildLast(SuperficiallyParseStatementBlock()); + + return node; +} + +asCScriptNode *asCParser::ParseStringConstant() +{ + asCScriptNode *node = CreateNode(snConstant); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttStringConstant && t.type != ttMultilineStringConstant && t.type != ttHeredocStringConstant ) + { + Error(TXT_EXPECTED_STRING, &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:12: FUNCCALL ::= SCOPE IDENTIFIER ARGLIST +asCScriptNode *asCParser::ParseFunctionCall() +{ + asCScriptNode *node = CreateNode(snFunctionCall); + if( node == 0 ) return 0; + + // Parse scope prefix + ParseOptionalScope(node); + + // Parse the function name followed by the argument list + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseArgList()); + + return node; +} + +// BNF:12: VARACCESS ::= SCOPE IDENTIFIER +asCScriptNode *asCParser::ParseVariableAccess() +{ + asCScriptNode *node = CreateNode(snVariableAccess); + if( node == 0 ) return 0; + + // Parse scope prefix + ParseOptionalScope(node); + + // Parse the variable name + node->AddChildLast(ParseIdentifier()); + + return node; +} + +// BNF:11: CONSTRUCTCALL ::= TYPE ARGLIST +asCScriptNode *asCParser::ParseConstructCall() +{ + asCScriptNode *node = CreateNode(snConstructCall); + if( node == 0 ) return 0; + + node->AddChildLast(ParseType(false)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseArgList()); + + return node; +} + +// BNF:13: ARGLIST ::= '(' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':'] ASSIGN} ')' +asCScriptNode *asCParser::ParseArgList(bool withParenthesis) +{ + asCScriptNode *node = CreateNode(snArgList); + if( node == 0 ) return 0; + + sToken t1; + if( withParenthesis ) + { + GetToken(&t1); + if( t1.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + } + + GetToken(&t1); + if( t1.type == ttCloseParanthesis || t1.type == ttCloseBracket ) + { + if( withParenthesis ) + { + if( t1.type == ttCloseParanthesis ) + node->UpdateSourcePos(t1.pos, t1.length); + else + { + asCString str; + str.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(ttCloseBracket)); + + Error(str.AddressOf(), &t1); + } + } + else + RewindTo(&t1); + + // Argument list has ended + return node; + } + else + { + RewindTo(&t1); + + for(;;) + { + // Determine if this is a named argument + sToken tl, t2; + GetToken(&tl); + GetToken(&t2); + RewindTo(&tl); + + // Named arguments uses the syntax: arg : expr + // This avoids confusion when the argument has the same name as a local variable, i.e. var = expr + // It also avoids conflict with expressions to that creates anonymous objects initialized with lists, i.e. type = {...} + // The alternate syntax: arg = expr, is supported to provide backwards compatibility with 2.29.0 + // TODO: 3.0.0: Remove the alternate syntax + if( tl.type == ttIdentifier && (t2.type == ttColon || (engine->ep.alterSyntaxNamedArgs && t2.type == ttAssignment)) ) + { + asCScriptNode *named = CreateNode(snNamedArgument); + if( named == 0 ) return 0; + node->AddChildLast(named); + + named->AddChildLast(ParseIdentifier()); + GetToken(&t2); + + if( engine->ep.alterSyntaxNamedArgs == 1 && t2.type == ttAssignment ) + Warning(TXT_NAMED_ARGS_WITH_OLD_SYNTAX, &t2); + + named->AddChildLast(ParseAssignment()); + } + else + node->AddChildLast(ParseAssignment()); + + if( isSyntaxError ) return node; + + // Check if list continues + GetToken(&t1); + if( t1.type == ttListSeparator ) + continue; + else + { + if( withParenthesis ) + { + if( t1.type == ttCloseParanthesis ) + node->UpdateSourcePos(t1.pos, t1.length); + else + { + Error(ExpectedTokens(")", ","), &t1); + Error(InsteadFound(t1), &t1); + } + } + else + RewindTo(&t1); + + return node; + } + } + } +} + +bool asCParser::IsFunctionCall() +{ + sToken s; + sToken t1, t2; + + GetToken(&s); + t1 = s; + + // A function call may be prefixed with scope resolution + if( t1.type == ttScope ) + GetToken(&t1); + GetToken(&t2); + + while( t1.type == ttIdentifier && t2.type == ttScope ) + { + GetToken(&t1); + GetToken(&t2); + } + + // A function call starts with an identifier followed by an argument list + // The parser doesn't have enough information about scope to determine if the + // identifier is a datatype, so even if it happens to be the parser will + // identify the expression as a function call rather than a construct call. + // The compiler will sort this out later + if( t1.type != ttIdentifier ) + { + RewindTo(&s); + return false; + } + + if( t2.type == ttOpenParanthesis ) + { + RewindTo(&s); + return true; + } + + RewindTo(&s); + return false; +} + +// BNF:13: ASSIGN ::= CONDITION [ ASSIGNOP ASSIGN ] +asCScriptNode *asCParser::ParseAssignment() +{ + asCScriptNode *node = CreateNode(snAssignment); + if( node == 0 ) return 0; + + node->AddChildLast(ParseCondition()); + if( isSyntaxError ) return node; + + sToken t; + GetToken(&t); + RewindTo(&t); + + if( IsAssignOperator(t.type) ) + { + node->AddChildLast(ParseAssignOperator()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + } + + return node; +} + +// BNF:14: CONDITION ::= EXPR ['?' ASSIGN ':' ASSIGN] +asCScriptNode *asCParser::ParseCondition() +{ + asCScriptNode *node = CreateNode(snCondition); + if( node == 0 ) return 0; + + node->AddChildLast(ParseExpression()); + if( isSyntaxError ) return node; + + sToken t; + GetToken(&t); + if( t.type == ttQuestion ) + { + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttColon ) + { + Error(ExpectedToken(":"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + } + else + RewindTo(&t); + + return node; +} + +// BNF:9: EXPR ::= EXPRTERM {EXPROP EXPRTERM} +asCScriptNode *asCParser::ParseExpression() +{ + asCScriptNode *node = CreateNode(snExpression); + if( node == 0 ) return 0; + + node->AddChildLast(ParseExprTerm()); + if( isSyntaxError ) return node; + + for(;;) + { + sToken t; + GetToken(&t); + RewindTo(&t); + + if( !IsOperator(t.type) ) + return node; + + node->AddChildLast(ParseExprOperator()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseExprTerm()); + if( isSyntaxError ) return node; + } + UNREACHABLE_RETURN; +} + +// BNF:10: EXPRTERM ::= ([TYPE '='] INITLIST) | ({EXPRPREOP} EXPRVALUE {EXPRPOSTOP}) +asCScriptNode *asCParser::ParseExprTerm() +{ + asCScriptNode *node = CreateNode(snExprTerm); + if( node == 0 ) return 0; + + // Check if the expression term is an initialization of a temp object with init list, i.e. type = {...} + sToken t; + GetToken(&t); + sToken t2 = t, t3; + if (IsDataType(t2) && CheckTemplateType(t2)) + { + // The next token must be a = followed by a { + GetToken(&t2); + GetToken(&t3); + if (t2.type == ttAssignment && t3.type == ttStartStatementBlock) + { + // It is an initialization, now parse it for real + RewindTo(&t); + node->AddChildLast(ParseType(false)); + GetToken(&t2); + node->AddChildLast(ParseInitList()); + return node; + } + } + // Or an anonymous init list, i.e. {...} + else if( t.type == ttStartStatementBlock ) + { + RewindTo(&t); + node->AddChildLast(ParseInitList()); + return node; + } + + // It wasn't an initialization, so it must be an ordinary expression term + RewindTo(&t); + + for(;;) + { + GetToken(&t); + RewindTo(&t); + if( !IsPreOperator(t.type) ) + break; + + node->AddChildLast(ParseExprPreOp()); + if( isSyntaxError ) return node; + } + + node->AddChildLast(ParseExprValue()); + if( isSyntaxError ) return node; + + + for(;;) + { + GetToken(&t); + RewindTo(&t); + if( !IsPostOperator(t.type) ) + return node; + + node->AddChildLast(ParseExprPostOp()); + if( isSyntaxError ) return node; + } + UNREACHABLE_RETURN; +} + +// BNF:11: EXPRPREOP ::= '-' | '+' | '!' | '++' | '--' | '~' | '@' +asCScriptNode *asCParser::ParseExprPreOp() +{ + asCScriptNode *node = CreateNode(snExprPreOp); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( !IsPreOperator(t.type) ) + { + Error(TXT_EXPECTED_PRE_OPERATOR, &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:11: EXPRPOSTOP ::= ('.' (FUNCCALL | IDENTIFIER)) | ('[' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':' ASSIGN} ']') | ARGLIST | '++' | '--' +asCScriptNode *asCParser::ParseExprPostOp() +{ + asCScriptNode *node = CreateNode(snExprPostOp); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( !IsPostOperator(t.type) ) + { + Error(TXT_EXPECTED_POST_OPERATOR, &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + if( t.type == ttDot ) + { + sToken t1, t2; + GetToken(&t1); + GetToken(&t2); + RewindTo(&t1); + if( t2.type == ttOpenParanthesis ) + node->AddChildLast(ParseFunctionCall()); + else + node->AddChildLast(ParseIdentifier()); + } + else if( t.type == ttOpenBracket ) + { + node->AddChildLast(ParseArgList(false)); + + GetToken(&t); + if( t.type != ttCloseBracket ) + { + Error(ExpectedToken("]"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + } + else if( t.type == ttOpenParanthesis ) + { + RewindTo(&t); + node->AddChildLast(ParseArgList()); + } + + return node; +} + +// BNF:15: EXPROP ::= MATHOP | COMPOP | LOGICOP | BITOP +// BNF:16: MATHOP ::= '+' | '-' | '*' | '/' | '%' | '**' +// BNF:16: COMPOP ::= '==' | '!=' | '<' | '<=' | '>' | '>=' | 'is' | '!is' +// BNF:16: LOGICOP ::= '&&' | '||' | '^^' | 'and' | 'or' | 'xor' +// BNF:16: BITOP ::= '&' | '|' | '^' | '<<' | '>>' | '>>>' +asCScriptNode *asCParser::ParseExprOperator() +{ + asCScriptNode *node = CreateNode(snExprOperator); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( !IsOperator(t.type) ) + { + Error(TXT_EXPECTED_OPERATOR, &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:16: ASSIGNOP ::= '=' | '+=' | '-=' | '*=' | '/=' | '|=' | '&=' | '^=' | '%=' | '**=' | '<<=' | '>>=' | '>>>=' +asCScriptNode *asCParser::ParseAssignOperator() +{ + asCScriptNode *node = CreateNode(snExprOperator); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( !IsAssignOperator(t.type) ) + { + Error(TXT_EXPECTED_OPERATOR, &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +bool asCParser::IsOperator(int tokenType) +{ + if( tokenType == ttPlus || + tokenType == ttMinus || + tokenType == ttStar || + tokenType == ttSlash || + tokenType == ttPercent || + tokenType == ttStarStar || + tokenType == ttAnd || + tokenType == ttOr || + tokenType == ttXor || + tokenType == ttEqual || + tokenType == ttNotEqual || + tokenType == ttLessThan || + tokenType == ttLessThanOrEqual || + tokenType == ttGreaterThan || + tokenType == ttGreaterThanOrEqual || + tokenType == ttAmp || + tokenType == ttBitOr || + tokenType == ttBitXor || + tokenType == ttBitShiftLeft || + tokenType == ttBitShiftRight || + tokenType == ttBitShiftRightArith || + tokenType == ttIs || + tokenType == ttNotIs ) + return true; + + return false; +} + +bool asCParser::IsAssignOperator(int tokenType) +{ + if( tokenType == ttAssignment || + tokenType == ttAddAssign || + tokenType == ttSubAssign || + tokenType == ttMulAssign || + tokenType == ttDivAssign || + tokenType == ttModAssign || + tokenType == ttPowAssign || + tokenType == ttAndAssign || + tokenType == ttOrAssign || + tokenType == ttXorAssign || + tokenType == ttShiftLeftAssign || + tokenType == ttShiftRightLAssign || + tokenType == ttShiftRightAAssign ) + return true; + + return false; +} + +bool asCParser::IsPreOperator(int tokenType) +{ + if( tokenType == ttMinus || + tokenType == ttPlus || + tokenType == ttNot || + tokenType == ttInc || + tokenType == ttDec || + tokenType == ttBitNot || + tokenType == ttHandle ) + return true; + return false; +} + +bool asCParser::IsPostOperator(int tokenType) +{ + if( tokenType == ttInc || // post increment + tokenType == ttDec || // post decrement + tokenType == ttDot || // member access + tokenType == ttOpenBracket || // index operator + tokenType == ttOpenParanthesis ) // argument list for call on function pointer + return true; + return false; +} + +bool asCParser::IsConstant(int tokenType) +{ + if( tokenType == ttIntConstant || + tokenType == ttFloatConstant || + tokenType == ttDoubleConstant || + tokenType == ttStringConstant || + tokenType == ttMultilineStringConstant || + tokenType == ttHeredocStringConstant || + tokenType == ttTrue || + tokenType == ttFalse || + tokenType == ttBitsConstant || + tokenType == ttNull ) + return true; + + return false; +} + +int asCParser::ParseScript(asCScriptCode *in_script) +{ + Reset(); + + this->script = in_script; + + scriptNode = ParseScript(false); + + if( errorWhileParsing ) + return -1; + + // TODO: Should allow application to request this warning to be generated. + // It should be off by default, since pre-processor may remove all + // code from a section while still being meant as valid code +/* + // Warn in case there isn't anything in the script + if( scriptNode->firstChild == 0 ) + { + if( builder ) + builder->WriteWarning(script->name, TXT_SECTION_IS_EMPTY, 1, 1); + } +*/ + return 0; +} + +int asCParser::ParseExpression(asCScriptCode *in_script) +{ + Reset(); + + this->script = in_script; + + checkValidTypes = true; + + scriptNode = ParseExpression(); + if( errorWhileParsing ) + return -1; + + return 0; +} + +// BNF:1: IMPORT ::= 'import' TYPE ['&'] IDENTIFIER PARAMLIST FUNCATTR 'from' STRING ';' +asCScriptNode *asCParser::ParseImport() +{ + asCScriptNode *node = CreateNode(snImport); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttImport ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttImport)), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + node->AddChildLast(ParseFunctionDefinition()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttIdentifier ) + { + Error(ExpectedToken(FROM_TOKEN), &t); + Error(InsteadFound(t), &t); + return node; + } + + tempString.Assign(&script->code[t.pos], t.length); + if( tempString != FROM_TOKEN ) + { + Error(ExpectedToken(FROM_TOKEN), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttStringConstant ) + { + Error(TXT_EXPECTED_STRING, &t); + Error(InsteadFound(t), &t); + return node; + } + + asCScriptNode *mod = CreateNode(snConstant); + if( mod == 0 ) return 0; + + node->AddChildLast(mod); + + mod->SetToken(&t); + mod->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttEndStatement ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatement)), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:0: SCRIPT ::= {IMPORT | ENUM | TYPEDEF | CLASS | MIXIN | INTERFACE | FUNCDEF | VIRTPROP | VAR | FUNC | NAMESPACE | ';'} +asCScriptNode *asCParser::ParseScript(bool inBlock) +{ + asCScriptNode *node = CreateNode(snScript); + if( node == 0 ) return 0; + + // Determine type of node + for(;;) + { + while( !isSyntaxError ) + { + sToken tStart; + GetToken(&tStart); + + // Optimize by skipping tokens 'shared', 'external', 'final', 'abstract' so they don't have to be checked in every condition + sToken t1 = tStart; + while (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN) || + IdentifierIs(t1, FINAL_TOKEN) || + IdentifierIs(t1, ABSTRACT_TOKEN)) + GetToken(&t1); + RewindTo(&tStart); + + if( t1.type == ttImport ) + node->AddChildLast(ParseImport()); + else if( t1.type == ttEnum ) + node->AddChildLast(ParseEnumeration()); // Handle enumerations + else if( t1.type == ttTypedef ) + node->AddChildLast(ParseTypedef()); // Handle primitive typedefs + else if( t1.type == ttClass ) + node->AddChildLast(ParseClass()); + else if( t1.type == ttMixin ) + node->AddChildLast(ParseMixin()); + else if( t1.type == ttInterface ) + node->AddChildLast(ParseInterface()); + else if( t1.type == ttFuncDef ) + node->AddChildLast(ParseFuncDef()); + else if( t1.type == ttConst || t1.type == ttScope || t1.type == ttAuto || IsDataType(t1) ) + { + if( IsVirtualPropertyDecl() ) + node->AddChildLast(ParseVirtualPropertyDecl(false, false)); + else if( IsVarDecl() ) + node->AddChildLast(ParseDeclaration(false, true)); + else + node->AddChildLast(ParseFunction()); + } + else if( t1.type == ttEndStatement ) + { + // Ignore a semicolon by itself + GetToken(&t1); + } + else if( t1.type == ttNamespace ) + node->AddChildLast(ParseNamespace()); + else if( t1.type == ttEnd ) + return node; + else if( inBlock && t1.type == ttEndStatementBlock ) + return node; + else + { + asCString str; + const char *t = asCTokenizer::GetDefinition(t1.type); + if( t == 0 ) t = ""; + + str.Format(TXT_UNEXPECTED_TOKEN_s, t); + + Error(str, &t1); + } + } + + if( isSyntaxError ) + { + // Search for either ';' or '{' or end + sToken t1; + GetToken(&t1); + while( t1.type != ttEndStatement && t1.type != ttEnd && + t1.type != ttStartStatementBlock ) + GetToken(&t1); + + if( t1.type == ttStartStatementBlock ) + { + // Find the end of the block and skip nested blocks + int level = 1; + while( level > 0 ) + { + GetToken(&t1); + if( t1.type == ttStartStatementBlock ) level++; + if( t1.type == ttEndStatementBlock ) level--; + if( t1.type == ttEnd ) break; + } + } + + isSyntaxError = false; + } + } + UNREACHABLE_RETURN; +} + +// BNF:1: NAMESPACE ::= 'namespace' IDENTIFIER '{' SCRIPT '}' +asCScriptNode *asCParser::ParseNamespace() +{ + asCScriptNode *node = CreateNode(snNamespace); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( t1.type == ttNamespace ) + node->UpdateSourcePos(t1.pos, t1.length); + else + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttNamespace)), &t1); + Error(InsteadFound(t1), &t1); + } + + // TODO: namespace: Allow declaration of multiple nested namespace with namespace A::B::C { } + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + GetToken(&t1); + if( t1.type == ttStartStatementBlock ) + node->UpdateSourcePos(t1.pos, t1.length); + else + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttStartStatementBlock)), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + sToken start = t1; + + node->AddChildLast(ParseScript(true)); + + if( !isSyntaxError ) + { + GetToken(&t1); + if( t1.type == ttEndStatementBlock ) + node->UpdateSourcePos(t1.pos, t1.length); + else + { + if( t1.type == ttEnd ) + Error(TXT_UNEXPECTED_END_OF_FILE, &t1); + else + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatementBlock)), &t1); + Error(InsteadFound(t1), &t1); + } + Info(TXT_WHILE_PARSING_NAMESPACE, &start); + return node; + } + } + + return node; +} + +int asCParser::ParseStatementBlock(asCScriptCode *in_script, asCScriptNode *in_block) +{ + TimeIt("asCParser::ParseStatementBlock"); + + Reset(); + + // Tell the parser to validate the identifiers as valid types + checkValidTypes = true; + + this->script = in_script; + sourcePos = in_block->tokenPos; + + scriptNode = ParseStatementBlock(); + + if( isSyntaxError || errorWhileParsing ) + return -1; + + return 0; +} + +// BNF:1: ENUM ::= {'shared' | 'external'} 'enum' IDENTIFIER (';' | ('{' IDENTIFIER ['=' EXPR] {',' IDENTIFIER ['=' EXPR]} '}')) +asCScriptNode *asCParser::ParseEnumeration() +{ + asCScriptNode *ident; + asCScriptNode *dataType; + + asCScriptNode *node = CreateNode(snEnum); + if( node == 0 ) return 0; + + sToken token; + + // Optional 'shared' and 'external' token + GetToken(&token); + while( IdentifierIs(token, SHARED_TOKEN) || + IdentifierIs(token, EXTERNAL_TOKEN) ) + { + RewindTo(&token); + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + GetToken(&token); + } + + // Check for enum + if( token.type != ttEnum ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEnum)), &token); + Error(InsteadFound(token), &token); + return node; + } + + node->SetToken(&token); + node->UpdateSourcePos(token.pos, token.length); + + // Get the identifier + GetToken(&token); + if(ttIdentifier != token.type) + { + Error(TXT_EXPECTED_IDENTIFIER, &token); + Error(InsteadFound(token), &token); + return node; + } + + dataType = CreateNode(snDataType); + if( dataType == 0 ) return node; + + node->AddChildLast(dataType); + + ident = CreateNode(snIdentifier); + if( ident == 0 ) return node; + + ident->SetToken(&token); + ident->UpdateSourcePos(token.pos, token.length); + dataType->AddChildLast(ident); + + // External shared declarations are ended with ';' + GetToken(&token); + if (token.type == ttEndStatement) + { + RewindTo(&token); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // check for the start of the declaration block + if( token.type != ttStartStatementBlock ) + { + RewindTo(&token); + int tokens[] = { ttStartStatementBlock, ttEndStatement }; + Error(ExpectedOneOf(tokens, 2), &token); + Error(InsteadFound(token), &token); + return node; + } + + while(ttEnd != token.type) + { + GetToken(&token); + + if( ttEndStatementBlock == token.type ) + { + RewindTo(&token); + break; + } + + if(ttIdentifier != token.type) + { + Error(TXT_EXPECTED_IDENTIFIER, &token); + Error(InsteadFound(token), &token); + return node; + } + + // Add the enum element + ident = CreateNode(snIdentifier); + if( ident == 0 ) return node; + + ident->SetToken(&token); + ident->UpdateSourcePos(token.pos, token.length); + node->AddChildLast(ident); + + GetToken(&token); + + if( token.type == ttAssignment ) + { + asCScriptNode *tmp; + + RewindTo(&token); + + tmp = SuperficiallyParseVarInit(); + + node->AddChildLast(tmp); + if( isSyntaxError ) return node; + GetToken(&token); + } + + if(ttListSeparator != token.type) + { + RewindTo(&token); + break; + } + } + + // check for the end of the declaration block + GetToken(&token); + if( token.type != ttEndStatementBlock ) + { + RewindTo(&token); + Error(ExpectedToken("}"), &token); + Error(InsteadFound(token), &token); + return node; + } + + return node; +} + +bool asCParser::IsVarDecl() +{ + // Set start point so that we can rewind + sToken t; + GetToken(&t); + RewindTo(&t); + + // A class property decl can be preceded by 'private' or 'protected' + sToken t1; + GetToken(&t1); + if( t1.type != ttPrivate && t1.type != ttProtected ) + RewindTo(&t1); + + // A variable decl starts with the type + if (!IsType(t1)) + { + RewindTo(&t); + return false; + } + + // Jump to the token after the type + RewindTo(&t1); + GetToken(&t1); + + // The declaration needs to have a name + if( t1.type != ttIdentifier ) + { + RewindTo(&t); + return false; + } + + // It can be followed by an initialization + GetToken(&t1); + if( t1.type == ttEndStatement || t1.type == ttAssignment || t1.type == ttListSeparator ) + { + RewindTo(&t); + return true; + } + if( t1.type == ttOpenParanthesis ) + { + // If the closing parenthesis is followed by a statement block, + // function decorator, or end-of-file, then treat it as a function. + // A function decl may have nested parenthesis so we need to check + // for this too. + int nest = 0; + while( t1.type != ttEnd ) + { + if( t1.type == ttOpenParanthesis ) + nest++; + else if( t1.type == ttCloseParanthesis ) + { + nest--; + if( nest == 0 ) + break; + } + GetToken(&t1); + } + + if (t1.type == ttEnd) + { + RewindTo(&t); + return false; + } + else + { + GetToken(&t1); + RewindTo(&t); + if( t1.type == ttStartStatementBlock || + t1.type == ttIdentifier || // function decorator + t1.type == ttEnd ) + return false; + } + + RewindTo(&t); + return true; + } + + RewindTo(&t); + return false; +} + +bool asCParser::IsVirtualPropertyDecl() +{ + // Set start point so that we can rewind + sToken t; + GetToken(&t); + RewindTo(&t); + + // A class property decl can be preceded by 'private' or 'protected' + sToken t1; + GetToken(&t1); + if( t1.type != ttPrivate && t1.type != ttProtected ) + RewindTo(&t1); + + // A variable decl starts with the type + if (!IsType(t1)) + { + RewindTo(&t); + return false; + } + + // Move to the token after the type + RewindTo(&t1); + GetToken(&t1); + + // The decl must have an identifier + if( t1.type != ttIdentifier ) + { + RewindTo(&t); + return false; + } + + // To be a virtual property it must also have a block for the get/set functions + GetToken(&t1); + if( t1.type == ttStartStatementBlock ) + { + RewindTo(&t); + return true; + } + + RewindTo(&t); + return false; +} + +bool asCParser::IsFuncDecl(bool isMethod) +{ + // Set start point so that we can rewind + sToken t; + GetToken(&t); + RewindTo(&t); + + if( isMethod ) + { + // A class method decl can be preceded by 'private' or 'protected' + sToken t1, t2; + GetToken(&t1); + if( t1.type != ttPrivate && t1.type != ttProtected ) + RewindTo(&t1); + + // A class constructor starts with identifier followed by parenthesis + // A class destructor starts with the ~ token + GetToken(&t1); + GetToken(&t2); + RewindTo(&t1); + if( (t1.type == ttIdentifier && t2.type == ttOpenParanthesis) || t1.type == ttBitNot ) + { + RewindTo(&t); + return true; + } + } + + // A function decl starts with a type + sToken t1; + if (!IsType(t1)) + { + RewindTo(&t); + return false; + } + + // Move to the token after the type + RewindTo(&t1); + GetToken(&t1); + + // There can be an ampersand if the function returns a reference + if( t1.type == ttAmp ) + { + RewindTo(&t); + return true; + } + + if( t1.type != ttIdentifier ) + { + RewindTo(&t); + return false; + } + + GetToken(&t1); + if( t1.type == ttOpenParanthesis ) + { + // If the closing parenthesis is not followed by a + // statement block then it is not a function. + // It's possible that there are nested parenthesis due to default + // arguments so this should be checked for. + int nest = 0; + GetToken(&t1); + while( (nest || t1.type != ttCloseParanthesis) && t1.type != ttEnd ) + { + if( t1.type == ttOpenParanthesis ) + nest++; + if( t1.type == ttCloseParanthesis ) + nest--; + + GetToken(&t1); + } + + if( t1.type == ttEnd ) + return false; + else + { + if( isMethod ) + { + // A class method can have a 'const' token after the parameter list + GetToken(&t1); + if( t1.type != ttConst ) + RewindTo(&t1); + } + + // A function may also have any number of additional attributes + for( ; ; ) + { + GetToken(&t1); + if( !IdentifierIs(t1, FINAL_TOKEN) && + !IdentifierIs(t1, OVERRIDE_TOKEN) && + !IdentifierIs(t1, EXPLICIT_TOKEN) && + !IdentifierIs(t1, PROPERTY_TOKEN) ) + { + RewindTo(&t1); + break; + } + } + + GetToken(&t1); + RewindTo(&t); + if( t1.type == ttStartStatementBlock ) + return true; + } + + RewindTo(&t); + return false; + } + + RewindTo(&t); + return false; +} + +// BNF:1: FUNCDEF ::= {'external' | 'shared'} 'funcdef' TYPE ['&'] IDENTIFIER PARAMLIST ';' +asCScriptNode *asCParser::ParseFuncDef() +{ + asCScriptNode *node = CreateNode(snFuncDef); + if( node == 0 ) return 0; + + // Allow keywords 'external' and 'shared' before 'interface' + sToken t1; + GetToken(&t1); + while (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN)) + { + RewindTo(&t1); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + + GetToken(&t1); + } + + if( t1.type != ttFuncDef ) + { + Error(asCTokenizer::GetDefinition(ttFuncDef), &t1); + return node; + } + + node->SetToken(&t1); + + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseParameterList()); + if( isSyntaxError ) return node; + + GetToken(&t1); + if( t1.type != ttEndStatement ) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttEndStatement)), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:1: FUNC ::= {'shared' | 'external'} ['private' | 'protected'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] FUNCATTR (';' | STATBLOCK) +asCScriptNode *asCParser::ParseFunction(bool isMethod) +{ + asCScriptNode *node = CreateNode(snFunction); + if( node == 0 ) return 0; + + sToken t1; + GetToken(&t1); + if (!isMethod) + { + // A global function can be marked as shared and external + while (t1.type == ttIdentifier) + { + if (IdentifierIs(t1, SHARED_TOKEN) || + IdentifierIs(t1, EXTERNAL_TOKEN)) + { + RewindTo(&t1); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + } + else + break; + + GetToken(&t1); + } + } + + // A class method can start with 'private' or 'protected' + if (isMethod && t1.type == ttPrivate) + { + RewindTo(&t1); + node->AddChildLast(ParseToken(ttPrivate)); + GetToken(&t1); + } + else if (isMethod && t1.type == ttProtected) + { + RewindTo(&t1); + node->AddChildLast(ParseToken(ttProtected)); + GetToken(&t1); + } + if( isSyntaxError ) return node; + + // If it is a global function, or a method, except constructor and destructor, then the return type is parsed + sToken t2; + GetToken(&t2); + RewindTo(&t1); + if( !isMethod || (t1.type != ttBitNot && t2.type != ttOpenParanthesis) ) + { + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; + } + + // If this is a class destructor then it starts with ~, and no return type is declared + if( isMethod && t1.type == ttBitNot ) + { + node->AddChildLast(ParseToken(ttBitNot)); + if( isSyntaxError ) return node; + } + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseParameterList()); + if( isSyntaxError ) return node; + + if( isMethod ) + { + GetToken(&t1); + RewindTo(&t1); + + // Is the method a const? + if( t1.type == ttConst ) + node->AddChildLast(ParseToken(ttConst)); + } + + // TODO: Should support abstract methods, in which case no statement block should be provided + ParseMethodAttributes(node); + if( isSyntaxError ) return node; + + // External shared functions must be ended with ';' + GetToken(&t1); + RewindTo(&t1); + if (t1.type == ttEndStatement) + { + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // We should just find the end of the statement block here. The statements + // will be parsed on request by the compiler once it starts the compilation. + node->AddChildLast(SuperficiallyParseStatementBlock()); + + return node; +} + +// BNF:2: INTFMTHD ::= TYPE ['&'] IDENTIFIER PARAMLIST ['const'] ';' +asCScriptNode *asCParser::ParseInterfaceMethod() +{ + asCScriptNode *node = CreateNode(snFunction); + if( node == 0 ) return 0; + + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseParameterList()); + if( isSyntaxError ) return node; + + // Parse an optional const after the method definition + sToken t1; + GetToken(&t1); + RewindTo(&t1); + if( t1.type == ttConst ) + node->AddChildLast(ParseToken(ttConst)); + + GetToken(&t1); + if( t1.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:1: VIRTPROP ::= ['private' | 'protected'] TYPE ['&'] IDENTIFIER '{' {('get' | 'set') ['const'] FUNCATTR (STATBLOCK | ';')} '}' +asCScriptNode *asCParser::ParseVirtualPropertyDecl(bool isMethod, bool isInterface) +{ + asCScriptNode *node = CreateNode(snVirtualProperty); + if( node == 0 ) return 0; + + sToken t1,t2; + GetToken(&t1); + GetToken(&t2); + RewindTo(&t1); + + // A class method can start with 'private' or 'protected' + if( isMethod && t1.type == ttPrivate ) + node->AddChildLast(ParseToken(ttPrivate)); + else if( isMethod && t1.type == ttProtected ) + node->AddChildLast(ParseToken(ttProtected)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseType(true)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseTypeMod(false)); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + GetToken(&t1); + if( t1.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + for(;;) + { + GetToken(&t1); + asCScriptNode *accessorNode = 0; + + if( IdentifierIs(t1, GET_TOKEN) || IdentifierIs(t1, SET_TOKEN) ) + { + accessorNode = CreateNode(snVirtualProperty); + if( accessorNode == 0 ) return 0; + + node->AddChildLast(accessorNode); + + RewindTo(&t1); + accessorNode->AddChildLast(ParseIdentifier()); + + if( isMethod ) + { + GetToken(&t1); + RewindTo(&t1); + if( t1.type == ttConst ) + accessorNode->AddChildLast(ParseToken(ttConst)); + + if( !isInterface ) + { + ParseMethodAttributes(accessorNode); + if( isSyntaxError ) return node; + } + } + + if( !isInterface ) + { + GetToken(&t1); + if( t1.type == ttStartStatementBlock ) + { + RewindTo(&t1); + accessorNode->AddChildLast(SuperficiallyParseStatementBlock()); + if( isSyntaxError ) return node; + } + else if( t1.type != ttEndStatement ) + { + Error(ExpectedTokens(";", "{"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + } + else + { + GetToken(&t1); + if( t1.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + } + } + else if( t1.type == ttEndStatementBlock ) + break; + else + { + const char *tokens[] = { GET_TOKEN, SET_TOKEN, asCTokenizer::GetDefinition(ttEndStatementBlock) }; + Error(ExpectedOneOf(tokens, 3), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + } + + return node; +} + +// BNF:1: INTERFACE ::= {'external' | 'shared'} 'interface' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | INTFMTHD} '}')) +asCScriptNode *asCParser::ParseInterface() +{ + asCScriptNode *node = CreateNode(snInterface); + if( node == 0 ) return 0; + + sToken t; + + // Allow keywords 'external' and 'shared' before 'interface' + GetToken(&t); + while( IdentifierIs(t, SHARED_TOKEN) || + IdentifierIs(t, EXTERNAL_TOKEN) ) + { + RewindTo(&t); + node->AddChildLast(ParseIdentifier()); + if (isSyntaxError) return node; + + GetToken(&t); + } + + if( t.type != ttInterface ) + { + Error(ExpectedToken("interface"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + node->AddChildLast(ParseIdentifier()); + + // External shared declarations are ended with ';' + GetToken(&t); + if (t.type == ttEndStatement) + { + RewindTo(&t); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // Can optionally have a list of interfaces that are inherited + if( t.type == ttColon ) + { + asCScriptNode *inherit = CreateNode(snIdentifier); + node->AddChildLast(inherit); + + ParseOptionalScope(inherit); + inherit->AddChildLast(ParseIdentifier()); + GetToken(&t); + while( t.type == ttListSeparator ) + { + inherit = CreateNode(snIdentifier); + node->AddChildLast(inherit); + + ParseOptionalScope(inherit); + inherit->AddChildLast(ParseIdentifier()); + GetToken(&t); + } + } + + if( t.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t); + Error(InsteadFound(t), &t); + return node; + } + + // Parse interface methods + GetToken(&t); + RewindTo(&t); + while( t.type != ttEndStatementBlock && t.type != ttEnd ) + { + if( IsVirtualPropertyDecl() ) + node->AddChildLast(ParseVirtualPropertyDecl(true, true)); + else if( t.type == ttEndStatement ) + // Skip empty declarations + GetToken(&t); + else + // Parse the method signature + node->AddChildLast(ParseInterfaceMethod()); + + if( isSyntaxError ) return node; + + GetToken(&t); + RewindTo(&t); + } + + GetToken(&t); + if( t.type != ttEndStatementBlock ) + { + Error(ExpectedToken("}"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:1: MIXIN ::= 'mixin' CLASS +asCScriptNode *asCParser::ParseMixin() +{ + asCScriptNode *node = CreateNode(snMixin); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + + if( t.type != ttMixin ) + { + Error(ExpectedToken("mixin"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + + // A mixin token must be followed by a class declaration + node->AddChildLast(ParseClass()); + + return node; +} + +// BNF:1: CLASS ::= {'shared' | 'abstract' | 'final' | 'external'} 'class' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | FUNC | VAR | FUNCDEF} '}')) +asCScriptNode *asCParser::ParseClass() +{ + asCScriptNode *node = CreateNode(snClass); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + + // Allow the keywords 'shared', 'abstract', 'final', and 'external' before 'class' + while( IdentifierIs(t, SHARED_TOKEN) || + IdentifierIs(t, ABSTRACT_TOKEN) || + IdentifierIs(t, FINAL_TOKEN) || + IdentifierIs(t, EXTERNAL_TOKEN) ) + { + RewindTo(&t); + node->AddChildLast(ParseIdentifier()); + GetToken(&t); + } + + if( t.type != ttClass ) + { + Error(ExpectedToken("class"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->SetToken(&t); + + if( engine->ep.allowImplicitHandleTypes ) + { + // Parse 'implicit handle class' construct + GetToken(&t); + + if ( t.type == ttHandle ) + node->SetToken(&t); + else + RewindTo(&t); + } + + node->AddChildLast(ParseIdentifier()); + + // External shared declarations are ended with ';' + GetToken(&t); + if (t.type == ttEndStatement) + { + RewindTo(&t); + node->AddChildLast(ParseToken(ttEndStatement)); + return node; + } + + // Optional list of interfaces that are being implemented and classes that are being inherited + if( t.type == ttColon ) + { + asCScriptNode *inherit = CreateNode(snIdentifier); + node->AddChildLast(inherit); + + ParseOptionalScope(inherit); + inherit->AddChildLast(ParseIdentifier()); + GetToken(&t); + while( t.type == ttListSeparator ) + { + inherit = CreateNode(snIdentifier); + node->AddChildLast(inherit); + + ParseOptionalScope(inherit); + inherit->AddChildLast(ParseIdentifier()); + GetToken(&t); + } + } + + if( t.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t); + Error(InsteadFound(t), &t); + return node; + } + + // Parse properties + GetToken(&t); + RewindTo(&t); + while( t.type != ttEndStatementBlock && t.type != ttEnd ) + { + // Is it a property or a method? + if (t.type == ttFuncDef) + node->AddChildLast(ParseFuncDef()); + else if( IsFuncDecl(true) ) + node->AddChildLast(ParseFunction(true)); + else if( IsVirtualPropertyDecl() ) + node->AddChildLast(ParseVirtualPropertyDecl(true, false)); + else if( IsVarDecl() ) + node->AddChildLast(ParseDeclaration(true)); + else if( t.type == ttEndStatement ) + // Skip empty declarations + GetToken(&t); + else + { + Error(TXT_EXPECTED_METHOD_OR_PROPERTY, &t); + Error(InsteadFound(t), &t); + return node; + } + + if( isSyntaxError ) + return node; + + GetToken(&t); + RewindTo(&t); + } + + GetToken(&t); + if( t.type != ttEndStatementBlock ) + { + Error(ExpectedToken("}"), &t); + Error(InsteadFound(t), &t); + return node; + } + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +int asCParser::ParseVarInit(asCScriptCode *in_script, asCScriptNode *in_init) +{ + Reset(); + + // Tell the parser to validate the identifiers as valid types + checkValidTypes = true; + + this->script = in_script; + sourcePos = in_init->tokenPos; + + // If next token is assignment, parse expression + sToken t; + GetToken(&t); + if( t.type == ttAssignment ) + { + GetToken(&t); + RewindTo(&t); + if( t.type == ttStartStatementBlock ) + scriptNode = ParseInitList(); + else + scriptNode = ParseAssignment(); + } + else if( t.type == ttOpenParanthesis ) + { + RewindTo(&t); + scriptNode = ParseArgList(); + } + else + { + int tokens[] = {ttAssignment, ttOpenParanthesis}; + Error(ExpectedOneOf(tokens, 2), &t); + Error(InsteadFound(t), &t); + } + + // Don't allow any more tokens after the expression + GetToken(&t); + if( t.type != ttEnd && t.type != ttEndStatement && t.type != ttListSeparator && t.type != ttEndStatementBlock ) + { + asCString msg; + msg.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(t.type)); + Error(msg, &t); + } + + if( isSyntaxError || errorWhileParsing ) + return -1; + + return 0; +} + +asCScriptNode *asCParser::SuperficiallyParseVarInit() +{ + asCScriptNode *node = CreateNode(snAssignment); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + node->UpdateSourcePos(t.pos, t.length); + + if( t.type == ttAssignment ) + { + GetToken(&t); + sToken start = t; + + // Find the end of the expression + int indentParan = 0; + int indentBrace = 0; + while( indentParan || indentBrace || (t.type != ttListSeparator && t.type != ttEndStatement && t.type != ttEndStatementBlock) ) + { + if( t.type == ttOpenParanthesis ) + indentParan++; + else if( t.type == ttCloseParanthesis ) + indentParan--; + else if( t.type == ttStartStatementBlock ) + indentBrace++; + else if( t.type == ttEndStatementBlock ) + indentBrace--; + else if( t.type == ttNonTerminatedStringConstant ) + { + Error(TXT_NONTERMINATED_STRING, &t); + break; + } + else if( t.type == ttEnd ) + { + Error(TXT_UNEXPECTED_END_OF_FILE, &t); + Info(TXT_WHILE_PARSING_EXPRESSION, &start); + break; + } + GetToken(&t); + } + + // Rewind so that the next token read is the list separator, end statement, or end statement block + RewindTo(&t); + } + else if( t.type == ttOpenParanthesis ) + { + sToken start = t; + + // Find the end of the argument list + int indent = 1; + while( indent ) + { + GetToken(&t); + if( t.type == ttOpenParanthesis ) + indent++; + else if( t.type == ttCloseParanthesis ) + indent--; + else if( t.type == ttNonTerminatedStringConstant ) + { + Error(TXT_NONTERMINATED_STRING, &t); + break; + } + else if( t.type == ttEnd ) + { + Error(TXT_UNEXPECTED_END_OF_FILE, &t); + Info(TXT_WHILE_PARSING_ARG_LIST, &start); + break; + } + } + } + else + { + int tokens[] = {ttAssignment, ttOpenParanthesis}; + Error(ExpectedOneOf(tokens, 2), &t); + Error(InsteadFound(t), &t); + } + + return node; +} + +asCScriptNode *asCParser::SuperficiallyParseStatementBlock() +{ + asCScriptNode *node = CreateNode(snStatementBlock); + if( node == 0 ) return 0; + + // This function will only superficially parse the statement block in order to find the end of it + sToken t1; + + GetToken(&t1); + if( t1.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + sToken start = t1; + + int level = 1; + while( level > 0 && !isSyntaxError ) + { + GetToken(&t1); + if( t1.type == ttEndStatementBlock ) + level--; + else if( t1.type == ttStartStatementBlock ) + level++; + else if( t1.type == ttNonTerminatedStringConstant ) + { + Error(TXT_NONTERMINATED_STRING, &t1); + break; + } + else if( t1.type == ttEnd ) + { + Error(TXT_UNEXPECTED_END_OF_FILE, &t1); + Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start); + break; + } + } + + node->UpdateSourcePos(t1.pos, t1.length); + + return node; +} + +// BNF:2: STATBLOCK ::= '{' {VAR | STATEMENT} '}' +asCScriptNode *asCParser::ParseStatementBlock() +{ + asCScriptNode *node = CreateNode(snStatementBlock); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( t1.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + sToken start = t1; + + node->UpdateSourcePos(t1.pos, t1.length); + + for(;;) + { + while( !isSyntaxError ) + { + GetToken(&t1); + if( t1.type == ttEndStatementBlock ) + { + node->UpdateSourcePos(t1.pos, t1.length); + + // Statement block is finished + return node; + } + else + { + RewindTo(&t1); + + if( IsVarDecl() ) + node->AddChildLast(ParseDeclaration()); + else + node->AddChildLast(ParseStatement()); + } + } + + if( isSyntaxError ) + { + // Search for either ';', '{', '}', or end + GetToken(&t1); + while( t1.type != ttEndStatement && t1.type != ttEnd && + t1.type != ttStartStatementBlock && t1.type != ttEndStatementBlock ) + { + GetToken(&t1); + } + + // Skip this statement block + if( t1.type == ttStartStatementBlock ) + { + // Find the end of the block and skip nested blocks + int level = 1; + while( level > 0 ) + { + GetToken(&t1); + if( t1.type == ttStartStatementBlock ) level++; + if( t1.type == ttEndStatementBlock ) level--; + if( t1.type == ttEnd ) break; + } + } + else if( t1.type == ttEndStatementBlock ) + { + RewindTo(&t1); + } + else if( t1.type == ttEnd ) + { + Error(TXT_UNEXPECTED_END_OF_FILE, &t1); + Info(TXT_WHILE_PARSING_STATEMENT_BLOCK, &start); + return node; + } + + isSyntaxError = false; + } + } + UNREACHABLE_RETURN; +} + +// BNF:4: INITLIST ::= '{' [ASSIGN | INITLIST] {',' [ASSIGN | INITLIST]} '}' +asCScriptNode *asCParser::ParseInitList() +{ + asCScriptNode *node = CreateNode(snInitList); + if( node == 0 ) return 0; + + sToken t1; + + GetToken(&t1); + if( t1.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + + node->UpdateSourcePos(t1.pos, t1.length); + + GetToken(&t1); + if( t1.type == ttEndStatementBlock ) + { + node->UpdateSourcePos(t1.pos, t1.length); + + // Statement block is finished + return node; + } + else + { + RewindTo(&t1); + for(;;) + { + GetToken(&t1); + if( t1.type == ttListSeparator ) + { + // No expression + node->AddChildLast(CreateNode(snUndefined)); + node->lastChild->UpdateSourcePos(t1.pos, 1); + + GetToken(&t1); + if( t1.type == ttEndStatementBlock ) + { + // No expression + node->AddChildLast(CreateNode(snUndefined)); + node->lastChild->UpdateSourcePos(t1.pos, 1); + node->UpdateSourcePos(t1.pos, t1.length); + return node; + } + RewindTo(&t1); + } + else if( t1.type == ttEndStatementBlock ) + { + // No expression + node->AddChildLast(CreateNode(snUndefined)); + node->lastChild->UpdateSourcePos(t1.pos, 1); + node->UpdateSourcePos(t1.pos, t1.length); + + // Statement block is finished + return node; + } + else if( t1.type == ttStartStatementBlock ) + { + RewindTo(&t1); + node->AddChildLast(ParseInitList()); + if( isSyntaxError ) return node; + + GetToken(&t1); + if( t1.type == ttListSeparator ) + continue; + else if( t1.type == ttEndStatementBlock ) + { + node->UpdateSourcePos(t1.pos, t1.length); + + // Statement block is finished + return node; + } + else + { + Error(ExpectedTokens("}", ","), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + } + else + { + RewindTo(&t1); + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + + GetToken(&t1); + if( t1.type == ttListSeparator ) + continue; + else if( t1.type == ttEndStatementBlock ) + { + node->UpdateSourcePos(t1.pos, t1.length); + + // Statement block is finished + return node; + } + else + { + Error(ExpectedTokens("}", ","), &t1); + Error(InsteadFound(t1), &t1); + return node; + } + } + } + } + UNREACHABLE_RETURN; +} + +// BNF:1: VAR ::= ['private'|'protected'] TYPE IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST] {',' IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST]} ';' +asCScriptNode *asCParser::ParseDeclaration(bool isClassProp, bool isGlobalVar) +{ + asCScriptNode *node = CreateNode(snDeclaration); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + RewindTo(&t); + + // A class property can be preceeded by private + if( t.type == ttPrivate && isClassProp ) + node->AddChildLast(ParseToken(ttPrivate)); + else if( t.type == ttProtected && isClassProp ) + node->AddChildLast(ParseToken(ttProtected)); + + // Parse data type + node->AddChildLast(ParseType(true, false, !isClassProp)); + if( isSyntaxError ) return node; + + for(;;) + { + // Parse identifier + node->AddChildLast(ParseIdentifier()); + if( isSyntaxError ) return node; + + if( isClassProp || isGlobalVar ) + { + // Only superficially parse the initialization info for the class property + GetToken(&t); + RewindTo(&t); + if( t.type == ttAssignment || t.type == ttOpenParanthesis ) + { + node->AddChildLast(SuperficiallyParseVarInit()); + if( isSyntaxError ) return node; + } + } + else + { + // If next token is assignment, parse expression + GetToken(&t); + if( t.type == ttOpenParanthesis ) + { + RewindTo(&t); + node->AddChildLast(ParseArgList()); + if( isSyntaxError ) return node; + } + else if( t.type == ttAssignment ) + { + GetToken(&t); + RewindTo(&t); + if( t.type == ttStartStatementBlock ) + { + node->AddChildLast(ParseInitList()); + if( isSyntaxError ) return node; + } + else + { + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + } + } + else + RewindTo(&t); + } + + // continue if list separator, else terminate with end statement + GetToken(&t); + if( t.type == ttListSeparator ) + continue; + else if( t.type == ttEndStatement ) + { + node->UpdateSourcePos(t.pos, t.length); + + return node; + } + else + { + Error(ExpectedTokens(",", ";"), &t); + Error(InsteadFound(t), &t); + return node; + } + } + UNREACHABLE_RETURN; +} + +// BNF:7: STATEMENT ::= (IF | FOR | WHILE | RETURN | STATBLOCK | BREAK | CONTINUE | DOWHILE | SWITCH | EXPRSTAT | TRY) +asCScriptNode *asCParser::ParseStatement() +{ + sToken t1; + + GetToken(&t1); + RewindTo(&t1); + + if (t1.type == ttIf) + return ParseIf(); + else if (t1.type == ttFor) + return ParseFor(); + else if (t1.type == ttWhile) + return ParseWhile(); + else if (t1.type == ttReturn) + return ParseReturn(); + else if (t1.type == ttStartStatementBlock) + return ParseStatementBlock(); + else if (t1.type == ttBreak) + return ParseBreak(); + else if (t1.type == ttContinue) + return ParseContinue(); + else if (t1.type == ttDo) + return ParseDoWhile(); + else if (t1.type == ttSwitch) + return ParseSwitch(); + else if (t1.type == ttTry) + return ParseTryCatch(); + else + { + if( IsVarDecl() ) + { + Error(TXT_UNEXPECTED_VAR_DECL, &t1); + return 0; + } + return ParseExpressionStatement(); + } +} + +// BNF:8: EXPRSTAT ::= [ASSIGN] ';' +asCScriptNode *asCParser::ParseExpressionStatement() +{ + asCScriptNode *node = CreateNode(snExpressionStatement); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type == ttEndStatement ) + { + node->UpdateSourcePos(t.pos, t.length); + + return node; + } + + RewindTo(&t); + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:8: SWITCH ::= 'switch' '(' ASSIGN ')' '{' {CASE} '}' +asCScriptNode *asCParser::ParseSwitch() +{ + asCScriptNode *node = CreateNode(snSwitch); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttSwitch ) + { + Error(ExpectedToken("switch"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t); + Error(InsteadFound(t), &t); + return node; + } + + GetToken(&t); + if( t.type != ttStartStatementBlock ) + { + Error(ExpectedToken("{"), &t); + Error(InsteadFound(t), &t); + return node; + } + + while( !isSyntaxError ) + { + GetToken(&t); + + if( t.type == ttEndStatementBlock ) + break; + + RewindTo(&t); + + if( t.type != ttCase && t.type != ttDefault ) + { + const char *tokens[] = {"case", "default"}; + Error(ExpectedOneOf(tokens, 2), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseCase()); + if( isSyntaxError ) return node; + } + + if( t.type != ttEndStatementBlock ) + { + Error(ExpectedToken("}"), &t); + Error(InsteadFound(t), &t); + return node; + } + + return node; +} + +// BNF:9: CASE ::= (('case' EXPR) | 'default') ':' {STATEMENT} +asCScriptNode *asCParser::ParseCase() +{ + asCScriptNode *node = CreateNode(snCase); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttCase && t.type != ttDefault ) + { + Error(ExpectedTokens("case", "default"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + if(t.type == ttCase) + { + node->AddChildLast(ParseExpression()); + } + + GetToken(&t); + if( t.type != ttColon ) + { + Error(ExpectedToken(":"), &t); + Error(InsteadFound(t), &t); + return node; + } + + // Parse statements until we find either of }, case, default, and break + GetToken(&t); + RewindTo(&t); + while( t.type != ttCase && + t.type != ttDefault && + t.type != ttEndStatementBlock && + t.type != ttBreak ) + { + if( IsVarDecl() ) + // Variable declarations are not allowed, but we parse it anyway to give a good error message + node->AddChildLast(ParseDeclaration()); + else + node->AddChildLast(ParseStatement()); + if( isSyntaxError ) return node; + + GetToken(&t); + RewindTo(&t); + } + + // If the case was ended with a break statement, add it to the node + if( t.type == ttBreak ) + node->AddChildLast(ParseBreak()); + + return node; +} + +// BNF:8: IF ::= 'if' '(' ASSIGN ')' STATEMENT ['else' STATEMENT] +asCScriptNode *asCParser::ParseIf() +{ + asCScriptNode *node = CreateNode(snIf); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttIf ) + { + Error(ExpectedToken("if"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseStatement()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttElse ) + { + // No else statement return already + RewindTo(&t); + return node; + } + + node->AddChildLast(ParseStatement()); + + return node; +} + +// BNF:8: TRY ::= 'try' STATBLOCK 'catch' STATBLOCK +asCScriptNode *asCParser::ParseTryCatch() +{ + asCScriptNode *node = CreateNode(snTryCatch); + if (node == 0) return 0; + + sToken t; + GetToken(&t); + if (t.type != ttTry) + { + Error(ExpectedToken("try"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + node->AddChildLast(ParseStatementBlock()); + if (isSyntaxError) return node; + + GetToken(&t); + if (t.type != ttCatch) + { + Error(ExpectedToken("catch"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseStatementBlock()); + if (isSyntaxError) return node; + + return node; +} + +// BNF:8: FOR ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN {',' ASSIGN}] ')' STATEMENT +asCScriptNode *asCParser::ParseFor() +{ + asCScriptNode *node = CreateNode(snFor); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttFor ) + { + Error(ExpectedToken("for"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t); + Error(InsteadFound(t), &t); + return node; + } + + if( IsVarDecl() ) + node->AddChildLast(ParseDeclaration()); + else + node->AddChildLast(ParseExpressionStatement()); + if( isSyntaxError ) return node; + + node->AddChildLast(ParseExpressionStatement()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttCloseParanthesis ) + { + RewindTo(&t); + + // Parse N increment statements separated by , + for(;;) + { + asCScriptNode *n = CreateNode(snExpressionStatement); + if( n == 0 ) return 0; + node->AddChildLast(n); + n->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type == ttListSeparator ) + continue; + else if( t.type == ttCloseParanthesis ) + break; + else + { + const char *tokens[] = {",", ")"}; + Error(ExpectedOneOf(tokens, 2), &t); + Error(InsteadFound(t), &t); + return node; + } + } + } + + node->AddChildLast(ParseStatement()); + + return node; +} + +// BNF:8: WHILE ::= 'while' '(' ASSIGN ')' STATEMENT +asCScriptNode *asCParser::ParseWhile() +{ + asCScriptNode *node = CreateNode(snWhile); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttWhile ) + { + Error(ExpectedToken("while"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseStatement()); + + return node; +} + +// BNF:8: DOWHILE ::= 'do' STATEMENT 'while' '(' ASSIGN ')' ';' +asCScriptNode *asCParser::ParseDoWhile() +{ + asCScriptNode *node = CreateNode(snDoWhile); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttDo ) + { + Error(ExpectedToken("do"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + node->AddChildLast(ParseStatement()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttWhile ) + { + Error(ExpectedToken("while"), &t); + Error(InsteadFound(t), &t); + return node; + } + + GetToken(&t); + if( t.type != ttOpenParanthesis ) + { + Error(ExpectedToken("("), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttCloseParanthesis ) + { + Error(ExpectedToken(")"), &t); + Error(InsteadFound(t), &t); + return node; + } + + GetToken(&t); + if( t.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t); + Error(InsteadFound(t), &t); + return node; + } + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:8: RETURN ::= 'return' [ASSIGN] ';' +asCScriptNode *asCParser::ParseReturn() +{ + asCScriptNode *node = CreateNode(snReturn); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttReturn ) + { + Error(ExpectedToken("return"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type == ttEndStatement ) + { + node->UpdateSourcePos(t.pos, t.length); + return node; + } + + RewindTo(&t); + + node->AddChildLast(ParseAssignment()); + if( isSyntaxError ) return node; + + GetToken(&t); + if( t.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:8: BREAK ::= 'break' ';' +asCScriptNode *asCParser::ParseBreak() +{ + asCScriptNode *node = CreateNode(snBreak); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttBreak ) + { + Error(ExpectedToken("break"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t); + Error(InsteadFound(t), &t); + } + + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// BNF:8: CONTINUE ::= 'continue' ';' +asCScriptNode *asCParser::ParseContinue() +{ + asCScriptNode *node = CreateNode(snContinue); + if( node == 0 ) return 0; + + sToken t; + GetToken(&t); + if( t.type != ttContinue ) + { + Error(ExpectedToken("continue"), &t); + Error(InsteadFound(t), &t); + return node; + } + + node->UpdateSourcePos(t.pos, t.length); + + GetToken(&t); + if( t.type != ttEndStatement ) + { + Error(ExpectedToken(";"), &t); + Error(InsteadFound(t), &t); + } + + node->UpdateSourcePos(t.pos, t.length); + + return node; +} + +// TODO: typedef: Typedefs should accept complex types as well +// BNF:1: TYPEDEF ::= 'typedef' PRIMTYPE IDENTIFIER ';' +asCScriptNode *asCParser::ParseTypedef() +{ + // Create the typedef node + asCScriptNode *node = CreateNode(snTypedef); + if( node == 0 ) return 0; + + sToken token; + + GetToken(&token); + if( token.type != ttTypedef) + { + Error(ExpectedToken(asCTokenizer::GetDefinition(ttTypedef)), &token); + Error(InsteadFound(token), &token); + return node; + } + + node->SetToken(&token); + node->UpdateSourcePos(token.pos, token.length); + + // Parse the base type + GetToken(&token); + RewindTo(&token); + + // Make sure it is a primitive type (except ttVoid) + if( !IsRealType(token.type) || token.type == ttVoid ) + { + asCString str; + str.Format(TXT_UNEXPECTED_TOKEN_s, asCTokenizer::GetDefinition(token.type)); + Error(str, &token); + return node; + } + + node->AddChildLast(ParseRealType()); + node->AddChildLast(ParseIdentifier()); + + // Check for the end of the typedef + GetToken(&token); + if( token.type != ttEndStatement ) + { + RewindTo(&token); + Error(ExpectedToken(asCTokenizer::GetDefinition(token.type)), &token); + Error(InsteadFound(token), &token); + } + + return node; +} + +#endif + +END_AS_NAMESPACE + + diff --git a/angelscript/source/as_parser.h b/angelscript/source/as_parser.h new file mode 100644 index 0000000..4aec264 --- /dev/null +++ b/angelscript/source/as_parser.h @@ -0,0 +1,197 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2018 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_parser.h +// +// This class parses the script code and builds a tree for compilation +// + + + +#ifndef AS_PARSER_H +#define AS_PARSER_H + +#include "as_scriptnode.h" +#include "as_scriptcode.h" +#include "as_builder.h" +#include "as_tokenizer.h" + +BEGIN_AS_NAMESPACE + +class asCParser +{ +public: + asCParser(asCBuilder *builder); + ~asCParser(); + + int ParseFunctionDefinition(asCScriptCode *script, bool expectListPattern); + int ParsePropertyDeclaration(asCScriptCode *script); + int ParseDataType(asCScriptCode *script, bool isReturnType); + int ParseTemplateDecl(asCScriptCode *script); + +#ifndef AS_NO_COMPILER + int ParseScript(asCScriptCode *script); + + // Called from compiler + int ParseStatementBlock(asCScriptCode *script, asCScriptNode *block); + int ParseVarInit(asCScriptCode *script, asCScriptNode *init); + int ParseExpression(asCScriptCode *script); +#endif + + asCScriptNode *GetScriptNode(); + +protected: + void Reset(); + + void GetToken(sToken *token); + void RewindTo(const sToken *token); + void SetPos(size_t pos); + void Error(const asCString &text, sToken *token); + void Warning(const asCString &text, sToken *token); + void Info(const asCString &text, sToken *token); + + asCScriptNode *CreateNode(eScriptNode type); + + asCScriptNode *ParseFunctionDefinition(); + asCScriptNode *ParseParameterList(); + asCScriptNode *SuperficiallyParseExpression(); + asCScriptNode *ParseType(bool allowConst, bool allowVariableType = false, bool allowAuto = false); + asCScriptNode *ParseTypeMod(bool isParam); + void ParseOptionalScope(asCScriptNode *node); + asCScriptNode *ParseRealType(); + asCScriptNode *ParseDataType(bool allowVariableType = false, bool allowAuto = false); + asCScriptNode *ParseIdentifier(); + bool ParseTemplTypeList(asCScriptNode *node, bool required = true); + void ParseMethodAttributes(asCScriptNode *funcNode); + + asCScriptNode *ParseListPattern(); + + bool IsRealType(int tokenType); + bool IsDataType(const sToken &token); + bool IdentifierIs(const sToken &t, const char *str); + +#ifndef AS_NO_COMPILER + // Statements + asCScriptNode *SuperficiallyParseStatementBlock(); + asCScriptNode *SuperficiallyParseVarInit(); + asCScriptNode *ParseStatementBlock(); + asCScriptNode *ParseStatement(); + asCScriptNode *ParseExpressionStatement(); + asCScriptNode *ParseSwitch(); + asCScriptNode *ParseCase(); + asCScriptNode *ParseIf(); + asCScriptNode *ParseFor(); + asCScriptNode *ParseWhile(); + asCScriptNode *ParseDoWhile(); + asCScriptNode *ParseReturn(); + asCScriptNode *ParseBreak(); + asCScriptNode *ParseContinue(); + asCScriptNode *ParseTryCatch(); + + // Declarations + asCScriptNode *ParseDeclaration(bool isClassProp = false, bool isGlobalVar = false); + asCScriptNode *ParseImport(); + asCScriptNode *ParseScript(bool inBlock); + asCScriptNode *ParseNamespace(); + asCScriptNode *ParseFunction(bool isMethod = false); + asCScriptNode *ParseFuncDef(); + asCScriptNode *ParseClass(); + asCScriptNode *ParseMixin(); + asCScriptNode *ParseInitList(); + asCScriptNode *ParseInterface(); + asCScriptNode *ParseInterfaceMethod(); + asCScriptNode *ParseVirtualPropertyDecl(bool isMethod, bool isInterface); + asCScriptNode *ParseEnumeration(); + asCScriptNode *ParseTypedef(); + bool IsVarDecl(); + bool IsVirtualPropertyDecl(); + bool IsFuncDecl(bool isMethod); + bool IsLambda(); + bool IsFunctionCall(); + + // Expressions + asCScriptNode *ParseAssignment(); + asCScriptNode *ParseAssignOperator(); + asCScriptNode *ParseCondition(); + asCScriptNode *ParseExpression(); + asCScriptNode *ParseExprTerm(); + asCScriptNode *ParseExprOperator(); + asCScriptNode *ParseExprPreOp(); + asCScriptNode *ParseExprPostOp(); + asCScriptNode *ParseExprValue(); + asCScriptNode *ParseArgList(bool withParenthesis = true); + asCScriptNode *ParseFunctionCall(); + asCScriptNode *ParseVariableAccess(); + asCScriptNode *ParseConstructCall(); + asCScriptNode *ParseCast(); + asCScriptNode *ParseConstant(); + asCScriptNode *ParseStringConstant(); + asCScriptNode *ParseLambda(); + + bool IsType(sToken &nextToken); + bool IsConstant(int tokenType); + bool IsOperator(int tokenType); + bool IsPreOperator(int tokenType); + bool IsPostOperator(int tokenType); + bool IsAssignOperator(int tokenType); + + bool CheckTemplateType(const sToken &t); +#endif + + asCScriptNode *ParseToken(int token); + asCScriptNode *ParseOneOf(int *tokens, int num); + + asCString ExpectedToken(const char *token); + asCString ExpectedTokens(const char *token1, const char *token2); + asCString ExpectedOneOf(int *tokens, int count); + asCString ExpectedOneOf(const char **tokens, int count); + asCString InsteadFound(sToken &t); + + bool errorWhileParsing; + bool isSyntaxError; + bool checkValidTypes; + bool isParsingAppInterface; + + asCScriptEngine *engine; + asCBuilder *builder; + asCScriptCode *script; + asCScriptNode *scriptNode; + + asCString tempString; // Used for reduzing amount of dynamic allocations + + sToken lastToken; + size_t sourcePos; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_property.h b/angelscript/source/as_property.h new file mode 100644 index 0000000..c318ec4 --- /dev/null +++ b/angelscript/source/as_property.h @@ -0,0 +1,129 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_property.h +// +// A class for storing object property information +// + + + +#ifndef AS_PROPERTY_H +#define AS_PROPERTY_H + +#include "as_string.h" +#include "as_datatype.h" +#include "as_atomic.h" +#include "as_scriptfunction.h" +#include "as_symboltable.h" + +BEGIN_AS_NAMESPACE + +struct asSNameSpace; + +class asCObjectProperty +{ +public: + asCObjectProperty() : byteOffset(0), accessMask(0xFFFFFFFF), compositeOffset(0), isCompositeIndirect(false), isPrivate(false), isProtected(false), isInherited(false) {} + asCObjectProperty(const asCObjectProperty &o) : name(o.name), type(o.type), byteOffset(o.byteOffset), accessMask(o.accessMask), compositeOffset(o.compositeOffset), isCompositeIndirect(o.isCompositeIndirect), isPrivate(o.isPrivate), isProtected(o.isProtected), isInherited(o.isInherited) {} + asCString name; + asCDataType type; + int byteOffset; + asDWORD accessMask; + int compositeOffset; + bool isCompositeIndirect; + bool isPrivate; + bool isProtected; + bool isInherited; +}; + +class asCGlobalProperty +{ +public: + asCGlobalProperty(); + ~asCGlobalProperty(); + + void AddRef(); + void Release(); + void DestroyInternal(); + + void *GetAddressOfValue(); + void AllocateMemory(); + void SetRegisteredAddress(void *p); + void *GetRegisteredAddress() const; + + asCString name; + asCDataType type; + asUINT id; + asSNameSpace *nameSpace; + + void SetInitFunc(asCScriptFunction *initFunc); + asCScriptFunction *GetInitFunc(); + +//protected: + // This is only stored for registered properties, and keeps the pointer given by the application + void *realAddress; + + bool memoryAllocated; + void *memory; + asQWORD storage; + + asCScriptFunction *initFunc; + + asDWORD accessMask; + + // The global property structure is reference counted, so that the + // engine can keep track of how many references to the property there are. + asCAtomic refCount; +}; + +class asCCompGlobPropType : public asIFilter +{ +public: + const asCDataType &m_type; + + asCCompGlobPropType(const asCDataType &type) : m_type(type) {} + + bool operator()(const void *p) const + { + const asCGlobalProperty* prop = reinterpret_cast(p); + return prop->type == m_type; + } + +private: + // The assignment operator is required for MSVC9, otherwise it will complain that it is not possible to auto generate the operator + asCCompGlobPropType &operator=(const asCCompGlobPropType &) {return *this;} +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_restore.cpp b/angelscript/source/as_restore.cpp new file mode 100644 index 0000000..a6b9abc --- /dev/null +++ b/angelscript/source/as_restore.cpp @@ -0,0 +1,5827 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_restore.cpp +// +// Functions for saving and restoring module bytecode +// asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be + +#include "as_config.h" +#include "as_restore.h" +#include "as_bytecode.h" +#include "as_scriptobject.h" +#include "as_texts.h" +#include "as_debug.h" + +BEGIN_AS_NAMESPACE + +// Macros for doing endianess agnostic bitmask serialization +#define SAVE_TO_BIT(dst, val, bit) ((dst) |= ((val) << (bit))) +#define LOAD_FROM_BIT(dst, val, bit) ((dst) = ((val) >> (bit)) & 1) + +asCReader::asCReader(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine) + : module(_module), stream(_stream), engine(_engine) +{ + error = false; + bytesRead = 0; +} + +int asCReader::ReadData(void *data, asUINT size) +{ + asASSERT(size == 1 || size == 2 || size == 4 || size == 8); + int ret = 0; +#if defined(AS_BIG_ENDIAN) + for( asUINT n = 0; ret >= 0 && n < size; n++ ) + ret = stream->Read(((asBYTE*)data)+n, 1); +#else + for( int n = size-1; ret >= 0 && n >= 0; n-- ) + ret = stream->Read(((asBYTE*)data)+n, 1); +#endif + if (ret < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); + bytesRead += size; + return ret; +} + +int asCReader::Read(bool *wasDebugInfoStripped) +{ + TimeIt("asCReader::Read"); + + // Before starting the load, make sure that + // any existing resources have been freed + module->InternalReset(); + + // Call the inner method to do the actual loading + int r = ReadInner(); + if( r < 0 ) + { + // Something went wrong while loading the bytecode, so we need + // to clean-up whatever has been created during the process. + + // Make sure none of the loaded functions attempt to release + // references that have not yet been increased + asUINT i; + for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) + if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) ) + if( module->m_scriptFunctions[i]->scriptData ) + module->m_scriptFunctions[i]->scriptData->byteCode.SetLength(0); + + asCSymbolTable::iterator it = module->m_scriptGlobals.List(); + for( ; it; it++ ) + if( (*it)->GetInitFunc() ) + if( (*it)->GetInitFunc()->scriptData ) + (*it)->GetInitFunc()->scriptData->byteCode.SetLength(0); + + module->InternalReset(); + } + else + { + // Init system functions properly + engine->PrepareEngine(); + + // Initialize the global variables (unless requested not to) + if( engine->ep.initGlobalVarsAfterBuild ) + r = module->ResetGlobalVars(0); + + if( wasDebugInfoStripped ) + *wasDebugInfoStripped = noDebugInfo; + } + + // Clean up the loaded string constants + for (asUINT n = 0; n < usedStringConstants.GetLength(); n++) + engine->stringFactory->ReleaseStringConstant(usedStringConstants[n]); + usedStringConstants.SetLength(0); + + return r; +} + +int asCReader::Error(const char *msg) +{ + // Don't write if it has already been reported an error earlier + if( !error ) + { + asCString str; + str.Format(msg, bytesRead); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + error = true; + } + + return asERROR; +} + +int asCReader::ReadInner() +{ + TimeIt("asCReader::ReadInner"); + + // This function will load each entity one by one from the stream. + // If any error occurs, it will return to the caller who is + // responsible for cleaning up the partially loaded entities. + + engine->deferValidationOfTemplateTypes = true; + + unsigned long i, count; + asCScriptFunction* func; + + // Read the flag as 1 byte even on platforms with 4byte booleans + noDebugInfo = ReadEncodedUInt() ? VALUE_OF_BOOLEAN_TRUE : 0; + + // Read enums + count = ReadEncodedUInt(); + module->m_enumTypes.Allocate(count, false); + for( i = 0; i < count && !error; i++ ) + { + asCEnumType *et = asNEW(asCEnumType)(engine); + if( et == 0 ) + { + error = true; + return asOUT_OF_MEMORY; + } + + bool isExternal = false; + ReadTypeDeclaration(et, 1, &isExternal); + + // If the type is shared then we should use the original if it exists + bool sharedExists = false; + if( et->IsShared() ) + { + for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) + { + asCTypeInfo *t = engine->sharedScriptTypes[n]; + if( t && + t->IsShared() && + t->name == et->name && + t->nameSpace == et->nameSpace && + (t->flags & asOBJ_ENUM) ) + { + asDELETE(et, asCEnumType); + et = CastToEnumType(t); + sharedExists = true; + break; + } + } + } + + if (isExternal && !sharedExists) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, et->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + asDELETE(et, asCEnumType); + error = true; + return asERROR; + } + + if( sharedExists ) + { + existingShared.Insert(et, true); + et->AddRefInternal(); + } + else + { + if( et->IsShared() ) + { + engine->sharedScriptTypes.PushLast(et); + et->AddRefInternal(); + } + + // Set this module as the owner + et->module = module; + } + module->AddEnumType(et); + + if (isExternal) + module->m_externalTypes.PushLast(et); + + ReadTypeDeclaration(et, 2); + } + + if( error ) return asERROR; + + // classTypes[] + // First restore the structure names, then the properties + count = ReadEncodedUInt(); + module->m_classTypes.Allocate(count, false); + for( i = 0; i < count && !error; ++i ) + { + asCObjectType *ot = asNEW(asCObjectType)(engine); + if( ot == 0 ) + { + error = true; + return asOUT_OF_MEMORY; + } + + bool isExternal = false; + ReadTypeDeclaration(ot, 1, &isExternal); + + // If the type is shared, then we should use the original if it exists + bool sharedExists = false; + if( ot->IsShared() ) + { + for( asUINT n = 0; n < engine->sharedScriptTypes.GetLength(); n++ ) + { + asCTypeInfo *ti = engine->sharedScriptTypes[n]; + asCObjectType *t = CastToObjectType(ti); + if( t && + t->IsShared() && + t->name == ot->name && + t->nameSpace == ot->nameSpace && + t->IsInterface() == ot->IsInterface() ) + { + asDELETE(ot, asCObjectType); + ot = CastToObjectType(t); + sharedExists = true; + break; + } + } + } + + if (isExternal && !sharedExists) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, ot->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + asDELETE(ot, asCObjectType); + error = true; + return asERROR; + } + + if( sharedExists ) + { + existingShared.Insert(ot, true); + ot->AddRefInternal(); + } + else + { + if( ot->IsShared() ) + { + engine->sharedScriptTypes.PushLast(ot); + ot->AddRefInternal(); + } + + // Set this module as the owner + ot->module = module; + } + module->AddClassType(ot); + + if (isExternal) + module->m_externalTypes.PushLast(ot); + } + + if( error ) return asERROR; + + // Read func defs + count = ReadEncodedUInt(); + module->m_funcDefs.Allocate(count, false); + for( i = 0; i < count && !error; i++ ) + { + bool isNew, isExternal; + asCScriptFunction *funcDef = ReadFunction(isNew, false, true, true, &isExternal); + if(funcDef) + { + funcDef->module = module; + + asCFuncdefType *fdt = funcDef->funcdefType; + fdt->module = module; + + module->AddFuncDef(fdt); + engine->funcDefs.PushLast(fdt); + + // TODO: clean up: This is also done by the builder. It should probably be moved to a method in the module + // Check if there is another identical funcdef from another module and if so reuse that instead + if(funcDef->IsShared()) + { + for( asUINT n = 0; n < engine->funcDefs.GetLength(); n++ ) + { + asCFuncdefType *f2 = engine->funcDefs[n]; + if( f2 == 0 || fdt == f2 ) + continue; + + if( !f2->funcdef->IsShared() ) + continue; + + if( f2->name == fdt->name && + f2->nameSpace == fdt->nameSpace && + f2->parentClass == fdt->parentClass && + f2->funcdef->IsSignatureExceptNameEqual(funcDef) ) + { + // Replace our funcdef for the existing one + module->ReplaceFuncDef(fdt, f2); + f2->AddRefInternal(); + + if (isExternal) + module->m_externalTypes.PushLast(f2); + + engine->funcDefs.RemoveValue(fdt); + + savedFunctions[savedFunctions.IndexOf(funcDef)] = f2->funcdef; + + if (fdt->parentClass) + { + // The real funcdef should already be in the object + asASSERT(fdt->parentClass->childFuncDefs.IndexOf(f2) >= 0); + + fdt->parentClass = 0; + } + + fdt->ReleaseInternal(); + funcDef = 0; + break; + } + } + } + + // Add the funcdef to the parentClass if this is a child funcdef + if (funcDef && fdt->parentClass) + fdt->parentClass->childFuncDefs.PushLast(fdt); + + // Check if an external shared funcdef was really found + if (isExternal && funcDef) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, funcDef->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + error = true; + return asERROR; + } + } + else + Error(TXT_INVALID_BYTECODE_d); + } + + // Read interface methods + for( i = 0; i < module->m_classTypes.GetLength() && !error; i++ ) + { + if( module->m_classTypes[i]->IsInterface() ) + ReadTypeDeclaration(module->m_classTypes[i], 2); + } + + // Read class methods and behaviours + for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + ReadTypeDeclaration(module->m_classTypes[i], 2); + } + + // Read class properties + for( i = 0; i < module->m_classTypes.GetLength() && !error; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + ReadTypeDeclaration(module->m_classTypes[i], 3); + } + + if( error ) return asERROR; + + // Read typedefs + count = ReadEncodedUInt(); + module->m_typeDefs.Allocate(count, false); + for( i = 0; i < count && !error; i++ ) + { + asCTypedefType *td = asNEW(asCTypedefType)(engine); + if( td == 0 ) + { + error = true; + return asOUT_OF_MEMORY; + } + + bool isExternal = false; + ReadTypeDeclaration(td, 1, &isExternal); + td->module = module; + module->AddTypeDef(td); + ReadTypeDeclaration(td, 2); + } + + if( error ) return asERROR; + + // scriptGlobals[] + count = ReadEncodedUInt(); + if( count && engine->ep.disallowGlobalVars ) + { + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_GLOBAL_VARS_NOT_ALLOWED); + Error(TXT_INVALID_BYTECODE_d); + } + module->m_scriptGlobals.Allocate(count, false); + for( i = 0; i < count && !error; ++i ) + { + ReadGlobalProperty(); + } + + // scriptFunctions[] + count = ReadEncodedUInt(); + for( i = 0; i < count && !error; ++i ) + { + size_t len = module->m_scriptFunctions.GetLength(); + bool isNew, isExternal; + func = ReadFunction(isNew, true, true, true, &isExternal); + if( func == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + break; + } + + // Is the function shared and was it created now? + if( func->IsShared() && len != module->m_scriptFunctions.GetLength() ) + { + // If the function already existed in another module, then + // we need to replace it with previously existing one + for( asUINT n = 0; n < engine->scriptFunctions.GetLength() && !error; n++ ) + { + asCScriptFunction *realFunc = engine->scriptFunctions[n]; + if( realFunc && + realFunc != func && + realFunc->IsShared() && + realFunc->nameSpace == func->nameSpace && + realFunc->IsSignatureEqual(func) ) + { + // Replace the recently created function with the pre-existing function + module->m_scriptFunctions[module->m_scriptFunctions.GetLength()-1] = realFunc; + realFunc->AddRefInternal(); + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + engine->RemoveScriptFunction(func); + + // Insert the function in the dontTranslate array + dontTranslate.Insert(realFunc, true); + + if (isExternal) + module->m_externalFunctions.PushLast(realFunc); + + // Release the function, but make sure nothing else is released + func->id = 0; + if( func->scriptData ) + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + func = 0; + break; + } + } + } + + // Check if an external shared func was really found + if (isExternal && func) + { + asCString msg; + msg.Format(TXT_EXTERNAL_SHARED_s_NOT_FOUND, func->name.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + error = true; + return asERROR; + } + } + + // globalFunctions[] + count = ReadEncodedUInt(); + for( i = 0; i < count && !error; ++i ) + { + bool isNew; + func = ReadFunction(isNew, false, false); + if( func ) + { + // All the global functions were already loaded while loading the scriptFunctions, here + // we're just re-reading the references to know which goes into the globalFunctions array + asASSERT( !isNew ); + + module->m_globalFunctions.Put(func); + } + else + Error(TXT_INVALID_BYTECODE_d); + } + + if( error ) return asERROR; + + // bindInformations[] + count = ReadEncodedUInt(); + module->m_bindInformations.Allocate(count, false); + for( i = 0; i < count && !error; ++i ) + { + sBindInfo *info = asNEW(sBindInfo); + if( info == 0 ) + { + error = true; + return asOUT_OF_MEMORY; + } + + bool isNew; + info->importedFunctionSignature = ReadFunction(isNew, false, false); + if( info->importedFunctionSignature == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + break; + } + + if( engine->freeImportedFunctionIdxs.GetLength() ) + { + int id = engine->freeImportedFunctionIdxs.PopLast(); + info->importedFunctionSignature->id = int(FUNC_IMPORTED + id); + engine->importedFunctions[id] = info; + } + else + { + info->importedFunctionSignature->id = int(FUNC_IMPORTED + engine->importedFunctions.GetLength()); + engine->importedFunctions.PushLast(info); + } + ReadString(&info->importFromModule); + info->boundFunctionId = -1; + module->m_bindInformations.PushLast(info); + } + + if( error ) return asERROR; + + // usedTypes[] + count = ReadEncodedUInt(); + usedTypes.Allocate(count, false); + for( i = 0; i < count && !error; ++i ) + { + asCTypeInfo *ti = ReadTypeInfo(); + usedTypes.PushLast(ti); + } + + // usedTypeIds[] + if( !error ) + ReadUsedTypeIds(); + + // usedFunctions[] + if( !error ) + ReadUsedFunctions(); + + // usedGlobalProperties[] + if( !error ) + ReadUsedGlobalProps(); + + // usedStringConstants[] + if( !error ) + ReadUsedStringConstants(); + + // usedObjectProperties + if( !error ) + ReadUsedObjectProps(); + + // Validate the template types + if( !error ) + { + for( i = 0; i < usedTypes.GetLength() && !error; i++ ) + { + asCObjectType *ot = CastToObjectType(usedTypes[i]); + if( !ot || + !(ot->flags & asOBJ_TEMPLATE) || + !ot->beh.templateCallback ) + continue; + + bool dontGarbageCollect = false; + asCScriptFunction *callback = engine->scriptFunctions[ot->beh.templateCallback]; + if( !engine->CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) ) + { + asCString sub = ot->templateSubTypes[0].Format(ot->nameSpace); + for( asUINT n = 1; n < ot->templateSubTypes.GetLength(); n++ ) + { + sub += ","; + sub += ot->templateSubTypes[n].Format(ot->nameSpace); + } + asCString str; + str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, ot->name.AddressOf(), sub.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + else + { + // If the callback said this template instance won't be garbage collected then remove the flag + if( dontGarbageCollect ) + ot->flags &= ~asOBJ_GC; + } + } + } + engine->deferValidationOfTemplateTypes = false; + + if( error ) return asERROR; + + // Update the loaded bytecode to point to the correct types, property offsets, + // function ids, etc. This is basically a linking stage. + for( i = 0; i < module->m_scriptFunctions.GetLength() && !error; i++ ) + if( module->m_scriptFunctions[i]->funcType == asFUNC_SCRIPT ) + TranslateFunction(module->m_scriptFunctions[i]); + + asCSymbolTable::iterator globIt = module->m_scriptGlobals.List(); + while( globIt && !error ) + { + asCScriptFunction *initFunc = (*globIt)->GetInitFunc(); + if( initFunc ) + TranslateFunction(initFunc); + globIt++; + } + + if( error ) return asERROR; + + // Add references for all functions (except for the pre-existing shared code) + for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) + if( !dontTranslate.MoveTo(0, module->m_scriptFunctions[i]) ) + module->m_scriptFunctions[i]->AddReferences(); + + globIt = module->m_scriptGlobals.List(); + while( globIt ) + { + asCScriptFunction *initFunc = (*globIt)->GetInitFunc(); + if( initFunc ) + initFunc->AddReferences(); + globIt++; + } + return error ? asERROR : asSUCCESS; +} + +void asCReader::ReadUsedStringConstants() +{ + TimeIt("asCReader::ReadUsedStringConstants"); + + asCString str; + + asUINT count; + count = ReadEncodedUInt(); + + if (count > 0 && engine->stringFactory == 0) + { + Error(TXT_STRINGS_NOT_RECOGNIZED); + return; + } + + usedStringConstants.Allocate(count, false); + for( asUINT i = 0; i < count; ++i ) + { + ReadString(&str); + usedStringConstants.PushLast(const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), (asUINT)str.GetLength()))); + } +} + +void asCReader::ReadUsedFunctions() +{ + TimeIt("asCReader::ReadUsedFunctions"); + + asUINT count; + count = ReadEncodedUInt(); + usedFunctions.SetLength(count); + if( usedFunctions.GetLength() != count ) + { + // Out of memory + error = true; + return; + } + memset(usedFunctions.AddressOf(), 0, sizeof(asCScriptFunction *)*count); + + for( asUINT n = 0; n < usedFunctions.GetLength(); n++ ) + { + char c; + + // Read the data to be able to uniquely identify the function + + // Is the function from the module or the application? + ReadData(&c, 1); + + if( c == 'n' ) + { + // Null function pointer + usedFunctions[n] = 0; + } + else + { + asCScriptFunction func(engine, c == 'm' ? module : 0, asFUNC_DUMMY); + asCObjectType *parentClass = 0; + ReadFunctionSignature(&func, &parentClass); + if( error ) + { + func.funcType = asFUNC_DUMMY; + return; + } + + // Find the correct function + if( c == 'm' ) + { + if( func.funcType == asFUNC_IMPORTED ) + { + for( asUINT i = 0; i < module->m_bindInformations.GetLength(); i++ ) + { + asCScriptFunction *f = module->m_bindInformations[i]->importedFunctionSignature; + if( func.objectType != f->objectType || + func.funcType != f->funcType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + else if( func.funcType == asFUNC_FUNCDEF ) + { + const asCArray &funcs = module->m_funcDefs; + for( asUINT i = 0; i < funcs.GetLength(); i++ ) + { + asCScriptFunction *f = funcs[i]->funcdef; + if( f == 0 || + func.name != f->name || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) || + funcs[i]->parentClass != parentClass ) + continue; + + asASSERT( f->objectType == 0 ); + + usedFunctions[n] = f; + break; + } + } + else + { + // TODO: optimize: Global functions should be searched for in module->globalFunctions + // TODO: optimize: funcdefs should be searched for in module->funcDefs + // TODO: optimize: object methods should be searched for directly in the object type + for( asUINT i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) + { + asCScriptFunction *f = module->m_scriptFunctions[i]; + if( func.objectType != f->objectType || + func.funcType != f->funcType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else if (c == 's') + { + // Look for shared entities in the engine, as they may not necessarily be part + // of the scope of the module if they have been inhereted from other modules. + if (func.funcType == asFUNC_FUNCDEF) + { + const asCArray &funcs = engine->funcDefs; + for (asUINT i = 0; i < funcs.GetLength(); i++) + { + asCScriptFunction *f = funcs[i]->funcdef; + if (f == 0 || + func.name != f->name || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) || + funcs[i]->parentClass != parentClass) + continue; + + asASSERT(f->objectType == 0); + + usedFunctions[n] = f; + break; + } + } + else + { + for (asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++) + { + asCScriptFunction *f = engine->scriptFunctions[i]; + if (f == 0 || !f->IsShared() || + func.objectType != f->objectType || + func.funcType != f->funcType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f)) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else + { + asASSERT(c == 'a'); + + if( func.funcType == asFUNC_FUNCDEF ) + { + // This is a funcdef (registered or shared) + const asCArray &funcs = engine->funcDefs; + for( asUINT i = 0; i < funcs.GetLength(); i++ ) + { + asCScriptFunction *f = funcs[i]->funcdef; + if( f == 0 || func.name != f->name || !func.IsSignatureExceptNameAndObjectTypeEqual(f) || funcs[i]->parentClass != parentClass ) + continue; + + asASSERT( f->objectType == 0 ); + + usedFunctions[n] = f; + break; + } + } + else if( func.name[0] == '$' ) + { + // This is a special function + + if( func.name == "$beh0" && func.objectType ) + { + if (func.objectType->flags & asOBJ_TEMPLATE) + { + // Look for the matching constructor inside the factory stubs generated for the template instance + // See asCCompiler::PerformFunctionCall + for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++) + { + asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]]; + + // Find the id of the real constructor and not the generated stub + asUINT id = 0; + asDWORD *bc = f->scriptData->byteCode.AddressOf(); + while (bc) + { + if ((*(asBYTE*)bc) == asBC_CALLSYS) + { + id = asBC_INTARG(bc); + break; + } + bc += asBCTypeSize[asBCInfo[*(asBYTE*)bc].type]; + } + + f = engine->scriptFunctions[id]; + if (f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f)) + continue; + + usedFunctions[n] = f; + break; + } + } + + if( usedFunctions[n] == 0 ) + { + // This is a class constructor, so we can search directly in the object type's constructors + for (asUINT i = 0; i < func.objectType->beh.constructors.GetLength(); i++) + { + asCScriptFunction *f = engine->scriptFunctions[func.objectType->beh.constructors[i]]; + if (f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f)) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else if( func.name == "$fact" || func.name == "$beh3" ) + { + // This is a factory (or stub), so look for the function in the return type's factories + asCObjectType *objType = CastToObjectType(func.returnType.GetTypeInfo()); + if( objType ) + { + for( asUINT i = 0; i < objType->beh.factories.GetLength(); i++ ) + { + asCScriptFunction *f = engine->scriptFunctions[objType->beh.factories[i]]; + if( f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + } + else if( func.name == "$list" ) + { + // listFactory is used for both factory is global and returns a handle and constructor that is a method + asCObjectType *objType = func.objectType ? func.objectType : CastToObjectType(func.returnType.GetTypeInfo()); + if( objType ) + { + asCScriptFunction *f = engine->scriptFunctions[objType->beh.listFactory]; + if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + usedFunctions[n] = f; + } + } + else if( func.name == "$beh2" ) + { + // This is a destructor, so check the object type's destructor + asCObjectType *objType = func.objectType; + if( objType ) + { + asCScriptFunction *f = engine->scriptFunctions[objType->beh.destruct]; + if( f && func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + usedFunctions[n] = f; + } + } + else if( func.name == "$dlgte" ) + { + // This is the delegate factory + asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY); + asASSERT( f && func.IsSignatureEqual(f) ); + usedFunctions[n] = f; + } + else + { + // Must match one of the above cases + asASSERT(false); + } + } + else if( func.objectType == 0 ) + { + // This is a global function + const asCArray &funcs = engine->registeredGlobalFuncs.GetIndexes(func.nameSpace, func.name); + for( asUINT i = 0; i < funcs.GetLength(); i++ ) + { + asCScriptFunction *f = engine->registeredGlobalFuncs.Get(funcs[i]); + if( f == 0 || + !func.IsSignatureExceptNameAndObjectTypeEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + else if( func.objectType ) + { + // It is a class member, so we can search directly in the object type's members + // TODO: virtual function is different that implemented method + for( asUINT i = 0; i < func.objectType->methods.GetLength(); i++ ) + { + asCScriptFunction *f = engine->scriptFunctions[func.objectType->methods[i]]; + if( f == 0 || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + } + + if( usedFunctions[n] == 0 ) + { + // TODO: clean up: This part of the code should never happen. All functions should + // be found in the above logic. The only valid reason to come here + // is if the bytecode is wrong and the function doesn't exist anyway. + // This loop is kept temporarily until we can be certain all scenarios + // are covered. + for( asUINT i = 0; i < engine->scriptFunctions.GetLength(); i++ ) + { + asCScriptFunction *f = engine->scriptFunctions[i]; + if( f == 0 || + func.objectType != f->objectType || + func.nameSpace != f->nameSpace || + !func.IsSignatureEqual(f) ) + continue; + + usedFunctions[n] = f; + break; + } + + // No function is expected to be found + asASSERT(usedFunctions[n] == 0); + } + } + + // Set the type to dummy so it won't try to release the id + func.funcType = asFUNC_DUMMY; + + if( usedFunctions[n] == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + } +} + +void asCReader::ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass) +{ + asUINT i, count; + asCDataType dt; + int num; + + ReadString(&func->name); + if( func->name == DELEGATE_FACTORY ) + { + // It's not necessary to read anymore, everything is known + asCScriptFunction *f = engine->registeredGlobalFuncs.GetFirst(engine->nameSpaces[0], DELEGATE_FACTORY); + asASSERT( f ); + func->returnType = f->returnType; + func->parameterTypes = f->parameterTypes; + func->inOutFlags = f->inOutFlags; + func->funcType = f->funcType; + func->defaultArgs = f->defaultArgs; + func->nameSpace = f->nameSpace; + return; + } + + ReadDataType(&func->returnType); + + count = ReadEncodedUInt(); + if( count > 256 ) + { + // Too many arguments, must be something wrong in the file + Error(TXT_INVALID_BYTECODE_d); + return; + } + func->parameterTypes.Allocate(count, false); + for( i = 0; i < count; ++i ) + { + ReadDataType(&dt); + func->parameterTypes.PushLast(dt); + } + + func->inOutFlags.SetLength(func->parameterTypes.GetLength()); + if( func->inOutFlags.GetLength() != func->parameterTypes.GetLength() ) + { + // Out of memory + error = true; + return; + } + memset(func->inOutFlags.AddressOf(), 0, sizeof(asETypeModifiers)*func->inOutFlags.GetLength()); + if (func->parameterTypes.GetLength() > 0) + { + count = ReadEncodedUInt(); + if (count > func->parameterTypes.GetLength()) + { + // Cannot be more than the number of arguments + Error(TXT_INVALID_BYTECODE_d); + return; + } + for (i = 0; i < count; ++i) + { + num = ReadEncodedUInt(); + func->inOutFlags[i] = static_cast(num); + } + } + + func->funcType = (asEFuncType)ReadEncodedUInt(); + + // Read the default args, from last to first + if (func->parameterTypes.GetLength() > 0) + { + count = ReadEncodedUInt(); + if (count > func->parameterTypes.GetLength()) + { + // Cannot be more than the number of arguments + Error(TXT_INVALID_BYTECODE_d); + return; + } + if (count) + { + func->defaultArgs.SetLength(func->parameterTypes.GetLength()); + if (func->defaultArgs.GetLength() != func->parameterTypes.GetLength()) + { + // Out of memory + error = true; + return; + } + memset(func->defaultArgs.AddressOf(), 0, sizeof(asCString*)*func->defaultArgs.GetLength()); + for (i = 0; i < count; i++) + { + asCString *str = asNEW(asCString); + if (str == 0) + { + // Out of memory + error = true; + return; + } + func->defaultArgs[func->defaultArgs.GetLength() - 1 - i] = str; + ReadString(str); + } + } + } + + func->objectType = CastToObjectType(ReadTypeInfo()); + if( func->objectType ) + { + func->objectType->AddRefInternal(); + + asBYTE b; + ReadData(&b, 1); + func->SetReadOnly((b & 1) ? true : false); + func->SetPrivate((b & 2) ? true : false); + func->SetProtected((b & 4) ? true : false); + func->nameSpace = func->objectType->nameSpace; + } + else + { + if (func->funcType == asFUNC_FUNCDEF) + { + asBYTE b; + ReadData(&b, 1); + if (b == 'n') + { + asCString ns; + ReadString(&ns); + func->nameSpace = engine->AddNameSpace(ns.AddressOf()); + } + else if (b == 'o') + { + func->nameSpace = 0; + if (parentClass) + *parentClass = CastToObjectType(ReadTypeInfo()); + else + error = true; + } + else + error = true; + } + else + { + asCString ns; + ReadString(&ns); + func->nameSpace = engine->AddNameSpace(ns.AddressOf()); + } + } +} + +asCScriptFunction *asCReader::ReadFunction(bool &isNew, bool addToModule, bool addToEngine, bool addToGC, bool *isExternal) +{ + isNew = false; + if (isExternal) *isExternal = false; + if( error ) return 0; + + char c; + ReadData(&c, 1); + + if( c == '\0' ) + { + // There is no function, so return a null pointer + return 0; + } + + if( c == 'r' ) + { + // This is a reference to a previously saved function + asUINT index = ReadEncodedUInt(); + if( index < savedFunctions.GetLength() ) + return savedFunctions[index]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + } + + // Load the new function + isNew = true; + asCScriptFunction *func = asNEW(asCScriptFunction)(engine,0,asFUNC_DUMMY); + if( func == 0 ) + { + // Out of memory + error = true; + return 0; + } + savedFunctions.PushLast(func); + + int i, count; + asCDataType dt; + int num; + + asCObjectType *parentClass = 0; + ReadFunctionSignature(func, &parentClass); + if( error ) + { + func->DestroyHalfCreated(); + return 0; + } + + if( func->funcType == asFUNC_SCRIPT ) + { + // Skip this for external shared entities + if (module->m_externalTypes.IndexOf(func->objectType) >= 0) + { + // Replace with the real function from the existing entity + isNew = false; + + asCObjectType *ot = func->objectType; + for (asUINT n = 0; n < ot->methods.GetLength(); n++) + { + asCScriptFunction *func2 = engine->scriptFunctions[ot->methods[n]]; + if (func2->funcType == asFUNC_VIRTUAL) + func2 = ot->virtualFunctionTable[func2->vfTableIdx]; + + if (func->IsSignatureEqual(func2)) + { + func->DestroyHalfCreated(); + + // as this is an existing function it shouldn't be translated as if just loaded + dontTranslate.Insert(func2, true); + + // update the saved functions for future references + savedFunctions[savedFunctions.GetLength() - 1] = func2; + + // As it is an existing function it shouldn't be added to the module or the engine + return func2; + } + } + } + else + { + char bits; + ReadData(&bits, 1); + func->SetShared((bits & 1) ? true : false); + func->SetExplicit((bits & 32) ? true : false); + func->dontCleanUpOnException = (bits & 2) ? true : false; + if ((bits & 4) && isExternal) + *isExternal = true; + + // for external shared functions the rest is not needed + if (!(bits & 4)) + { + func->AllocateScriptFunctionData(); + if (func->scriptData == 0) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + + if (addToGC && !addToModule) + engine->gc.AddScriptObjectToGC(func, &engine->functionBehaviours); + + ReadByteCode(func); + + func->scriptData->variableSpace = ReadEncodedUInt(); + + func->scriptData->objVariablesOnHeap = 0; + if (bits & 8) + { + count = ReadEncodedUInt(); + func->scriptData->objVariablePos.Allocate(count, false); + func->scriptData->objVariableTypes.Allocate(count, false); + for (i = 0; i < count; ++i) + { + func->scriptData->objVariableTypes.PushLast(ReadTypeInfo()); + num = ReadEncodedUInt(); + func->scriptData->objVariablePos.PushLast(num); + + if (error) + { + // No need to continue (the error has already been reported before) + func->DestroyHalfCreated(); + return 0; + } + } + if (count > 0) + func->scriptData->objVariablesOnHeap = ReadEncodedUInt(); + + int length = ReadEncodedUInt(); + func->scriptData->objVariableInfo.SetLength(length); + for (i = 0; i < length; ++i) + { + func->scriptData->objVariableInfo[i].programPos = ReadEncodedUInt(); + func->scriptData->objVariableInfo[i].variableOffset = ReadEncodedUInt(); + asEObjVarInfoOption option = (asEObjVarInfoOption)ReadEncodedUInt(); + func->scriptData->objVariableInfo[i].option = option; + if (option != asOBJ_INIT && + option != asOBJ_UNINIT && + option != asBLOCK_BEGIN && + option != asBLOCK_END && + option != asOBJ_VARDECL) + { + error = true; + func->DestroyHalfCreated(); + return 0; + } + } + } + + if (bits & 16) + { + // Read info on try/catch blocks + int length = ReadEncodedUInt(); + func->scriptData->tryCatchInfo.SetLength(length); + for (i = 0; i < length; ++i) + { + // The program position must be adjusted to be in number of instructions + func->scriptData->tryCatchInfo[i].tryPos = ReadEncodedUInt(); + func->scriptData->tryCatchInfo[i].catchPos = ReadEncodedUInt(); + } + } + + if (!noDebugInfo) + { + int length = ReadEncodedUInt(); + func->scriptData->lineNumbers.SetLength(length); + if (int(func->scriptData->lineNumbers.GetLength()) != length) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + for (i = 0; i < length; ++i) + func->scriptData->lineNumbers[i] = ReadEncodedUInt(); + + // Read the array of script sections + length = ReadEncodedUInt(); + func->scriptData->sectionIdxs.SetLength(length); + if (int(func->scriptData->sectionIdxs.GetLength()) != length) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + for (i = 0; i < length; ++i) + { + if ((i & 1) == 0) + func->scriptData->sectionIdxs[i] = ReadEncodedUInt(); + else + { + asCString str; + ReadString(&str); + func->scriptData->sectionIdxs[i] = engine->GetScriptSectionNameIndex(str.AddressOf()); + } + } + } + + // Read the variable information + if (!noDebugInfo) + { + int length = ReadEncodedUInt(); + func->scriptData->variables.Allocate(length, false); + for (i = 0; i < length; i++) + { + asSScriptVariable *var = asNEW(asSScriptVariable); + if (var == 0) + { + // Out of memory + error = true; + func->DestroyHalfCreated(); + return 0; + } + func->scriptData->variables.PushLast(var); + + var->declaredAtProgramPos = ReadEncodedUInt(); + var->stackOffset = ReadEncodedUInt(); + ReadString(&var->name); + ReadDataType(&var->type); + + if (error) + { + // No need to continue (the error has already been reported before) + func->DestroyHalfCreated(); + return 0; + } + } + } + + // Read script section name + if (!noDebugInfo) + { + asCString name; + ReadString(&name); + func->scriptData->scriptSectionIdx = engine->GetScriptSectionNameIndex(name.AddressOf()); + func->scriptData->declaredAt = ReadEncodedUInt(); + } + + // Read parameter names + if (!noDebugInfo) + { + asUINT countParam = asUINT(ReadEncodedUInt64()); + if (countParam > func->parameterTypes.GetLength()) + { + error = true; + func->DestroyHalfCreated(); + return 0; + } + func->parameterNames.SetLength(countParam); + for (asUINT n = 0; n < countParam; n++) + ReadString(&func->parameterNames[n]); + } + } + } + } + else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) + { + func->vfTableIdx = ReadEncodedUInt(); + } + else if( func->funcType == asFUNC_FUNCDEF ) + { + asBYTE bits; + ReadData(&bits, 1); + if( bits & 1 ) + func->SetShared(true); + if ((bits & 2) && isExternal) + *isExternal = true; + + // The asCFuncdefType constructor adds itself to the func->funcdefType member + asCFuncdefType *fdt = asNEW(asCFuncdefType)(engine, func); + fdt->parentClass = parentClass; + } + + // Methods loaded for shared objects, owned by other modules should not be created as new functions + if( func->objectType && func->objectType->module != module ) + { + // Return the real function from the object + asCScriptFunction *realFunc = 0; + bool found = false; + if( func->funcType == asFUNC_SCRIPT ) + { + realFunc = engine->scriptFunctions[func->objectType->beh.destruct]; + if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) + { + found = true; + } + for( asUINT n = 0; !found && n < func->objectType->beh.constructors.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->beh.constructors[n]]; + if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + for( asUINT n = 0; !found && n < func->objectType->beh.factories.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->beh.factories[n]]; + if( realFunc && realFunc->funcType != asFUNC_VIRTUAL && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + for( asUINT n = 0; !found && n < func->objectType->methods.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->methods[n]]; + if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + for( asUINT n = 0; !found && n < func->objectType->virtualFunctionTable.GetLength(); n++ ) + { + realFunc = func->objectType->virtualFunctionTable[n]; + if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) + { + found = true; + break; + } + } + } + else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) + { + // If the loaded function is a virtual function, then look for the identical virtual function in the methods array + for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ ) + { + realFunc = engine->scriptFunctions[func->objectType->methods[n]]; + if( realFunc && realFunc->funcType == func->funcType && func->IsSignatureEqual(realFunc) ) + { + asASSERT( func->vfTableIdx == realFunc->vfTableIdx ); + found = true; + break; + } + } + } + + if( found ) + { + // as this is an existing function it shouldn't be translated as if just loaded + dontTranslate.Insert(realFunc, true); + + // update the saved functions for future references + savedFunctions[savedFunctions.GetLength() - 1] = realFunc; + + if( realFunc->funcType == asFUNC_VIRTUAL && addToModule ) + { + // Virtual methods must be added to the module's script functions array, + // even if they are not owned by the module + module->m_scriptFunctions.PushLast(realFunc); + realFunc->AddRefInternal(); + } + } + else + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, func->objectType->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + + Error(TXT_INVALID_BYTECODE_d); + savedFunctions.PopLast(); + realFunc = 0; + } + + // Destroy the newly created function instance since it has been replaced by an existing function + isNew = false; + func->DestroyHalfCreated(); + + // As it is an existing function it shouldn't be added to the module or the engine + return realFunc; + } + + if( addToModule ) + { + // The refCount is already 1 + module->m_scriptFunctions.PushLast(func); + func->module = module; + } + if( addToEngine ) + { + func->id = engine->GetNextScriptFunctionId(); + engine->AddScriptFunction(func); + } + if( func->objectType ) + func->ComputeSignatureId(); + + return func; +} + +void asCReader::ReadTypeDeclaration(asCTypeInfo *type, int phase, bool *isExternal) +{ + if( phase == 1 ) + { + asASSERT(isExternal); + if (isExternal) + *isExternal = false; + + // Read the initial attributes + ReadString(&type->name); + ReadData(&type->flags, 4); + type->size = ReadEncodedUInt(); + asCString ns; + ReadString(&ns); + type->nameSpace = engine->AddNameSpace(ns.AddressOf()); + + // Verify that the flags match the asCTypeInfo + if ((CastToEnumType(type) && !(type->flags & asOBJ_ENUM)) || + (CastToFuncdefType(type) && !(type->flags & asOBJ_FUNCDEF)) || + (CastToObjectType(type) && !(type->flags & (asOBJ_REF | asOBJ_VALUE)))) + { + error = true; + return; + } + + // Reset the size of script classes, since it will be recalculated as properties are added + if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size != 0 ) + type->size = sizeof(asCScriptObject); + + asCObjectType *ot = CastToObjectType(type); + if (ot) + { + // Use the default script class behaviours + ot->beh = engine->scriptTypeBehaviours.beh; + ot->beh.construct = 0; + ot->beh.factory = 0; + ot->beh.constructors.PopLast(); // These will be read from the file + ot->beh.factories.PopLast(); // These will be read from the file + engine->scriptFunctions[ot->beh.addref]->AddRefInternal(); + engine->scriptFunctions[ot->beh.release]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); + engine->scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); + engine->scriptFunctions[ot->beh.copy]->AddRefInternal(); + // TODO: weak: Should not do this if the class has been declared with 'noweak' + engine->scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); + } + + // external shared flag + if (type->flags & asOBJ_SHARED) + { + char c; + ReadData(&c, 1); + if (c == 'e') + *isExternal = true; + else if (c != ' ') + { + error = true; + return; + } + } + } + else if( phase == 2 ) + { + // external shared types doesn't store this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + if( type->flags & asOBJ_ENUM ) + { + asCEnumType *t = CastToEnumType(type); + int count = ReadEncodedUInt(); + bool sharedExists = existingShared.MoveTo(0, type); + if( !sharedExists ) + { + t->enumValues.Allocate(count, false); + for( int n = 0; n < count; n++ ) + { + asSEnumValue *e = asNEW(asSEnumValue); + if( e == 0 ) + { + // Out of memory + error = true; + return; + } + ReadString(&e->name); + ReadData(&e->value, 4); // TODO: Should be encoded + t->enumValues.PushLast(e); + } + } + else + { + // Verify that the enum values exists in the original + asCString name; + int value; + for( int n = 0; n < count; n++ ) + { + ReadString(&name); + ReadData(&value, 4); // TODO: Should be encoded + bool found = false; + for( asUINT e = 0; e < t->enumValues.GetLength(); e++ ) + { + if( t->enumValues[e]->name == name && + t->enumValues[e]->value == value ) + { + found = true; + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + } + } + } + else if( type->flags & asOBJ_TYPEDEF ) + { + asCTypedefType *td = CastToTypedefType(type); + asASSERT(td); + eTokenType t = (eTokenType)ReadEncodedUInt(); + td->aliasForType = asCDataType::CreatePrimitive(t, false); + } + else + { + asCObjectType *ot = CastToObjectType(type); + asASSERT(ot); + + // If the type is shared and pre-existing, we should just + // validate that the loaded methods match the original + bool sharedExists = existingShared.MoveTo(0, type); + if( sharedExists ) + { + asCObjectType *dt = CastToObjectType(ReadTypeInfo()); + if( ot->derivedFrom != dt ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + } + else + { + ot->derivedFrom = CastToObjectType(ReadTypeInfo()); + if( ot->derivedFrom ) + ot->derivedFrom->AddRefInternal(); + } + + // interfaces[] / interfaceVFTOffsets[] + int size = ReadEncodedUInt(); + if( sharedExists ) + { + for( int n = 0; n < size; n++ ) + { + asCObjectType *intf = CastToObjectType(ReadTypeInfo()); + if (!ot->IsInterface()) + ReadEncodedUInt(); + + if( !type->Implements(intf) ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + } + } + else + { + ot->interfaces.Allocate(size, false); + if( !ot->IsInterface() ) + ot->interfaceVFTOffsets.Allocate(size, false); + for( int n = 0; n < size; n++ ) + { + asCObjectType *intf = CastToObjectType(ReadTypeInfo()); + ot->interfaces.PushLast(intf); + + if (!ot->IsInterface()) + { + asUINT offset = ReadEncodedUInt(); + ot->interfaceVFTOffsets.PushLast(offset); + } + } + } + + // behaviours + if( !ot->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM ) + { + bool isNew; + asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); + if( sharedExists ) + { + // Find the real function in the object, and update the savedFunctions array + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.destruct); + if( (realFunc == 0 && func == 0) || realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( func && savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + } + else + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + if( func ) + { + if( isNew ) + { + // Destroy the function without releasing any references + func->id = 0; + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + } + dontTranslate.Insert(realFunc, true); + } + } + else + { + if( func ) + { + ot->beh.destruct = func->id; + func->AddRefInternal(); + } + else + ot->beh.destruct = 0; + } + + size = ReadEncodedUInt(); + for( int n = 0; n < size; n++ ) + { + func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); + if( func ) + { + if( sharedExists ) + { + // Find the real function in the object, and update the savedFunctions array + bool found = false; + for( asUINT f = 0; f < ot->beh.constructors.GetLength(); f++ ) + { + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.constructors[f]); + if( realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + found = true; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + if( isNew ) + { + // Destroy the function without releasing any references + func->id = 0; + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + } + } + else + { + ot->beh.constructors.PushLast(func->id); + func->AddRefInternal(); + + if( func->parameterTypes.GetLength() == 0 ) + ot->beh.construct = func->id; + } + } + else + { + Error(TXT_INVALID_BYTECODE_d); + } + + func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); + if( func ) + { + if( sharedExists ) + { + // Find the real function in the object, and update the savedFunctions array + bool found = false; + for( asUINT f = 0; f < ot->beh.factories.GetLength(); f++ ) + { + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->beh.factories[f]); + if( realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + found = true; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + if( isNew ) + { + // Destroy the function without releasing any references + func->id = 0; + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + } + } + else + { + ot->beh.factories.PushLast(func->id); + func->AddRefInternal(); + + if( func->parameterTypes.GetLength() == 0 ) + ot->beh.factory = func->id; + } + } + else + { + Error(TXT_INVALID_BYTECODE_d); + } + } + } + + // methods[] + size = ReadEncodedUInt(); + int n; + for( n = 0; n < size; n++ ) + { + bool isNew; + asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); + if( func ) + { + if( sharedExists ) + { + // Find the real function in the object, and update the savedFunctions array + bool found = false; + for( asUINT f = 0; f < ot->methods.GetLength(); f++ ) + { + asCScriptFunction *realFunc = engine->GetScriptFunction(ot->methods[f]); + if( realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + found = true; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + if( isNew ) + { + // Destroy the function without releasing any references + if( func->id == func->signatureId ) + engine->signatureIds.RemoveValue(func); + func->id = 0; + if( func->scriptData ) + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + } + } + else + { + // If the method is the assignment operator we need to replace the default implementation + if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && + func->parameterTypes[0].GetTypeInfo() == func->objectType && + (func->inOutFlags[0] & asTM_INREF) ) + { + engine->scriptFunctions[ot->beh.copy]->ReleaseInternal(); + ot->beh.copy = func->id; + func->AddRefInternal(); + } + + ot->methods.PushLast(func->id); + func->AddRefInternal(); + } + } + else + { + Error(TXT_INVALID_BYTECODE_d); + } + } + + // virtualFunctionTable[] + size = ReadEncodedUInt(); + for( n = 0; n < size; n++ ) + { + bool isNew; + asCScriptFunction *func = ReadFunction(isNew, !sharedExists, !sharedExists, !sharedExists); + if( func ) + { + if( sharedExists ) + { + // Find the real function in the object, and update the savedFunctions array + bool found = false; + for( asUINT f = 0; f < ot->virtualFunctionTable.GetLength(); f++ ) + { + asCScriptFunction *realFunc = ot->virtualFunctionTable[f]; + if( realFunc->IsSignatureEqual(func) ) + { + // If the function is not the last, then the substitution has already occurred before + if( savedFunctions[savedFunctions.GetLength()-1] == func ) + savedFunctions[savedFunctions.GetLength()-1] = realFunc; + found = true; + dontTranslate.Insert(realFunc, true); + break; + } + } + if( !found ) + { + asCString str; + str.Format(TXT_SHARED_s_DOESNT_MATCH_ORIGINAL, type->GetName()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + } + if( isNew ) + { + // Destroy the function without releasing any references + func->id = 0; + if( func->scriptData ) + func->scriptData->byteCode.SetLength(0); + func->ReleaseInternal(); + } + } + else + { + ot->virtualFunctionTable.PushLast(func); + func->AddRefInternal(); + } + } + else + { + Error(TXT_INVALID_BYTECODE_d); + } + } + } + } + else if( phase == 3 ) + { + // external shared types doesn't store this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + asCObjectType *ot = CastToObjectType(type); + + // This is only done for object types + asASSERT(ot); + + // properties[] + asUINT size = ReadEncodedUInt(); + for( asUINT n = 0; n < size; n++ ) + ReadObjectProperty(ot); + } +} + +asWORD asCReader::ReadEncodedUInt16() +{ + asDWORD dw = ReadEncodedUInt(); + if( (dw>>16) != 0 && (dw>>16) != 0xFFFF ) + { + Error(TXT_INVALID_BYTECODE_d); + } + + return asWORD(dw & 0xFFFF); +} + +asUINT asCReader::ReadEncodedUInt() +{ + asQWORD qw = ReadEncodedUInt64(); + if( (qw>>32) != 0 && (qw>>32) != 0xFFFFFFFF ) + { + Error(TXT_INVALID_BYTECODE_d); + } + + return asUINT(qw & 0xFFFFFFFFu); +} + +asQWORD asCReader::ReadEncodedUInt64() +{ + asQWORD i = 0; + asBYTE b; + ReadData(&b, 1); + bool isNegative = ( b & 0x80 ) ? true : false; + b &= 0x7F; + + if( (b & 0x7F) == 0x7F ) + { + ReadData(&b, 1); i = asQWORD(b) << 56; + ReadData(&b, 1); i += asQWORD(b) << 48; + ReadData(&b, 1); i += asQWORD(b) << 40; + ReadData(&b, 1); i += asQWORD(b) << 32; + ReadData(&b, 1); i += asUINT(b) << 24; + ReadData(&b, 1); i += asUINT(b) << 16; + ReadData(&b, 1); i += asUINT(b) << 8; + ReadData(&b, 1); i += b; + } + else if( (b & 0x7E) == 0x7E ) + { + i = asQWORD(b & 0x01) << 48; + ReadData(&b, 1); i += asQWORD(b) << 40; + ReadData(&b, 1); i += asQWORD(b) << 32; + ReadData(&b, 1); i += asUINT(b) << 24; + ReadData(&b, 1); i += asUINT(b) << 16; + ReadData(&b, 1); i += asUINT(b) << 8; + ReadData(&b, 1); i += b; + } + else if( (b & 0x7C) == 0x7C ) + { + i = asQWORD(b & 0x03) << 40; + ReadData(&b, 1); i += asQWORD(b) << 32; + ReadData(&b, 1); i += asUINT(b) << 24; + ReadData(&b, 1); i += asUINT(b) << 16; + ReadData(&b, 1); i += asUINT(b) << 8; + ReadData(&b, 1); i += b; + } + else if( (b & 0x78) == 0x78 ) + { + i = asQWORD(b & 0x07) << 32; + ReadData(&b, 1); i += asUINT(b) << 24; + ReadData(&b, 1); i += asUINT(b) << 16; + ReadData(&b, 1); i += asUINT(b) << 8; + ReadData(&b, 1); i += b; + } + else if( (b & 0x70) == 0x70 ) + { + i = asUINT(b & 0x0F) << 24; + ReadData(&b, 1); i += asUINT(b) << 16; + ReadData(&b, 1); i += asUINT(b) << 8; + ReadData(&b, 1); i += b; + } + else if( (b & 0x60) == 0x60 ) + { + i = asUINT(b & 0x1F) << 16; + ReadData(&b, 1); i += asUINT(b) << 8; + ReadData(&b, 1); i += b; + } + else if( (b & 0x40) == 0x40 ) + { + i = asUINT(b & 0x3F) << 8; + ReadData(&b, 1); i += b; + } + else + { + i = b; + } + if( isNegative ) + i = (asQWORD)(-asINT64(i)); + + return i; +} + +void asCReader::ReadString(asCString* str) +{ + asUINT len = ReadEncodedUInt(); + if( len & 1 ) + { + asUINT idx = len/2; + if( idx < savedStrings.GetLength() ) + *str = savedStrings[idx]; + else + Error(TXT_INVALID_BYTECODE_d); + } + else if( len > 0 ) + { + len /= 2; + str->SetLength(len); + int r = stream->Read(str->AddressOf(), len); + if (r < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); + + savedStrings.PushLast(*str); + } + else + str->SetLength(0); +} + +void asCReader::ReadGlobalProperty() +{ + asCString name; + asCDataType type; + + ReadString(&name); + + asCString ns; + ReadString(&ns); + asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); + + ReadDataType(&type); + + asCGlobalProperty *prop = module->AllocateGlobalProperty(name.AddressOf(), type, nameSpace); + + // Read the initialization function + bool isNew; + // Do not add the function to the GC at this time. It will + // only be added to the GC when the module releases the property + asCScriptFunction *func = ReadFunction(isNew, false, true, false); + if( func ) + { + // Make sure the function knows it is owned by the module + func->module = module; + + prop->SetInitFunc(func); + func->ReleaseInternal(); + } +} + +void asCReader::ReadObjectProperty(asCObjectType *ot) +{ + asCString name; + ReadString(&name); + asCDataType dt; + ReadDataType(&dt); + int flags = ReadEncodedUInt(); + bool isPrivate = (flags & 1) ? true : false; + bool isProtected = (flags & 2) ? true : false; + bool isInherited = (flags & 4) ? true : false; + + // TODO: shared: If the type is shared and pre-existing, we should just + // validate that the loaded methods match the original + if( !existingShared.MoveTo(0, ot) ) + ot->AddPropertyToClass(name, dt, isPrivate, isProtected, isInherited); +} + +void asCReader::ReadDataType(asCDataType *dt) +{ + // Check if this is a previously used type + asUINT idx = ReadEncodedUInt(); + if( idx != 0 ) + { + // Get the datatype from the cache + *dt = savedDataTypes[idx-1]; + return; + } + + // Read the type definition + eTokenType tokenType = (eTokenType)ReadEncodedUInt(); + + // Reserve a spot in the savedDataTypes + asUINT saveSlot = savedDataTypes.GetLength(); + savedDataTypes.PushLast(asCDataType()); + + // Read the datatype for the first time + asCTypeInfo *ti = 0; + if( tokenType == ttIdentifier ) + ti = ReadTypeInfo(); + + // Read type flags as a bitmask + // Endian-safe code + bool isObjectHandle, isHandleToConst, isReference, isReadOnly; + char b = 0; + ReadData(&b, 1); + LOAD_FROM_BIT(isObjectHandle, b, 0); + LOAD_FROM_BIT(isHandleToConst, b, 1); + LOAD_FROM_BIT(isReference, b, 2); + LOAD_FROM_BIT(isReadOnly, b, 3); + + if( tokenType == ttIdentifier ) + *dt = asCDataType::CreateType(ti, false); + else + *dt = asCDataType::CreatePrimitive(tokenType, false); + if( isObjectHandle ) + { + dt->MakeReadOnly(isHandleToConst ? true : false); + + // Here we must allow a scoped type to be a handle + // e.g. if the datatype is for a system function + dt->MakeHandle(true, true); + } + dt->MakeReadOnly(isReadOnly ? true : false); + dt->MakeReference(isReference ? true : false); + + // Update the previously saved slot + savedDataTypes[saveSlot] = *dt; +} + +asCTypeInfo* asCReader::ReadTypeInfo() +{ + asCTypeInfo *ot = 0; + char ch; + ReadData(&ch, 1); + if( ch == 'a' ) + { + // Read the name of the template type + asCString typeName, ns; + ReadString(&typeName); + ReadString(&ns); + asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); + + asCTypeInfo *tmp = engine->GetRegisteredType(typeName.AddressOf(), nameSpace); + asCObjectType *tmpl = CastToObjectType(tmp); + if( tmpl == 0 ) + { + asCString str; + str.Format(TXT_TEMPLATE_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + asUINT numSubTypes = ReadEncodedUInt(); + asCArray subTypes; + for( asUINT n = 0; n < numSubTypes; n++ ) + { + ReadData(&ch, 1); + if( ch == 's' ) + { + asCDataType dt; + ReadDataType(&dt); + subTypes.PushLast(dt); + } + else + { + eTokenType tokenType = (eTokenType)ReadEncodedUInt(); + asCDataType dt = asCDataType::CreatePrimitive(tokenType, false); + subTypes.PushLast(dt); + } + } + + // Return the actual template if the subtypes are the template's dummy types + if( tmpl->templateSubTypes == subTypes ) + ot = tmpl; + else + { + // Get the template instance type based on the loaded subtypes + ot = engine->GetTemplateInstanceType(tmpl, subTypes, module); + } + + if( ot == 0 ) + { + // Show all subtypes in error message + asCString sub = subTypes[0].Format(nameSpace); + for( asUINT n = 1; n < subTypes.GetLength(); n++ ) + { + sub += ","; + sub += subTypes[n].Format(nameSpace); + } + asCString str; + str.Format(TXT_INSTANCING_INVLD_TMPL_TYPE_s_s, typeName.AddressOf(), sub.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + } + else if( ch == 'l' ) + { + asCObjectType *st = CastToObjectType(ReadTypeInfo()); + if( st == 0 || st->beh.listFactory == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + ot = engine->GetListPatternType(st->beh.listFactory); + } + else if( ch == 's' ) + { + // Read the name of the template subtype + asCString typeName; + ReadString(&typeName); + + // Find the template subtype + ot = 0; + for( asUINT n = 0; n < engine->templateSubTypes.GetLength(); n++ ) + { + if( engine->templateSubTypes[n] && engine->templateSubTypes[n]->name == typeName ) + { + ot = engine->templateSubTypes[n]; + break; + } + } + + if( ot == 0 ) + { + asCString str; + str.Format(TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST, typeName.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + } + else if( ch == 'o' ) + { + // Read the object type name + asCString typeName, ns; + ReadString(&typeName); + ReadString(&ns); + asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); + + if( typeName.GetLength() && typeName != "$obj" && typeName != "$func" ) + { + // Find the object type + ot = module->GetType(typeName.AddressOf(), nameSpace); + if (!ot) + ot = engine->GetRegisteredType(typeName.AddressOf(), nameSpace); + + if( ot == 0 ) + { + asCString str; + str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + } + else if( typeName == "$obj" ) + { + ot = &engine->scriptTypeBehaviours; + } + else if( typeName == "$func" ) + { + ot = &engine->functionBehaviours; + } + else + asASSERT( false ); + } + else if (ch == 'c') + { + // Read the object type name + asCString typeName, ns; + ReadString(&typeName); + + // Read the parent class + asCObjectType *parentClass = CastToObjectType(ReadTypeInfo()); + if (parentClass == 0) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + // Find the child type in the parentClass + for (asUINT n = 0; n < parentClass->childFuncDefs.GetLength(); n++) + { + if (parentClass->childFuncDefs[n]->name == typeName) + ot = parentClass->childFuncDefs[n]; + } + + if (ot == 0) + { + asCString str; + str.Format(TXT_OBJECT_TYPE_s_DOESNT_EXIST, typeName.AddressOf()); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + } + else + { + // No object type + asASSERT( ch == '\0' || error ); + ot = 0; + } + + return ot; +} + +void asCReader::ReadByteCode(asCScriptFunction *func) +{ + asASSERT( func->scriptData ); + + // Read number of instructions + asUINT total, numInstructions; + total = numInstructions = ReadEncodedUInt(); + + // Reserve some space for the instructions + func->scriptData->byteCode.AllocateNoConstruct(numInstructions, false); + + asUINT pos = 0; + while( numInstructions ) + { + asBYTE b; + ReadData(&b, 1); + + // Allocate the space for the instruction + asUINT len = asBCTypeSize[asBCInfo[b].type]; + asUINT newSize = asUINT(func->scriptData->byteCode.GetLength()) + len; + if( func->scriptData->byteCode.GetCapacity() < newSize ) + { + // Determine the average size of the loaded instructions and re-estimate the final size + asUINT size = asUINT(float(newSize) / (total - numInstructions) * total) + 1; + func->scriptData->byteCode.AllocateNoConstruct(size, true); + } + if( !func->scriptData->byteCode.SetLengthNoConstruct(newSize) ) + { + // Out of memory + error = true; + return; + } + + asDWORD *bc = func->scriptData->byteCode.AddressOf() + pos; + pos += len; + + switch( asBCInfo[b].type ) + { + case asBCTYPE_NO_ARG: + { + *(asBYTE*)(bc) = b; + bc++; + } + break; + case asBCTYPE_W_ARG: + case asBCTYPE_wW_ARG: + case asBCTYPE_rW_ARG: + { + *(asBYTE*)(bc) = b; + + // Read the argument + asWORD w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + + bc++; + } + break; + case asBCTYPE_rW_DW_ARG: + case asBCTYPE_wW_DW_ARG: + case asBCTYPE_W_DW_ARG: + { + *(asBYTE*)(bc) = b; + + // Read the word argument + asWORD w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + bc++; + + // Read the dword argument + *bc++ = ReadEncodedUInt(); + } + break; + case asBCTYPE_DW_ARG: + { + *(asBYTE*)(bc) = b; + bc++; + + // Read the argument + *bc++ = ReadEncodedUInt(); + } + break; + case asBCTYPE_DW_DW_ARG: + { + *(asBYTE*)(bc) = b; + bc++; + + // Read the first argument + *bc++ = ReadEncodedUInt(); + + // Read the second argument + *bc++ = ReadEncodedUInt(); + } + break; + case asBCTYPE_wW_rW_rW_ARG: + { + *(asBYTE*)(bc) = b; + + // Read the first argument + asWORD w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + bc++; + + // Read the second argument + w = ReadEncodedUInt16(); + *(asWORD*)bc = w; + + // Read the third argument + w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + + bc++; + } + break; + case asBCTYPE_wW_rW_ARG: + case asBCTYPE_rW_rW_ARG: + case asBCTYPE_wW_W_ARG: + { + *(asBYTE*)(bc) = b; + + // Read the first argument + asWORD w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + bc++; + + // Read the second argument + w = ReadEncodedUInt16(); + *(asWORD*)bc = w; + + bc++; + } + break; + case asBCTYPE_wW_rW_DW_ARG: + case asBCTYPE_rW_W_DW_ARG: + { + *(asBYTE*)(bc) = b; + + // Read the first argument + asWORD w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + bc++; + + // Read the second argument + w = ReadEncodedUInt16(); + *(asWORD*)bc = w; + bc++; + + // Read the third argument + asDWORD dw = ReadEncodedUInt(); + *bc++ = dw; + } + break; + case asBCTYPE_QW_ARG: + { + *(asBYTE*)(bc) = b; + bc++; + + // Read the argument + asQWORD qw = ReadEncodedUInt64(); + *(asQWORD*)bc = qw; + bc += 2; + } + break; + case asBCTYPE_QW_DW_ARG: + { + *(asBYTE*)(bc) = b; + bc++; + + // Read the first argument + asQWORD qw = ReadEncodedUInt64(); + *(asQWORD*)bc = qw; + bc += 2; + + // Read the second argument + asDWORD dw = ReadEncodedUInt(); + *bc++ = dw; + } + break; + case asBCTYPE_rW_QW_ARG: + case asBCTYPE_wW_QW_ARG: + { + *(asBYTE*)(bc) = b; + + // Read the first argument + asWORD w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + bc++; + + // Read the argument + asQWORD qw = ReadEncodedUInt64(); + *(asQWORD*)bc = qw; + bc += 2; + } + break; + case asBCTYPE_rW_DW_DW_ARG: + { + *(asBYTE*)(bc) = b; + + // Read the 1st argument + asWORD w = ReadEncodedUInt16(); + *(((asWORD*)bc)+1) = w; + bc++; + + // Read the 2nd argument + *bc++ = ReadEncodedUInt(); + + // Read the 3rd argument + *bc++ = ReadEncodedUInt(); + } + break; + default: + { + // This should never happen + asASSERT(false); + + // Read the next 3 bytes + asDWORD c; asBYTE t; +#if defined(AS_BIG_ENDIAN) + c = b << 24; + ReadData(&t, 1); c += t << 16; + ReadData(&t, 1); c += t << 8; + ReadData(&t, 1); c += t; +#else + c = b; + ReadData(&t, 1); c += t << 8; + ReadData(&t, 1); c += t << 16; + ReadData(&t, 1); c += t << 24; +#endif + + *bc++ = c; + c = *(asBYTE*)&c; + + // Read the bc as is + for( int n = 1; n < asBCTypeSize[asBCInfo[c].type]; n++ ) + ReadData(&*bc++, 4); + } + } + + numInstructions--; + } + + // Correct the final size in case we over-estimated it + func->scriptData->byteCode.SetLengthNoConstruct(pos); +} + +void asCReader::ReadUsedTypeIds() +{ + TimeIt("asCReader::ReadUsedTypeIds"); + + asUINT count = ReadEncodedUInt(); + usedTypeIds.Allocate(count, false); + for( asUINT n = 0; n < count; n++ ) + { + asCDataType dt; + ReadDataType(&dt); + usedTypeIds.PushLast(engine->GetTypeIdFromDataType(dt)); + } +} + +void asCReader::ReadUsedGlobalProps() +{ + TimeIt("asCReader::ReadUsedGlobalProps"); + + int c = ReadEncodedUInt(); + + usedGlobalProperties.Allocate(c, false); + + for( int n = 0; n < c; n++ ) + { + asCString name, ns; + asCDataType type; + char moduleProp; + + ReadString(&name); + ReadString(&ns); + ReadDataType(&type); + ReadData(&moduleProp, 1); + + asSNameSpace *nameSpace = engine->AddNameSpace(ns.AddressOf()); + + // Find the real property + asCGlobalProperty *globProp = 0; + if( moduleProp ) + globProp = module->m_scriptGlobals.GetFirst(nameSpace, name); + else + globProp = engine->registeredGlobalProps.GetFirst(nameSpace, name); + + void *prop = 0; + if( globProp && globProp->type == type ) + prop = globProp->GetAddressOfValue(); + + usedGlobalProperties.PushLast(prop); + + if( prop == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + } + } +} + +void asCReader::ReadUsedObjectProps() +{ + TimeIt("asCReader::ReadUsedObjectProps"); + + asUINT c = ReadEncodedUInt(); + + usedObjectProperties.SetLength(c); + for( asUINT n = 0; n < c; n++ ) + { + asCObjectType *objType = CastToObjectType(ReadTypeInfo()); + if( objType == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + break; + } + + asCString name; + ReadString(&name); + + // Find the property + bool found = false; + for( asUINT p = 0; p < objType->properties.GetLength(); p++ ) + { + if( objType->properties[p]->name == name ) + { + usedObjectProperties[n].objType = objType; + usedObjectProperties[n].prop = objType->properties[p]; + found = true; + break; + } + } + + if( !found ) + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } +} + +short asCReader::FindObjectPropOffset(asWORD index) +{ + static asCObjectProperty *lastCompositeProp = 0; + if (lastCompositeProp) + { + if (index != 0) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + short offset = (short)lastCompositeProp->byteOffset; + lastCompositeProp = 0; + return offset; + } + + if( index >= usedObjectProperties.GetLength() ) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + if (usedObjectProperties[index].prop->compositeOffset || usedObjectProperties[index].prop->isCompositeIndirect) + { + lastCompositeProp = usedObjectProperties[index].prop; + return (short)lastCompositeProp->compositeOffset; + } + return (short)usedObjectProperties[index].prop->byteOffset; +} + +asCScriptFunction *asCReader::FindFunction(int idx) +{ + if( idx >= 0 && idx < (int)usedFunctions.GetLength() ) + return usedFunctions[idx]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } +} + +void asCReader::TranslateFunction(asCScriptFunction *func) +{ + // Skip this if the function is part of an pre-existing shared object + if( dontTranslate.MoveTo(0, func) ) return; + + asASSERT( func->scriptData ); + + // Pre-compute the size of each instruction in order to translate jump offsets + asUINT n; + asDWORD *bc = func->scriptData->byteCode.AddressOf(); + asUINT bcLength = (asUINT)func->scriptData->byteCode.GetLength(); + asCArray bcSizes(bcLength); + asCArray instructionNbrToPos(bcLength); + for( n = 0; n < bcLength; ) + { + int c = *(asBYTE*)&bc[n]; + asUINT size = asBCTypeSize[asBCInfo[c].type]; + if( size == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + bcSizes.PushLast(size); + instructionNbrToPos.PushLast(n); + n += size; + } + + asUINT bcNum = 0; + for( n = 0; n < bcLength; bcNum++ ) + { + int c = *(asBYTE*)&bc[n]; + if( c == asBC_REFCPY || + c == asBC_RefCpyV || + c == asBC_OBJTYPE ) + { + // Translate the index to the true object type + asPWORD *ot = (asPWORD*)&bc[n+1]; + *(asCObjectType**)ot = CastToObjectType(FindType(int(*ot))); + } + else if( c == asBC_TYPEID || + c == asBC_Cast ) + { + // Translate the index to the type id + int *tid = (int*)&bc[n+1]; + *tid = FindTypeId(*tid); + } + else if( c == asBC_ADDSi || + c == asBC_LoadThisR ) + { + // Translate the index to the type id + int *tid = (int*)&bc[n+1]; + *tid = FindTypeId(*tid); + + // Translate the prop index into the property offset + *(((short*)&bc[n])+1) = FindObjectPropOffset(*(((short*)&bc[n])+1)); + } + else if( c == asBC_LoadRObjR || + c == asBC_LoadVObjR ) + { + // Translate the index to the type id + int *tid = (int*)&bc[n+2]; + *tid = FindTypeId(*tid); + + asCObjectType *ot = engine->GetObjectTypeFromTypeId(*tid); + if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) + { + // List patterns have a different way of adjusting the offsets + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + *(((short*)&bc[n])+2) = (short)listAdj->AdjustOffset(*(((short*)&bc[n])+2)); + } + else + { + // Translate the prop index into the property offset + *(((short*)&bc[n])+2) = FindObjectPropOffset(*(((short*)&bc[n])+2)); + } + } + else if( c == asBC_COPY ) + { + // Translate the index to the type id + int *tid = (int*)&bc[n+1]; + *tid = FindTypeId(*tid); + + // COPY is used to copy POD types that don't have the opAssign method. It is + // also used to copy references to scoped types during variable initializations. + // Update the number of dwords to copy as it may be different on the target platform + if( (*tid) & asTYPEID_OBJHANDLE ) + { + // It is the actual reference that is being copied, not the object itself + asBC_SWORDARG0(&bc[n]) = AS_PTR_SIZE; + } + else + { + asCDataType dt = engine->GetDataTypeFromTypeId(*tid); + if( !dt.IsValid() ) + { + Error(TXT_INVALID_BYTECODE_d); + } + else + asBC_SWORDARG0(&bc[n]) = (short)dt.GetSizeInMemoryDWords(); + } + } + else if( c == asBC_RET ) + { + // Determine the correct amount of DWORDs to pop + asWORD dw = (asWORD)func->GetSpaceNeededForArguments(); + if( func->DoesReturnOnStack() ) dw += AS_PTR_SIZE; + if( func->objectType ) dw += AS_PTR_SIZE; + asBC_WORDARG0(&bc[n]) = dw; + } + else if( c == asBC_CALL || + c == asBC_CALLINTF || + c == asBC_CALLSYS || + c == asBC_Thiscall1 ) + { + // Translate the index to the func id + int *fid = (int*)&bc[n+1]; + asCScriptFunction *f = FindFunction(*fid); + if( f ) + *fid = f->id; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + else if( c == asBC_FuncPtr ) + { + // Translate the index to the func pointer + asPWORD *fid = (asPWORD*)&bc[n+1]; + *fid = (asPWORD)FindFunction(int(*fid)); + } + else if( c == asBC_ALLOC ) + { + // Translate the index to the true object type + asPWORD *arg = (asPWORD*)&bc[n+1]; + *(asCObjectType**)arg = CastToObjectType(FindType(int(*arg))); + + // The constructor function id must be translated, unless it is zero + int *fid = (int*)&bc[n+1+AS_PTR_SIZE]; + if( *fid != 0 ) + { + // Subtract 1 from the id, as it was incremented during the writing + asCScriptFunction *f = FindFunction(*fid-1); + if( f ) + *fid = f->id; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + } + else if( c == asBC_STR ) + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + else if( c == asBC_CALLBND ) + { + // Translate the function id + asUINT *fid = (asUINT*)&bc[n+1]; + if( *fid < module->m_bindInformations.GetLength() ) + { + sBindInfo *bi = module->m_bindInformations[*fid]; + if( bi ) + *fid = bi->importedFunctionSignature->id; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + else if( c == asBC_PGA || + c == asBC_PshGPtr || + c == asBC_LDG || + c == asBC_PshG4 || + c == asBC_LdGRdR4 || + c == asBC_CpyGtoV4 || + c == asBC_CpyVtoG4 || + c == asBC_SetG4 ) + { + // Translate the index to pointer + asPWORD *index = (asPWORD*)&bc[n + 1]; + if ((*index & 1)) + { + if ((asUINT(*index)>>1) < usedGlobalProperties.GetLength()) + *(void**)index = usedGlobalProperties[asUINT(*index)>>1]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + else + { + // Only PGA and PshGPtr can hold string constants + asASSERT(c == asBC_PGA || c == asBC_PshGPtr); + + if ((asUINT(*index)>>1) < usedStringConstants.GetLength()) + *(void**)index = usedStringConstants[asUINT(*index)>>1]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + } + } + else if( c == asBC_JMP || + c == asBC_JZ || + c == asBC_JNZ || + c == asBC_JLowZ || + c == asBC_JLowNZ || + c == asBC_JS || + c == asBC_JNS || + c == asBC_JP || + c == asBC_JNP ) // The JMPP instruction doesn't need modification + { + // Get the offset + int offset = int(bc[n+1]); + + // Count the instruction sizes to the destination instruction + int size = 0; + if( offset >= 0 ) + // If moving ahead, then start from next instruction + for( asUINT num = bcNum+1; offset-- > 0; num++ ) + size += bcSizes[num]; + else + // If moving backwards, then start at current instruction + for( asUINT num = bcNum; offset++ < 0; num-- ) + size -= bcSizes[num]; + + // The size is dword offset + bc[n+1] = size; + } + else if( c == asBC_AllocMem ) + { + // The size of the allocated memory is only known after all the elements has been seen. + // This helper class will collect this information and adjust the size when the + // corresponding asBC_FREE is encountered + + // The adjuster also needs to know the list type so it can know the type of the elements + asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(asBC_SWORDARG0(&bc[n]))); + listAdjusters.PushLast(asNEW(SListAdjuster)(this, &bc[n], ot)); + } + else if( c == asBC_FREE ) + { + // Translate the index to the true object type + asPWORD *pot = (asPWORD*)&bc[n+1]; + *(asCObjectType**)pot = CastToObjectType(FindType(int(*pot))); + + asCObjectType *ot = *(asCObjectType**)pot; + if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) + { + if( listAdjusters.GetLength() == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + return; + } + + // Finalize the adjustment of the list buffer that was initiated with asBC_AllocMem + SListAdjuster *list = listAdjusters.PopLast(); + list->AdjustAllocMem(); + asDELETE(list, SListAdjuster); + } + } + else if( c == asBC_SetListSize ) + { + // Adjust the offset in the list where the size is informed + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + bc[n+1] = listAdj->AdjustOffset(bc[n+1]); + + // Inform the list adjuster how many values will be repeated + listAdj->SetRepeatCount(bc[n+2]); + } + else if( c == asBC_PshListElmnt ) + { + // Adjust the offset in the list where the size is informed + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + bc[n+1] = listAdj->AdjustOffset(bc[n+1]); + } + else if( c == asBC_SetListType ) + { + // Adjust the offset in the list where the typeid is informed + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + bc[n+1] = listAdj->AdjustOffset(bc[n+1]); + + // Translate the type id + bc[n+2] = FindTypeId(bc[n+2]); + + // Inform the list adjuster the type id of the next element + listAdj->SetNextType(bc[n+2]); + } + + n += asBCTypeSize[asBCInfo[c].type]; + } + + // Calculate the stack adjustments + CalculateAdjustmentByPos(func); + + // Adjust all variable positions in the bytecode + bc = func->scriptData->byteCode.AddressOf(); + for( n = 0; n < bcLength; ) + { + int c = *(asBYTE*)&bc[n]; + switch( asBCInfo[c].type ) + { + case asBCTYPE_wW_ARG: + case asBCTYPE_rW_DW_ARG: + case asBCTYPE_wW_QW_ARG: + case asBCTYPE_rW_ARG: + case asBCTYPE_wW_DW_ARG: + case asBCTYPE_wW_W_ARG: + case asBCTYPE_rW_QW_ARG: + case asBCTYPE_rW_W_DW_ARG: + case asBCTYPE_rW_DW_DW_ARG: + { + asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n])); + } + break; + + case asBCTYPE_wW_rW_ARG: + case asBCTYPE_wW_rW_DW_ARG: + case asBCTYPE_rW_rW_ARG: + { + asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n])); + asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n])); + } + break; + + case asBCTYPE_wW_rW_rW_ARG: + { + asBC_SWORDARG0(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG0(&bc[n])); + asBC_SWORDARG1(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG1(&bc[n])); + asBC_SWORDARG2(&bc[n]) = (short)AdjustStackPosition(asBC_SWORDARG2(&bc[n])); + } + break; + + default: + // The other types don't treat variables so won't be modified + break; + } + + n += asBCTypeSize[asBCInfo[c].type]; + } + + // Adjust the space needed for local variables + func->scriptData->variableSpace = AdjustStackPosition(func->scriptData->variableSpace); + + // Adjust the variable information. This will be used during the adjustment below + for( n = 0; n < func->scriptData->variables.GetLength(); n++ ) + { + func->scriptData->variables[n]->declaredAtProgramPos = instructionNbrToPos[func->scriptData->variables[n]->declaredAtProgramPos]; + func->scriptData->variables[n]->stackOffset = AdjustStackPosition(func->scriptData->variables[n]->stackOffset); + } + + // objVariablePos + for( n = 0; n < func->scriptData->objVariablePos.GetLength(); n++ ) + func->scriptData->objVariablePos[n] = AdjustStackPosition(func->scriptData->objVariablePos[n]); + + // Adjust the get offsets. This must be done in the second iteration because + // it relies on the function ids and variable position already being correct in the + // bytecodes that come after the GET instructions. + // TODO: optimize: Instead of doing a full extra loop. We can push the GET instructions + // on a stack, and then when a call instruction is found update all of them. + // This will also make the AdjustGetOffset() function quicker as it can + // receive the called function directly instead of having to search for it. + bc = func->scriptData->byteCode.AddressOf(); + for( n = 0; n < bcLength; ) + { + int c = *(asBYTE*)&bc[n]; + + if( c == asBC_GETREF || + c == asBC_GETOBJ || + c == asBC_GETOBJREF || + c == asBC_ChkNullS ) + { + asBC_WORDARG0(&bc[n]) = (asWORD)AdjustGetOffset(asBC_WORDARG0(&bc[n]), func, n); + } + + n += asBCTypeSize[asBCInfo[c].type]; + } + + for( n = 0; n < func->scriptData->objVariableInfo.GetLength(); n++ ) + { + // The program position must be adjusted as it is stored in number of instructions + func->scriptData->objVariableInfo[n].programPos = instructionNbrToPos[func->scriptData->objVariableInfo[n].programPos]; + func->scriptData->objVariableInfo[n].variableOffset = AdjustStackPosition(func->scriptData->objVariableInfo[n].variableOffset); + } + + for (n = 0; n < func->scriptData->tryCatchInfo.GetLength(); n++) + { + func->scriptData->tryCatchInfo[n].tryPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].tryPos]; + func->scriptData->tryCatchInfo[n].catchPos = instructionNbrToPos[func->scriptData->tryCatchInfo[n].catchPos]; + } + + // The program position (every even number) needs to be adjusted + // for the line numbers to be in number of dwords instead of number of instructions + for( n = 0; n < func->scriptData->lineNumbers.GetLength(); n += 2 ) + func->scriptData->lineNumbers[n] = instructionNbrToPos[func->scriptData->lineNumbers[n]]; + for( n = 0; n < func->scriptData->sectionIdxs.GetLength(); n += 2 ) + func->scriptData->sectionIdxs[n] = instructionNbrToPos[func->scriptData->sectionIdxs[n]]; + + CalculateStackNeeded(func); +} + +asCReader::SListAdjuster::SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *listType) : + reader(rd), allocMemBC(bc), maxOffset(0), patternType(listType), repeatCount(0), lastOffset(-1), nextOffset(0), nextTypeId(-1) +{ + asASSERT( patternType && (patternType->flags & asOBJ_LIST_PATTERN) ); + + // Find the first expected value in the list + asSListPatternNode *node = patternType->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; + asASSERT( node && node->type == asLPT_START ); + patternNode = node->next; +} + +int asCReader::SListAdjuster::AdjustOffset(int offset) +{ + if( offset < lastOffset ) + { + reader->Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + // If it is the same offset being accessed again, just return the same adjusted value + if( lastOffset == offset ) + return lastAdjustedOffset; + + lastOffset = offset; + lastAdjustedOffset = maxOffset; + + // What is being expected at this position? + if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ) + { + // Align the offset to 4 bytes boundary + if( maxOffset & 0x3 ) + { + maxOffset += 4 - (maxOffset & 0x3); + lastAdjustedOffset = maxOffset; + } + + // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too + maxOffset += 4; + nextOffset = offset+1; + return lastAdjustedOffset; + } + else if( patternNode->type == asLPT_TYPE ) + { + const asCDataType &dt = reinterpret_cast(patternNode)->dataType; + if( dt.GetTokenType() == ttQuestion ) + { + if( nextTypeId != -1 ) + { + if( repeatCount > 0 ) + repeatCount--; + + asCDataType nextdt = patternType->engine->GetDataTypeFromTypeId(nextTypeId); + asUINT size; + if(nextdt.IsObjectHandle() || (nextdt.GetTypeInfo() && (nextdt.GetTypeInfo()->flags & asOBJ_REF)) ) + size = AS_PTR_SIZE*4; + else + size = nextdt.GetSizeInMemoryBytes(); + + // Align the offset to 4 bytes boundary + if( size >= 4 && (maxOffset & 0x3) ) + { + maxOffset += 4 - (maxOffset & 0x3); + lastAdjustedOffset = maxOffset; + } + + // Only move the patternNode if we're not expecting any more repeated entries + if( repeatCount == 0 ) + patternNode = patternNode->next; + + nextTypeId = -1; + + maxOffset += size; + nextOffset = offset+1; + return lastAdjustedOffset; + } + else + { + // Align the offset to 4 bytes boundary + if( maxOffset & 0x3 ) + { + maxOffset += 4 - (maxOffset & 0x3); + lastAdjustedOffset = maxOffset; + } + + // The first adjustment is for the typeId + maxOffset += 4; + nextOffset = offset+1; + return lastAdjustedOffset; + } + } + else + { + // Determine the size of the element + asUINT size; + if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) ) + size = AS_PTR_SIZE*4; + else + size = dt.GetSizeInMemoryBytes(); + + // If values are skipped, the offset needs to be incremented + while( nextOffset <= offset ) + { + if( repeatCount > 0 ) + repeatCount--; + + // Align the offset to 4 bytes boundary + if( size >= 4 && (maxOffset & 0x3) ) + maxOffset += 4 - (maxOffset & 0x3); + + lastAdjustedOffset = maxOffset; + nextOffset += 1; + maxOffset += size; + } + + // Only move the patternNode if we're not expecting any more repeated entries + if( repeatCount == 0 ) + patternNode = patternNode->next; + + nextOffset = offset+1; + return lastAdjustedOffset; + } + } + else if( patternNode->type == asLPT_START ) + { + if( repeatCount > 0 ) + repeatCount--; + SInfo info = {repeatCount, patternNode}; + stack.PushLast(info); + + repeatCount = 0; + patternNode = patternNode->next; + + lastOffset--; + return AdjustOffset(offset); + } + else if( patternNode->type == asLPT_END ) + { + if( stack.GetLength() == 0 ) + { + reader->Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + SInfo info = stack.PopLast(); + repeatCount = info.repeatCount; + if( repeatCount ) + patternNode = info.startNode; + else + patternNode = patternNode->next; + + lastOffset--; + return AdjustOffset(offset); + } + else + { + // Something is wrong with the pattern list declaration + reader->Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + UNREACHABLE_RETURN; +} + +void asCReader::SListAdjuster::SetRepeatCount(asUINT rc) +{ + // Make sure the list is expecting a repeat at this location + asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ); + + // Now move to the next patternNode + patternNode = patternNode->next; + + repeatCount = rc; +} + +void asCReader::SListAdjuster::AdjustAllocMem() +{ + allocMemBC[1] = maxOffset; +} + +void asCReader::SListAdjuster::SetNextType(int typeId) +{ + asASSERT( nextTypeId == -1 ); + + nextTypeId = typeId; +} + +void asCReader::CalculateStackNeeded(asCScriptFunction *func) +{ + asASSERT( func->scriptData ); + + int largestStackUsed = 0; + + // Clear the known stack size for each bytecode + asCArray stackSize; + stackSize.SetLength(func->scriptData->byteCode.GetLength()); + memset(&stackSize[0], -1, stackSize.GetLength()*4); + + // Add the first instruction to the list of unchecked code + // paths and set the stack size at that instruction to variableSpace + asCArray paths; + paths.PushLast(0); + stackSize[0] = func->scriptData->variableSpace; + + // Go through each of the code paths + for( asUINT p = 0; p < paths.GetLength(); ++p ) + { + asUINT pos = paths[p]; + int currStackSize = stackSize[pos]; + + asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[pos]; + if( bc == asBC_RET ) + continue; + + // Determine the change in stack size for this instruction + int stackInc = asBCInfo[bc].stackInc; + if( stackInc == 0xFFFF ) + { + // Determine the true delta from the instruction arguments + if( bc == asBC_CALL || + bc == asBC_CALLSYS || + bc == asBC_Thiscall1 || + bc == asBC_CALLBND || + bc == asBC_ALLOC || + bc == asBC_CALLINTF || + bc == asBC_CallPtr ) + { + asCScriptFunction *called = GetCalledFunction(func, pos); + if( called ) + { + stackInc = -called->GetSpaceNeededForArguments(); + if( called->objectType ) + stackInc -= AS_PTR_SIZE; + if( called->DoesReturnOnStack() ) + stackInc -= AS_PTR_SIZE; + } + else + { + // It is an allocation for an object without a constructor + asASSERT( bc == asBC_ALLOC ); + stackInc = -AS_PTR_SIZE; + } + } + } + + currStackSize += stackInc; + asASSERT( currStackSize >= 0 ); + + if( currStackSize > largestStackUsed ) + largestStackUsed = currStackSize; + + if( bc == asBC_JMP ) + { + // Find the label that we should jump to + int offset = asBC_INTARG(&func->scriptData->byteCode[pos]); + pos += 2 + offset; + + // Add the destination as a new path + if( stackSize[pos] == -1 ) + { + stackSize[pos] = currStackSize; + paths.PushLast(pos); + } + else + asASSERT(stackSize[pos] == currStackSize); + continue; + } + else if( bc == asBC_JZ || bc == asBC_JNZ || + bc == asBC_JLowZ || bc == asBC_JLowNZ || + bc == asBC_JS || bc == asBC_JNS || + bc == asBC_JP || bc == asBC_JNP ) + { + // Find the label that is being jumped to + int offset = asBC_INTARG(&func->scriptData->byteCode[pos]); + + // Add both paths to the code paths + pos += 2; + if( stackSize[pos] == -1 ) + { + stackSize[pos] = currStackSize; + paths.PushLast(pos); + } + else + asASSERT(stackSize[pos] == currStackSize); + + pos += offset; + if( stackSize[pos] == -1 ) + { + stackSize[pos] = currStackSize; + paths.PushLast(pos); + } + else + asASSERT(stackSize[pos] == currStackSize); + + continue; + } + else if( bc == asBC_JMPP ) + { + pos++; + + // Add all subsequent JMP instructions to the path + while( *(asBYTE*)&func->scriptData->byteCode[pos] == asBC_JMP ) + { + if( stackSize[pos] == -1 ) + { + stackSize[pos] = currStackSize; + paths.PushLast(pos); + } + else + asASSERT(stackSize[pos] == currStackSize); + pos += 2; + } + continue; + } + else + { + // Add next instruction to the paths + pos += asBCTypeSize[asBCInfo[bc].type]; + if( stackSize[pos] == -1 ) + { + stackSize[pos] = currStackSize; + paths.PushLast(pos); + } + else + asASSERT(stackSize[pos] == currStackSize); + + continue; + } + } + + func->scriptData->stackNeeded = largestStackUsed; +} + +void asCReader::CalculateAdjustmentByPos(asCScriptFunction *func) +{ + // Adjust the offset of all negative variables (parameters) as + // all pointers have been stored as having a size of 1 dword + asUINT n; + asCArray adjustments; + asUINT offset = 0; + if( func->objectType ) + { + adjustments.PushLast(offset); + adjustments.PushLast(1-AS_PTR_SIZE); + offset += 1; + } + if( func->DoesReturnOnStack() ) + { + adjustments.PushLast(offset); + adjustments.PushLast(1-AS_PTR_SIZE); + offset += 1; + } + for( n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + if( !func->parameterTypes[n].IsPrimitive() || + func->parameterTypes[n].IsReference() ) + { + adjustments.PushLast(offset); + adjustments.PushLast(1-AS_PTR_SIZE); + offset += 1; + } + else + { + asASSERT( func->parameterTypes[n].IsPrimitive() ); + offset += func->parameterTypes[n].GetSizeOnStackDWords(); + } + } + + // Build look-up table with the adjustments for each stack position + adjustNegativeStackByPos.SetLength(offset); + memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int)); + for( n = 0; n < adjustments.GetLength(); n+=2 ) + { + int pos = adjustments[n]; + int adjust = adjustments[n+1]; + + for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ ) + adjustNegativeStackByPos[i] += adjust; + } + + // The bytecode has been stored as if all object variables take up only 1 dword. + // It is necessary to adjust to the size according to the current platform. + adjustments.SetLength(0); + int highestPos = 0; + for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ ) + { + // Determine the size the variable currently occupies on the stack + int size = AS_PTR_SIZE; + + // objVariableTypes is null if the type is a null pointer + if( func->scriptData->objVariableTypes[n] && + (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && + n >= func->scriptData->objVariablesOnHeap ) + { + size = func->scriptData->objVariableTypes[n]->GetSize(); + if( size < 4 ) + size = 1; + else + size /= 4; + } + + // Check if type has a different size than stored + if( size > 1 ) + { + if( func->scriptData->objVariablePos[n] > highestPos ) + highestPos = func->scriptData->objVariablePos[n]; + + adjustments.PushLast(func->scriptData->objVariablePos[n]); + adjustments.PushLast(size-1); + } + } + + // Count position 0 too + adjustByPos.SetLength(highestPos+1); + memset(adjustByPos.AddressOf(), 0, adjustByPos.GetLength()*sizeof(int)); + + // Build look-up table with the adjustments for each stack position + for( n = 0; n < adjustments.GetLength(); n+=2 ) + { + int pos = adjustments[n]; + int adjust = adjustments[n+1]; + + for( asUINT i = pos; i < adjustByPos.GetLength(); i++ ) + adjustByPos[i] += adjust; + } +} + +int asCReader::AdjustStackPosition(int pos) +{ + if( pos >= (int)adjustByPos.GetLength() ) + { + // It can be higher for primitives allocated on top of highest object variable + if( adjustByPos.GetLength() ) + pos += (short)adjustByPos[adjustByPos.GetLength()-1]; + } + else if( pos >= 0 ) + pos += (short)adjustByPos[pos]; + else if( -pos >= (int)adjustNegativeStackByPos.GetLength() ) + Error(TXT_INVALID_BYTECODE_d); + else + pos += (short)adjustNegativeStackByPos[-pos]; + + return pos; +} + +asCScriptFunction *asCReader::GetCalledFunction(asCScriptFunction *func, asDWORD programPos) +{ + asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[programPos]; + + if( bc == asBC_CALL || + bc == asBC_CALLSYS || + bc == asBC_Thiscall1 || + bc == asBC_CALLINTF ) + { + // Find the function from the function id in bytecode + int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]); + return engine->scriptFunctions[funcId]; + } + else if( bc == asBC_ALLOC ) + { + // Find the function from the function id in the bytecode + int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos+AS_PTR_SIZE]); + return engine->scriptFunctions[funcId]; + } + else if( bc == asBC_CALLBND ) + { + // Find the function from the engine's bind array + int funcId = asBC_INTARG(&func->scriptData->byteCode[programPos]); + return engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature; + } + else if( bc == asBC_CallPtr ) + { + asUINT v; + int var = asBC_SWORDARG0(&func->scriptData->byteCode[programPos]); + + // Find the funcdef from the local variable + for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) + if( func->scriptData->objVariablePos[v] == var ) + return CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; + + // Look in parameters + int paramPos = 0; + if( func->objectType ) + paramPos -= AS_PTR_SIZE; + if( func->DoesReturnOnStack() ) + paramPos -= AS_PTR_SIZE; + for( v = 0; v < func->parameterTypes.GetLength(); v++ ) + { + if (var == paramPos) + { + if (func->parameterTypes[v].IsFuncdef()) + return CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; + else + { + error = true; + return 0; + } + } + paramPos -= func->parameterTypes[v].GetSizeOnStackDWords(); + } + } + + return 0; +} + +int asCReader::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos) +{ + // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime + // the function can remember where it found the function and check if the programPos is still valid + + // Get offset 0 doesn't need adjustment + if( offset == 0 ) return 0; + + bool bcAlloc = false; + + // Find out which function that will be called + asCScriptFunction *calledFunc = 0; + int stackDelta = 0; + for( asUINT n = programPos; func->scriptData->byteCode.GetLength(); ) + { + asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n]; + if( bc == asBC_CALL || + bc == asBC_CALLSYS || + bc == asBC_Thiscall1 || + bc == asBC_CALLINTF || + bc == asBC_ALLOC || + bc == asBC_CALLBND || + bc == asBC_CallPtr ) + { + // The alloc instruction allocates the object memory + // so it doesn't take the this pointer as input + if (bc == asBC_ALLOC) + bcAlloc = true; + + calledFunc = GetCalledFunction(func, n); + break; + } + else if( bc == asBC_REFCPY || + bc == asBC_COPY ) + { + // In this case we know there is only 1 pointer on the stack above + asASSERT( offset == 1 ); + return offset - (1 - AS_PTR_SIZE); + } + + // Keep track of the stack size between the + // instruction that needs to be adjusted and the call + stackDelta += asBCInfo[bc].stackInc; + + n += asBCTypeSize[asBCInfo[bc].type]; + } + + if( calledFunc == 0 ) + { + Error(TXT_INVALID_BYTECODE_d); + return offset; + } + + // Count the number of pointers pushed on the stack above the + // current offset, and then adjust the offset accordingly + asUINT numPtrs = 0; + int currOffset = -stackDelta; + if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) + { + currOffset++; + if( currOffset > 0 ) + numPtrs++; +#if AS_PTR_SIZE == 2 + // For 64bit platforms it is necessary to increment the currOffset by one more + // DWORD since the stackDelta was counting the full 64bit size of the pointer + else if( stackDelta ) + currOffset++; +#endif + } + if( offset > currOffset && calledFunc->DoesReturnOnStack() ) + { + currOffset++; + if( currOffset > 0 ) + numPtrs++; +#if AS_PTR_SIZE == 2 + // For 64bit platforms it is necessary to increment the currOffset by one more + // DWORD since the stackDelta was counting the full 64bit size of the pointer + else if( stackDelta ) + currOffset++; +#endif + } + for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ ) + { + if( offset <= currOffset ) break; + + if( !calledFunc->parameterTypes[p].IsPrimitive() || + calledFunc->parameterTypes[p].IsReference() ) + { + currOffset++; + if( currOffset > 0 ) + numPtrs++; +#if AS_PTR_SIZE == 2 + // For 64bit platforms it is necessary to increment the currOffset by one more + // DWORD since the stackDelta was counting the full 64bit size of the pointer + else if( stackDelta ) + currOffset++; +#endif + + // The variable arg ? has an additiona 32bit integer with the typeid + if( calledFunc->parameterTypes[p].IsAnyType() ) + currOffset += 1; + } + else + { + // Enums or built-in primitives are passed by value + asASSERT( calledFunc->parameterTypes[p].IsPrimitive() ); + currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords(); + } + } + + return offset - numPtrs * (1 - AS_PTR_SIZE); +} + +int asCReader::FindTypeId(int idx) +{ + if( idx >= 0 && idx < (int)usedTypeIds.GetLength() ) + return usedTypeIds[idx]; + else + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } +} + +asCTypeInfo *asCReader::FindType(int idx) +{ + if( idx < 0 || idx >= (int)usedTypes.GetLength() ) + { + Error(TXT_INVALID_BYTECODE_d); + return 0; + } + + return usedTypes[idx]; +} + +#ifndef AS_NO_COMPILER + +asCWriter::asCWriter(asCModule* _module, asIBinaryStream* _stream, asCScriptEngine* _engine, bool _stripDebug) + : module(_module), stream(_stream), engine(_engine), stripDebugInfo(_stripDebug), error(false), bytesWritten(0) +{ +} + +int asCWriter::Error(const char *msg) +{ + // Don't write if it has already been reported an error earlier + if (!error) + { + asCString str; + str.Format(msg, bytesWritten); + engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + error = true; + } + + return asERROR; +} + +int asCWriter::WriteData(const void *data, asUINT size) +{ + asASSERT(size == 1 || size == 2 || size == 4 || size == 8); + int ret = 0; +#if defined(AS_BIG_ENDIAN) + for( asUINT n = 0; ret >= 0 && n < size; n++ ) + ret = stream->Write(((asBYTE*)data)+n, 1); +#else + for( int n = size-1; ret >= 0 && n >= 0; n-- ) + ret = stream->Write(((asBYTE*)data)+n, 1); +#endif + if (ret < 0) + Error(TXT_UNEXPECTED_END_OF_FILE); + bytesWritten += size; + return ret; +} + +int asCWriter::Write() +{ + TimeIt("asCWriter::Write"); + + unsigned long i, count; + + // Store everything in the same order that the builder parses scripts + + // TODO: Should be possible to skip saving the enum values. They are usually not needed after the script is compiled anyway + // TODO: Should be possible to skip saving the typedefs. They are usually not needed after the script is compiled anyway + // TODO: Should be possible to skip saving constants. They are usually not needed after the script is compiled anyway + + // Write the flag as 1byte even on platforms with 4byte booleans + WriteEncodedInt64(stripDebugInfo ? 1 : 0); + + // Store enums + { + TimeIt("store enums"); + + count = (asUINT)module->m_enumTypes.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + { + WriteTypeDeclaration(module->m_enumTypes[i], 1); + WriteTypeDeclaration(module->m_enumTypes[i], 2); + } + } + + // Store type declarations first + { + TimeIt("type declarations"); + + count = (asUINT)module->m_classTypes.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + { + // Store only the name of the class/interface types + WriteTypeDeclaration(module->m_classTypes[i], 1); + } + } + + // Store func defs + { + TimeIt("func defs"); + + count = (asUINT)module->m_funcDefs.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + WriteFunction(module->m_funcDefs[i]->funcdef); + } + + // Now store all interface methods + { + TimeIt("interface methods"); + + count = (asUINT)module->m_classTypes.GetLength(); + for( i = 0; i < count; i++ ) + { + if( module->m_classTypes[i]->IsInterface() ) + WriteTypeDeclaration(module->m_classTypes[i], 2); + } + } + + // Then store the class methods and behaviours + { + TimeIt("class methods and behaviours"); + + for( i = 0; i < count; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + WriteTypeDeclaration(module->m_classTypes[i], 2); + } + } + + // Then store the class properties + { + TimeIt("class properties"); + + for( i = 0; i < count; ++i ) + { + if( !module->m_classTypes[i]->IsInterface() ) + WriteTypeDeclaration(module->m_classTypes[i], 3); + } + } + + // Store typedefs + { + TimeIt("type defs"); + + count = (asUINT)module->m_typeDefs.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; i++ ) + { + WriteTypeDeclaration(module->m_typeDefs[i], 1); + WriteTypeDeclaration(module->m_typeDefs[i], 2); + } + } + + // scriptGlobals[] + { + TimeIt("script globals"); + + count = (asUINT)module->m_scriptGlobals.GetSize(); + WriteEncodedInt64(count); + asCSymbolTable::iterator it = module->m_scriptGlobals.List(); + for( ; it; it++ ) + WriteGlobalProperty(*it); + } + + // scriptFunctions[] + { + TimeIt("scriptFunctions"); + + count = 0; + for( i = 0; i < module->m_scriptFunctions.GetLength(); i++ ) + if( module->m_scriptFunctions[i]->objectType == 0 ) + count++; + WriteEncodedInt64(count); + for( i = 0; i < module->m_scriptFunctions.GetLength(); ++i ) + if( module->m_scriptFunctions[i]->objectType == 0 ) + WriteFunction(module->m_scriptFunctions[i]); + } + + // globalFunctions[] + { + TimeIt("globalFunctions"); + + count = (int)module->m_globalFunctions.GetSize(); + asCSymbolTable::iterator funcIt = module->m_globalFunctions.List(); + WriteEncodedInt64(count); + while( funcIt ) + { + WriteFunction(*funcIt); + funcIt++; + } + } + + // bindInformations[] + { + TimeIt("bindInformations"); + + count = (asUINT)module->m_bindInformations.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; ++i ) + { + WriteFunction(module->m_bindInformations[i]->importedFunctionSignature); + WriteString(&module->m_bindInformations[i]->importFromModule); + } + } + + // usedTypes[] + { + TimeIt("usedTypes"); + + count = (asUINT)usedTypes.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; ++i ) + WriteTypeInfo(usedTypes[i]); + } + + // usedTypeIds[] + WriteUsedTypeIds(); + + // usedFunctions[] + WriteUsedFunctions(); + + // usedGlobalProperties[] + WriteUsedGlobalProps(); + + // usedStringConstants[] + WriteUsedStringConstants(); + + // usedObjectProperties[] + WriteUsedObjectProps(); + + return error ? asERROR : asSUCCESS; +} + +int asCWriter::FindStringConstantIndex(void *str) +{ + asSMapNode *cursor = 0; + if (stringToIndexMap.MoveTo(&cursor, str)) + return cursor->value; + + usedStringConstants.PushLast(str); + int index = int(usedStringConstants.GetLength() - 1); + stringToIndexMap.Insert(str, index); + return index; +} + +void asCWriter::WriteUsedStringConstants() +{ + TimeIt("asCWriter::WriteUsedStringConstants"); + + asUINT count = (asUINT)usedStringConstants.GetLength(); + WriteEncodedInt64(count); + + asCString str; + for (asUINT i = 0; i < count; ++i) + { + asUINT length; + engine->stringFactory->GetRawStringData(usedStringConstants[i], 0, &length); + str.SetLength(length); + engine->stringFactory->GetRawStringData(usedStringConstants[i], str.AddressOf(), &length); + WriteString(&str); + } +} + +void asCWriter::WriteUsedFunctions() +{ + TimeIt("asCWriter::WriteUsedFunctions"); + + asUINT count = (asUINT)usedFunctions.GetLength(); + WriteEncodedInt64(count); + + for( asUINT n = 0; n < usedFunctions.GetLength(); n++ ) + { + char c; + + // Write enough data to be able to uniquely identify the function upon load + asCScriptFunction *func = usedFunctions[n]; + if(func) + { + // Is the function from the module or the application? + c = func->module ? 'm' : 'a'; + + // Functions and methods that are shared should be stored as 's' as the bytecode + // may be imported from other modules (even if the current module have received ownership) + if (c == 'm' && func->IsShared() ) + c = 's'; + + WriteData(&c, 1); + WriteFunctionSignature(func); + } + else + { + // null function pointer + c = 'n'; + WriteData(&c, 1); + } + } +} + +void asCWriter::WriteFunctionSignature(asCScriptFunction *func) +{ + asUINT i, count; + + WriteString(&func->name); + if( func->name == DELEGATE_FACTORY ) + { + // It's not necessary to write anything else + return; + } + + WriteDataType(&func->returnType); + + count = (asUINT)func->parameterTypes.GetLength(); + WriteEncodedInt64(count); + for( i = 0; i < count; ++i ) + WriteDataType(&func->parameterTypes[i]); + + // Only write the inout flags if any of them are set + // If the number of parameters is 0, then no need to save this + if (func->parameterTypes.GetLength() > 0) + { + count = 0; + for (i = asUINT(func->inOutFlags.GetLength()); i > 0; i--) + if (func->inOutFlags[i - 1] != asTM_NONE) + { + count = i; + break; + } + WriteEncodedInt64(count); + for (i = 0; i < count; ++i) + WriteEncodedInt64(func->inOutFlags[i]); + } + + WriteEncodedInt64(func->funcType); + + // Write the default args, from last to first + // If the number of parameters is 0, then no need to save this + if (func->parameterTypes.GetLength() > 0) + { + count = 0; + for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; ) + if (func->defaultArgs[i]) + count++; + WriteEncodedInt64(count); + for (i = (asUINT)func->defaultArgs.GetLength(); i-- > 0; ) + if (func->defaultArgs[i]) + WriteString(func->defaultArgs[i]); + } + + WriteTypeInfo(func->objectType); + + if( func->objectType ) + { + asBYTE b = 0; + b += func->IsReadOnly() ? 1 : 0; + b += func->IsPrivate() ? 2 : 0; + b += func->IsProtected() ? 4 : 0; + WriteData(&b, 1); + } + else + { + if (func->funcType == asFUNC_FUNCDEF) + { + if (func->nameSpace) + { + // This funcdef was declared as global entity + asBYTE b = 'n'; + WriteData(&b, 1); + WriteString(&func->nameSpace->name); + } + else + { + // This funcdef was declared as class member + asBYTE b = 'o'; + WriteData(&b, 1); + WriteTypeInfo(func->funcdefType->parentClass); + } + } + else + WriteString(&func->nameSpace->name); + } +} + +void asCWriter::WriteFunction(asCScriptFunction* func) +{ + char c; + + // If there is no function, then store a null char + if( func == 0 ) + { + c = '\0'; + WriteData(&c, 1); + return; + } + + // First check if the function has been saved already + for( asUINT f = 0; f < savedFunctions.GetLength(); f++ ) + { + if( savedFunctions[f] == func ) + { + c = 'r'; + WriteData(&c, 1); + WriteEncodedInt64(f); + return; + } + } + + // Keep a reference to the function in the list + savedFunctions.PushLast(func); + + c = 'f'; + WriteData(&c, 1); + + asUINT i, count; + + WriteFunctionSignature(func); + + if( func->funcType == asFUNC_SCRIPT ) + { + // Skip this for external shared entities + if (module->m_externalTypes.IndexOf(func->objectType) >= 0) + return; + + char bits = 0; + bits += func->IsShared() ? 1 : 0; + bits += func->dontCleanUpOnException ? 2 : 0; + if (module->m_externalFunctions.IndexOf(func) >= 0) + bits += 4; + if (func->scriptData->objVariablePos.GetLength() || func->scriptData->objVariableInfo.GetLength()) + bits += 8; + if (func->scriptData->tryCatchInfo.GetLength()) + bits += 16; + bits += func->IsExplicit() ? 32 : 0; + WriteData(&bits, 1); + + // For external shared functions the rest is not needed + if (bits & 4) + return; + + // Calculate the adjustment by position lookup table + CalculateAdjustmentByPos(func); + + WriteByteCode(func); + + asDWORD varSpace = AdjustStackPosition(func->scriptData->variableSpace); + WriteEncodedInt64(varSpace); + + if (bits & 8) + { + count = (asUINT)func->scriptData->objVariablePos.GetLength(); + WriteEncodedInt64(count); + for (i = 0; i < count; ++i) + { + WriteTypeInfo(func->scriptData->objVariableTypes[i]); + WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariablePos[i])); + } + if (count > 0) + WriteEncodedInt64(func->scriptData->objVariablesOnHeap); + + WriteEncodedInt64((asUINT)func->scriptData->objVariableInfo.GetLength()); + for (i = 0; i < func->scriptData->objVariableInfo.GetLength(); ++i) + { + // The program position must be adjusted to be in number of instructions + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->objVariableInfo[i].programPos]); + WriteEncodedInt64(AdjustStackPosition(func->scriptData->objVariableInfo[i].variableOffset)); + WriteEncodedInt64(func->scriptData->objVariableInfo[i].option); + } + } + + if (bits & 16) + { + // Write info on try/catch blocks + WriteEncodedInt64((asUINT)func->scriptData->tryCatchInfo.GetLength()); + for (i = 0; i < func->scriptData->tryCatchInfo.GetLength(); ++i) + { + // The program position must be adjusted to be in number of instructions + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].tryPos]); + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->tryCatchInfo[i].catchPos]); + } + } + + // The program position (every even number) needs to be adjusted + // to be in number of instructions instead of DWORD offset + if( !stripDebugInfo ) + { + asUINT length = (asUINT)func->scriptData->lineNumbers.GetLength(); + WriteEncodedInt64(length); + for( i = 0; i < length; ++i ) + { + if( (i & 1) == 0 ) + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->lineNumbers[i]]); + else + WriteEncodedInt64(func->scriptData->lineNumbers[i]); + } + + // Write the array of script sections + length = (asUINT)func->scriptData->sectionIdxs.GetLength(); + WriteEncodedInt64(length); + for( i = 0; i < length; ++i ) + { + if( (i & 1) == 0 ) + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->sectionIdxs[i]]); + else + { + if( func->scriptData->sectionIdxs[i] >= 0 ) + WriteString(engine->scriptSectionNames[func->scriptData->sectionIdxs[i]]); + else + { + c = 0; + WriteData(&c, 1); + } + } + } + } + + // Write the variable information + if( !stripDebugInfo ) + { + WriteEncodedInt64((asUINT)func->scriptData->variables.GetLength()); + for( i = 0; i < func->scriptData->variables.GetLength(); i++ ) + { + // The program position must be adjusted to be in number of instructions + WriteEncodedInt64(bytecodeNbrByPos[func->scriptData->variables[i]->declaredAtProgramPos]); + // The stack position must be adjusted according to the pointer sizes + WriteEncodedInt64(AdjustStackPosition(func->scriptData->variables[i]->stackOffset)); + WriteString(&func->scriptData->variables[i]->name); + WriteDataType(&func->scriptData->variables[i]->type); + } + } + + // Store script section name + if( !stripDebugInfo ) + { + if( func->scriptData->scriptSectionIdx >= 0 ) + WriteString(engine->scriptSectionNames[func->scriptData->scriptSectionIdx]); + else + { + c = 0; + WriteData(&c, 1); + } + WriteEncodedInt64(func->scriptData->declaredAt); + } + + // Store the parameter names + if( !stripDebugInfo ) + { + count = asUINT(func->parameterNames.GetLength()); + WriteEncodedInt64(count); + for( asUINT n = 0; n < count; n++ ) + WriteString(&func->parameterNames[n]); + } + } + else if( func->funcType == asFUNC_VIRTUAL || func->funcType == asFUNC_INTERFACE ) + { + // TODO: Do we really need to store this? It can probably be reconstructed by the reader + WriteEncodedInt64(func->vfTableIdx); + } + else if( func->funcType == asFUNC_FUNCDEF ) + { + char bits = 0; + bits += func->IsShared() ? 1 : 0; + if (module->m_externalTypes.IndexOf(func->funcdefType) >= 0) + bits += 2; + WriteData(&bits,1); + } +} + +void asCWriter::WriteTypeDeclaration(asCTypeInfo *type, int phase) +{ + if( phase == 1 ) + { + // name + WriteString(&type->name); + // flags + WriteData(&type->flags, 4); + + // size + // TODO: Do we really need to store this? The reader should be able to + // determine the correct size from the object type's flags + if( (type->flags & asOBJ_SCRIPT_OBJECT) && type->size > 0 ) + { + // The size for script objects may vary from platform to platform so + // only store 1 to diferentiate from interfaces that have size 0. + WriteEncodedInt64(1); + } + else + { + // Enums, typedefs, and interfaces have fixed sizes independently + // of platform so it is safe to serialize the size directly. + WriteEncodedInt64(type->size); + } + + // namespace + WriteString(&type->nameSpace->name); + + // external shared flag + if ((type->flags & asOBJ_SHARED)) + { + char c = ' '; + if (module->m_externalTypes.IndexOf(type) >= 0) + c = 'e'; + WriteData(&c, 1); + } + } + else if( phase == 2 ) + { + // external shared types doesn't need to save this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + if(type->flags & asOBJ_ENUM ) + { + // enumValues[] + asCEnumType *t = CastToEnumType(type); + int size = (int)t->enumValues.GetLength(); + WriteEncodedInt64(size); + + for( int n = 0; n < size; n++ ) + { + WriteString(&t->enumValues[n]->name); + WriteData(&t->enumValues[n]->value, 4); + } + } + else if(type->flags & asOBJ_TYPEDEF ) + { + asCTypedefType *td = CastToTypedefType(type); + eTokenType t = td->aliasForType.GetTokenType(); + WriteEncodedInt64(t); + } + else + { + asCObjectType *t = CastToObjectType(type); + WriteTypeInfo(t->derivedFrom); + + // interfaces[] / interfaceVFTOffsets[] + // TOOD: Is it really necessary to store the VFTOffsets? Can't the reader calculate those? + int size = (asUINT)t->interfaces.GetLength(); + WriteEncodedInt64(size); + asUINT n; + asASSERT( t->IsInterface() || t->interfaces.GetLength() == t->interfaceVFTOffsets.GetLength() ); + for( n = 0; n < t->interfaces.GetLength(); n++ ) + { + WriteTypeInfo(t->interfaces[n]); + if( !t->IsInterface() ) + WriteEncodedInt64(t->interfaceVFTOffsets[n]); + } + + // behaviours + // TODO: Default behaviours should just be stored as a indicator + // to avoid storing the actual function object + if( !t->IsInterface() && type->flags != asOBJ_TYPEDEF && type->flags != asOBJ_ENUM ) + { + WriteFunction(engine->scriptFunctions[t->beh.destruct]); + size = (int)t->beh.constructors.GetLength(); + WriteEncodedInt64(size); + for( n = 0; n < t->beh.constructors.GetLength(); n++ ) + { + WriteFunction(engine->scriptFunctions[t->beh.constructors[n]]); + WriteFunction(engine->scriptFunctions[t->beh.factories[n]]); + } + } + + // methods[] + // TODO: Avoid storing inherited methods in interfaces, as the reader + // can add those directly from the base interface + size = (int)t->methods.GetLength(); + WriteEncodedInt64(size); + for( n = 0; n < t->methods.GetLength(); n++ ) + { + WriteFunction(engine->scriptFunctions[t->methods[n]]); + } + + // virtualFunctionTable[] + // TODO: Is it really necessary to store this? Can't it be easily rebuilt by the reader + size = (int)t->virtualFunctionTable.GetLength(); + WriteEncodedInt64(size); + for( n = 0; n < (asUINT)size; n++ ) + { + WriteFunction(t->virtualFunctionTable[n]); + } + } + } + else if( phase == 3 ) + { + // external shared types doesn't need to save this + if ((type->flags & asOBJ_SHARED) && module->m_externalTypes.IndexOf(type) >= 0) + return; + + // properties[] + asCObjectType *t = CastToObjectType(type); + + // This is only done for object types + asASSERT(t); + + asUINT size = (asUINT)t->properties.GetLength(); + WriteEncodedInt64(size); + for (asUINT n = 0; n < t->properties.GetLength(); n++) + { + WriteObjectProperty(t->properties[n]); + } + } +} + +void asCWriter::WriteEncodedInt64(asINT64 i) +{ + asBYTE signBit = ( i & asINT64(1)<<63 ) ? 0x80 : 0; + if( signBit ) i = -i; + + asBYTE b; + if( i < (1<<6) ) + { + b = (asBYTE)(signBit + i); WriteData(&b, 1); + } + else if( i < (1<<13) ) + { + b = asBYTE(0x40 + signBit + (i >> 8)); WriteData(&b, 1); + b = asBYTE(i & 0xFF); WriteData(&b, 1); + } + else if( i < (1<<20) ) + { + b = asBYTE(0x60 + signBit + (i >> 16)); WriteData(&b, 1); + b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); + b = asBYTE(i & 0xFF); WriteData(&b, 1); + } + else if( i < (1<<27) ) + { + b = asBYTE(0x70 + signBit + (i >> 24)); WriteData(&b, 1); + b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); + b = asBYTE(i & 0xFF); WriteData(&b, 1); + } + else if( i < (asINT64(1)<<34) ) + { + b = asBYTE(0x78 + signBit + (i >> 32)); WriteData(&b, 1); + b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); + b = asBYTE(i & 0xFF); WriteData(&b, 1); + } + else if( i < (asINT64(1)<<41) ) + { + b = asBYTE(0x7C + signBit + (i >> 40)); WriteData(&b, 1); + b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); + b = asBYTE(i & 0xFF); WriteData(&b, 1); + } + else if( i < (asINT64(1)<<48) ) + { + b = asBYTE(0x7E + signBit + (i >> 48)); WriteData(&b, 1); + b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); + b = asBYTE(i & 0xFF); WriteData(&b, 1); + } + else + { + b = asBYTE(0x7F + signBit); WriteData(&b, 1); + b = asBYTE((i >> 56) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 48) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 40) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 32) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 24) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 16) & 0xFF); WriteData(&b, 1); + b = asBYTE((i >> 8) & 0xFF); WriteData(&b, 1); + b = asBYTE(i & 0xFF); WriteData(&b, 1); + } +} + +void asCWriter::WriteString(asCString* str) +{ + // First check if the string hasn't been saved already + asSMapNode *cursor = 0; + if (stringToIdMap.MoveTo(&cursor, *str)) + { + // Save a reference to the existing string + // The lowest bit is set to 1 to indicate a reference + WriteEncodedInt64(cursor->value*2+1); + return; + } + + // Save a new string + // The lowest bit is set to 0 to indicate a new string + asUINT len = (asUINT)str->GetLength(); + WriteEncodedInt64(len*2); + + if( len > 0 ) + { + stream->Write(str->AddressOf(), (asUINT)len); + bytesWritten += len; + + savedStrings.PushLast(*str); + stringToIdMap.Insert(*str, int(savedStrings.GetLength()) - 1); + } +} + +void asCWriter::WriteGlobalProperty(asCGlobalProperty* prop) +{ + // TODO: We might be able to avoid storing the name and type of the global + // properties twice if we merge this with the WriteUsedGlobalProperties. + WriteString(&prop->name); + WriteString(&prop->nameSpace->name); + WriteDataType(&prop->type); + + // Store the initialization function + WriteFunction(prop->GetInitFunc()); +} + +void asCWriter::WriteObjectProperty(asCObjectProperty* prop) +{ + WriteString(&prop->name); + WriteDataType(&prop->type); + int flags = 0; + if( prop->isPrivate ) flags |= 1; + if( prop->isProtected ) flags |= 2; + if( prop->isInherited ) flags |= 4; + WriteEncodedInt64(flags); +} + +void asCWriter::WriteDataType(const asCDataType *dt) +{ + // First check if the datatype has already been saved + for( asUINT n = 0; n < savedDataTypes.GetLength(); n++ ) + { + if( *dt == savedDataTypes[n] ) + { + WriteEncodedInt64(n+1); + return; + } + } + + // Indicate a new type with a null byte + asUINT c = 0; + WriteEncodedInt64(c); + + // Save the new datatype + savedDataTypes.PushLast(*dt); + + int t = dt->GetTokenType(); + WriteEncodedInt64(t); + if( t == ttIdentifier ) + WriteTypeInfo(dt->GetTypeInfo()); + + // Endianess safe bitmask + char bits = 0; + SAVE_TO_BIT(bits, dt->IsObjectHandle(), 0); + SAVE_TO_BIT(bits, dt->IsHandleToConst(), 1); + SAVE_TO_BIT(bits, dt->IsReference(), 2); + SAVE_TO_BIT(bits, dt->IsReadOnly(), 3); + WriteData(&bits, 1); +} + +void asCWriter::WriteTypeInfo(asCTypeInfo* ti) +{ + char ch; + + if( ti ) + { + // Check for template instances/specializations + asCObjectType *ot = CastToObjectType(ti); + if( ot && ot->templateSubTypes.GetLength() ) + { + // Check for list pattern type or template type + if( ot->flags & asOBJ_LIST_PATTERN ) + { + ch = 'l'; // list + WriteData(&ch, 1); + WriteTypeInfo(ot->templateSubTypes[0].GetTypeInfo()); + } + else + { + ch = 'a'; // array + WriteData(&ch, 1); + WriteString(&ot->name); + WriteString(&ot->nameSpace->name); + + WriteEncodedInt64(ot->templateSubTypes.GetLength()); + for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) + { + if( !ot->templateSubTypes[n].IsPrimitive() || ot->templateSubTypes[n].IsEnumType() ) + { + ch = 's'; // sub type + WriteData(&ch, 1); + WriteDataType(&ot->templateSubTypes[n]); + } + else + { + ch = 't'; // token + WriteData(&ch, 1); + eTokenType t = ot->templateSubTypes[n].GetTokenType(); + WriteEncodedInt64(t); + } + } + } + } + else if( ti->flags & asOBJ_TEMPLATE_SUBTYPE ) + { + ch = 's'; // sub type + WriteData(&ch, 1); + WriteString(&ti->name); + } + else if( !ti->GetParentType() ) + { + ch = 'o'; // object + WriteData(&ch, 1); + WriteString(&ti->name); + WriteString(&ti->nameSpace->name); + } + else + { + asASSERT(ti->flags & asOBJ_FUNCDEF); + + ch = 'c'; // child type + WriteData(&ch, 1); + WriteString(&ti->name); + WriteTypeInfo(CastToFuncdefType(ti)->parentClass); + } + } + else + { + ch = '\0'; + WriteData(&ch, 1); + } +} + +void asCWriter::CalculateAdjustmentByPos(asCScriptFunction *func) +{ + // Adjust the offset of all negative variables (parameters) so all pointers will have a size of 1 dword + asUINT n; + asCArray adjustments; + asUINT offset = 0; + if( func->objectType ) + { + adjustments.PushLast(offset); + adjustments.PushLast(1-AS_PTR_SIZE); + offset += AS_PTR_SIZE; + } + if( func->DoesReturnOnStack() ) + { + adjustments.PushLast(offset); + adjustments.PushLast(1-AS_PTR_SIZE); + offset += AS_PTR_SIZE; + } + for( n = 0; n < func->parameterTypes.GetLength(); n++ ) + { + if( !func->parameterTypes[n].IsPrimitive() || + func->parameterTypes[n].IsReference() ) + { + adjustments.PushLast(offset); + adjustments.PushLast(1-AS_PTR_SIZE); + offset += AS_PTR_SIZE; + } + else + { + asASSERT( func->parameterTypes[n].IsPrimitive() ); + offset += func->parameterTypes[n].GetSizeOnStackDWords(); + } + } + + // Build look-up table with the adjustments for each stack position + adjustNegativeStackByPos.SetLength(offset); + memset(adjustNegativeStackByPos.AddressOf(), 0, adjustNegativeStackByPos.GetLength()*sizeof(int)); + for( n = 0; n < adjustments.GetLength(); n+=2 ) + { + int pos = adjustments[n]; + int adjust = adjustments[n+1]; + + for( asUINT i = pos+1; i < adjustNegativeStackByPos.GetLength(); i++ ) + adjustNegativeStackByPos[i] += adjust; + } + + // Adjust the offset of all positive variables so that all object types and handles have a size of 1 dword + // This is similar to how the adjustment is done in the asCReader::TranslateFunction, only the reverse + adjustments.SetLength(0); + for( n = 0; n < func->scriptData->objVariableTypes.GetLength(); n++ ) + { + // Determine the size the variable currently occupies on the stack + int size = AS_PTR_SIZE; + + // objVariableTypes is null if the variable type is a null pointer + if( func->scriptData->objVariableTypes[n] && + (func->scriptData->objVariableTypes[n]->GetFlags() & asOBJ_VALUE) && + n >= func->scriptData->objVariablesOnHeap ) + { + size = func->scriptData->objVariableTypes[n]->GetSize(); + if( size < 4 ) + size = 1; + else + size /= 4; + } + + // If larger than 1 dword, adjust the offsets accordingly + if (size > 1) + { + // How much needs to be adjusted? + adjustments.PushLast(func->scriptData->objVariablePos[n]); + adjustments.PushLast(-(size - 1)); + } + } + + // Build look-up table with the adjustments for each stack position + adjustStackByPos.SetLength(func->scriptData->stackNeeded); + memset(adjustStackByPos.AddressOf(), 0, adjustStackByPos.GetLength()*sizeof(int)); + for( n = 0; n < adjustments.GetLength(); n+=2 ) + { + int pos = adjustments[n]; + int adjust = adjustments[n+1]; + + for( asUINT i = pos; i < adjustStackByPos.GetLength(); i++ ) + adjustStackByPos[i] += adjust; + } + + // Compute the sequence number of each bytecode instruction in order to update the jump offsets + asUINT length = func->scriptData->byteCode.GetLength(); + asDWORD *bc = func->scriptData->byteCode.AddressOf(); + bytecodeNbrByPos.SetLength(length); + asUINT num; + for( offset = 0, num = 0; offset < length; ) + { + bytecodeNbrByPos[offset] = num; + offset += asBCTypeSize[asBCInfo[*(asBYTE*)(bc+offset)].type]; + num++; + } + + // Store the number of instructions in the last position of bytecodeNbrByPos, + // so this can be easily queried in SaveBytecode. Normally this is already done + // as most functions end with BC_RET, but in some cases the last instruction in + // the function is not a BC_RET, e.g. when a function has a never ending loop. + bytecodeNbrByPos[length - 1] = num - 1; +} + +int asCWriter::AdjustStackPosition(int pos) +{ + if( pos >= (int)adjustStackByPos.GetLength() ) + { + // This happens for example if the function only have temporary variables + // The adjustByPos can also be empty if the function doesn't have any variables at all, but receive a handle by parameter + if( adjustStackByPos.GetLength() > 0 ) + pos += adjustStackByPos[adjustStackByPos.GetLength()-1]; + } + else if( pos >= 0 ) + pos += adjustStackByPos[pos]; + else + { + asASSERT( -pos < (int)adjustNegativeStackByPos.GetLength() ); + pos -= (short)adjustNegativeStackByPos[-pos]; + } + + return pos; +} + +int asCWriter::AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos) +{ + // TODO: optimize: multiple instructions for the same function doesn't need to look for the function everytime + // the function can remember where it found the function and check if the programPos is still valid + + // Get offset 0 doesn't need adjustment + if( offset == 0 ) return 0; + + bool bcAlloc = false; + + // Find out which function that will be called + asCScriptFunction *calledFunc = 0; + int stackDelta = 0; + for( asUINT n = programPos; n < func->scriptData->byteCode.GetLength(); ) + { + asBYTE bc = *(asBYTE*)&func->scriptData->byteCode[n]; + if( bc == asBC_CALL || + bc == asBC_CALLSYS || + bc == asBC_Thiscall1 || + bc == asBC_CALLINTF ) + { + // Find the function from the function id in bytecode + int funcId = asBC_INTARG(&func->scriptData->byteCode[n]); + calledFunc = engine->scriptFunctions[funcId]; + break; + } + else if( bc == asBC_ALLOC ) + { + // The alloc instruction doesn't take the object pointer on the stack, + // as the memory will be allocated by the instruction itself + bcAlloc = true; + + // Find the function from the function id in the bytecode + int funcId = asBC_INTARG(&func->scriptData->byteCode[n+AS_PTR_SIZE]); + calledFunc = engine->scriptFunctions[funcId]; + break; + } + else if( bc == asBC_CALLBND ) + { + // Find the function from the engine's bind array + int funcId = asBC_INTARG(&func->scriptData->byteCode[n]); + calledFunc = engine->importedFunctions[funcId & ~FUNC_IMPORTED]->importedFunctionSignature; + break; + } + else if( bc == asBC_CallPtr ) + { + int var = asBC_SWORDARG0(&func->scriptData->byteCode[n]); + asUINT v; + // Find the funcdef from the local variable + for( v = 0; v < func->scriptData->objVariablePos.GetLength(); v++ ) + { + if( func->scriptData->objVariablePos[v] == var ) + { + calledFunc = CastToFuncdefType(func->scriptData->objVariableTypes[v])->funcdef; + break; + } + } + if( !calledFunc ) + { + // Look in parameters + int paramPos = 0; + if( func->objectType ) + paramPos -= AS_PTR_SIZE; + if( func->DoesReturnOnStack() ) + paramPos -= AS_PTR_SIZE; + for( v = 0; v < func->parameterTypes.GetLength(); v++ ) + { + if( var == paramPos ) + { + calledFunc = CastToFuncdefType(func->parameterTypes[v].GetTypeInfo())->funcdef; + break; + } + paramPos -= func->parameterTypes[v].GetSizeOnStackDWords(); + } + } + break; + } + else if( bc == asBC_REFCPY || + bc == asBC_COPY ) + { + // In this case we know there is only 1 pointer on the stack above + asASSERT( offset == AS_PTR_SIZE ); + return offset + (1 - AS_PTR_SIZE); + } + + // Keep track of the stack size between the + // instruction that needs to be adjusted and the call + stackDelta += asBCInfo[bc].stackInc; + + n += asBCTypeSize[asBCInfo[bc].type]; + } + + asASSERT( calledFunc ); + + // Count the number of pointers pushed on the stack above the + // current offset, and then adjust the offset accordingly + asUINT numPtrs = 0; + int currOffset = -stackDelta; + if( offset > currOffset && calledFunc->GetObjectType() && !bcAlloc ) + { + currOffset += AS_PTR_SIZE; + if( currOffset > 0 ) + numPtrs++; + } + if( offset > currOffset && calledFunc->DoesReturnOnStack() ) + { + currOffset += AS_PTR_SIZE; + if( currOffset > 0 ) + numPtrs++; + } + for( asUINT p = 0; p < calledFunc->parameterTypes.GetLength(); p++ ) + { + if( offset <= currOffset ) break; + + if( !calledFunc->parameterTypes[p].IsPrimitive() || + calledFunc->parameterTypes[p].IsReference() ) + { + // objects and references are passed by pointer + currOffset += AS_PTR_SIZE; + if( currOffset > 0 ) + numPtrs++; + + // The variable arg ? has an additional 32bit int with the typeid + if( calledFunc->parameterTypes[p].IsAnyType() ) + currOffset += 1; + } + else + { + // built-in primitives or enums are passed by value + asASSERT( calledFunc->parameterTypes[p].IsPrimitive() ); + currOffset += calledFunc->parameterTypes[p].GetSizeOnStackDWords(); + } + } + + // The get offset must match one of the parameter offsets + asASSERT( offset == currOffset ); + + return offset + numPtrs * (1 - AS_PTR_SIZE); +} + +void asCWriter::WriteByteCode(asCScriptFunction *func) +{ + asDWORD *bc = func->scriptData->byteCode.AddressOf(); + size_t length = func->scriptData->byteCode.GetLength(); + + // The length cannot be stored, because it is platform dependent, + // instead we store the number of instructions + asUINT count = bytecodeNbrByPos[bytecodeNbrByPos.GetLength()-1] + 1; + WriteEncodedInt64(count); + + asDWORD *startBC = bc; + while( length ) + { + asDWORD tmpBC[4]; // The biggest instructions take up 4 DWORDs + asDWORD c = *(asBYTE*)bc; + + // Copy the instruction to a temp buffer so we can work on it before saving + memcpy(tmpBC, bc, asBCTypeSize[asBCInfo[c].type]*sizeof(asDWORD)); + + if( c == asBC_ALLOC ) // PTR_DW_ARG + { + // Translate the object type + asCObjectType *ot = *(asCObjectType**)(tmpBC+1); + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); + + // Translate the constructor func id, unless it is 0 + if( *(int*)&tmpBC[1+AS_PTR_SIZE] != 0 ) + { + // Increment 1 to the translated function id, as 0 will be reserved for no function + *(int*)&tmpBC[1+AS_PTR_SIZE] = 1+FindFunctionIndex(engine->scriptFunctions[*(int*)&tmpBC[1+AS_PTR_SIZE]]); + } + } + else if( c == asBC_REFCPY || // PTR_ARG + c == asBC_RefCpyV || // wW_PTR_ARG + c == asBC_OBJTYPE ) // PTR_ARG + { + // Translate object type pointers into indices + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(*(asCObjectType**)(tmpBC+1)); + } + else if( c == asBC_JitEntry ) // PTR_ARG + { + // We don't store the JIT argument + *(asPWORD*)(tmpBC+1) = 0; + } + else if( c == asBC_TYPEID || // DW_ARG + c == asBC_Cast ) // DW_ARG + { + // Translate type ids into indices + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); + } + else if( c == asBC_ADDSi || // W_DW_ARG + c == asBC_LoadThisR ) // W_DW_ARG + { + // Translate property offsets into indices + *(((short*)tmpBC)+1) = (short)FindObjectPropIndex(*(((short*)tmpBC)+1), *(int*)(tmpBC+1), bc); + + // Translate type ids into indices + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); + } + else if( c == asBC_LoadRObjR || // rW_W_DW_ARG + c == asBC_LoadVObjR ) // rW_W_DW_ARG + { + asCObjectType *ot = engine->GetObjectTypeFromTypeId(*(int*)(tmpBC+2)); + if( ot->flags & asOBJ_LIST_PATTERN ) + { + // List patterns have a different way of translating the offsets + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + *(((short*)tmpBC)+2) = (short)listAdj->AdjustOffset(*(((short*)tmpBC)+2), ot); + } + else + { + // Translate property offsets into indices + *(((short*)tmpBC)+2) = (short)FindObjectPropIndex(*(((short*)tmpBC)+2), *(int*)(tmpBC+2), bc); + } + + // Translate type ids into indices + *(int*)(tmpBC+2) = FindTypeIdIdx(*(int*)(tmpBC+2)); + } + else if( c == asBC_COPY ) // W_DW_ARG + { + // Translate type ids into indices + *(int*)(tmpBC+1) = FindTypeIdIdx(*(int*)(tmpBC+1)); + + // Update the WORDARG0 to 0, as this will be recalculated on the target platform + asBC_WORDARG0(tmpBC) = 0; + } + else if( c == asBC_RET ) // W_ARG + { + // Save with arg 0, as this will be recalculated on the target platform + asBC_WORDARG0(tmpBC) = 0; + } + else if( c == asBC_CALL || // DW_ARG + c == asBC_CALLINTF || // DW_ARG + c == asBC_CALLSYS || // DW_ARG + c == asBC_Thiscall1 ) // DW_ARG + { + // Translate the function id + *(int*)(tmpBC+1) = FindFunctionIndex(engine->scriptFunctions[*(int*)(tmpBC+1)]); + } + else if( c == asBC_FuncPtr ) // PTR_ARG + { + // Translate the function pointer + *(asPWORD*)(tmpBC+1) = FindFunctionIndex(*(asCScriptFunction**)(tmpBC+1)); + } + else if( c == asBC_CALLBND ) // DW_ARG + { + // Translate the function id + int funcId = tmpBC[1]; + for( asUINT n = 0; n < module->m_bindInformations.GetLength(); n++ ) + if( module->m_bindInformations[n]->importedFunctionSignature->id == funcId ) + { + funcId = n; + break; + } + + tmpBC[1] = funcId; + } + else if( c == asBC_PGA || // PTR_ARG + c == asBC_PshGPtr || // PTR_ARG + c == asBC_LDG || // PTR_ARG + c == asBC_PshG4 || // PTR_ARG + c == asBC_LdGRdR4 || // wW_PTR_ARG + c == asBC_CpyGtoV4 || // wW_PTR_ARG + c == asBC_CpyVtoG4 || // rW_PTR_ARG + c == asBC_SetG4 ) // PTR_DW_ARG + { + // Check if the address is a global property or a string constant + void *ptr = *(void**)(tmpBC + 1); + if (engine->varAddressMap.MoveTo(0, ptr)) + { + // Translate global variable pointers into indices + // Flag the first bit to signal global property + *(asPWORD*)(tmpBC + 1) = (FindGlobalPropPtrIndex(*(void**)(tmpBC + 1)) << 1) + 1; + } + else + { + // Only PGA and PshGPtr can hold string constants + asASSERT(c == asBC_PGA || c == asBC_PshGPtr); + + // Translate string constants into indices + // Leave the first bit clear to signal string constant + *(asPWORD*)(tmpBC + 1) = FindStringConstantIndex(*(void**)(tmpBC + 1)) << 1; + } + } + else if( c == asBC_JMP || // DW_ARG + c == asBC_JZ || + c == asBC_JNZ || + c == asBC_JLowZ || + c == asBC_JLowNZ || + c == asBC_JS || + c == asBC_JNS || + c == asBC_JP || + c == asBC_JNP ) // The JMPP instruction doesn't need modification + { + // Get the DWORD offset from arg + int offset = *(int*)(tmpBC+1); + + // Determine instruction number for next instruction and destination + int bcSeqNum = bytecodeNbrByPos[asUINT(bc - startBC)] + 1; + asDWORD *targetBC = bc + 2 + offset; + int targetBcSeqNum = bytecodeNbrByPos[asUINT(targetBC - startBC)]; + + // Set the offset in number of instructions + *(int*)(tmpBC+1) = targetBcSeqNum - bcSeqNum; + } + else if( c == asBC_GETOBJ || // W_ARG + c == asBC_GETOBJREF || + c == asBC_GETREF || + c == asBC_ChkNullS ) + { + // Adjust the offset according to the function call that comes after + asBC_WORDARG0(tmpBC) = (asWORD)AdjustGetOffset(asBC_WORDARG0(tmpBC), func, asDWORD(bc - startBC)); + } + else if( c == asBC_AllocMem ) + { + // It's not necessary to store the size of the list buffer, as it will be recalculated in the reader + asBC_DWORDARG(tmpBC) = 0; + + // Determine the type of the list pattern from the variable + short var = asBC_WORDARG0(tmpBC); + asCObjectType *ot = CastToObjectType(func->GetTypeInfoOfLocalVar(var)); + + // Create this helper object to adjust the offset of the elements accessed in the buffer + listAdjusters.PushLast(asNEW(SListAdjuster)(ot)); + } + else if( c == asBC_FREE ) // wW_PTR_ARG + { + // Translate object type pointers into indices + asCObjectType *ot = *(asCObjectType**)(tmpBC+1); + *(asPWORD*)(tmpBC+1) = FindTypeInfoIdx(ot); + + // Pop and destroy the list adjuster helper that was created with asBC_AllocMem + if( ot && (ot->flags & asOBJ_LIST_PATTERN) ) + { + SListAdjuster *list = listAdjusters.PopLast(); + asDELETE(list, SListAdjuster); + } + } + else if( c == asBC_SetListSize ) + { + // Adjust the offset in the initialization list + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); + + // Tell the adjuster how many repeated values there are + listAdj->SetRepeatCount(tmpBC[2]); + } + else if( c == asBC_PshListElmnt ) // W_DW_ARG + { + // Adjust the offset in the initialization list + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); + } + else if( c == asBC_SetListType ) + { + // Adjust the offset in the initialization list + SListAdjuster *listAdj = listAdjusters[listAdjusters.GetLength()-1]; + tmpBC[1] = listAdj->AdjustOffset(tmpBC[1], listAdj->patternType); + + // Inform the adjuster of the type id of the next element + listAdj->SetNextType(tmpBC[2]); + + // Translate the type id + tmpBC[2] = FindTypeIdIdx(tmpBC[2]); + } + // Adjust the variable offsets + switch( asBCInfo[c].type ) + { + case asBCTYPE_wW_ARG: + case asBCTYPE_rW_DW_ARG: + case asBCTYPE_wW_QW_ARG: + case asBCTYPE_rW_ARG: + case asBCTYPE_wW_DW_ARG: + case asBCTYPE_wW_W_ARG: + case asBCTYPE_rW_QW_ARG: + case asBCTYPE_rW_W_DW_ARG: + case asBCTYPE_rW_DW_DW_ARG: + { + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + } + break; + + case asBCTYPE_wW_rW_ARG: + case asBCTYPE_wW_rW_DW_ARG: + case asBCTYPE_rW_rW_ARG: + { + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); + } + break; + + case asBCTYPE_wW_rW_rW_ARG: + { + asBC_SWORDARG0(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG0(tmpBC)); + asBC_SWORDARG1(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG1(tmpBC)); + asBC_SWORDARG2(tmpBC) = (short)AdjustStackPosition(asBC_SWORDARG2(tmpBC)); + } + break; + + default: + // The other types don't treat variables so won't be modified + break; + } + + // TODO: bytecode: Must make sure that floats and doubles are always stored the same way regardless of platform. + // Some platforms may not use the IEEE 754 standard, in which case it is necessary to encode the values + + // Now store the instruction in the smallest possible way + switch( asBCInfo[c].type ) + { + case asBCTYPE_NO_ARG: + { + // Just write 1 byte + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + } + break; + case asBCTYPE_W_ARG: + case asBCTYPE_wW_ARG: + case asBCTYPE_rW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the argument + short w = *(((short*)tmpBC)+1); + WriteEncodedInt64(w); + } + break; + case asBCTYPE_rW_DW_ARG: + case asBCTYPE_wW_DW_ARG: + case asBCTYPE_W_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the word argument + short w = *(((short*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[1]); + } + break; + case asBCTYPE_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the argument + WriteEncodedInt64((int)tmpBC[1]); + } + break; + case asBCTYPE_DW_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[1]); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[2]); + } + break; + case asBCTYPE_wW_rW_rW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the first argument + short w = *(((short*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the second argument + w = *(((short*)tmpBC)+2); + WriteEncodedInt64(w); + + // Write the third argument + w = *(((short*)tmpBC)+3); + WriteEncodedInt64(w); + } + break; + case asBCTYPE_wW_rW_ARG: + case asBCTYPE_rW_rW_ARG: + case asBCTYPE_wW_W_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the first argument + short w = *(((short*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the second argument + w = *(((short*)tmpBC)+2); + WriteEncodedInt64(w); + } + break; + case asBCTYPE_wW_rW_DW_ARG: + case asBCTYPE_rW_W_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the first argument + short w = *(((short*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the second argument + w = *(((short*)tmpBC)+2); + WriteEncodedInt64(w); + + // Write the third argument + int dw = tmpBC[2]; + WriteEncodedInt64(dw); + } + break; + case asBCTYPE_QW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the argument + asQWORD qw = *(asQWORD*)&tmpBC[1]; + WriteEncodedInt64(qw); + } + break; + case asBCTYPE_QW_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the argument + asQWORD qw = *(asQWORD*)&tmpBC[1]; + WriteEncodedInt64(qw); + + // Write the second argument + int dw = tmpBC[3]; + WriteEncodedInt64(dw); + } + break; + case asBCTYPE_rW_QW_ARG: + case asBCTYPE_wW_QW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the first argument + short w = *(((short*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the argument + asQWORD qw = *(asQWORD*)&tmpBC[1]; + WriteEncodedInt64(qw); + } + break; + case asBCTYPE_rW_DW_DW_ARG: + { + // Write the instruction code + asBYTE b = (asBYTE)c; + WriteData(&b, 1); + + // Write the short argument + short w = *(((short*)tmpBC)+1); + WriteEncodedInt64(w); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[1]); + + // Write the dword argument + WriteEncodedInt64((int)tmpBC[2]); + } + break; + default: + { + // This should never happen + asASSERT(false); + + // Store the bc as is + for( int n = 0; n < asBCTypeSize[asBCInfo[c].type]; n++ ) + WriteData(&tmpBC[n], 4); + } + } + + // Move to the next instruction + bc += asBCTypeSize[asBCInfo[c].type]; + length -= asBCTypeSize[asBCInfo[c].type]; + } +} + +asCWriter::SListAdjuster::SListAdjuster(asCObjectType *ot) : patternType(ot), repeatCount(0), entries(0), lastOffset(-1), nextOffset(0), nextTypeId(-1) +{ + asASSERT( ot && (ot->flags & asOBJ_LIST_PATTERN) ); + + // Find the first expected value in the list + asSListPatternNode *node = ot->engine->scriptFunctions[patternType->templateSubTypes[0].GetBehaviour()->listFactory]->listPattern; + asASSERT( node && node->type == asLPT_START ); + patternNode = node->next; +} + +int asCWriter::SListAdjuster::AdjustOffset(int offset, asCObjectType *listPatternType) +{ + // TODO: cleanup: The listPatternType parameter is not needed + asASSERT( patternType == listPatternType ); + UNUSED_VAR(listPatternType); + + asASSERT( offset >= lastOffset ); + + // If it is the same offset being accessed again, just return the same adjusted value + if( offset == lastOffset ) + return entries-1; + + asASSERT( offset >= nextOffset ); + + // Update last offset for next call + lastOffset = offset; + + // What is being expected at this position? + if( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ) + { + // Don't move the patternNode yet because the caller must make a call to SetRepeatCount too + nextOffset = offset + 4; + return entries++; + } + else if( patternNode->type == asLPT_TYPE ) + { + const asCDataType &dt = reinterpret_cast(patternNode)->dataType; + if( dt.GetTokenType() == ttQuestion ) + { + // The bytecode need to inform the type that will + // come next and then adjust that position too before + // we can move to the next node + if( nextTypeId != -1 ) + { + nextOffset = offset + 4; + + if( repeatCount > 0 ) + repeatCount--; + + // Only move the patternNode if we're not expecting any more repeated entries + if( repeatCount == 0 ) + patternNode = patternNode->next; + + nextTypeId = -1; + } + } + else + { + if( repeatCount > 0 ) + { + // Was any value skipped? + asUINT size; + if( dt.IsObjectHandle() || (dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_REF)) ) + size = AS_PTR_SIZE*4; + else + size = dt.GetSizeInMemoryBytes(); + + int count = 0; + while( nextOffset <= offset ) + { + count++; + nextOffset += size; + + // Align the offset on 4 byte boundaries + if( size >= 4 && (nextOffset & 0x3) ) + nextOffset += 4 - (nextOffset & 0x3); + } + + if( --count > 0 ) + { + // Skip these values + repeatCount -= count; + entries += count; + } + + nextOffset = offset + size; + repeatCount--; + } + + // Only move the patternNode if we're not expecting any more repeated entries + if( repeatCount == 0 ) + patternNode = patternNode->next; + } + + return entries++; + } + else if( patternNode->type == asLPT_START ) + { + if( repeatCount > 0 ) + repeatCount--; + SInfo info = {repeatCount, patternNode}; + stack.PushLast(info); + + repeatCount = 0; + patternNode = patternNode->next; + + lastOffset--; + return AdjustOffset(offset, listPatternType); + } + else if( patternNode->type == asLPT_END ) + { + SInfo info = stack.PopLast(); + repeatCount = info.repeatCount; + if( repeatCount ) + patternNode = info.startNode; + else + patternNode = patternNode->next; + + lastOffset--; + return AdjustOffset(offset, listPatternType); + } + else + { + // Something is wrong with the pattern list declaration + asASSERT( false ); + } + + return 0; +} + +void asCWriter::SListAdjuster::SetRepeatCount(asUINT rc) +{ + // Make sure the list is expecting a repeat at this location + asASSERT( patternNode->type == asLPT_REPEAT || patternNode->type == asLPT_REPEAT_SAME ); + + // Now move to the next patternNode + patternNode = patternNode->next; + + repeatCount = rc; +} + +void asCWriter::SListAdjuster::SetNextType(int typeId) +{ + // Make sure the list is expecting a type at this location + asASSERT( patternNode->type == asLPT_TYPE && + reinterpret_cast(patternNode)->dataType.GetTokenType() == ttQuestion ); + + // Inform the type id for the next adjustment + nextTypeId = typeId; +} + +void asCWriter::WriteUsedTypeIds() +{ + TimeIt("asCWriter::WriteUsedTypeIds"); + + asUINT count = (asUINT)usedTypeIds.GetLength(); + WriteEncodedInt64(count); + for( asUINT n = 0; n < count; n++ ) + { + asCDataType dt = engine->GetDataTypeFromTypeId(usedTypeIds[n]); + WriteDataType(&dt); + } +} + +int asCWriter::FindGlobalPropPtrIndex(void *ptr) +{ + int i = usedGlobalProperties.IndexOf(ptr); + if( i >= 0 ) return i; + + usedGlobalProperties.PushLast(ptr); + return (int)usedGlobalProperties.GetLength()-1; +} + +void asCWriter::WriteUsedGlobalProps() +{ + TimeIt("asCWriter::WriteUsedGlobalProps"); + + int c = (int)usedGlobalProperties.GetLength(); + WriteEncodedInt64(c); + + for( int n = 0; n < c; n++ ) + { + asPWORD *p = (asPWORD*)usedGlobalProperties[n]; + + // Find the property descriptor from the address + asCGlobalProperty *prop = 0; + asSMapNode *cursor; + if( engine->varAddressMap.MoveTo(&cursor, p) ) + { + prop = engine->varAddressMap.GetValue(cursor); + } + + asASSERT(prop); + + // Store the name and type of the property so we can find it again on loading + WriteString(&prop->name); + WriteString(&prop->nameSpace->name); + WriteDataType(&prop->type); + + // Also store whether the property is a module property or a registered property + char moduleProp = 0; + if( prop->realAddress == 0 ) + moduleProp = 1; + WriteData(&moduleProp, 1); + } +} + +void asCWriter::WriteUsedObjectProps() +{ + TimeIt("asCWriter::WriteUsedObjectProps"); + + int c = (int)usedObjectProperties.GetLength(); + WriteEncodedInt64(c); + + for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) + { + WriteTypeInfo(usedObjectProperties[n].objType); + WriteString(&usedObjectProperties[n].prop->name); + } +} + +int asCWriter::FindObjectPropIndex(short offset, int typeId, asDWORD *bc) +{ + // If the last property was a composite property, then just return 0, because it won't be translated + static bool lastWasComposite = false; + if (lastWasComposite) + { + lastWasComposite = false; + return 0; + } + + asCObjectType *objType = engine->GetObjectTypeFromTypeId(typeId); + asCObjectProperty *objProp = 0; + + // Look for composite properties first + for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) + { + // TODO: Composite: Perhaps it would be better to add metadata to the bytecode instruction to give the exact property. + // That would also allow me to remove the typeId from the bytecode instruction itself + // Or perhaps a new bytecode instruction all together for accessing composite properties + // One that would do both offsets and indirection in a single go. + // TODO: Composite: Need to be able to handle instructions replaced in bytecode optimizations too + if (objType->properties[n]->compositeOffset == offset) + { + // This is a potential composite property. Need to check the following instructions to be sure + objProp = objType->properties[n]; + asDWORD *bcTemp = bc; + bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; + if (objProp->isCompositeIndirect) + { + // The next instruction would be a asBC_RDSPtr + if ((*(asBYTE*)bcTemp) != asBC_RDSPtr) + { + objProp = 0; + continue; + } + bcTemp += asBCTypeSize[asBCInfo[*(asBYTE*)bcTemp].type]; + } + // The next instruction would be asBC_ADDSi + if ((*(asBYTE*)bcTemp) != asBC_ADDSi) + { + objProp = 0; + continue; + } + // Make sure the offset is the expected one + if (*(((short*)bcTemp) + 1) != objProp->byteOffset) + { + objProp = 0; + continue; + } + } + } + + // If none of the composite properties matched, then look for ordinary property + for (asUINT n = 0; objProp == 0 && n < objType->properties.GetLength(); n++) + { + if (objType->properties[n]->byteOffset == offset && !(objType->properties[n]->compositeOffset || objType->properties[n]->isCompositeIndirect)) + objProp = objType->properties[n]; + } + + asASSERT(objProp); + + // Remember if this is a composite property as the next call will then be for the same property + if (objProp->compositeOffset || objProp->isCompositeIndirect) + lastWasComposite = true; + + // Now check if the same property has already been accessed + for( asUINT n = 0; n < usedObjectProperties.GetLength(); n++ ) + { + if( usedObjectProperties[n].objType == objType && + usedObjectProperties[n].prop == objProp ) + return n; + } + + // Insert the new property + SObjProp prop = {objType, objProp}; + usedObjectProperties.PushLast(prop); + return (int)usedObjectProperties.GetLength() - 1; +} + +int asCWriter::FindFunctionIndex(asCScriptFunction *func) +{ + for( asUINT n = 0; n < usedFunctions.GetLength(); n++ ) + { + if( usedFunctions[n] == func ) + return n; + } + + usedFunctions.PushLast(func); + return (int)usedFunctions.GetLength() - 1; +} + +int asCWriter::FindTypeIdIdx(int typeId) +{ + asUINT n; + for( n = 0; n < usedTypeIds.GetLength(); n++ ) + { + if( usedTypeIds[n] == typeId ) + return n; + } + + usedTypeIds.PushLast(typeId); + return (int)usedTypeIds.GetLength() - 1; +} + +int asCWriter::FindTypeInfoIdx(asCTypeInfo *obj) +{ + asUINT n; + for( n = 0; n < usedTypes.GetLength(); n++ ) + { + if( usedTypes[n] == obj ) + return n; + } + + usedTypes.PushLast(obj); + return (int)usedTypes.GetLength() - 1; +} + +#endif // AS_NO_COMPILER + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_restore.h b/angelscript/source/as_restore.h new file mode 100644 index 0000000..462c2ae --- /dev/null +++ b/angelscript/source/as_restore.h @@ -0,0 +1,259 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_restore.h +// +// Functions for saving and restoring module bytecode +// asCRestore was originally written by Dennis Bollyn, dennis@gyrbo.be +// It was later split in two classes asCReader and asCWriter by me + +#ifndef AS_RESTORE_H +#define AS_RESTORE_H + +#include "as_scriptengine.h" +#include "as_context.h" +#include "as_map.h" + +BEGIN_AS_NAMESPACE + +class asCReader +{ +public: + asCReader(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine); + + int Read(bool *wasDebugInfoStripped); + +protected: + asCModule *module; + asIBinaryStream *stream; + asCScriptEngine *engine; + bool noDebugInfo; + bool error; + asUINT bytesRead; + + int Error(const char *msg); + + int ReadInner(); + + int ReadData(void *data, asUINT size); + void ReadString(asCString *str); + asCScriptFunction *ReadFunction(bool &isNew, bool addToModule = true, bool addToEngine = true, bool addToGC = true, bool *isExternal = 0); + void ReadFunctionSignature(asCScriptFunction *func, asCObjectType **parentClass = 0); + void ReadGlobalProperty(); + void ReadObjectProperty(asCObjectType *ot); + void ReadDataType(asCDataType *dt); + asCTypeInfo *ReadTypeInfo(); + void ReadTypeDeclaration(asCTypeInfo *ot, int phase, bool *isExternal = 0); + void ReadByteCode(asCScriptFunction *func); + asWORD ReadEncodedUInt16(); + asUINT ReadEncodedUInt(); + asQWORD ReadEncodedUInt64(); + + void ReadUsedTypeIds(); + void ReadUsedFunctions(); + void ReadUsedGlobalProps(); + void ReadUsedStringConstants(); + void ReadUsedObjectProps(); + + asCTypeInfo * FindType(int idx); + int FindTypeId(int idx); + short FindObjectPropOffset(asWORD index); + asCScriptFunction *FindFunction(int idx); + + // After loading, each function needs to be translated to update pointers, function ids, etc + void TranslateFunction(asCScriptFunction *func); + void CalculateAdjustmentByPos(asCScriptFunction *func); + int AdjustStackPosition(int pos); + int AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos); + void CalculateStackNeeded(asCScriptFunction *func); + asCScriptFunction *GetCalledFunction(asCScriptFunction *func, asDWORD programPos); + + // Temporary storage for persisting variable data + asCArray usedTypeIds; + asCArray usedTypes; + asCArray usedFunctions; + asCArray usedGlobalProperties; + asCArray usedStringConstants; + + asCArray savedFunctions; + asCArray savedDataTypes; + asCArray savedStrings; + + asCArray adjustByPos; + asCArray adjustNegativeStackByPos; + + struct SObjProp + { + asCObjectType *objType; + asCObjectProperty *prop; + }; + asCArray usedObjectProperties; + + asCMap existingShared; + asCMap dontTranslate; + + // Helper class for adjusting offsets within initialization list buffers + struct SListAdjuster + { + SListAdjuster(asCReader *rd, asDWORD *bc, asCObjectType *ot); + void AdjustAllocMem(); + int AdjustOffset(int offset); + void SetRepeatCount(asUINT rc); + void SetNextType(int typeId); + + struct SInfo + { + asUINT repeatCount; + asSListPatternNode *startNode; + }; + asCArray stack; + + asCReader *reader; + asDWORD *allocMemBC; + asUINT maxOffset; + asCObjectType *patternType; + asUINT repeatCount; + int lastOffset; + int nextOffset; + asUINT lastAdjustedOffset; + asSListPatternNode *patternNode; + int nextTypeId; + }; + asCArray listAdjusters; +}; + +#ifndef AS_NO_COMPILER + +class asCWriter +{ +public: + asCWriter(asCModule *module, asIBinaryStream *stream, asCScriptEngine *engine, bool stripDebugInfo); + + int Write(); + +protected: + asCModule *module; + asIBinaryStream *stream; + asCScriptEngine *engine; + bool stripDebugInfo; + bool error; + asUINT bytesWritten; + + int Error(const char *msg); + + int WriteData(const void *data, asUINT size); + + void WriteString(asCString *str); + void WriteFunction(asCScriptFunction *func); + void WriteFunctionSignature(asCScriptFunction *func); + void WriteGlobalProperty(asCGlobalProperty *prop); + void WriteObjectProperty(asCObjectProperty *prop); + void WriteDataType(const asCDataType *dt); + void WriteTypeInfo(asCTypeInfo *ot); + void WriteTypeDeclaration(asCTypeInfo *ot, int phase); + void WriteByteCode(asCScriptFunction *func); + void WriteEncodedInt64(asINT64 i); + + // Helper functions for storing variable data + int FindTypeInfoIdx(asCTypeInfo *ti); + int FindTypeIdIdx(int typeId); + int FindFunctionIndex(asCScriptFunction *func); + int FindGlobalPropPtrIndex(void *); + int FindStringConstantIndex(void *str); + int FindObjectPropIndex(short offset, int typeId, asDWORD *bc); + + void CalculateAdjustmentByPos(asCScriptFunction *func); + int AdjustStackPosition(int pos); + int AdjustProgramPosition(int pos); + int AdjustGetOffset(int offset, asCScriptFunction *func, asDWORD programPos); + + // Intermediate data used for storing that which isn't constant, function id's, pointers, etc + void WriteUsedTypeIds(); + void WriteUsedFunctions(); + void WriteUsedGlobalProps(); + void WriteUsedStringConstants(); + void WriteUsedObjectProps(); + + // Temporary storage for persisting variable data + asCArray usedTypeIds; + asCArray usedTypes; + asCArray usedFunctions; + asCArray usedGlobalProperties; + asCArray usedStringConstants; + asCMap stringToIndexMap; + + asCArray savedFunctions; + asCArray savedDataTypes; + asCArray savedStrings; + asCMap stringToIdMap; + asCArray adjustStackByPos; + asCArray adjustNegativeStackByPos; + asCArray bytecodeNbrByPos; + + struct SObjProp + { + asCObjectType *objType; + asCObjectProperty *prop; + }; + asCArray usedObjectProperties; + + // Helper class for adjusting offsets within initialization list buffers + struct SListAdjuster + { + SListAdjuster(asCObjectType *ot); + int AdjustOffset(int offset, asCObjectType *listPatternType); + void SetRepeatCount(asUINT rc); + void SetNextType(int typeId); + + struct SInfo + { + asUINT repeatCount; + asSListPatternNode *startNode; + }; + asCArray stack; + + asCObjectType *patternType; + asUINT repeatCount; + asSListPatternNode *patternNode; + asUINT entries; + int lastOffset; // Last offset adjusted + int nextOffset; // next expected offset to be adjusted + int nextTypeId; + }; + asCArray listAdjusters; +}; + +#endif + +END_AS_NAMESPACE + +#endif // AS_RESTORE_H diff --git a/angelscript/source/as_scriptcode.cpp b/angelscript/source/as_scriptcode.cpp new file mode 100644 index 0000000..833b401 --- /dev/null +++ b/angelscript/source/as_scriptcode.cpp @@ -0,0 +1,151 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptcode.cpp +// +// A container class for the script code to be compiled +// + + + +#include "as_config.h" +#include "as_scriptcode.h" + +BEGIN_AS_NAMESPACE + +asCScriptCode::asCScriptCode() +{ + lineOffset = 0; + code = 0; + codeLength = 0; + sharedCode = false; +} + +asCScriptCode::~asCScriptCode() +{ + if( !sharedCode && code ) + { + asDELETEARRAY(code); + } +} + +int asCScriptCode::SetCode(const char *in_name, const char *in_code, bool in_makeCopy) +{ + return SetCode(in_name, in_code, 0, in_makeCopy); +} + +int asCScriptCode::SetCode(const char *in_name, const char *in_code, size_t in_length, bool in_makeCopy) +{ + if( !in_code) return asINVALID_ARG; + this->name = in_name ? in_name : ""; + if( !sharedCode && code ) + asDELETEARRAY(code); + + if( in_length == 0 ) + in_length = strlen(in_code); + if( in_makeCopy ) + { + codeLength = in_length; + sharedCode = false; + code = asNEWARRAY(char, in_length); + if( code == 0 ) + return asOUT_OF_MEMORY; + memcpy(code, in_code, in_length); + } + else + { + codeLength = in_length; + code = const_cast(in_code); + sharedCode = true; + } + + // Find the positions of each line + linePositions.PushLast(0); + for( size_t n = 0; n < in_length; n++ ) + if( in_code[n] == '\n' ) linePositions.PushLast(n+1); + linePositions.PushLast(in_length); + + return asSUCCESS; +} + +void asCScriptCode::ConvertPosToRowCol(size_t pos, int *row, int *col) +{ + if( linePositions.GetLength() == 0 ) + { + if( row ) *row = lineOffset; + if( col ) *col = 1; + return; + } + + // Do a binary search in the buffer + int max = (int)linePositions.GetLength() - 1; + int min = 0; + int i = max/2; + + for(;;) + { + if( linePositions[i] < pos ) + { + // Have we found the largest number < programPosition? + if( min == i ) break; + + min = i; + i = (max + min)/2; + } + else if( linePositions[i] > pos ) + { + // Have we found the smallest number > programPoisition? + if( max == i ) break; + + max = i; + i = (max + min)/2; + } + else + { + // We found the exact position + break; + } + } + + if( row ) *row = i + 1 + lineOffset; + if( col ) *col = (int)(pos - linePositions[i]) + 1; +} + +bool asCScriptCode::TokenEquals(size_t pos, size_t len, const char *str) +{ + if( pos + len > codeLength ) return false; + if( strncmp(code + pos, str, len) == 0 && strlen(str) == len ) + return true; + return false; +} + +END_AS_NAMESPACE diff --git a/angelscript/source/as_scriptcode.h b/angelscript/source/as_scriptcode.h new file mode 100644 index 0000000..be1af3b --- /dev/null +++ b/angelscript/source/as_scriptcode.h @@ -0,0 +1,72 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2011 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptcode.h +// +// A container class for the script code to be compiled +// + + + +#ifndef AS_SCRIPTCODE_H +#define AS_SCRIPTCODE_H + +#include "as_array.h" +#include "as_string.h" + +BEGIN_AS_NAMESPACE + +class asCScriptCode +{ +public: + asCScriptCode(); + ~asCScriptCode(); + + int SetCode(const char *name, const char *code, bool makeCopy); + int SetCode(const char *name, const char *code, size_t length, bool makeCopy); + + void ConvertPosToRowCol(size_t pos, int *row, int *col); + + bool TokenEquals(size_t pos, size_t len, const char *str); + + asCString name; + char *code; + size_t codeLength; + bool sharedCode; + int idx; + int lineOffset; + asCArray linePositions; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_scriptengine.cpp b/angelscript/source/as_scriptengine.cpp new file mode 100644 index 0000000..d8aa274 --- /dev/null +++ b/angelscript/source/as_scriptengine.cpp @@ -0,0 +1,6599 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptengine.cpp +// +// The implementation of the script engine interface +// + + +#include + +#include "as_config.h" +#include "as_scriptengine.h" +#include "as_builder.h" +#include "as_context.h" +#include "as_string_util.h" +#include "as_tokenizer.h" +#include "as_texts.h" +#include "as_module.h" +#include "as_callfunc.h" +#include "as_generic.h" +#include "as_scriptobject.h" +#include "as_compiler.h" +#include "as_bytecode.h" +#include "as_debug.h" + +BEGIN_AS_NAMESPACE + + + +#ifdef AS_PROFILE +// Instantiate the profiler once +CProfiler g_profiler; +#endif + + + + +extern "C" +{ + +AS_API const char * asGetLibraryVersion() +{ +#ifdef _DEBUG + return ANGELSCRIPT_VERSION_STRING " DEBUG"; +#else + return ANGELSCRIPT_VERSION_STRING; +#endif +} + +AS_API const char * asGetLibraryOptions() +{ + const char *string = " " + + // Options +#ifdef AS_MAX_PORTABILITY + "AS_MAX_PORTABILITY " +#endif +#ifdef AS_DEBUG + "AS_DEBUG " +#endif +#ifdef AS_NO_CLASS_METHODS + "AS_NO_CLASS_METHODS " +#endif +#ifdef AS_USE_DOUBLE_AS_FLOAT + "AS_USE_DOUBLE_AS_FLOAT " +#endif +#ifdef AS_64BIT_PTR + "AS_64BIT_PTR " +#endif +#ifdef AS_NO_THREADS + "AS_NO_THREADS " +#endif +#ifdef AS_NO_ATOMIC + "AS_NO_ATOMIC " +#endif +#ifdef AS_NO_COMPILER + "AS_NO_COMPILER " +#endif +#ifdef AS_NO_MEMBER_INIT + "AS_NO_MEMBER_INIT " +#endif +#ifdef AS_NO_THISCALL_FUNCTOR_METHOD + "AS_NO_THISCALL_FUNCTOR_METHOD " +#endif +#ifdef AS_NO_EXCEPTIONS + "AS_NO_EXCEPTIONS " +#endif +#ifdef WIP_16BYTE_ALIGN + "WIP_16BYTE_ALIGN " +#endif +#ifdef AS_BIG_ENDIAN + "AS_BIG_ENDIAN " +#endif + + // Target system +#ifdef AS_WIN + "AS_WIN " +#endif +#ifdef AS_LINUX + "AS_LINUX " +#endif +#ifdef AS_MAC + "AS_MAC " +#endif +#ifdef AS_SUN + "AS_SUN " +#endif +#ifdef AS_BSD + "AS_BSD " +#endif +#ifdef AS_XBOX + "AS_XBOX " +#endif +#ifdef AS_XBOX360 + "AS_XBOX360 " +#endif +#ifdef AS_PSP + "AS_PSP " +#endif +#ifdef AS_PS2 + "AS_PS2 " +#endif +#ifdef AS_PS3 + "AS_PS3 " +#endif +#ifdef AS_PSVITA + "AS_PSVITA " +#endif +#ifdef AS_DC + "AS_DC " +#endif +#ifdef AS_GC + "AS_GC " +#endif +#ifdef AS_WII + "AS_WII " +#endif +#ifdef AS_WIIU + "AS_WIIU " +#endif +#ifdef AS_IPHONE + "AS_IPHONE " +#endif +#ifdef AS_ANDROID + "AS_ANDROID " +#endif +#ifdef AS_HAIKU + "AS_HAIKU " +#endif +#ifdef AS_ILLUMOS + "AS_ILLUMOS " +#endif +#ifdef AS_MARMALADE + "AS_MARMALADE " +#endif + + + // CPU family +#ifdef AS_PPC + "AS_PPC " +#endif +#ifdef AS_PPC_64 + "AS_PPC_64 " +#endif +#ifdef AS_X86 + "AS_X86 " +#endif +#ifdef AS_MIPS + "AS_MIPS " +#endif +#ifdef AS_SH4 + "AS_SH4 " +#endif +#ifdef AS_XENON + "AS_XENON " +#endif +#ifdef AS_ARM + "AS_ARM " +#endif +#ifdef AS_SOFTFP + "AS_SOFTFP " +#endif +#ifdef AS_X64_GCC + "AS_X64_GCC " +#endif +#ifdef AS_X64_MSVC + "AS_X64_MSVC " +#endif +#ifdef AS_SPARC + "AS_SPARC " +#endif +#ifdef AS_ARM64 + "AS_ARM64 " +#endif + ; + + return string; +} + +AS_API asIScriptEngine *asCreateScriptEngine(asDWORD version) +{ + // Verify the version that the application expects + if( (version/10000) != (ANGELSCRIPT_VERSION/10000) ) + return 0; + + if( (version/100)%100 != (ANGELSCRIPT_VERSION/100)%100 ) + return 0; + + if( (version%100) > (ANGELSCRIPT_VERSION%100) ) + return 0; + + // Verify the size of the types + asASSERT( sizeof(asBYTE) == 1 ); + asASSERT( sizeof(asWORD) == 2 ); + asASSERT( sizeof(asDWORD) == 4 ); + asASSERT( sizeof(asQWORD) == 8 ); + asASSERT( sizeof(asPWORD) == sizeof(void*) ); + + // Verify the boolean type + asASSERT( sizeof(bool) == AS_SIZEOF_BOOL ); + asASSERT( true == VALUE_OF_BOOLEAN_TRUE ); + + // Verify endianess +#ifdef AS_BIG_ENDIAN + asDWORD dw = 0x00010203; + asQWORD qw = ((asQWORD(0x00010203)<<32)|asQWORD(0x04050607)); +#else + asDWORD dw = 0x03020100; + // C++ didn't have a standard way of declaring 64bit literal constants until C++11, so + // I'm forced to do it like this to avoid compilers warnings when compiling with the full + // C++ compliance. + asQWORD qw = ((asQWORD(0x07060504)<<32)|asQWORD(0x03020100)); +#endif + asASSERT( memcmp("\x00\x01\x02\x03", &dw, 4) == 0 ); + asASSERT( memcmp("\x00\x01\x02\x03\x04\x05\x06\x07", &qw, 8) == 0 ); + UNUSED_VAR(dw); + UNUSED_VAR(qw); + + return asNEW(asCScriptEngine)(); +} + +} // extern "C" + + +// interface +int asCScriptEngine::SetEngineProperty(asEEngineProp property, asPWORD value) +{ + switch( property ) + { + case asEP_ALLOW_UNSAFE_REFERENCES: + ep.allowUnsafeReferences = value ? true : false; + break; + + case asEP_OPTIMIZE_BYTECODE: + ep.optimizeByteCode = value ? true : false; + break; + + case asEP_COPY_SCRIPT_SECTIONS: + ep.copyScriptSections = value ? true : false; + break; + + case asEP_MAX_STACK_SIZE: + if( value == 0 ) + { + // Restore default: no limit and initially size 4KB + ep.maximumContextStackSize = 0; + } + else + { + // The size is given in bytes, but we only store dwords + ep.maximumContextStackSize = (asUINT)value/4; + } + break; + + case asEP_INIT_STACK_SIZE: + if (value < 4) + { + // At least one dword + ep.initContextStackSize = 1; + } + else + { + // The size is given in bytes, but we only store dwords + ep.initContextStackSize = (asUINT)value / 4; + } + break; + + case asEP_USE_CHARACTER_LITERALS: + ep.useCharacterLiterals = value ? true : false; + break; + + case asEP_ALLOW_MULTILINE_STRINGS: + ep.allowMultilineStrings = value ? true : false; + break; + + case asEP_ALLOW_IMPLICIT_HANDLE_TYPES: + ep.allowImplicitHandleTypes = value ? true : false; + break; + + case asEP_BUILD_WITHOUT_LINE_CUES: + ep.buildWithoutLineCues = value ? true : false; + break; + + case asEP_INIT_GLOBAL_VARS_AFTER_BUILD: + ep.initGlobalVarsAfterBuild = value ? true : false; + break; + + case asEP_REQUIRE_ENUM_SCOPE: + ep.requireEnumScope = value ? true : false; + break; + + case asEP_SCRIPT_SCANNER: + if( value <= 1 ) + ep.scanner = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_INCLUDE_JIT_INSTRUCTIONS: + ep.includeJitInstructions = value ? true : false; + break; + + case asEP_STRING_ENCODING: + if( value <= 1 ) + ep.stringEncoding = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_PROPERTY_ACCESSOR_MODE: + if( value <= 3 ) + ep.propertyAccessorMode = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_EXPAND_DEF_ARRAY_TO_TMPL: + ep.expandDefaultArrayToTemplate = value ? true : false; + break; + + case asEP_AUTO_GARBAGE_COLLECT: + ep.autoGarbageCollect = value ? true : false; + break; + + case asEP_DISALLOW_GLOBAL_VARS: + ep.disallowGlobalVars = value ? true : false; + break; + + case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT: + ep.alwaysImplDefaultConstruct = value ? true : false; + break; + + case asEP_COMPILER_WARNINGS: + if( value <= 2 ) + ep.compilerWarnings = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE: + ep.disallowValueAssignForRefType = value ? true : false; + break; + + case asEP_ALTER_SYNTAX_NAMED_ARGS: + if( value <= 2 ) + ep.alterSyntaxNamedArgs = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_DISABLE_INTEGER_DIVISION: + ep.disableIntegerDivision = value ? true : false; + break; + + case asEP_DISALLOW_EMPTY_LIST_ELEMENTS: + ep.disallowEmptyListElements = value ? true : false; + break; + + case asEP_PRIVATE_PROP_AS_PROTECTED: + ep.privatePropAsProtected = value ? true : false; + break; + + case asEP_ALLOW_UNICODE_IDENTIFIERS: + ep.allowUnicodeIdentifiers = value ? true : false; + break; + + case asEP_HEREDOC_TRIM_MODE: + if (value <= 2) + ep.heredocTrimMode = (int)value; + else + return asINVALID_ARG; + break; + + case asEP_MAX_NESTED_CALLS: + if (value > 0xFFFFFFFF) + ep.maxNestedCalls = 0xFFFFFFFF; + else + ep.maxNestedCalls = (asUINT)value; + break; + + case asEP_GENERIC_CALL_MODE: + if (value > 1) + ep.genericCallMode = 1; + else + ep.genericCallMode = (asUINT)value; + break; + + case asEP_INIT_CALL_STACK_SIZE: + ep.initCallStackSize = (asUINT)value; + break; + + case asEP_MAX_CALL_STACK_SIZE: + ep.maxCallStackSize = (asUINT)value; + break; + + default: + return asINVALID_ARG; + } + + return asSUCCESS; +} + +// interface +asPWORD asCScriptEngine::GetEngineProperty(asEEngineProp property) const +{ + switch( property ) + { + case asEP_ALLOW_UNSAFE_REFERENCES: + return ep.allowUnsafeReferences; + + case asEP_OPTIMIZE_BYTECODE: + return ep.optimizeByteCode; + + case asEP_COPY_SCRIPT_SECTIONS: + return ep.copyScriptSections; + + case asEP_MAX_STACK_SIZE: + return ep.maximumContextStackSize * 4; + + case asEP_INIT_STACK_SIZE: + return ep.initContextStackSize * 4; + + case asEP_USE_CHARACTER_LITERALS: + return ep.useCharacterLiterals; + + case asEP_ALLOW_MULTILINE_STRINGS: + return ep.allowMultilineStrings; + + case asEP_ALLOW_IMPLICIT_HANDLE_TYPES: + return ep.allowImplicitHandleTypes; + + case asEP_BUILD_WITHOUT_LINE_CUES: + return ep.buildWithoutLineCues; + + case asEP_INIT_GLOBAL_VARS_AFTER_BUILD: + return ep.initGlobalVarsAfterBuild; + + case asEP_REQUIRE_ENUM_SCOPE: + return ep.requireEnumScope; + + case asEP_SCRIPT_SCANNER: + return ep.scanner; + + case asEP_INCLUDE_JIT_INSTRUCTIONS: + return ep.includeJitInstructions; + + case asEP_STRING_ENCODING: + return ep.stringEncoding; + + case asEP_PROPERTY_ACCESSOR_MODE: + return ep.propertyAccessorMode; + + case asEP_EXPAND_DEF_ARRAY_TO_TMPL: + return ep.expandDefaultArrayToTemplate; + + case asEP_AUTO_GARBAGE_COLLECT: + return ep.autoGarbageCollect; + + case asEP_DISALLOW_GLOBAL_VARS: + return ep.disallowGlobalVars; + + case asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT: + return ep.alwaysImplDefaultConstruct; + + case asEP_COMPILER_WARNINGS: + return ep.compilerWarnings; + + case asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE: + return ep.disallowValueAssignForRefType; + + case asEP_ALTER_SYNTAX_NAMED_ARGS: + return ep.alterSyntaxNamedArgs; + + case asEP_DISABLE_INTEGER_DIVISION: + return ep.disableIntegerDivision; + + case asEP_DISALLOW_EMPTY_LIST_ELEMENTS: + return ep.disallowEmptyListElements; + + case asEP_PRIVATE_PROP_AS_PROTECTED: + return ep.privatePropAsProtected; + + case asEP_ALLOW_UNICODE_IDENTIFIERS: + return ep.allowUnicodeIdentifiers; + + case asEP_HEREDOC_TRIM_MODE: + return ep.heredocTrimMode; + + case asEP_MAX_NESTED_CALLS: + return ep.maxNestedCalls; + + case asEP_GENERIC_CALL_MODE: + return ep.genericCallMode; + + case asEP_INIT_CALL_STACK_SIZE: + return ep.initCallStackSize; + + case asEP_MAX_CALL_STACK_SIZE: + return ep.maxCallStackSize; + + default: + return 0; + } + + UNREACHABLE_RETURN; +} + +// interface +asIScriptFunction *asCScriptEngine::CreateDelegate(asIScriptFunction *func, void *obj) +{ + if( func == 0 || obj == 0 ) + return 0; + + // The function must be a class method + asITypeInfo *type = func->GetObjectType(); + if( type == 0 ) + return 0; + + // The object type must allow handles + if( (type->GetFlags() & asOBJ_REF) == 0 || (type->GetFlags() & (asOBJ_SCOPED | asOBJ_NOHANDLE)) ) + return 0; + + // Create the delegate the same way it would be created by the scripts + return AS_NAMESPACE_QUALIFIER CreateDelegate(reinterpret_cast(func), obj); +} + +asCScriptEngine::asCScriptEngine() +{ + asCThreadManager::Prepare(0); + + shuttingDown = false; + inDestructor = false; + + // Engine properties + { + ep.allowUnsafeReferences = false; + ep.optimizeByteCode = true; + ep.copyScriptSections = true; + ep.maximumContextStackSize = 0; // no limit + ep.initContextStackSize = 1024; // 4KB default init stack size + ep.useCharacterLiterals = false; + ep.allowMultilineStrings = false; + ep.allowImplicitHandleTypes = false; + // TODO: optimize: Maybe this should be turned off by default? If a debugger is not used + // then this is just slowing down the execution. + ep.buildWithoutLineCues = false; + ep.initGlobalVarsAfterBuild = true; + ep.requireEnumScope = false; + ep.scanner = 1; // utf8. 0 = ascii + ep.includeJitInstructions = false; + ep.stringEncoding = 0; // utf8. 1 = utf16 + ep.propertyAccessorMode = 3; // 0 = disable, 1 = app registered only, 2 = app and script created, 3 = flag with 'property' + ep.expandDefaultArrayToTemplate = false; + ep.autoGarbageCollect = true; + ep.disallowGlobalVars = false; + ep.alwaysImplDefaultConstruct = false; + ep.compilerWarnings = 1; // 0 = no warnings, 1 = warning, 2 = treat as error + // TODO: 3.0.0: disallowValueAssignForRefType should be true by default + ep.disallowValueAssignForRefType = false; + ep.alterSyntaxNamedArgs = 0; // 0 = no alternate syntax, 1 = accept alternate syntax but warn, 2 = accept without warning + ep.disableIntegerDivision = false; + ep.disallowEmptyListElements = false; + ep.privatePropAsProtected = false; + ep.allowUnicodeIdentifiers = false; + ep.heredocTrimMode = 1; // 0 = never trim, 1 = don't trim on single line, 2 = trim initial and final empty line + ep.maxNestedCalls = 100; + ep.genericCallMode = 1; // 0 = old (pre 2.33.0) behavior where generic ignored auto handles, 1 = treat handles like in native call + ep.initCallStackSize = 10; // 10 levels of calls + ep.maxCallStackSize = 0; // 0 = no limit + } + + gc.engine = this; + tok.engine = this; + + refCount.set(1); + stringFactory = 0; + configFailed = false; + isPrepared = false; + isBuilding = false; + deferValidationOfTemplateTypes = false; + lastModule = 0; + + typeIdSeqNbr = 0; + currentGroup = &defaultGroup; + defaultAccessMask = 0xFFFFFFFF; // All bits set so that built-in functions/types will be available to all modules + + msgCallback = 0; + jitCompiler = 0; + + // Create the global namespace + defaultNamespace = AddNameSpace(""); + + requestCtxFunc = 0; + returnCtxFunc = 0; + ctxCallbackParam = 0; + + // We must set the namespace in the built-in types explicitly as + // this wasn't done by the default constructor. If we do not do + // this we will get null pointer access in other parts of the code + scriptTypeBehaviours.nameSpace = defaultNamespace; + functionBehaviours.nameSpace = defaultNamespace; + + // Reserve function id 0 for no function + scriptFunctions.PushLast(0); + + // Reserve the first typeIds for the primitive types + typeIdSeqNbr = asTYPEID_DOUBLE + 1; + + // Make sure typeId for the built-in primitives are defined according to asETypeIdFlags + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttVoid, false)) == asTYPEID_VOID ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttBool, false)) == asTYPEID_BOOL ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt8, false)) == asTYPEID_INT8 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt16, false)) == asTYPEID_INT16 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt, false)) == asTYPEID_INT32 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttInt64, false)) == asTYPEID_INT64 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt8, false)) == asTYPEID_UINT8 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt16, false)) == asTYPEID_UINT16 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt, false)) == asTYPEID_UINT32 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttUInt64, false)) == asTYPEID_UINT64 ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttFloat, false)) == asTYPEID_FLOAT ); + asASSERT( GetTypeIdFromDataType(asCDataType::CreatePrimitive(ttDouble, false)) == asTYPEID_DOUBLE ); + + defaultArrayObjectType = 0; + + RegisterScriptObject(this); + RegisterScriptFunction(this); + +#ifndef AS_NO_EXCEPTIONS + translateExceptionCallback = false; +#endif +} + +void asCScriptEngine::DeleteDiscardedModules() +{ + // TODO: redesign: Prevent more than one thread from entering this function at the same time. + // If a thread is already doing the work for the clean-up the other thread should + // simply return, as the first thread will continue. + + ACQUIRESHARED(engineRWLock); + asUINT maxCount = discardedModules.GetLength(); + RELEASESHARED(engineRWLock); + + for( asUINT n = 0; n < maxCount; n++ ) + { + ACQUIRESHARED(engineRWLock); + asCModule *mod = discardedModules[n]; + RELEASESHARED(engineRWLock); + + if( !mod->HasExternalReferences(shuttingDown) ) + { + asDELETE(mod, asCModule); + n--; + } + + ACQUIRESHARED(engineRWLock); + // Determine the max count again, since another module may have been discarded during the processing + maxCount = discardedModules.GetLength(); + RELEASESHARED(engineRWLock); + } + + // Go over the list of global properties, to see if it is possible to clean + // up some variables that are no longer referred to by any functions + for( asUINT n = 0; n < globalProperties.GetLength(); n++ ) + { + asCGlobalProperty *prop = globalProperties[n]; + if( prop && prop->refCount.get() == 1 ) + RemoveGlobalProperty(prop); + } +} + +asCScriptEngine::~asCScriptEngine() +{ + // TODO: clean-up: Clean up redundant code + + inDestructor = true; + + asASSERT(refCount.get() == 0); + + // If ShutDown hasn't been called yet do it now + if( !shuttingDown ) + { + AddRef(); + ShutDownAndRelease(); + } + + // Unravel the registered interface + if( defaultArrayObjectType ) + { + defaultArrayObjectType->ReleaseInternal(); + defaultArrayObjectType = 0; + } + + // Delete the functions for generated template types that may references object types + for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) + { + asCObjectType *templateType = generatedTemplateTypes[n]; + if( templateType ) + templateType->DestroyInternal(); + } + for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) + { + asCObjectType *type = listPatternTypes[n]; + if( type ) + type->ReleaseInternal(); + } + listPatternTypes.SetLength(0); + + // No script types must have survived + asASSERT( sharedScriptTypes.GetLength() == 0 ); + + // It is allowed to create new references to the engine temporarily while destroying objects + // but these references must be release immediately or else something is can go wrong later on + if( refCount.get() > 0 ) + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN); + + mapTypeIdToTypeInfo.EraseAll(); + + // First remove what is not used, so that other groups can be deleted safely + defaultGroup.RemoveConfiguration(this, true); + while( configGroups.GetLength() ) + { + // Delete config groups in the right order + asCConfigGroup *grp = configGroups.PopLast(); + if( grp ) + { + grp->RemoveConfiguration(this); + asDELETE(grp,asCConfigGroup); + } + } + // Remove what is remaining + defaultGroup.RemoveConfiguration(this); + + // Any remaining objects in templateInstanceTypes is from generated template instances + for( asUINT n = 0; n < templateInstanceTypes.GetLength(); n++ ) + { + asCObjectType *templateType = templateInstanceTypes[n]; + if( templateInstanceTypes[n] ) + templateType->ReleaseInternal(); + } + templateInstanceTypes.SetLength(0); + + asCSymbolTable::iterator it = registeredGlobalProps.List(); + for( ; it; it++ ) + { + RemoveGlobalProperty(*it); + (*it)->Release(); + } + registeredGlobalProps.Clear(); + + for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ ) + { + if( templateSubTypes[n] ) + { + templateSubTypes[n]->DestroyInternal(); + templateSubTypes[n]->ReleaseInternal(); + } + } + templateSubTypes.SetLength(0); + registeredTypeDefs.SetLength(0); + registeredEnums.SetLength(0); + registeredObjTypes.SetLength(0); + + asCSymbolTable::iterator funcIt = registeredGlobalFuncs.List(); + for( ; funcIt; funcIt++ ) + (*funcIt)->ReleaseInternal(); + registeredGlobalFuncs.Clear(); + + scriptTypeBehaviours.ReleaseAllFunctions(); + functionBehaviours.ReleaseAllFunctions(); + + for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ ) + if( scriptFunctions[n] ) + { + scriptFunctions[n]->DestroyInternal(); + + // Set the engine pointer to null to signal that the function is no longer part of the engine + scriptFunctions[n]->engine = 0; + } + scriptFunctions.SetLength(0); + + // Increase the internal ref count for these builtin object types, so the destructor is not called incorrectly + scriptTypeBehaviours.AddRefInternal(); + functionBehaviours.AddRefInternal(); + + // Destroy the funcdefs + // As funcdefs are shared between modules it shouldn't be a problem to keep the objects until the engine is released + for( asUINT n = 0; n < funcDefs.GetLength(); n++ ) + if( funcDefs[n] ) + { + funcDefs[n]->DestroyInternal(); + funcDefs[n]->ReleaseInternal(); + } + funcDefs.SetLength(0); + + // Free the global properties + for( asUINT n = 0; n < globalProperties.GetLength(); n++ ) + { + asCGlobalProperty *prop = globalProperties[n]; + if( prop ) + { + asASSERT( prop->refCount.get() == 1 ); + RemoveGlobalProperty(prop); + } + } + + // Free the script section names + for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ ) + asDELETE(scriptSectionNames[n],asCString); + scriptSectionNames.SetLength(0); + + // Clean the user data + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) + { + if( userData[n+1] ) + { + for( asUINT c = 0; c < cleanEngineFuncs.GetLength(); c++ ) + if( cleanEngineFuncs[c].type == userData[n] ) + cleanEngineFuncs[c].cleanFunc(this); + } + } + + // Free namespaces + for( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) + asDELETE(nameSpaces[n], asSNameSpace); + nameSpaces.SetLength(0); + + asCThreadManager::Unprepare(); +} + +// interface +int asCScriptEngine::SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param) +{ + // Both callbacks or neither must be set + if( (requestCtx == 0 && returnCtx != 0) || (requestCtx != 0 && returnCtx == 0) ) + return asINVALID_ARG; + + requestCtxFunc = requestCtx; + returnCtxFunc = returnCtx; + ctxCallbackParam = param; + + return 0; +} + +// interface +asIScriptContext *asCScriptEngine::RequestContext() +{ + if( requestCtxFunc ) + { + // The return callback must also exist + asASSERT( returnCtxFunc ); + + asIScriptContext *ctx = requestCtxFunc(this, ctxCallbackParam); + return ctx; + } + + // As fallback we create a new context + return CreateContext(); +} + +// internal +asCModule *asCScriptEngine::FindNewOwnerForSharedType(asCTypeInfo *in_type, asCModule *in_mod) +{ + asASSERT( in_type->IsShared() ); + + if( in_type->module != in_mod) + return in_type->module; + + for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) + { + // TODO: optimize: If the modules already stored the shared types separately, this would be quicker + int foundIdx = -1; + asCModule *mod = scriptModules[n]; + if( mod == in_type->module ) continue; + if( in_type->flags & asOBJ_ENUM ) + foundIdx = mod->m_enumTypes.IndexOf(CastToEnumType(in_type)); + else if (in_type->flags & asOBJ_TYPEDEF) + foundIdx = mod->m_typeDefs.IndexOf(CastToTypedefType(in_type)); + else if (in_type->flags & asOBJ_FUNCDEF) + foundIdx = mod->m_funcDefs.IndexOf(CastToFuncdefType(in_type)); + else if (in_type->flags & asOBJ_TEMPLATE) + foundIdx = mod->m_templateInstances.IndexOf(CastToObjectType(in_type)); + else + foundIdx = mod->m_classTypes.IndexOf(CastToObjectType(in_type)); + + if( foundIdx >= 0 ) + { + in_type->module = mod; + break; + } + } + + return in_type->module; +} + +// internal +asCModule *asCScriptEngine::FindNewOwnerForSharedFunc(asCScriptFunction *in_func, asCModule *in_mod) +{ + asASSERT( in_func->IsShared() ); + asASSERT(!(in_func->funcType & asFUNC_FUNCDEF)); + + if( in_func->module != in_mod) + return in_func->module; + + if (in_func->objectType && in_func->objectType->module && + in_func->objectType->module != in_func->module) + { + // The object type for the method has already been transferred to + // another module, so transfer the method to the same module + in_func->module = in_func->objectType->module; + + // Make sure the function is listed in the module + // The compiler may not have done this earlier, since the object + // type is shared and originally compiled from another module + if (in_func->module->m_scriptFunctions.IndexOf(in_func) < 0) + { + in_func->module->m_scriptFunctions.PushLast(in_func); + in_func->AddRefInternal(); + } + } + + for( asUINT n = 0; n < scriptModules.GetLength(); n++ ) + { + // TODO: optimize: If the modules already stored the shared types separately, this would be quicker + int foundIdx = -1; + asCModule *mod = scriptModules[n]; + if( mod == in_func->module ) continue; + foundIdx = mod->m_scriptFunctions.IndexOf(in_func); + + if( foundIdx >= 0 ) + { + in_func->module = mod; + break; + } + } + + return in_func->module; +} + +// interface +void asCScriptEngine::ReturnContext(asIScriptContext *ctx) +{ + if( returnCtxFunc ) + { + returnCtxFunc(this, ctx, ctxCallbackParam); + return; + } + + // As fallback we just release the context + if( ctx ) + ctx->Release(); +} + +// interface +int asCScriptEngine::AddRef() const +{ + asASSERT( refCount.get() > 0 || inDestructor ); + return refCount.atomicInc(); +} + +// interface +int asCScriptEngine::Release() const +{ + int r = refCount.atomicDec(); + + if( r == 0 ) + { + // It is possible that some function will temporarily increment the engine ref count + // during clean-up for example while destroying the objects in the garbage collector. + if( !inDestructor ) + asDELETE(const_cast(this),asCScriptEngine); + return 0; + } + + return r; +} + +// interface +int asCScriptEngine::ShutDownAndRelease() +{ + // Do a full garbage collection cycle to clean up any object that may still hold on to the engine + GarbageCollect(); + + // Set the flag that the engine is being shutdown now. This will speed up + // the process, and will also allow the engine to warn about invalid calls + shuttingDown = true; + + // Clear the context callbacks. If new context's are needed for the clean-up the engine will take care of this itself. + // Context callbacks are normally used for pooling contexts, and if we allow new contexts to be created without being + // immediately destroyed afterwards it means the engine's refcount will increase. This is turn may cause memory access + // violations later on when the pool releases its contexts. + SetContextCallbacks(0, 0, 0); + + // The modules must be deleted first, as they may use + // object types from the config groups + for( asUINT n = (asUINT)scriptModules.GetLength(); n-- > 0; ) + if( scriptModules[n] ) + scriptModules[n]->Discard(); + scriptModules.SetLength(0); + + // Do another full garbage collection to destroy the object types/functions + // that may have been placed in the gc when destroying the modules + GarbageCollect(); + + // Do another sweep to delete discarded modules, that may not have + // been deleted earlier due to still having external references + DeleteDiscardedModules(); + + // If the application hasn't registered GC behaviours for all types + // that can form circular references with script types, then there + // may still be objects in the GC. + gc.ReportAndReleaseUndestroyedObjects(); + + // Release the engine reference + return Release(); +} + +// internal +asSNameSpace *asCScriptEngine::AddNameSpace(const char *name) +{ + // First check if it doesn't exist already + asSNameSpace *ns = FindNameSpace(name); + if( ns ) return ns; + + ns = asNEW(asSNameSpace); + if( ns == 0 ) + { + // Out of memory + return 0; + } + ns->name = name; + + nameSpaces.PushLast(ns); + + return ns; +} + +// internal +asSNameSpace *asCScriptEngine::FindNameSpace(const char *name) const +{ + // TODO: optimize: Improve linear search + for( asUINT n = 0; n < nameSpaces.GetLength(); n++ ) + if( nameSpaces[n]->name == name ) + return nameSpaces[n]; + + return 0; +} + +// interface +const char *asCScriptEngine::GetDefaultNamespace() const +{ + return defaultNamespace->name.AddressOf(); +} + +// interface +int asCScriptEngine::SetDefaultNamespace(const char *nameSpace) +{ + if( nameSpace == 0 ) + return ConfigError(asINVALID_ARG, "SetDefaultNamespace", nameSpace, 0); + + asCString ns = nameSpace; + if( ns != "" ) + { + // Make sure the namespace is composed of alternating identifier and :: + size_t pos = 0; + bool expectIdentifier = true; + size_t len; + eTokenType t = ttIdentifier; + + for( ; pos < ns.GetLength(); pos += len) + { + t = tok.GetToken(ns.AddressOf() + pos, ns.GetLength() - pos, &len); + if( (expectIdentifier && t != ttIdentifier) || (!expectIdentifier && t != ttScope) ) + return ConfigError(asINVALID_DECLARATION, "SetDefaultNamespace", nameSpace, 0); + + // Make sure parent namespaces are registred in case of nested namespaces + if (expectIdentifier) + AddNameSpace(ns.SubString(0, pos + len).AddressOf()); + + expectIdentifier = !expectIdentifier; + } + + // If the namespace ends with :: then strip it off + if( t == ttScope ) + ns.SetLength(ns.GetLength()-2); + } + + defaultNamespace = AddNameSpace(ns.AddressOf()); + + return 0; +} + +// interface +void *asCScriptEngine::SetUserData(void *data, asPWORD type) +{ + // As a thread might add a new new user data at the same time as another + // it is necessary to protect both read and write access to the userData member + ACQUIREEXCLUSIVE(engineRWLock); + + // It is not intended to store a lot of different types of userdata, + // so a more complex structure like a associative map would just have + // more overhead than a simple array. + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) + { + if( userData[n] == type ) + { + void *oldData = reinterpret_cast(userData[n+1]); + userData[n+1] = reinterpret_cast(data); + + RELEASEEXCLUSIVE(engineRWLock); + + return oldData; + } + } + + userData.PushLast(type); + userData.PushLast(reinterpret_cast(data)); + + RELEASEEXCLUSIVE(engineRWLock); + + return 0; +} + +// interface +void *asCScriptEngine::GetUserData(asPWORD type) const +{ + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + ACQUIRESHARED(engineRWLock); + + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) + { + if( userData[n] == type ) + { + RELEASESHARED(engineRWLock); + return reinterpret_cast(userData[n+1]); + } + } + + RELEASESHARED(engineRWLock); + + return 0; +} + +// interface +int asCScriptEngine::SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv) +{ + msgCallback = true; + msgCallbackObj = obj; + bool isObj = false; + if( (unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST ) + { + msgCallback = false; + return asNOT_SUPPORTED; + } + if( (unsigned)callConv >= asCALL_THISCALL ) + { + isObj = true; + if( obj == 0 ) + { + msgCallback = false; + return asINVALID_ARG; + } + } + int r = DetectCallingConvention(isObj, callback, callConv, 0, &msgCallbackFunc); + if( r < 0 ) msgCallback = false; + return r; +} + +// interface +int asCScriptEngine::ClearMessageCallback() +{ + msgCallback = false; + return 0; +} + +// interface +int asCScriptEngine::WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message) +{ + // Validate input parameters + if( section == 0 || + message == 0 ) + return asINVALID_ARG; + + // If there is no callback then there's nothing to do + if( !msgCallback ) + return 0; + + // If a pre-message has been set, then write that first + if( preMessage.isSet ) + { + asSMessageInfo msg; + msg.section = preMessage.scriptname.AddressOf(); + msg.row = preMessage.r; + msg.col = preMessage.c; + msg.type = asMSGTYPE_INFORMATION; + msg.message = preMessage.message.AddressOf(); + + if( msgCallbackFunc.callConv < ICC_THISCALL ) + CallGlobalFunction(&msg, msgCallbackObj, &msgCallbackFunc, 0); + else + CallObjectMethod(msgCallbackObj, &msg, &msgCallbackFunc, 0); + + preMessage.isSet = false; + } + + // Write the message to the callback + asSMessageInfo msg; + msg.section = section; + msg.row = row; + msg.col = col; + msg.type = type; + msg.message = message; + + if( msgCallbackFunc.callConv < ICC_THISCALL ) + CallGlobalFunction(&msg, msgCallbackObj, &msgCallbackFunc, 0); + else + CallObjectMethod(msgCallbackObj, &msg, &msgCallbackFunc, 0); + + return 0; +} + +int asCScriptEngine::SetJITCompiler(asIJITCompiler *compiler) +{ + jitCompiler = compiler; + return asSUCCESS; +} + +asIJITCompiler *asCScriptEngine::GetJITCompiler() const +{ + return jitCompiler; +} + +// interface +asETokenClass asCScriptEngine::ParseToken(const char *string, size_t stringLength, asUINT *tokenLength) const +{ + if( stringLength == 0 ) + stringLength = strlen(string); + + size_t len; + asETokenClass tc; + tok.GetToken(string, stringLength, &len, &tc); + + if( tokenLength ) + *tokenLength = (asUINT)len; + + return tc; +} + +// interface +asIScriptModule *asCScriptEngine::GetModule(const char *module, asEGMFlags flag) +{ + asCModule *mod = GetModule(module, false); + + if( flag == asGM_ALWAYS_CREATE ) + { + if( mod != 0 ) + mod->Discard(); + + return GetModule(module, true); + } + + if( mod == 0 && flag == asGM_CREATE_IF_NOT_EXISTS ) + return GetModule(module, true); + + return mod; +} + +// interface +int asCScriptEngine::DiscardModule(const char *module) +{ + asCModule *mod = GetModule(module, false); + if( mod == 0 ) return asNO_MODULE; + + mod->Discard(); + + return 0; +} + +// interface +asUINT asCScriptEngine::GetModuleCount() const +{ + ACQUIRESHARED(engineRWLock); + asUINT length = asUINT(scriptModules.GetLength()); + RELEASESHARED(engineRWLock); + return length; +} + +// interface +asIScriptModule *asCScriptEngine::GetModuleByIndex(asUINT index) const +{ + asIScriptModule *mod = 0; + ACQUIRESHARED(engineRWLock); + if( index < scriptModules.GetLength() ) + mod = scriptModules[index]; + RELEASESHARED(engineRWLock); + return mod; +} + +// internal +int asCScriptEngine::GetFactoryIdByDecl(const asCObjectType *ot, const char *decl) +{ + asCModule *mod = 0; + + // Is this a script class? + if( (ot->flags & asOBJ_SCRIPT_OBJECT) && ot->size > 0 ) + mod = scriptFunctions[ot->beh.factories[0]]->module; + + asCBuilder bld(this, mod); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCScriptFunction func(this, mod, asFUNC_DUMMY); + int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace); + if( r < 0 ) + return asINVALID_DECLARATION; + + // Search for matching factory function + int id = -1; + for( asUINT n = 0; n < ot->beh.factories.GetLength(); n++ ) + { + asCScriptFunction *f = scriptFunctions[ot->beh.factories[n]]; + if( f->IsSignatureEqual(&func) ) + { + id = ot->beh.factories[n]; + break; + } + } + + if( id == -1 ) return asNO_FUNCTION; + + return id; +} + + +// internal +int asCScriptEngine::GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod) +{ + asCBuilder bld(this, mod); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCScriptFunction func(this, mod, asFUNC_DUMMY); + + // Set the object type so that the signature can be properly compared + // This cast is OK, it will only be used for comparison + func.objectType = const_cast(ot); + func.objectType->AddRefInternal(); + + int r = bld.ParseFunctionDeclaration(func.objectType, decl, &func, false); + if( r < 0 ) + return asINVALID_DECLARATION; + + // Search script functions for matching interface + int id = -1; + for( asUINT n = 0; n < ot->methods.GetLength(); ++n ) + { + if( func.IsSignatureEqual(scriptFunctions[ot->methods[n]]) ) + { + if( id == -1 ) + id = ot->methods[n]; + else + return asMULTIPLE_FUNCTIONS; + } + } + + if( id == -1 ) return asNO_FUNCTION; + + return id; +} + + +// internal +asCString asCScriptEngine::GetFunctionDeclaration(int funcId) +{ + asCString str; + asCScriptFunction *func = GetScriptFunction(funcId); + if( func ) + str = func->GetDeclarationStr(); + + return str; +} + +// internal +asCScriptFunction *asCScriptEngine::GetScriptFunction(int funcId) const +{ + if( funcId < 0 || funcId >= (int)scriptFunctions.GetLength() ) + return 0; + + return scriptFunctions[funcId]; +} + + +// interface +asIScriptContext *asCScriptEngine::CreateContext() +{ + asIScriptContext *ctx = 0; + CreateContext(&ctx, false); + return ctx; +} + +// internal +int asCScriptEngine::CreateContext(asIScriptContext **context, bool isInternal) +{ + *context = asNEW(asCContext)(this, !isInternal); + if( *context == 0 ) + return asOUT_OF_MEMORY; + + // We need to make sure the engine has been + // prepared before any context is executed + PrepareEngine(); + + return 0; +} + +// interface +int asCScriptEngine::RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset, bool isCompositeIndirect) +{ + int r; + asCDataType dt; + asCBuilder bld(this, 0); + r = bld.ParseDataType(obj, &dt, defaultNamespace); + if( r < 0 ) + return ConfigError(r, "RegisterObjectProperty", obj, declaration); + + if (dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) + return ConfigError(asINVALID_OBJECT, "RegisterObjectProperty", obj, declaration); + + // Don't allow modifying generated template instances + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectProperty", obj, declaration); + + // Verify that the correct config group is used + if( currentGroup->FindType(dt.GetTypeInfo()->name.AddressOf()) == 0 ) + return ConfigError(asWRONG_CONFIG_GROUP, "RegisterObjectProperty", obj, declaration); + + asCDataType type; + asCString name; + + if( (r = bld.VerifyProperty(&dt, declaration, name, type, 0)) < 0 ) + return ConfigError(r, "RegisterObjectProperty", obj, declaration); + + // The VM currently only supports 16bit offsets + // TODO: The VM needs to have support for 32bit offsets. Probably with a second ADDSi instruction + // However, when implementing this it is necessary for the bytecode serialization to support + // the switch between the instructions upon loading bytecode as the offset may not be the + // same on all platforms + if( byteOffset > 32767 || byteOffset < -32768 ) + return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration); + // The composite offset must also obey the ADDSi restriction + if (compositeOffset > 32767 || compositeOffset < -32768) + return ConfigError(asINVALID_ARG, "RegisterObjectProperty", obj, declaration); + + asCObjectProperty *prop = asNEW(asCObjectProperty); + if( prop == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectProperty", obj, declaration); + + prop->name = name; + prop->type = type; + prop->byteOffset = byteOffset; + prop->isPrivate = false; + prop->isProtected = false; + prop->compositeOffset = compositeOffset; + prop->isCompositeIndirect = isCompositeIndirect; + prop->accessMask = defaultAccessMask; + + asCObjectType *ot = CastToObjectType(dt.GetTypeInfo()); + asUINT idx = ot->properties.GetLength(); + ot->properties.PushLast(prop); + + // Add references to types so they are not released too early + if( type.GetTypeInfo() ) + { + type.GetTypeInfo()->AddRefInternal(); + + // Add template instances to the config group + if( (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && !currentGroup->types.Exists(type.GetTypeInfo()) ) + currentGroup->types.PushLast(type.GetTypeInfo()); + } + + currentGroup->AddReferencesForType(this, type.GetTypeInfo()); + + // Return the index of the property to signal success + return idx; +} + +// interface +int asCScriptEngine::RegisterInterface(const char *name) +{ + if( name == 0 ) return ConfigError(asINVALID_NAME, "RegisterInterface", 0, 0); + + // Verify if the name has been registered as a type already + if( GetRegisteredType(name, defaultNamespace) ) + return asALREADY_REGISTERED; + + // Use builder to parse the datatype + asCDataType dt; + asCBuilder bld(this, 0); + bool oldMsgCallback = msgCallback; msgCallback = false; + int r = bld.ParseDataType(name, &dt, defaultNamespace); + msgCallback = oldMsgCallback; + if( r >= 0 ) + { + // If it is not in the defaultNamespace then the type was successfully parsed because + // it is declared in a parent namespace which shouldn't be treated as an error + if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) + return ConfigError(asERROR, "RegisterInterface", name, 0); + } + + // Make sure the name is not a reserved keyword + size_t tokenLen; + int token = tok.GetToken(name, strlen(name), &tokenLen); + if( token != ttIdentifier || strlen(name) != tokenLen ) + return ConfigError(asINVALID_NAME, "RegisterInterface", name, 0); + + r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true, false); + if( r < 0 ) + return ConfigError(asNAME_TAKEN, "RegisterInterface", name, 0); + + // Don't have to check against members of object + // types as they are allowed to use the names + + // Register the object type for the interface + asCObjectType *st = asNEW(asCObjectType)(this); + if( st == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterInterface", name, 0); + + st->flags = asOBJ_REF | asOBJ_SCRIPT_OBJECT | asOBJ_SHARED; + st->size = 0; // Cannot be instantiated + st->name = name; + st->nameSpace = defaultNamespace; + + // Use the default script class behaviours + st->beh.factory = 0; + st->beh.addref = scriptTypeBehaviours.beh.addref; + scriptFunctions[st->beh.addref]->AddRefInternal(); + st->beh.release = scriptTypeBehaviours.beh.release; + scriptFunctions[st->beh.release]->AddRefInternal(); + st->beh.copy = 0; + + allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); + registeredObjTypes.PushLast(st); + + currentGroup->types.PushLast(st); + + return GetTypeIdByDecl(name); +} + +// interface +int asCScriptEngine::RegisterInterfaceMethod(const char *intf, const char *declaration) +{ + // Verify that the correct config group is set. + if( currentGroup->FindType(intf) == 0 ) + return ConfigError(asWRONG_CONFIG_GROUP, "RegisterInterfaceMethod", intf, declaration); + + asCDataType dt; + asCBuilder bld(this, 0); + int r = bld.ParseDataType(intf, &dt, defaultNamespace); + if( r < 0 ) + return ConfigError(r, "RegisterInterfaceMethod", intf, declaration); + + asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_INTERFACE); + if( func == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterInterfaceMethod", intf, declaration); + + func->objectType = CastToObjectType(dt.GetTypeInfo()); + func->objectType->AddRefInternal(); + + r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, false); + if( r < 0 ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asINVALID_DECLARATION, "RegisterInterfaceMethod", intf, declaration); + } + + // Check name conflicts + r = bld.CheckNameConflictMember(dt.GetTypeInfo(), func->name.AddressOf(), 0, 0, false, false); + if( r < 0 ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterInterfaceMethod", intf, declaration); + } + + func->id = GetNextScriptFunctionId(); + AddScriptFunction(func); + + // The index into the interface's vftable chunk should be + // its index in the methods array. + func->vfTableIdx = int(func->objectType->methods.GetLength()); + + func->objectType->methods.PushLast(func->id); + + func->ComputeSignatureId(); + + currentGroup->AddReferencesForFunc(this, func); + + // Return function id as success + return func->id; +} + +int asCScriptEngine::RegisterObjectType(const char *name, int byteSize, asDWORD flags) +{ + int r; + + isPrepared = false; + + // Verify flags + // Must have either asOBJ_REF or asOBJ_VALUE + if( flags & asOBJ_REF ) + { + // Can optionally have the asOBJ_GC, asOBJ_NOHANDLE, asOBJ_SCOPED, or asOBJ_TEMPLATE flag set, but nothing else + if( flags & ~(asOBJ_REF | asOBJ_GC | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_TEMPLATE | asOBJ_NOCOUNT | asOBJ_IMPLICIT_HANDLE) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + + // flags are exclusive + if( (flags & asOBJ_GC) && (flags & (asOBJ_NOHANDLE|asOBJ_SCOPED|asOBJ_NOCOUNT)) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + if( (flags & asOBJ_NOHANDLE) && (flags & (asOBJ_GC|asOBJ_SCOPED|asOBJ_NOCOUNT|asOBJ_IMPLICIT_HANDLE)) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + if( (flags & asOBJ_SCOPED) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_NOCOUNT|asOBJ_IMPLICIT_HANDLE)) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + if( (flags & asOBJ_NOCOUNT) && (flags & (asOBJ_GC|asOBJ_NOHANDLE|asOBJ_SCOPED)) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + + // Implicit handle is only allowed if the engine property for this is turned on + if( !ep.allowImplicitHandleTypes && (flags & asOBJ_IMPLICIT_HANDLE) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + else if( flags & asOBJ_VALUE ) + { + // Cannot use reference flags + if( flags & (asOBJ_REF | asOBJ_NOHANDLE | asOBJ_SCOPED | asOBJ_NOCOUNT | asOBJ_IMPLICIT_HANDLE) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + + // Flags are exclusive + if( (flags & asOBJ_POD) && (flags & (asOBJ_ASHANDLE | asOBJ_TEMPLATE)) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + + // If the app type is given, we must validate the flags + if( flags & asOBJ_APP_CLASS ) + { + // Must not set the primitive or float flag + if( flags & (asOBJ_APP_PRIMITIVE | asOBJ_APP_FLOAT | asOBJ_APP_ARRAY) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + else + { + // Must not set the class properties, without the class flag + if( flags & (asOBJ_APP_CLASS_CONSTRUCTOR | + asOBJ_APP_CLASS_DESTRUCTOR | + asOBJ_APP_CLASS_ASSIGNMENT | + asOBJ_APP_CLASS_COPY_CONSTRUCTOR | + asOBJ_APP_CLASS_ALLINTS | + asOBJ_APP_CLASS_ALLFLOATS) ) + { + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + } + + if( flags & asOBJ_APP_PRIMITIVE ) + { + if( flags & (asOBJ_APP_CLASS | + asOBJ_APP_FLOAT | + asOBJ_APP_ARRAY) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + else if( flags & asOBJ_APP_FLOAT ) + { + if( flags & (asOBJ_APP_CLASS | + asOBJ_APP_PRIMITIVE | + asOBJ_APP_ARRAY) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + else if( flags & asOBJ_APP_ARRAY ) + { + if( flags & (asOBJ_APP_CLASS | + asOBJ_APP_PRIMITIVE | + asOBJ_APP_FLOAT) ) + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + } + else + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + + // Don't allow anything else than the defined flags +#ifndef WIP_16BYTE_ALIGN + if( flags - (flags & asOBJ_MASK_VALID_FLAGS) ) +#else + if( flags - (flags & (asOBJ_MASK_VALID_FLAGS | asOBJ_APP_ALIGN16)) ) +#endif + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + + // Value types must have a defined size + if( (flags & asOBJ_VALUE) && byteSize == 0 ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_VALUE_TYPE_MUST_HAVE_SIZE); + return ConfigError(asINVALID_ARG, "RegisterObjectType", name, 0); + } + + // Verify type name + if( name == 0 ) + return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0); + + asCString typeName; + asCBuilder bld(this, 0); + if( flags & asOBJ_TEMPLATE ) + { + asCArray subtypeNames; + r = bld.ParseTemplateDecl(name, &typeName, subtypeNames); + if( r < 0 ) + return ConfigError(r, "RegisterObjectType", name, 0); + + // Verify that the template name hasn't been registered as a type already + if( GetRegisteredType(typeName, defaultNamespace) ) + // This is not an irrepairable error, as it may just be that the same type is registered twice + return asALREADY_REGISTERED; + + asCObjectType *type = asNEW(asCObjectType)(this); + if( type == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); + + type->name = typeName; + type->nameSpace = defaultNamespace; + type->size = byteSize; +#ifdef WIP_16BYTE_ALIGN + // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries + type->alignment = (flags & asOBJ_APP_ALIGN16) ? 16 : 4; +#endif + type->flags = flags; + type->accessMask = defaultAccessMask; + + // Store it in the object types + allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); + currentGroup->types.PushLast(type); + registeredObjTypes.PushLast(type); + registeredTemplateTypes.PushLast(type); + + // Define the template subtypes + for( asUINT subTypeIdx = 0; subTypeIdx < subtypeNames.GetLength(); subTypeIdx++ ) + { + asCTypeInfo *subtype = 0; + for( asUINT n = 0; n < templateSubTypes.GetLength(); n++ ) + { + if( templateSubTypes[n]->name == subtypeNames[subTypeIdx] ) + { + subtype = templateSubTypes[n]; + break; + } + } + if( subtype == 0 ) + { + // Create the new subtype if not already existing + subtype = asNEW(asCTypeInfo)(this); + if( subtype == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); + + subtype->name = subtypeNames[subTypeIdx]; + subtype->size = 0; + subtype->flags = asOBJ_TEMPLATE_SUBTYPE; + templateSubTypes.PushLast(subtype); + } + type->templateSubTypes.PushLast(asCDataType::CreateType(subtype, false)); + subtype->AddRefInternal(); + } + } + else + { + typeName = name; + + // Verify if the name has been registered as a type already + if( GetRegisteredType(typeName, defaultNamespace) ) + // This is not an irrepairable error, as it may just be that the same type is registered twice + return asALREADY_REGISTERED; + + // Keep the most recent template generated instance type, so we know what it was before parsing the datatype + asCObjectType *mostRecentTemplateInstanceType = 0; + asUINT originalSizeOfGeneratedTemplateTypes = (asUINT)generatedTemplateTypes.GetLength(); + if( originalSizeOfGeneratedTemplateTypes ) + mostRecentTemplateInstanceType = generatedTemplateTypes[originalSizeOfGeneratedTemplateTypes-1]; + + // Use builder to parse the datatype + asCDataType dt; + bool oldMsgCallback = msgCallback; msgCallback = false; + r = bld.ParseDataType(name, &dt, defaultNamespace); + msgCallback = oldMsgCallback; + + // If the builder fails or the namespace is different than the default + // namespace, then the type name is new and it should be registered + if( r < 0 || dt.GetTypeInfo()->nameSpace != defaultNamespace ) + { + // Make sure the name is not a reserved keyword + size_t tokenLen; + int token = tok.GetToken(name, typeName.GetLength(), &tokenLen); + if( token != ttIdentifier || typeName.GetLength() != tokenLen ) + return ConfigError(asINVALID_NAME, "RegisterObjectType", name, 0); + + r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true, false); + if( r < 0 ) + return ConfigError(asNAME_TAKEN, "RegisterObjectType", name, 0); + + // Don't have to check against members of object + // types as they are allowed to use the names + + // Put the data type in the list + asCObjectType *type = asNEW(asCObjectType)(this); + if( type == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); + + type->name = typeName; + type->nameSpace = defaultNamespace; + type->size = byteSize; +#ifdef WIP_16BYTE_ALIGN + // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries + type->alignment = (flags & asOBJ_APP_ALIGN16) ? 16 : 4; +#endif + type->flags = flags; + type->accessMask = defaultAccessMask; + + allRegisteredTypes.Insert(asSNameSpaceNamePair(type->nameSpace, type->name), type); + registeredObjTypes.PushLast(type); + + currentGroup->types.PushLast(type); + } + else + { + // The application is registering a template specialization so we + // need to replace the template instance type with the new type. + + // TODO: Template: We don't require the lower dimensions to be registered first for registered template types + // int[][] must not be allowed to be registered + // if int[] hasn't been registered first + if( dt.GetSubType().IsTemplate() ) + return ConfigError(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED, "RegisterObjectType", name, 0); + + if( dt.IsReadOnly() || + dt.IsReference() ) + return ConfigError(asINVALID_TYPE, "RegisterObjectType", name, 0); + + // Was the template instance type generated before? + if( generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) && + generatedTemplateTypes[generatedTemplateTypes.GetLength()-1] == mostRecentTemplateInstanceType ) + { + asCString str; + str.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, typeName.AddressOf()); + WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0); + } + + // If this is not a generated template instance type, then it means it is an + // already registered template specialization + if( !generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectType", name, 0); + + // TODO: Add this again. The type is used by the factory stubs so we need to discount that + // Is the template instance type already being used? +// if( dt.GetTypeInfo()->GetRefCount() > 1 ) +// return ConfigError(asNOT_SUPPORTED, "RegisterObjectType", name, 0); + + // Put the data type in the list + asCObjectType *type = asNEW(asCObjectType)(this); + if( type == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectType", name, 0); + + type->name = dt.GetTypeInfo()->name; + // The namespace will be the same as the original template type + type->nameSpace = dt.GetTypeInfo()->nameSpace; + type->templateSubTypes.PushLast(dt.GetSubType()); + for( asUINT s = 0; s < type->templateSubTypes.GetLength(); s++ ) + if( type->templateSubTypes[s].GetTypeInfo() ) + type->templateSubTypes[s].GetTypeInfo()->AddRefInternal(); + type->size = byteSize; +#ifdef WIP_16BYTE_ALIGN + // TODO: Types smaller than 4 don't need to be aligned to 4 byte boundaries + type->alignment = (flags & asOBJ_APP_ALIGN16) ? 16 : 4; +#endif + type->flags = flags; + type->accessMask = defaultAccessMask; + + templateInstanceTypes.PushLast(type); + + currentGroup->types.PushLast(type); + + // Remove the template instance type, which will no longer be used. + // It is possible that multiple template instances are generated if + // they have any relationship, so all of them must be removed + while( generatedTemplateTypes.GetLength() > originalSizeOfGeneratedTemplateTypes ) + RemoveTemplateInstanceType(generatedTemplateTypes[generatedTemplateTypes.GetLength()-1]); + } + } + + // Return the type id as the success (except for template types) + if( flags & asOBJ_TEMPLATE ) + return asSUCCESS; + + return GetTypeIdByDecl(name); +} + +// interface +int asCScriptEngine::RegisterObjectBehaviour(const char *datatype, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) +{ + if( datatype == 0 ) return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", datatype, decl); + + // Determine the object type + asCBuilder bld(this, 0); + asCDataType type; + int r = bld.ParseDataType(datatype, &type, defaultNamespace); + if( r < 0 ) + return ConfigError(r, "RegisterObjectBehaviour", datatype, decl); + + if( type.GetTypeInfo() == 0 || (type.IsObjectHandle() && !(type.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE)) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + + // Don't allow application to modify built-in types + if( type.GetTypeInfo() == &functionBehaviours || + type.GetTypeInfo() == &scriptTypeBehaviours ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + + if( type.IsReadOnly() || type.IsReference() ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + + // Don't allow modifying generated template instances + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(type.GetTypeInfo())) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectBehaviour", datatype, decl); + + return RegisterBehaviourToObjectType(CastToObjectType(type.GetTypeInfo()), behaviour, decl, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); +} + +// internal +int asCScriptEngine::RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) +{ +#ifdef AS_MAX_PORTABILITY + if( callConv != asCALL_GENERIC ) + return ConfigError(asNOT_SUPPORTED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); +#endif + + asSSystemFunctionInterface internal; + bool isMethod = !(behaviour == asBEHAVE_FACTORY || + behaviour == asBEHAVE_LIST_FACTORY || + behaviour == asBEHAVE_TEMPLATE_CALLBACK); + int r = DetectCallingConvention(isMethod, funcPointer, callConv, auxiliary, &internal); + if( r < 0 ) + return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + internal.compositeOffset = compositeOffset; + internal.isCompositeIndirect = isCompositeIndirect; + if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) + return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType + // If the object type is a template, make sure there are no generated instances already + if( objectType->flags & asOBJ_TEMPLATE ) + { + for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) + { + asCObjectType *tmpl = generatedTemplateTypes[n]; + if( tmpl->name == objectType->name && + tmpl->nameSpace == objectType->nameSpace && + !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + { + asCString msg; + msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); + WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); + return ConfigError(asERROR, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + } + } + + isPrepared = false; + + asSTypeBehaviour *beh = &objectType->beh; + + // Verify function declaration + asCScriptFunction func(this, 0, asFUNC_DUMMY); + + bool expectListPattern = behaviour == asBEHAVE_LIST_FACTORY || behaviour == asBEHAVE_LIST_CONSTRUCT; + asCScriptNode *listPattern = 0; + asCBuilder bld(this, 0); + r = bld.ParseFunctionDeclaration(objectType, decl, &func, true, &internal.paramAutoHandles, &internal.returnAutoHandle, 0, expectListPattern ? &listPattern : 0); + if( r < 0 ) + { + if( listPattern ) + listPattern->Destroy(this); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + func.name.Format("$beh%d", behaviour); + + if( behaviour != asBEHAVE_FACTORY && behaviour != asBEHAVE_LIST_FACTORY ) + { + func.objectType = objectType; + func.objectType->AddRefInternal(); + } + + // Check if the method restricts that use of the template to value types or reference types + if( objectType->flags & asOBJ_TEMPLATE ) + { + r = SetTemplateRestrictions(objectType, &func, "RegisterObjectBehaviour", decl); + if (r < 0) + return r; + } + + if( behaviour == asBEHAVE_CONSTRUCT ) + { + // Verify that the return type is void + if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + if( objectType->flags & asOBJ_SCRIPT_OBJECT ) + { + // The script object is a special case + asASSERT(func.parameterTypes.GetLength() == 1); + + beh->construct = AddBehaviourFunction(func, internal); + beh->factory = beh->construct; + scriptFunctions[beh->factory]->AddRefInternal(); + beh->constructors.PushLast(beh->construct); + beh->factories.PushLast(beh->factory); + func.id = beh->construct; + } + else + { + // Verify that it is a value type + if( !(func.objectType->flags & asOBJ_VALUE) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // The templates take a hidden parameter with the object type + if( (objectType->flags & asOBJ_TEMPLATE) && + (func.parameterTypes.GetLength() == 0 || + !func.parameterTypes[0].IsReference()) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // TODO: Verify that the same constructor hasn't been registered already + + // Store all constructors in a list + func.id = AddBehaviourFunction(func, internal); + beh->constructors.PushLast(func.id); + if( func.parameterTypes.GetLength() == 0 || + (func.parameterTypes.GetLength() == 1 && (objectType->flags & asOBJ_TEMPLATE)) ) + { + beh->construct = func.id; + } + else if( func.parameterTypes.GetLength() == 1 ) + { + // Is this the copy constructor? + asCDataType paramType = func.parameterTypes[0]; + + // If the parameter is object, and const reference for input or inout, + // and same type as this class, then this is a copy constructor. + if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && + (func.inOutFlags[0] & asTM_INREF) && paramType.GetTypeInfo() == objectType ) + beh->copyconstruct = func.id; + } + } + } + else if( behaviour == asBEHAVE_DESTRUCT ) + { + // Must be a value type + if( !(func.objectType->flags & asOBJ_VALUE) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + if( beh->destruct ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that the return type is void + if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that there are no parameters + if( func.parameterTypes.GetLength() > 0 ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + func.id = beh->destruct = AddBehaviourFunction(func, internal); + } + else if( behaviour == asBEHAVE_LIST_CONSTRUCT ) + { + func.name = "$list"; + + // Verify that the return type is void + if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) + { + if( listPattern ) + listPattern->Destroy(this); + + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Verify that it is a value type + if( !(func.objectType->flags & asOBJ_VALUE) ) + { + if( listPattern ) + listPattern->Destroy(this); + + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Verify the parameters + if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() ) + { + if( listPattern ) + listPattern->Destroy(this); + + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Don't accept duplicates + if( beh->listFactory ) + { + if( listPattern ) + listPattern->Destroy(this); + + return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Add the function + func.id = AddBehaviourFunction(func, internal); + + // Re-use the listFactory member, as it is not possible to have both anyway + beh->listFactory = func.id; + + // Store the list pattern for this function + r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); + + if( listPattern ) + listPattern->Destroy(this); + + if( r < 0 ) + return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + else if( behaviour == asBEHAVE_FACTORY || behaviour == asBEHAVE_LIST_FACTORY ) + { + if( behaviour == asBEHAVE_LIST_FACTORY ) + func.name = "$list"; + + // Must be a ref type and must not have asOBJ_NOHANDLE + if( !(objectType->flags & asOBJ_REF) || (objectType->flags & asOBJ_NOHANDLE) ) + { + if( listPattern ) + listPattern->Destroy(this); + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Verify that the return type is a handle to the type + if( func.returnType != asCDataType::CreateObjectHandle(objectType, false) ) + { + if( listPattern ) + listPattern->Destroy(this); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // The templates take a hidden parameter with the object type + if( (objectType->flags & asOBJ_TEMPLATE) && + (func.parameterTypes.GetLength() == 0 || + !func.parameterTypes[0].IsReference()) ) + { + if( listPattern ) + listPattern->Destroy(this); + + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + if( behaviour == asBEHAVE_LIST_FACTORY ) + { + // Make sure the factory takes a reference as its last parameter + if( objectType->flags & asOBJ_TEMPLATE ) + { + if( func.parameterTypes.GetLength() != 2 || !func.parameterTypes[1].IsReference() ) + { + if( listPattern ) + listPattern->Destroy(this); + + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_TEMPLATE_LIST_FACTORY_EXPECTS_2_REF_PARAMS); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + } + else + { + if( func.parameterTypes.GetLength() != 1 || !func.parameterTypes[0].IsReference() ) + { + if( listPattern ) + listPattern->Destroy(this); + + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + } + } + + // TODO: Verify that the same factory function hasn't been registered already + + // Don't accept duplicates + if( behaviour == asBEHAVE_LIST_FACTORY && beh->listFactory ) + { + if( listPattern ) + listPattern->Destroy(this); + + return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Store all factory functions in a list + func.id = AddBehaviourFunction(func, internal); + + // The list factory is a special factory and isn't stored together with the rest + if( behaviour != asBEHAVE_LIST_FACTORY ) + beh->factories.PushLast(func.id); + + if( (func.parameterTypes.GetLength() == 0) || + (func.parameterTypes.GetLength() == 1 && (objectType->flags & asOBJ_TEMPLATE)) ) + { + beh->factory = func.id; + } + else if( (func.parameterTypes.GetLength() == 1) || + (func.parameterTypes.GetLength() == 2 && (objectType->flags & asOBJ_TEMPLATE)) ) + { + if( behaviour == asBEHAVE_LIST_FACTORY ) + { + beh->listFactory = func.id; + + // Store the list pattern for this function + r = scriptFunctions[func.id]->RegisterListPattern(decl, listPattern); + + if( listPattern ) + listPattern->Destroy(this); + + if( r < 0 ) + return ConfigError(r, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + else + { + // Is this the copy factory? + asCDataType paramType = func.parameterTypes[func.parameterTypes.GetLength()-1]; + + // If the parameter is object, and const reference for input, + // and same type as this class, then this is a copy constructor. + if( paramType.IsObject() && paramType.IsReference() && paramType.IsReadOnly() && func.inOutFlags[func.parameterTypes.GetLength()-1] == asTM_INREF && paramType.GetTypeInfo() == objectType ) + beh->copyfactory = func.id; + } + } + } + else if( behaviour == asBEHAVE_ADDREF ) + { + // Must be a ref type and must not have asOBJ_NOHANDLE, nor asOBJ_SCOPED + if( !(func.objectType->flags & asOBJ_REF) || + (func.objectType->flags & asOBJ_NOHANDLE) || + (func.objectType->flags & asOBJ_SCOPED) || + (func.objectType->flags & asOBJ_NOCOUNT) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + if( beh->addref ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that the return type is void + if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that there are no parameters + if( func.parameterTypes.GetLength() > 0 ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + func.id = beh->addref = AddBehaviourFunction(func, internal); + } + else if( behaviour == asBEHAVE_RELEASE ) + { + // Must be a ref type and must not have asOBJ_NOHANDLE + if( !(func.objectType->flags & asOBJ_REF) || + (func.objectType->flags & asOBJ_NOHANDLE) || + (func.objectType->flags & asOBJ_NOCOUNT) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + if( beh->release ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that the return type is void + if( func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that there are no parameters + if( func.parameterTypes.GetLength() > 0 ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + func.id = beh->release = AddBehaviourFunction(func, internal); + } + else if( behaviour == asBEHAVE_TEMPLATE_CALLBACK ) + { + // Must be a template type + if( !(func.objectType->flags & asOBJ_TEMPLATE) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + if( beh->templateCallback ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that the return type is bool + if( func.returnType != asCDataType::CreatePrimitive(ttBool, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that there are two parameters + if( func.parameterTypes.GetLength() != 2 ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // The first parameter must be an inref (to receive the object type), and + // the second must be a bool out ref (to return if the type should or shouldn't be garbage collected) + if( func.inOutFlags[0] != asTM_INREF || func.inOutFlags[1] != asTM_OUTREF || !func.parameterTypes[1].IsEqualExceptRef(asCDataType::CreatePrimitive(ttBool, false)) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + func.id = beh->templateCallback = AddBehaviourFunction(func, internal); + } + else if( behaviour >= asBEHAVE_FIRST_GC && + behaviour <= asBEHAVE_LAST_GC ) + { + // Only allow GC behaviours for types registered to be garbage collected + if( !(func.objectType->flags & asOBJ_GC) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Verify parameter count + if( (behaviour == asBEHAVE_GETREFCOUNT || + behaviour == asBEHAVE_SETGCFLAG || + behaviour == asBEHAVE_GETGCFLAG) && + func.parameterTypes.GetLength() != 0 ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + if( (behaviour == asBEHAVE_ENUMREFS || + behaviour == asBEHAVE_RELEASEREFS) && + func.parameterTypes.GetLength() != 1 ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify return type + if( behaviour == asBEHAVE_GETREFCOUNT && + func.returnType != asCDataType::CreatePrimitive(ttInt, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + if( behaviour == asBEHAVE_GETGCFLAG && + func.returnType != asCDataType::CreatePrimitive(ttBool, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + if( (behaviour == asBEHAVE_SETGCFLAG || + behaviour == asBEHAVE_ENUMREFS || + behaviour == asBEHAVE_RELEASEREFS) && + func.returnType != asCDataType::CreatePrimitive(ttVoid, false) ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + if( behaviour == asBEHAVE_GETREFCOUNT ) + func.id = beh->gcGetRefCount = AddBehaviourFunction(func, internal); + else if( behaviour == asBEHAVE_SETGCFLAG ) + func.id = beh->gcSetFlag = AddBehaviourFunction(func, internal); + else if( behaviour == asBEHAVE_GETGCFLAG ) + func.id = beh->gcGetFlag = AddBehaviourFunction(func, internal); + else if( behaviour == asBEHAVE_ENUMREFS ) + func.id = beh->gcEnumReferences = AddBehaviourFunction(func, internal); + else if( behaviour == asBEHAVE_RELEASEREFS ) + func.id = beh->gcReleaseAllReferences = AddBehaviourFunction(func, internal); + } + else if ( behaviour == asBEHAVE_GET_WEAKREF_FLAG ) + { + // This behaviour is only allowed for reference types + if( !(func.objectType->flags & asOBJ_REF) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Don't allow it if the type is registered with nohandle or scoped + if( func.objectType->flags & (asOBJ_NOHANDLE|asOBJ_SCOPED) ) + { + WriteMessage("", 0, 0, asMSGTYPE_ERROR, TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE); + return ConfigError(asILLEGAL_BEHAVIOUR_FOR_TYPE, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + // Verify that the return type is a reference since it needs to return a pointer to an asISharedBool + if( !func.returnType.IsReference() ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Verify that there are no parameters + if( func.parameterTypes.GetLength() != 0 ) + return ConfigError(asINVALID_DECLARATION, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + if( beh->getWeakRefFlag ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + func.id = beh->getWeakRefFlag = AddBehaviourFunction(func, internal); + } + else + { + asASSERT(false); + + return ConfigError(asINVALID_ARG, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + } + + if( func.id < 0 ) + return ConfigError(func.id, "RegisterObjectBehaviour", objectType->name.AddressOf(), decl); + + // Return function id as success + return func.id; +} + +int asCScriptEngine::SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl) +{ + asASSERT(templateType->flags & asOBJ_TEMPLATE); + + for (asUINT subTypeIdx = 0; subTypeIdx < templateType->templateSubTypes.GetLength(); subTypeIdx++) + { + if (func->returnType.GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) + { + if (func->returnType.IsObjectHandle()) + templateType->acceptValueSubType = false; + else if (!func->returnType.IsReference()) + templateType->acceptRefSubType = false; + + // Can't support template subtypes by value, since each type is treated differently in the ABI + if (!func->returnType.IsObjectHandle() && !func->returnType.IsReference()) + return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); + } + + for (asUINT n = 0; n < func->parameterTypes.GetLength(); n++) + { + if (func->parameterTypes[n].GetTypeInfo() == templateType->templateSubTypes[subTypeIdx].GetTypeInfo()) + { + if (func->parameterTypes[n].IsObjectHandle() || + (!ep.allowUnsafeReferences && func->parameterTypes[n].IsReference() && func->inOutFlags[n] == asTM_INOUTREF)) + templateType->acceptValueSubType = false; + else if (!func->parameterTypes[n].IsReference()) + templateType->acceptRefSubType = false; + + // Can't support template subtypes by value, since each type is treated differently in the ABI + if (!func->parameterTypes[n].IsObjectHandle() && !func->parameterTypes[n].IsReference()) + return ConfigError(asNOT_SUPPORTED, caller, templateType->name.AddressOf(), decl); + } + } + } + + return asSUCCESS; +} + +int asCScriptEngine::VerifyVarTypeNotInFunction(asCScriptFunction *func) +{ + // Don't allow var type in this function + if( func->returnType.GetTokenType() == ttQuestion ) + return asINVALID_DECLARATION; + + for( unsigned int n = 0; n < func->parameterTypes.GetLength(); n++ ) + if( func->parameterTypes[n].GetTokenType() == ttQuestion ) + return asINVALID_DECLARATION; + + return 0; +} + +int asCScriptEngine::AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal) +{ + asUINT n; + + int id = GetNextScriptFunctionId(); + + asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); + if( newInterface == 0 ) + return asOUT_OF_MEMORY; + + asCScriptFunction *f = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); + if( f == 0 ) + { + asDELETE(newInterface, asSSystemFunctionInterface); + return asOUT_OF_MEMORY; + } + + asASSERT(func.name != "" && func.name != "f"); + f->name = func.name; + f->sysFuncIntf = newInterface; + f->returnType = func.returnType; + f->objectType = func.objectType; + if( f->objectType ) + f->objectType->AddRefInternal(); + f->id = id; + f->SetReadOnly(func.IsReadOnly()); + f->accessMask = defaultAccessMask; + f->parameterTypes = func.parameterTypes; + f->parameterNames = func.parameterNames; + f->inOutFlags = func.inOutFlags; + f->traits = func.traits; + for( n = 0; n < func.defaultArgs.GetLength(); n++ ) + if( func.defaultArgs[n] ) + f->defaultArgs.PushLast(asNEW(asCString)(*func.defaultArgs[n])); + else + f->defaultArgs.PushLast(0); + + AddScriptFunction(f); + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, f); + + return id; +} + +// interface +int asCScriptEngine::RegisterGlobalProperty(const char *declaration, void *pointer) +{ + // Don't accept a null pointer + if( pointer == 0 ) + return ConfigError(asINVALID_ARG, "RegisterGlobalProperty", declaration, 0); + + asCDataType type; + asCString name; + + int r; + asCBuilder bld(this, 0); + if( (r = bld.VerifyProperty(0, declaration, name, type, defaultNamespace)) < 0 ) + return ConfigError(r, "RegisterGlobalProperty", declaration, 0); + + // Don't allow registering references as global properties + if( type.IsReference() ) + return ConfigError(asINVALID_TYPE, "RegisterGlobalProperty", declaration, 0); + + // Store the property info + asCGlobalProperty *prop = AllocateGlobalProperty(); + prop->name = name; + prop->nameSpace = defaultNamespace; + prop->type = type; + prop->accessMask = defaultAccessMask; + + prop->SetRegisteredAddress(pointer); + varAddressMap.Insert(prop->GetAddressOfValue(), prop); + + asUINT idx = registeredGlobalProps.Put(prop); + prop->AddRef(); + currentGroup->globalProps.PushLast(prop); + + currentGroup->AddReferencesForType(this, type.GetTypeInfo()); + + // Return the index of the property to signal success + return int(idx); +} + +// internal +asCGlobalProperty *asCScriptEngine::AllocateGlobalProperty() +{ + asCGlobalProperty *prop = asNEW(asCGlobalProperty); + if( prop == 0 ) + { + // Out of memory + return 0; + } + + // First check the availability of a free slot + if( freeGlobalPropertyIds.GetLength() ) + { + prop->id = freeGlobalPropertyIds.PopLast(); + globalProperties[prop->id] = prop; + return prop; + } + + prop->id = (asUINT)globalProperties.GetLength(); + globalProperties.PushLast(prop); + return prop; +} + +// internal +void asCScriptEngine::RemoveGlobalProperty(asCGlobalProperty *prop) +{ + int index = globalProperties.IndexOf(prop); + if( index >= 0 ) + { + freeGlobalPropertyIds.PushLast(index); + globalProperties[index] = 0; + + asSMapNode *node; + varAddressMap.MoveTo(&node, prop->GetAddressOfValue()); + asASSERT(node); + if( node ) + varAddressMap.Erase(node); + + prop->Release(); + } +} + +// interface +asUINT asCScriptEngine::GetGlobalPropertyCount() const +{ + return asUINT(registeredGlobalProps.GetSize()); +} + +// interface +// TODO: If the typeId ever encodes the const flag, then the isConst parameter should be removed +int asCScriptEngine::GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace, int *typeId, bool *isConst, const char **configGroup, void **pointer, asDWORD *accessMask) const +{ + const asCGlobalProperty *prop = registeredGlobalProps.Get(index); + if( !prop ) + return asINVALID_ARG; + + if( name ) *name = prop->name.AddressOf(); + if( nameSpace ) *nameSpace = prop->nameSpace->name.AddressOf(); + if( typeId ) *typeId = GetTypeIdFromDataType(prop->type); + if( isConst ) *isConst = prop->type.IsReadOnly(); + if( pointer ) *pointer = prop->GetRegisteredAddress(); + if( accessMask ) *accessMask = prop->accessMask; + + if( configGroup ) + { + asCConfigGroup *group = FindConfigGroupForGlobalVar(index); + if( group ) + *configGroup = group->groupName.AddressOf(); + else + *configGroup = 0; + } + + return asSUCCESS; +} + +// interface +int asCScriptEngine::GetGlobalPropertyIndexByName(const char *in_name) const +{ + asCString name; + asSNameSpace *ns = 0; + if( DetermineNameAndNamespace(in_name, defaultNamespace, name, ns) < 0 ) + return asINVALID_ARG; + + // Find the global var id + while( ns ) + { + int id = registeredGlobalProps.GetFirstIndex(ns, name); + if( id >= 0 ) + return id; + + // Recursively search parent namespace + ns = GetParentNameSpace(ns); + } + + return asNO_GLOBAL_VAR; +} + +// interface +int asCScriptEngine::GetGlobalPropertyIndexByDecl(const char *decl) const +{ + // This const cast is OK. The builder won't modify the engine + asCBuilder bld(const_cast(this), 0); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCString name; + asSNameSpace *ns; + asCDataType dt; + int r = bld.ParseVariableDeclaration(decl, defaultNamespace, name, ns, dt); + if( r < 0 ) + return r; + + // Search for a match + while( ns ) + { + int id = registeredGlobalProps.GetFirstIndex(ns, name, asCCompGlobPropType(dt)); + if( id >= 0 ) + return id; + + ns = GetParentNameSpace(ns); + } + + return asNO_GLOBAL_VAR; +} + +// interface +int asCScriptEngine::RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) +{ + if( obj == 0 ) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); + + // Determine the object type + asCDataType dt; + asCBuilder bld(this, 0); + int r = bld.ParseDataType(obj, &dt, defaultNamespace); + if( r < 0 ) + return ConfigError(r, "RegisterObjectMethod", obj, declaration); + + // Don't allow application to modify primitives or handles + if( dt.GetTypeInfo() == 0 || (dt.IsObjectHandle() && !(dt.GetTypeInfo()->GetFlags() & asOBJ_IMPLICIT_HANDLE))) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); + + // Don't allow application to modify built-in types or funcdefs + if( dt.GetTypeInfo() == &functionBehaviours || + dt.GetTypeInfo() == &scriptTypeBehaviours || + CastToFuncdefType(dt.GetTypeInfo()) ) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", obj, declaration); + + // Don't allow modifying generated template instances + if( dt.GetTypeInfo() && (dt.GetTypeInfo()->flags & asOBJ_TEMPLATE) && generatedTemplateTypes.Exists(CastToObjectType(dt.GetTypeInfo())) ) + return ConfigError(asINVALID_TYPE, "RegisterObjectMethod", obj, declaration); + + return RegisterMethodToObjectType(CastToObjectType(dt.GetTypeInfo()), declaration, funcPointer, callConv, auxiliary, compositeOffset, isCompositeIndirect); +} + +// internal +int asCScriptEngine::RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary, int compositeOffset, bool isCompositeIndirect) +{ +#ifdef AS_MAX_PORTABILITY + if( callConv != asCALL_GENERIC ) + return ConfigError(asNOT_SUPPORTED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); +#endif + + asSSystemFunctionInterface internal; + int r = DetectCallingConvention(true, funcPointer, callConv, auxiliary, &internal); + if( r < 0 ) + return ConfigError(r, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + + internal.compositeOffset = compositeOffset; + internal.isCompositeIndirect = isCompositeIndirect; + if( (compositeOffset || isCompositeIndirect) && callConv != asCALL_THISCALL ) + return ConfigError(asINVALID_ARG, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + + // TODO: cleanup: This is identical to what is in RegisterMethodToObjectType + // If the object type is a template, make sure there are no generated instances already + if( objectType->flags & asOBJ_TEMPLATE ) + { + for( asUINT n = 0; n < generatedTemplateTypes.GetLength(); n++ ) + { + asCObjectType *tmpl = generatedTemplateTypes[n]; + if( tmpl->name == objectType->name && + tmpl->nameSpace == objectType->nameSpace && + !(tmpl->templateSubTypes[0].GetTypeInfo() && (tmpl->templateSubTypes[0].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE)) ) + { + asCString msg; + msg.Format(TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER, asCDataType::CreateType(tmpl, false).Format(tmpl->nameSpace).AddressOf()); + WriteMessage("",0,0, asMSGTYPE_ERROR, msg.AddressOf()); + return ConfigError(asERROR, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + } + } + + isPrepared = false; + + // Put the system function in the list of system functions + asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); + if( newInterface == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + + asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); + if( func == 0 ) + { + asDELETE(newInterface, asSSystemFunctionInterface); + return ConfigError(asOUT_OF_MEMORY, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + + func->sysFuncIntf = newInterface; + func->objectType = objectType; + func->objectType->AddRefInternal(); + + asCBuilder bld(this, 0); + r = bld.ParseFunctionDeclaration(func->objectType, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle); + if( r < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asINVALID_DECLARATION, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + + // Check name conflicts + r = bld.CheckNameConflictMember(objectType, func->name.AddressOf(), 0, 0, false, false); + if( r < 0 ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + + // Validate property signature + if( func->IsProperty() && (r = bld.ValidateVirtualProperty(func)) < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + if( r == -5 ) + return ConfigError(asNAME_TAKEN, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + else + return ConfigError(asINVALID_DECLARATION, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + + // Check against duplicate methods + if( func->name == "opConv" || func->name == "opImplConv" || func->name == "opCast" || func->name == "opImplCast" ) + { + // opConv and opCast are special methods that the compiler differentiates between by the return type + for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ ) + { + asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]]; + if( f->name == func->name && + f->IsSignatureExceptNameEqual(func) ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + } + } + else + { + for( asUINT n = 0; n < func->objectType->methods.GetLength(); n++ ) + { + asCScriptFunction *f = scriptFunctions[func->objectType->methods[n]]; + if( f->name == func->name && + f->IsSignatureExceptNameAndReturnTypeEqual(func) ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + } + } + } + + func->id = GetNextScriptFunctionId(); + func->objectType->methods.PushLast(func->id); + func->accessMask = defaultAccessMask; + AddScriptFunction(func); + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, func); + + // Check if the method restricts that use of the template to value types or reference types + if( func->objectType->flags & asOBJ_TEMPLATE ) + { + r = SetTemplateRestrictions(func->objectType, func, "RegisterObjectMethod", declaration); + if (r < 0) + return r; + } + + // TODO: beh.copy member will be removed, so this is not necessary + // Is this the default copy behaviour? + if( func->name == "opAssign" && func->parameterTypes.GetLength() == 1 && !func->IsReadOnly() && + ((objectType->flags & asOBJ_SCRIPT_OBJECT) || func->parameterTypes[0].IsEqualExceptRefAndConst(asCDataType::CreateType(func->objectType, false))) ) + { + if( func->objectType->beh.copy != 0 ) + return ConfigError(asALREADY_REGISTERED, "RegisterObjectMethod", objectType->name.AddressOf(), declaration); + + func->objectType->beh.copy = func->id; + func->AddRefInternal(); + } + + // Return the function id as success + return func->id; +} + +// interface +int asCScriptEngine::RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary) +{ +#ifdef AS_MAX_PORTABILITY + if( callConv != asCALL_GENERIC ) + return ConfigError(asNOT_SUPPORTED, "RegisterGlobalFunction", declaration, 0); +#endif + + asSSystemFunctionInterface internal; + int r = DetectCallingConvention(false, funcPointer, callConv, auxiliary, &internal); + if( r < 0 ) + return ConfigError(r, "RegisterGlobalFunction", declaration, 0); + + isPrepared = false; + + // Put the system function in the list of system functions + asSSystemFunctionInterface *newInterface = asNEW(asSSystemFunctionInterface)(internal); + if( newInterface == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterGlobalFunction", declaration, 0); + + asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_SYSTEM); + if( func == 0 ) + { + asDELETE(newInterface, asSSystemFunctionInterface); + return ConfigError(asOUT_OF_MEMORY, "RegisterGlobalFunction", declaration, 0); + } + + func->sysFuncIntf = newInterface; + + asCBuilder bld(this, 0); + r = bld.ParseFunctionDeclaration(0, declaration, func, true, &newInterface->paramAutoHandles, &newInterface->returnAutoHandle, defaultNamespace); + if( r < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asINVALID_DECLARATION, "RegisterGlobalFunction", declaration, 0); + } + + // TODO: namespace: What if the declaration defined an explicit namespace? + func->nameSpace = defaultNamespace; + + // Check name conflicts + r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace, false, false); + if( r < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0); + } + + // Validate property signature + if( func->IsProperty() && (r = bld.ValidateVirtualProperty(func)) < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + if( r == -5 ) + return ConfigError(asNAME_TAKEN, "RegisterGlobalFunction", declaration, 0); + else + return ConfigError(asINVALID_DECLARATION, "RegisterGlobalFunction", declaration, 0); + } + + // Make sure the function is not identical to a previously registered function + asUINT n; + const asCArray &idxs = registeredGlobalFuncs.GetIndexes(func->nameSpace, func->name); + for( n = 0; n < idxs.GetLength(); n++ ) + { + asCScriptFunction *f = registeredGlobalFuncs.Get(idxs[n]); + if( f->IsSignatureExceptNameAndReturnTypeEqual(func) ) + { + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asALREADY_REGISTERED, "RegisterGlobalFunction", declaration, 0); + } + } + + func->id = GetNextScriptFunctionId(); + AddScriptFunction(func); + + currentGroup->scriptFunctions.PushLast(func); + func->accessMask = defaultAccessMask; + registeredGlobalFuncs.Put(func); + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, func); + + // Return the function id as success + return func->id; +} + +// interface +asUINT asCScriptEngine::GetGlobalFunctionCount() const +{ + // Don't count the builtin delegate factory + return asUINT(registeredGlobalFuncs.GetSize()-1); +} + +// interface +asIScriptFunction *asCScriptEngine::GetGlobalFunctionByIndex(asUINT index) const +{ + // Don't count the builtin delegate factory + index++; + + if( index >= registeredGlobalFuncs.GetSize() ) + return 0; + + return static_cast(const_cast(registeredGlobalFuncs.Get(index))); +} + +// interface +asIScriptFunction *asCScriptEngine::GetGlobalFunctionByDecl(const char *decl) const +{ + asCBuilder bld(const_cast(this), 0); + + // Don't write parser errors to the message callback + bld.silent = true; + + asCScriptFunction func(const_cast(this), 0, asFUNC_DUMMY); + int r = bld.ParseFunctionDeclaration(0, decl, &func, false, 0, 0, defaultNamespace); + if( r < 0 ) + return 0; + + asSNameSpace *ns = defaultNamespace; + // Search script functions for matching interface + while( ns ) + { + asIScriptFunction *f = 0; + const asCArray &idxs = registeredGlobalFuncs.GetIndexes(ns, func.name); + for( unsigned int n = 0; n < idxs.GetLength(); n++ ) + { + const asCScriptFunction *funcPtr = registeredGlobalFuncs.Get(idxs[n]); + if( funcPtr->objectType == 0 && + func.returnType == funcPtr->returnType && + func.parameterTypes.GetLength() == funcPtr->parameterTypes.GetLength() + ) + { + bool match = true; + for( asUINT p = 0; p < func.parameterTypes.GetLength(); ++p ) + { + if( func.parameterTypes[p] != funcPtr->parameterTypes[p] ) + { + match = false; + break; + } + } + + if( match ) + { + if( f == 0 ) + f = const_cast(funcPtr); + else + // Multiple functions + return 0; + } + } + } + + if( f ) + return f; + + // Recursively search parent namespaces + ns = GetParentNameSpace(ns); + } + + return 0; +} + + +asCTypeInfo *asCScriptEngine::GetRegisteredType(const asCString &type, asSNameSpace *ns) const +{ + asSMapNode *cursor; + if( allRegisteredTypes.MoveTo(&cursor, asSNameSpaceNamePair(ns, type)) ) + return cursor->value; + + return 0; +} + + + + +void asCScriptEngine::PrepareEngine() +{ + if( isPrepared ) return; + if( configFailed ) return; + + asUINT n; + for( n = 0; n < scriptFunctions.GetLength(); n++ ) + { + // Determine the host application interface + if( scriptFunctions[n] && scriptFunctions[n]->funcType == asFUNC_SYSTEM ) + { + if( scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_FUNC || + scriptFunctions[n]->sysFuncIntf->callConv == ICC_GENERIC_METHOD ) + PrepareSystemFunctionGeneric(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this); + else + PrepareSystemFunction(scriptFunctions[n], scriptFunctions[n]->sysFuncIntf, this); + } + } + + // Validate object type registrations + for( n = 0; n < registeredObjTypes.GetLength(); n++ ) + { + asCObjectType *type = registeredObjTypes[n]; + if( type && !(type->flags & asOBJ_SCRIPT_OBJECT) ) + { + bool missingBehaviour = false; + const char *infoMsg = 0; + + // Verify that GC types have all behaviours + if( type->flags & asOBJ_GC ) + { + if (type->flags & asOBJ_REF) + { + if (type->beh.addref == 0 || + type->beh.release == 0 || + type->beh.gcGetRefCount == 0 || + type->beh.gcSetFlag == 0 || + type->beh.gcGetFlag == 0 || + type->beh.gcEnumReferences == 0 || + type->beh.gcReleaseAllReferences == 0) + { + infoMsg = TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR; + missingBehaviour = true; + } + } + else + { + if (type->beh.gcEnumReferences == 0) + { + infoMsg = TXT_VALUE_GC_REQUIRE_GC_BEHAVIOUR; + missingBehaviour = true; + } + } + } + // Verify that scoped ref types have the release behaviour + if( type->flags & asOBJ_SCOPED ) + { + if( type->beh.release == 0 ) + { + infoMsg = TXT_SCOPE_REQUIRE_REL_BEHAVIOUR; + missingBehaviour = true; + } + } + // Verify that ref types have add ref and release behaviours + if( (type->flags & asOBJ_REF) && + !(type->flags & asOBJ_SCOPED) && + !(type->flags & asOBJ_NOHANDLE) && + !(type->flags & asOBJ_NOCOUNT) ) + { + if( type->beh.addref == 0 || + type->beh.release == 0 ) + { + infoMsg = TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR; + missingBehaviour = true; + } + } + // Verify that non-pod value types have the constructor and destructor registered + if( (type->flags & asOBJ_VALUE) && + !(type->flags & asOBJ_POD) ) + { + if( type->beh.constructors.GetLength() == 0 || + type->beh.destruct == 0 ) + { + infoMsg = TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR; + missingBehaviour = true; + } + } + + if( missingBehaviour ) + { + asCString str; + str.Format(TXT_TYPE_s_IS_MISSING_BEHAVIOURS, type->name.AddressOf()); + WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + WriteMessage("", 0, 0, asMSGTYPE_INFORMATION, infoMsg); + ConfigError(asINVALID_CONFIGURATION, 0, 0, 0); + } + } + } + + isPrepared = true; +} + +int asCScriptEngine::ConfigError(int err, const char *funcName, const char *arg1, const char *arg2) +{ + configFailed = true; + if( funcName ) + { + asCString str; + if( arg1 ) + { + if( arg2 ) + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_s_d, funcName, arg1, arg2, errorNames[-err], err); + else + str.Format(TXT_FAILED_IN_FUNC_s_WITH_s_s_d, funcName, arg1, errorNames[-err], err); + } + else + str.Format(TXT_FAILED_IN_FUNC_s_s_d, funcName, errorNames[-err], err); + + WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + } + return err; +} + +// interface +int asCScriptEngine::RegisterDefaultArrayType(const char *type) +{ + asCBuilder bld(this, 0); + asCDataType dt; + int r = bld.ParseDataType(type, &dt, defaultNamespace); + if( r < 0 ) return r; + + if( dt.GetTypeInfo() == 0 || + !(dt.GetTypeInfo()->GetFlags() & asOBJ_TEMPLATE) ) + return asINVALID_TYPE; + + defaultArrayObjectType = CastToObjectType(dt.GetTypeInfo()); + defaultArrayObjectType->AddRefInternal(); + + return 0; +} + +// interface +int asCScriptEngine::GetDefaultArrayTypeId() const +{ + if( defaultArrayObjectType ) + return GetTypeIdFromDataType(asCDataType::CreateType(defaultArrayObjectType, false)); + + return asINVALID_TYPE; +} + +// interface +int asCScriptEngine::RegisterStringFactory(const char *datatype, asIStringFactory *factory) +{ + if (factory == 0) + return ConfigError(asINVALID_ARG, "RegisterStringFactory", datatype, 0); + + // Parse the data type + asCBuilder bld(this, 0); + asCDataType dt; + int r = bld.ParseDataType(datatype, &dt, defaultNamespace, true); + if (r < 0) + return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); + + // Validate the type. It must not be reference or handle + if (dt.IsReference() || dt.IsObjectHandle()) + return ConfigError(asINVALID_TYPE, "RegisterStringFactory", datatype, 0); + + // All string literals will be treated as const + dt.MakeReadOnly(true); + + stringType = dt; + stringFactory = factory; + + return asSUCCESS; +} + +// interface +int asCScriptEngine::GetStringFactoryReturnTypeId(asDWORD *flags) const +{ + if( stringFactory == 0 ) + return asNO_FUNCTION; + + if( flags ) + *flags = 0; + return GetTypeIdFromDataType(stringType); +} + +// internal +asCModule *asCScriptEngine::GetModule(const char *name, bool create) +{ + // Accept null as well as zero-length string + if( name == 0 ) name = ""; + + asCModule *retModule = 0; + + ACQUIRESHARED(engineRWLock); + if( lastModule && lastModule->m_name == name ) + retModule = lastModule; + else + { + // TODO: optimize: Improve linear search + for( asUINT n = 0; n < scriptModules.GetLength(); ++n ) + if( scriptModules[n] && scriptModules[n]->m_name == name ) + { + retModule = scriptModules[n]; + break; + } + } + RELEASESHARED(engineRWLock); + + if( retModule ) + { + ACQUIREEXCLUSIVE(engineRWLock); + lastModule = retModule; + RELEASEEXCLUSIVE(engineRWLock); + + return retModule; + } + + if( create ) + { + retModule = asNEW(asCModule)(name, this); + if( retModule == 0 ) + { + // Out of memory + return 0; + } + + ACQUIREEXCLUSIVE(engineRWLock); + scriptModules.PushLast(retModule); + lastModule = retModule; + RELEASEEXCLUSIVE(engineRWLock); + } + + return retModule; +} + +asCModule *asCScriptEngine::GetModuleFromFuncId(int id) +{ + if( id < 0 ) return 0; + if( id >= (int)scriptFunctions.GetLength() ) return 0; + asCScriptFunction *func = scriptFunctions[id]; + if( func == 0 ) return 0; + return func->module; +} + +// internal +int asCScriptEngine::RequestBuild() +{ + ACQUIREEXCLUSIVE(engineRWLock); + if( isBuilding ) + { + RELEASEEXCLUSIVE(engineRWLock); + return asBUILD_IN_PROGRESS; + } + isBuilding = true; + RELEASEEXCLUSIVE(engineRWLock); + + return 0; +} + +// internal +void asCScriptEngine::BuildCompleted() +{ + // Always free up pooled memory after a completed build + memoryMgr.FreeUnusedMemory(); + + isBuilding = false; +} + +void asCScriptEngine::RemoveTemplateInstanceType(asCObjectType *t) +{ + // If there is a module that still owns the generated type, then don't remove it + if( t->module ) + return; + + // Don't remove it if there are external refernces + if( t->externalRefCount.get() ) + return; + + // Only remove the template instance type if no config group is using it + if( defaultGroup.generatedTemplateInstances.Exists(t) ) + return; + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + if( configGroups[n]->generatedTemplateInstances.Exists(t) ) + return; + + t->DestroyInternal(); + templateInstanceTypes.RemoveValue(t); + generatedTemplateTypes.RemoveValue(t); + t->ReleaseInternal(); +} + +// internal +asCObjectType *asCScriptEngine::GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes, asCModule *requestingModule) +{ + asUINT n; + + // Is there any template instance type or template specialization already with this subtype? + for( n = 0; n < templateInstanceTypes.GetLength(); n++ ) + { + asCObjectType *type = templateInstanceTypes[n]; + if( type && + type->name == templateType->name && + type->nameSpace == templateType->nameSpace && + type->templateSubTypes == subTypes ) + { + // If the template instance is generated, then the module should hold a reference + // to it so the config group can determine see that the template type is in use. + // Template specializations will be treated as normal types + if( requestingModule && generatedTemplateTypes.Exists(type) ) + { + if( type->module == 0 ) + { + // Set the ownership of this template type + // It may be without ownership if it was previously created from application with for example GetTypeInfoByDecl + type->module = requestingModule; + } + if( !requestingModule->m_templateInstances.Exists(type) ) + { + requestingModule->m_templateInstances.PushLast(type); + type->AddRefInternal(); + } + } + + return templateInstanceTypes[n]; + } + } + + // No previous template instance exists + + // Make sure this template supports the subtype + for( n = 0; n < subTypes.GetLength(); n++ ) + { + if( !templateType->acceptValueSubType && (subTypes[n].IsPrimitive() || (subTypes[n].GetTypeInfo()->flags & asOBJ_VALUE)) ) + return 0; + + if( !templateType->acceptRefSubType && (subTypes[n].IsObject() && (subTypes[n].GetTypeInfo()->flags & asOBJ_REF)) ) + return 0; + } + + // Create a new template instance type based on the templateType + asCObjectType *ot = asNEW(asCObjectType)(this); + if( ot == 0 ) + { + // Out of memory + return 0; + } + + ot->templateSubTypes = subTypes; + ot->flags = templateType->flags; + ot->size = templateType->size; + ot->name = templateType->name; + ot->nameSpace = templateType->nameSpace; + + // If the template is being requested from a module, then the module should hold a reference to the type + if( requestingModule ) + { + // Set the ownership of this template type + ot->module = requestingModule; + requestingModule->m_templateInstances.PushLast(ot); + ot->AddRefInternal(); + } + else + { + // If the template type is not requested directly from a module, then set the ownership + // of it to the same module as one of the subtypes. If none of the subtypes are owned by] + // any module, the template instance will be without ownership and can be removed from the + // engine at any time (unless the application holds an external reference). + for( n = 0; n < subTypes.GetLength(); n++ ) + { + if( subTypes[n].GetTypeInfo() ) + { + ot->module = subTypes[n].GetTypeInfo()->module; + if( ot->module ) + { + ot->module->m_templateInstances.PushLast(ot); + ot->AddRefInternal(); + break; + } + } + } + } + + // Before filling in the methods, call the template instance callback behaviour to validate the type + if( templateType->beh.templateCallback ) + { + // If the validation is deferred then the validation will be done later, + // so it is necessary to continue the preparation of the template instance type + if( !deferValidationOfTemplateTypes ) + { + asCScriptFunction *callback = scriptFunctions[templateType->beh.templateCallback]; + + bool dontGarbageCollect = false; + if( !CallGlobalFunctionRetBool(ot, &dontGarbageCollect, callback->sysFuncIntf, callback) ) + { + // The type cannot be instantiated + ot->templateSubTypes.SetLength(0); + if( ot->module ) + { + ot->module->m_templateInstances.RemoveValue(ot); + ot->ReleaseInternal(); + } + ot->ReleaseInternal(); + return 0; + } + + // If the callback said this template instance won't be garbage collected then remove the flag + if( dontGarbageCollect ) + ot->flags &= ~asOBJ_GC; + } + + ot->beh.templateCallback = templateType->beh.templateCallback; + scriptFunctions[ot->beh.templateCallback]->AddRefInternal(); + } + + ot->methods = templateType->methods; + for( n = 0; n < ot->methods.GetLength(); n++ ) + scriptFunctions[ot->methods[n]]->AddRefInternal(); + + if( templateType->flags & asOBJ_REF ) + { + // Store the real factory in the constructor. This is used by the CreateScriptObject function. + // Otherwise it wouldn't be necessary to store the real factory ids. + ot->beh.construct = templateType->beh.factory; + ot->beh.constructors = templateType->beh.factories; + } + else + { + ot->beh.construct = templateType->beh.construct; + ot->beh.constructors = templateType->beh.constructors; + } + for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) + scriptFunctions[ot->beh.constructors[n]]->AddRefInternal(); + + + // Before proceeding with the generation of the template functions for the template instance it is necessary + // to include the new template instance type in the list of known types, otherwise it is possible that we get + // a infinite recursive loop as the template instance type is requested again during the generation of the + // template functions. + templateInstanceTypes.PushLast(ot); + + // Store the template instance types that have been created automatically by the engine from a template type + // The object types in templateInstanceTypes that are not also in generatedTemplateTypes are registered template specializations + generatedTemplateTypes.PushLast(ot); + + // Any child funcdefs must be copied to the template instance (with adjustments in case of template subtypes) + // This must be done before resolving other methods, to make sure the other methods that may refer to the + // templated funcdef will resolve to the new funcdef + for (n = 0; n < templateType->childFuncDefs.GetLength(); n++) + { + asCFuncdefType *funcdef = GenerateNewTemplateFuncdef(templateType, ot, templateType->childFuncDefs[n]); + funcdef->parentClass = ot; + ot->childFuncDefs.PushLast(funcdef); + } + + // As the new template type is instantiated the engine should + // generate new functions to substitute the ones with the template subtype. + for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) + { + int funcId = ot->beh.constructors[n]; + asCScriptFunction *func = scriptFunctions[funcId]; + + if( GenerateNewTemplateFunction(templateType, ot, func, &func) ) + { + // Release the old function, the new one already has its ref count set to 1 + scriptFunctions[funcId]->ReleaseInternal(); + ot->beh.constructors[n] = func->id; + + if( ot->beh.construct == funcId ) + ot->beh.construct = func->id; + } + } + + ot->beh.factory = 0; + + if( templateType->flags & asOBJ_REF ) + { + // Generate factory stubs for each of the factories + for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) + { + asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, ot->beh.constructors[n]); + + ot->beh.factories.PushLast(func->id); + + // Set the default factory as well + if( ot->beh.constructors[n] == ot->beh.construct ) + ot->beh.factory = func->id; + } + } + else + { + // Generate factory stubs for each of the constructors + for( n = 0; n < ot->beh.constructors.GetLength(); n++ ) + { + asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, ot->beh.constructors[n]); + + if( ot->beh.constructors[n] == ot->beh.construct ) + ot->beh.construct = func->id; + + // Release previous constructor + scriptFunctions[ot->beh.constructors[n]]->ReleaseInternal(); + + ot->beh.constructors[n] = func->id; + } + } + + // Generate stub for the list factory as well + if( templateType->beh.listFactory ) + { + asCScriptFunction *func = GenerateTemplateFactoryStub(templateType, ot, templateType->beh.listFactory); + + // Rename the function to easily identify it in LoadByteCode + func->name = "$list"; + + ot->beh.listFactory = func->id; + } + + ot->beh.addref = templateType->beh.addref; + if( scriptFunctions[ot->beh.addref] ) scriptFunctions[ot->beh.addref]->AddRefInternal(); + ot->beh.release = templateType->beh.release; + if( scriptFunctions[ot->beh.release] ) scriptFunctions[ot->beh.release]->AddRefInternal(); + ot->beh.destruct = templateType->beh.destruct; + if( scriptFunctions[ot->beh.destruct] ) scriptFunctions[ot->beh.destruct]->AddRefInternal(); + ot->beh.copy = templateType->beh.copy; + if( scriptFunctions[ot->beh.copy] ) scriptFunctions[ot->beh.copy]->AddRefInternal(); + ot->beh.gcGetRefCount = templateType->beh.gcGetRefCount; + if( scriptFunctions[ot->beh.gcGetRefCount] ) scriptFunctions[ot->beh.gcGetRefCount]->AddRefInternal(); + ot->beh.gcSetFlag = templateType->beh.gcSetFlag; + if( scriptFunctions[ot->beh.gcSetFlag] ) scriptFunctions[ot->beh.gcSetFlag]->AddRefInternal(); + ot->beh.gcGetFlag = templateType->beh.gcGetFlag; + if( scriptFunctions[ot->beh.gcGetFlag] ) scriptFunctions[ot->beh.gcGetFlag]->AddRefInternal(); + ot->beh.gcEnumReferences = templateType->beh.gcEnumReferences; + if( scriptFunctions[ot->beh.gcEnumReferences] ) scriptFunctions[ot->beh.gcEnumReferences]->AddRefInternal(); + ot->beh.gcReleaseAllReferences = templateType->beh.gcReleaseAllReferences; + if( scriptFunctions[ot->beh.gcReleaseAllReferences] ) scriptFunctions[ot->beh.gcReleaseAllReferences]->AddRefInternal(); + ot->beh.getWeakRefFlag = templateType->beh.getWeakRefFlag; + if( scriptFunctions[ot->beh.getWeakRefFlag] ) scriptFunctions[ot->beh.getWeakRefFlag]->AddRefInternal(); + + // As the new template type is instantiated, the engine should + // generate new functions to substitute the ones with the template subtype. + for( n = 0; n < ot->methods.GetLength(); n++ ) + { + int funcId = ot->methods[n]; + asCScriptFunction *func = scriptFunctions[funcId]; + + if( GenerateNewTemplateFunction(templateType, ot, func, &func) ) + { + // Release the old function, the new one already has its ref count set to 1 + scriptFunctions[funcId]->ReleaseInternal(); + ot->methods[n] = func->id; + } + } + + // Increase ref counter for sub type if it is an object type + for( n = 0; n < ot->templateSubTypes.GetLength(); n++ ) + if( ot->templateSubTypes[n].GetTypeInfo() ) + ot->templateSubTypes[n].GetTypeInfo()->AddRefInternal(); + + // Copy the properties to the template instance + for( n = 0; n < templateType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = templateType->properties[n]; + ot->properties.PushLast(asNEW(asCObjectProperty)(*prop)); + if( prop->type.GetTypeInfo() ) + prop->type.GetTypeInfo()->AddRefInternal(); + } + + return ot; +} + +// interface +asILockableSharedBool *asCScriptEngine::GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const +{ + // Make sure it is not a null pointer + if( obj == 0 || type == 0 ) return 0; + + const asCObjectType *objType = static_cast(type); + asILockableSharedBool *dest = 0; + if( objType->beh.getWeakRefFlag ) + { + // Call the getweakrefflag behaviour + dest = reinterpret_cast(CallObjectMethodRetPtr(obj, objType->beh.getWeakRefFlag)); + } + return dest; +} + +// internal +// orig is the parameter type that is to be replaced +// tmpl is the registered template. Used to find which subtype is being replaced +// ot is the new template instance that is being created. Used to find the target type +asCDataType asCScriptEngine::DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot) +{ + asCDataType dt; + if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) + { + bool found = false; + for( asUINT n = 0; n < tmpl->templateSubTypes.GetLength(); n++ ) + { + if( orig.GetTypeInfo() == tmpl->templateSubTypes[n].GetTypeInfo() ) + { + found = true; + dt = ot->templateSubTypes[n]; + if( orig.IsObjectHandle() && !ot->templateSubTypes[n].IsObjectHandle() ) + { + dt.MakeHandle(true, true); + asASSERT(dt.IsObjectHandle()); + if( orig.IsHandleToConst() ) + dt.MakeHandleToConst(true); + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(orig.IsReadOnly()); + } + else + { + // The target type is a handle, then check if the application + // wants this handle to be to a const object. This is done by + // flagging the type with 'if_handle_then_const' in the declaration. + if (dt.IsObjectHandle() && orig.HasIfHandleThenConst()) + dt.MakeHandleToConst(true); + + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(ot->templateSubTypes[n].IsReadOnly() || orig.IsReadOnly()); + + // If the target is a @& then don't make the handle const, + // as it is not possible to declare functions with @const & + if (orig.IsReference() && dt.IsObjectHandle()) + dt.MakeReadOnly(false); + } + break; + } + } + asASSERT( found ); + UNUSED_VAR( found ); + } + else if( orig.GetTypeInfo() == tmpl ) + { + if( orig.IsObjectHandle() ) + dt = asCDataType::CreateObjectHandle(ot, false); + else + dt = asCDataType::CreateType(ot, false); + + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(orig.IsReadOnly()); + } + else if( orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) + { + // The type is itself a template, so it is necessary to find the correct template instance type + asCArray tmplSubTypes; + asCObjectType *origType = CastToObjectType(orig.GetTypeInfo()); + bool needInstance = true; + + // Find the matching replacements for the subtypes + for( asUINT n = 0; n < origType->templateSubTypes.GetLength(); n++ ) + { + if( origType->templateSubTypes[n].GetTypeInfo() == 0 || + !(origType->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) + { + // The template is already an instance so we shouldn't attempt to create another instance + needInstance = false; + break; + } + + for( asUINT m = 0; m < tmpl->templateSubTypes.GetLength(); m++ ) + if( origType->templateSubTypes[n].GetTypeInfo() == tmpl->templateSubTypes[m].GetTypeInfo() ) + tmplSubTypes.PushLast(ot->templateSubTypes[m]); + + if( tmplSubTypes.GetLength() != n+1 ) + { + asASSERT( false ); + return orig; + } + } + + asCObjectType *ntype = origType; + if( needInstance ) + { + // Always find the original template type when creating a new template instance otherwise the + // generation will fail since it will attempt to create factory stubs when they already exists, etc + for( asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++ ) + if( registeredTemplateTypes[n]->name == origType->name && + registeredTemplateTypes[n]->nameSpace == origType->nameSpace ) + { + origType = registeredTemplateTypes[n]; + break; + } + + ntype = GetTemplateInstanceType(origType, tmplSubTypes, ot->module); + if( ntype == 0 ) + { + // It not possible to instantiate the subtype + asASSERT( false ); + ntype = tmpl; + } + } + + if( orig.IsObjectHandle() ) + dt = asCDataType::CreateObjectHandle(ntype, false); + else + dt = asCDataType::CreateType(ntype, false); + + dt.MakeReference(orig.IsReference()); + dt.MakeReadOnly(orig.IsReadOnly()); + } + else if (orig.GetTypeInfo() && (orig.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(orig.GetTypeInfo())->parentClass == tmpl) + { + // The type is a child funcdef. Find the corresponding child funcdef in the template instance + for (asUINT n = 0; n < ot->childFuncDefs.GetLength(); n++) + { + if (ot->childFuncDefs[n]->name == orig.GetTypeInfo()->name) + { + dt = orig; + dt.SetTypeInfo(ot->childFuncDefs[n]); + } + } + } + else + dt = orig; + + return dt; +} + +// internal +asCScriptFunction *asCScriptEngine::GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *ot, int factoryId) +{ + asCScriptFunction *factory = scriptFunctions[factoryId]; + + // By first instantiating the function as a dummy and then changing it to be a script function + // I avoid having it added to the garbage collector. As it is known that this object will stay + // alive until the template instance is no longer used there is no need to have the GC check + // this function all the time. + asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_DUMMY); + if( func == 0 ) + { + // Out of memory + return 0; + } + + func->funcType = asFUNC_SCRIPT; + func->AllocateScriptFunctionData(); + func->id = GetNextScriptFunctionId(); + AddScriptFunction(func); + + func->traits = factory->traits; + func->SetShared(true); + if( templateType->flags & asOBJ_REF ) + { + func->name = "$fact"; + func->returnType = asCDataType::CreateObjectHandle(ot, false); + } + else + { + func->name = "$beh0"; + func->returnType = factory->returnType; // constructors return nothing + func->objectType = ot; + func->objectType->AddRefInternal(); + } + + // Skip the first parameter as this is the object type pointer that the stub will add + func->parameterTypes.SetLength(factory->parameterTypes.GetLength()-1); + func->parameterNames.SetLength(factory->parameterNames.GetLength()-1); + func->inOutFlags.SetLength(factory->inOutFlags.GetLength()-1); + func->defaultArgs.SetLength(factory->defaultArgs.GetLength()-1); + for( asUINT p = 1; p < factory->parameterTypes.GetLength(); p++ ) + { + func->parameterTypes[p-1] = factory->parameterTypes[p]; + func->parameterNames[p-1] = factory->parameterNames[p]; + func->inOutFlags[p-1] = factory->inOutFlags[p]; + func->defaultArgs[p-1] = factory->defaultArgs[p] ? asNEW(asCString)(*factory->defaultArgs[p]) : 0; + } + func->scriptData->objVariablesOnHeap = 0; + + // Generate the bytecode for the factory stub + asUINT bcLength = asBCTypeSize[asBCInfo[asBC_OBJTYPE].type] + + asBCTypeSize[asBCInfo[asBC_CALLSYS].type] + + asBCTypeSize[asBCInfo[asBC_RET].type]; + + if( ep.includeJitInstructions ) + bcLength += asBCTypeSize[asBCInfo[asBC_JitEntry].type]; + if( templateType->flags & asOBJ_VALUE ) + bcLength += asBCTypeSize[asBCInfo[asBC_SwapPtr].type]; + + func->scriptData->byteCode.SetLength(bcLength); + asDWORD *bc = func->scriptData->byteCode.AddressOf(); + + if( ep.includeJitInstructions ) + { + *(asBYTE*)bc = asBC_JitEntry; + *(asPWORD*)(bc+1) = 0; + bc += asBCTypeSize[asBCInfo[asBC_JitEntry].type]; + } + + *(asBYTE*)bc = asBC_OBJTYPE; + *(asPWORD*)(bc+1) = (asPWORD)ot; + bc += asBCTypeSize[asBCInfo[asBC_OBJTYPE].type]; + if( templateType->flags & asOBJ_VALUE ) + { + // Swap the object pointer with the object type + *(asBYTE*)bc = asBC_SwapPtr; + bc += asBCTypeSize[asBCInfo[asBC_SwapPtr].type]; + } + *(asBYTE*)bc = asBC_CALLSYS; + *(asDWORD*)(bc+1) = factoryId; + bc += asBCTypeSize[asBCInfo[asBC_CALLSYS].type]; + *(asBYTE*)bc = asBC_RET; + *(((asWORD*)bc)+1) = (asWORD)func->GetSpaceNeededForArguments() + (func->objectType ? AS_PTR_SIZE : 0); + + func->AddReferences(); + func->scriptData->stackNeeded = AS_PTR_SIZE; + + // Tell the virtual machine not to clean up the object on exception + func->dontCleanUpOnException = true; + + func->JITCompile(); + + // Need to translate the list pattern too so the VM and compiler will know the correct type of the members + if( factory->listPattern ) + { + asSListPatternNode *n = factory->listPattern; + asSListPatternNode *last = 0; + while( n ) + { + asSListPatternNode *newNode = n->Duplicate(); + if( newNode->type == asLPT_TYPE ) + { + asSListPatternDataTypeNode *typeNode = reinterpret_cast(newNode); + typeNode->dataType = DetermineTypeForTemplate(typeNode->dataType, templateType, ot); + } + + if( last ) + last->next = newNode; + else + func->listPattern = newNode; + + last = newNode; + + n = n->next; + } + } + + return func; +} + +bool asCScriptEngine::RequireTypeReplacement(asCDataType &type, asCObjectType *templateType) +{ + if( type.GetTypeInfo() == templateType ) return true; + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE) ) return true; + if( type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_TEMPLATE) ) + { + asCObjectType *ot = CastToObjectType(type.GetTypeInfo()); + for( asUINT n = 0; n < ot->templateSubTypes.GetLength(); n++ ) + if( ot->templateSubTypes[n].GetTypeInfo() && + ot->templateSubTypes[n].GetTypeInfo()->flags & asOBJ_TEMPLATE_SUBTYPE ) + return true; + } + if (type.GetTypeInfo() && (type.GetTypeInfo()->flags & asOBJ_FUNCDEF) && CastToFuncdefType(type.GetTypeInfo())->parentClass == templateType) + return true; + + return false; +} + +bool asCScriptEngine::GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *ot, asCScriptFunction *func, asCScriptFunction **newFunc) +{ + // Due to the objectType it is always required to generate a new function, + // even if none of the function arguments needs to be changed. +/* + // TODO: Can we store the new function in some other optimized way to avoid + // duplicating all information just because of the different objectType member? + bool needNewFunc = false; + + if( RequireTypeReplacement(func->returnType, templateType) ) + needNewFunc = true; + else + { + for( asUINT p = 0; p < func->parameterTypes.GetLength(); p++ ) + { + if( RequireTypeReplacement(func->parameterTypes[p], templateType) ) + { + needNewFunc = true; + break; + } + } + } + + if( !needNewFunc ) + return false; +*/ + + asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcType); + if( func2 == 0 ) + { + // Out of memory + return false; + } + + func2->name = func->name; + + func2->returnType = DetermineTypeForTemplate(func->returnType, templateType, ot); + func2->parameterTypes.SetLength(func->parameterTypes.GetLength()); + for (asUINT p = 0; p < func->parameterTypes.GetLength(); p++) + func2->parameterTypes[p] = DetermineTypeForTemplate(func->parameterTypes[p], templateType, ot); + + for (asUINT n = 0; n < func->defaultArgs.GetLength(); n++) + if (func->defaultArgs[n]) + func2->defaultArgs.PushLast(asNEW(asCString)(*func->defaultArgs[n])); + else + func2->defaultArgs.PushLast(0); + + // TODO: template: Must be careful when instantiating templates for garbage collected types + // If the template hasn't been registered with the behaviours, it shouldn't + // permit instantiation of garbage collected types that in turn may refer to + // this instance. + + func2->parameterNames = func->parameterNames; + func2->inOutFlags = func->inOutFlags; + func2->traits = func->traits; + func2->SetReadOnly(func->IsReadOnly()); + func2->objectType = ot; + func2->objectType->AddRefInternal(); + func2->sysFuncIntf = asNEW(asSSystemFunctionInterface)(*func->sysFuncIntf); + + // Adjust the clean up instructions + if( func2->sysFuncIntf->callConv == ICC_GENERIC_FUNC || + func2->sysFuncIntf->callConv == ICC_GENERIC_METHOD ) + PrepareSystemFunctionGeneric(func2, func2->sysFuncIntf, this); + else + PrepareSystemFunction(func2, func2->sysFuncIntf, this); + + func2->id = GetNextScriptFunctionId(); + AddScriptFunction(func2); + + // Return the new function + *newFunc = func2; + + return true; +} + +asCFuncdefType *asCScriptEngine::GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *ot, asCFuncdefType *func) +{ + // TODO: Only generate the new funcdef if it used the template subtypes. + // Remember to also update the clean up in asCObjectType::DestroyInternal so it doesn't delete + // child funcdefs that have not been created specificially for the template instance. + // Perhaps a new funcdef is always needed, since the funcdef will have a reference to the + // parent class (in this case the template instance). + + asCScriptFunction *func2 = asNEW(asCScriptFunction)(this, 0, func->funcdef->funcType); + if (func2 == 0) + { + // Out of memory + return 0; + } + + func2->name = func->name; + + func2->returnType = DetermineTypeForTemplate(func->funcdef->returnType, templateType, ot); + func2->parameterTypes.SetLength(func->funcdef->parameterTypes.GetLength()); + for (asUINT p = 0; p < func->funcdef->parameterTypes.GetLength(); p++) + func2->parameterTypes[p] = DetermineTypeForTemplate(func->funcdef->parameterTypes[p], templateType, ot); + + // TODO: template: Must be careful when instantiating templates for garbage collected types + // If the template hasn't been registered with the behaviours, it shouldn't + // permit instantiation of garbage collected types that in turn may refer to + // this instance. + + func2->inOutFlags = func->funcdef->inOutFlags; + func2->SetReadOnly(func->funcdef->IsReadOnly()); + asASSERT(func->funcdef->objectType == 0); + asASSERT(func->funcdef->sysFuncIntf == 0); + + func2->id = GetNextScriptFunctionId(); + AddScriptFunction(func2); + + asCFuncdefType *fdt2 = asNEW(asCFuncdefType)(this, func2); + funcDefs.PushLast(fdt2); // don't increase refCount as the constructor already set it to 1 + + // Return the new function + return fdt2; +} + +void asCScriptEngine::CallObjectMethod(void *obj, int func) const +{ + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + CallObjectMethod(obj, s->sysFuncIntf, s); +} + +void asCScriptEngine::CallObjectMethod(void *obj, asSSystemFunctionInterface *i, asCScriptFunction *s) const +{ +#if defined(__GNUC__) || defined(AS_PSVITA) + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + } + else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) + { + // For virtual thiscalls we must call the method as a true class method + // so that the compiler will lookup the function address in the vftable + union + { + asSIMPLEMETHOD_t mthd; + struct + { + asFUNCTION_t func; + asPWORD baseOffset; // Same size as the pointer + } f; + } p; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + void (asCSimpleDummy::*f)() = p.mthd; + (((asCSimpleDummy*)obj)->*f)(); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + void (*f)(void *) = (void (*)(void *))(i->func); + f(obj); + } +#else +#ifndef AS_NO_CLASS_METHODS + if( i->callConv == ICC_THISCALL ) + { + union + { + asSIMPLEMETHOD_t mthd; + asFUNCTION_t func; + } p; + p.func = (asFUNCTION_t)(i->func); + void (asCSimpleDummy::*f)() = p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + obj = (void*)(asPWORD(obj) + i->baseOffset); + (((asCSimpleDummy*)obj)->*f)(); + } + else +#endif + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + void (*f)(void *) = (void (*)(void *))(i->func); + f(obj); + } +#endif +} + +bool asCScriptEngine::CallObjectMethodRetBool(void *obj, int func) const +{ + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + asSSystemFunctionInterface *i = s->sysFuncIntf; + +#if defined(__GNUC__) || defined(AS_PSVITA) + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(bool*)gen.GetReturnPointer(); + } + else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) + { + // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable + union + { + asSIMPLEMETHOD_t mthd; + struct + { + asFUNCTION_t func; + asPWORD baseOffset; + } f; + } p; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())(p.mthd); + return (((asCSimpleDummy*)obj)->*f)(); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + bool (*f)(void *) = (bool (*)(void *))(i->func); + return f(obj); + } +#else +#ifndef AS_NO_CLASS_METHODS + if( i->callConv == ICC_THISCALL ) + { + union + { + asSIMPLEMETHOD_t mthd; + asFUNCTION_t func; + } p; + p.func = (asFUNCTION_t)(i->func); + bool (asCSimpleDummy::*f)() = (bool (asCSimpleDummy::*)())p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + obj = (void*)(asPWORD(obj) + i->baseOffset); + return (((asCSimpleDummy*)obj)->*f)(); + } + else +#endif + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(bool*)gen.GetReturnPointer(); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + bool (*f)(void *) = (bool (*)(void *))(i->func); + return f(obj); + } +#endif +} + +int asCScriptEngine::CallObjectMethodRetInt(void *obj, int func) const +{ + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + asSSystemFunctionInterface *i = s->sysFuncIntf; + +#if defined(__GNUC__) || defined(AS_PSVITA) + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(int*)gen.GetReturnPointer(); + } + else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) + { + // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable + union + { + asSIMPLEMETHOD_t mthd; + struct + { + asFUNCTION_t func; + asPWORD baseOffset; + } f; + } p; + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())(p.mthd); + return (((asCSimpleDummy*)obj)->*f)(); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + int (*f)(void *) = (int (*)(void *))(i->func); + return f(obj); + } +#else +#ifndef AS_NO_CLASS_METHODS + if( i->callConv == ICC_THISCALL ) + { + union + { + asSIMPLEMETHOD_t mthd; + asFUNCTION_t func; + } p; + p.func = (asFUNCTION_t)(i->func); + int (asCSimpleDummy::*f)() = (int (asCSimpleDummy::*)())p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + obj = (void*)(asPWORD(obj) + i->baseOffset); + return (((asCSimpleDummy*)obj)->*f)(); + } + else +#endif + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(int*)gen.GetReturnPointer(); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + int (*f)(void *) = (int (*)(void *))(i->func); + return f(obj); + } +#endif +} + +void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int func) const +{ + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + asSSystemFunctionInterface *i = s->sysFuncIntf; + +#if defined(__GNUC__) || defined(AS_PSVITA) + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(void**)gen.GetReturnPointer(); + } + else if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) + { + // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable + union + { + asSIMPLEMETHOD_t mthd; + struct + { + asFUNCTION_t func; + asPWORD baseOffset; + } f; + } p; + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())(p.mthd); + return (((asCSimpleDummy*)obj)->*f)(); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + void *(*f)(void *) = (void *(*)(void *))(i->func); + return f(obj); + } +#else +#ifndef AS_NO_CLASS_METHODS + if( i->callConv == ICC_THISCALL ) + { + union + { + asSIMPLEMETHOD_t mthd; + asFUNCTION_t func; + } p; + p.func = (asFUNCTION_t)(i->func); + void *(asCSimpleDummy::*f)() = (void *(asCSimpleDummy::*)())p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + obj = (void*)(asPWORD(obj) + i->baseOffset); + return (((asCSimpleDummy*)obj)->*f)(); + } + else +#endif + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(void **)gen.GetReturnPointer(); + } + else /*if( i->callConv == ICC_CDECL_OBJLAST || i->callConv == ICC_CDECL_OBJFIRST )*/ + { + void *(*f)(void *) = (void *(*)(void *))(i->func); + return f(obj); + } +#endif +} + +void *asCScriptEngine::CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const +{ + asASSERT( obj != 0 ); + asASSERT( func != 0 ); + asSSystemFunctionInterface *i = func->sysFuncIntf; + +#ifndef AS_NO_CLASS_METHODS + if( i->callConv == ICC_THISCALL || i->callConv == ICC_VIRTUAL_THISCALL ) + { +#if defined(__GNUC__) || defined(AS_PSVITA) + // For virtual thiscalls we must call the method as a true class method so that the compiler will lookup the function address in the vftable + union + { + asSIMPLEMETHOD_t mthd; + struct + { + asFUNCTION_t func; + asPWORD baseOffset; + } f; + } p; + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))(p.mthd); + return (((asCSimpleDummy*)obj)->*f)(param1); +#else + union + { + asSIMPLEMETHOD_t mthd; + asFUNCTION_t func; + } p; + p.func = (asFUNCTION_t)(i->func); + void *(asCSimpleDummy::*f)(int) = (void *(asCSimpleDummy::*)(int))p.mthd; + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + obj = (void*)(asPWORD(obj) + i->baseOffset); + return (((asCSimpleDummy*)obj)->*f)(param1); +#endif + } + else +#endif + if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), func, obj, reinterpret_cast(¶m1)); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(void **)gen.GetReturnPointer(); + } + else if( i->callConv == ICC_CDECL_OBJLAST ) + { + void *(*f)(int, void *) = (void *(*)(int, void *))(i->func); + return f(param1, obj); + } + else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/ + { + void *(*f)(void *, int) = (void *(*)(void *, int))(i->func); + return f(obj, param1); + } +} + +void *asCScriptEngine::CallGlobalFunctionRetPtr(int func) const +{ + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + return CallGlobalFunctionRetPtr(s->sysFuncIntf, s); +} + +void *asCScriptEngine::CallGlobalFunctionRetPtr(int func, void *param1) const +{ + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + return CallGlobalFunctionRetPtr(s->sysFuncIntf, s, param1); +} + +void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s) const +{ + if( i->callConv == ICC_CDECL ) + { + void *(*f)() = (void *(*)())(i->func); + return f(); + } + else if( i->callConv == ICC_STDCALL ) + { + typedef void *(STDCALL *func_t)(); + func_t f = (func_t)(i->func); + return f(); + } + else + { + asCGeneric gen(const_cast(this), s, 0, 0); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(void**)gen.GetReturnPointer(); + } +} + +void *asCScriptEngine::CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s, void *param1) const +{ + if( i->callConv == ICC_CDECL ) + { + void *(*f)(void *) = (void *(*)(void *))(i->func); + return f(param1); + } + else if( i->callConv == ICC_STDCALL ) + { + typedef void *(STDCALL *func_t)(void *); + func_t f = (func_t)(i->func); + return f(param1); + } + else + { + asCGeneric gen(const_cast(this), s, 0, (asDWORD*)¶m1); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(void**)gen.GetReturnPointer(); + } +} + +void asCScriptEngine::CallObjectMethod(void *obj, void *param, int func) const +{ + asCScriptFunction *s = scriptFunctions[func]; + asASSERT( s != 0 ); + CallObjectMethod(obj, param, s->sysFuncIntf, s); +} + +void asCScriptEngine::CallObjectMethod(void *obj, void *param, asSSystemFunctionInterface *i, asCScriptFunction *s) const +{ +#if defined(__GNUC__) || defined(AS_PSVITA) + if( i->callConv == ICC_CDECL_OBJLAST ) + { + void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); + f(param, obj); + } + else if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, (asDWORD*)¶m); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + } + else if( i->callConv == ICC_VIRTUAL_THISCALL || i->callConv == ICC_THISCALL ) + { + // For virtual thiscalls we must call the method as a true class method + // so that the compiler will lookup the function address in the vftable + union + { + asSIMPLEMETHOD_t mthd; + struct + { + asFUNCTION_t func; + asPWORD baseOffset; // Same size as the pointer + } f; + } p; + p.f.func = (asFUNCTION_t)(i->func); + p.f.baseOffset = asPWORD(i->baseOffset); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + void (asCSimpleDummy::*f)(void*) = (void (asCSimpleDummy::*)(void*))(p.mthd); + (((asCSimpleDummy*)obj)->*f)(param); + } + else /*if( i->callConv == ICC_CDECL_OBJFIRST */ + { + void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); + f(obj, param); + } +#else +#ifndef AS_NO_CLASS_METHODS + if( i->callConv == ICC_THISCALL ) + { + union + { + asSIMPLEMETHOD_t mthd; + asFUNCTION_t func; + } p; + p.func = (asFUNCTION_t)(i->func); + void (asCSimpleDummy::*f)(void *) = (void (asCSimpleDummy::*)(void *))(p.mthd); + + obj = (void*) ((char*) obj + i->compositeOffset); + if(i->isCompositeIndirect) + obj = *((void**)obj); + + obj = (void*)(asPWORD(obj) + i->baseOffset); + (((asCSimpleDummy*)obj)->*f)(param); + } + else +#endif + if( i->callConv == ICC_CDECL_OBJLAST ) + { + void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); + f(param, obj); + } + else if( i->callConv == ICC_GENERIC_METHOD ) + { + asCGeneric gen(const_cast(this), s, obj, (asDWORD*)¶m); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + } + else /*if( i->callConv == ICC_CDECL_OBJFIRST )*/ + { + void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); + f(obj, param); + } +#endif +} + +void asCScriptEngine::CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s) const +{ + if( i->callConv == ICC_CDECL ) + { + void (*f)(void *, void *) = (void (*)(void *, void *))(i->func); + f(param1, param2); + } + else if( i->callConv == ICC_STDCALL ) + { + typedef void (STDCALL *func_t)(void *, void *); + func_t f = (func_t)(i->func); + f(param1, param2); + } + else + { + // We must guarantee the order of the arguments which is why we copy them to this + // array. Otherwise the compiler may put them anywhere it likes, or even keep them + // in the registers which causes problem. + void *params[2] = {param1, param2}; + + asCGeneric gen(const_cast(this), s, 0, (asDWORD*)¶ms); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + } +} + +bool asCScriptEngine::CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *i, asCScriptFunction *s) const +{ + if( i->callConv == ICC_CDECL ) + { + bool (*f)(void *, void *) = (bool (*)(void *, void *))(i->func); + return f(param1, param2); + } + else if( i->callConv == ICC_STDCALL ) + { + typedef bool (STDCALL *func_t)(void *, void *); + func_t f = (func_t)(i->func); + return f(param1, param2); + } + else + { + // TODO: When simulating a 64bit environment by defining AS_64BIT_PTR on a 32bit platform this code + // fails, because the stack given to asCGeneric is not prepared with two 64bit arguments. + + // We must guarantee the order of the arguments which is why we copy them to this + // array. Otherwise the compiler may put them anywhere it likes, or even keep them + // in the registers which causes problem. + void *params[2] = {param1, param2}; + asCGeneric gen(const_cast(this), s, 0, (asDWORD*)params); + void (*f)(asIScriptGeneric *) = (void (*)(asIScriptGeneric *))(i->func); + f(&gen); + return *(bool*)gen.GetReturnPointer(); + } +} + +void *asCScriptEngine::CallAlloc(const asCObjectType *type) const +{ + // Allocate 4 bytes as the smallest size. Otherwise CallSystemFunction may try to + // copy a DWORD onto a smaller memory block, in case the object type is return in registers. + + // Pad to the next even 4 bytes to avoid asBC_CPY writing outside of allocated buffer for registered POD types + asUINT size = type->size; + if( size & 0x3 ) + size += 4 - (size & 0x3); + +#ifndef WIP_16BYTE_ALIGN +#if defined(AS_DEBUG) + return ((asALLOCFUNCDEBUG_t)userAlloc)(size, __FILE__, __LINE__); +#else + return userAlloc(size); +#endif +#else +#if defined(AS_DEBUG) + return ((asALLOCALIGNEDFUNCDEBUG_t)userAllocAligned)(size, type->alignment, __FILE__, __LINE__); +#else + return userAllocAligned(size, type->alignment); +#endif +#endif +} + +void asCScriptEngine::CallFree(void *obj) const +{ +#ifndef WIP_16BYTE_ALIGN + userFree(obj); +#else + userFreeAligned(obj); +#endif +} + +// interface +int asCScriptEngine::NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type) +{ + return gc.AddScriptObjectToGC(obj, static_cast(type)); +} + +// interface +int asCScriptEngine::GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj, asITypeInfo **type) +{ + return gc.GetObjectInGC(idx, seqNbr, obj, type); +} + +// interface +int asCScriptEngine::GarbageCollect(asDWORD flags, asUINT iterations) +{ + int r = gc.GarbageCollect(flags, iterations); + + if( r == 0 ) + { + // Delete any modules that have been discarded previously but not + // removed due to being referred to by objects in the garbage collector + DeleteDiscardedModules(); + } + + return r; +} + +// interface +void asCScriptEngine::GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const +{ + gc.GetStatistics(currentSize, totalDestroyed, totalDetected, newObjects, totalNewDestroyed); +} + +// interface +void asCScriptEngine::GCEnumCallback(void *reference) +{ + gc.GCEnumCallback(reference); +} + +// interface +void asCScriptEngine::ForwardGCEnumReferences(void *ref, asITypeInfo *type) +{ + asCTypeInfo *t = reinterpret_cast(type); + if ((t->flags & asOBJ_VALUE) && (t->flags & asOBJ_GC)) + { + CallObjectMethod(ref, this, CastToObjectType(t)->beh.gcEnumReferences); + } +} + +// interface +void asCScriptEngine::ForwardGCReleaseReferences(void *ref, asITypeInfo *type) +{ + asCTypeInfo *t = reinterpret_cast(type); + if ((t->flags & asOBJ_VALUE) && (t->flags & asOBJ_GC)) + { + CallObjectMethod(ref, this, CastToObjectType(t)->beh.gcReleaseAllReferences); + } +} + +// interface +void asCScriptEngine::SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param) +{ + gc.circularRefDetectCallbackFunc = callback; + gc.circularRefDetectCallbackParam = param; +} + +int asCScriptEngine::GetTypeIdFromDataType(const asCDataType &dtIn) const +{ + if( dtIn.IsNullHandle() ) return asTYPEID_VOID; + + if( dtIn.GetTypeInfo() == 0 ) + { + // Primitives have pre-fixed typeIds + switch( dtIn.GetTokenType() ) + { + case ttVoid: return asTYPEID_VOID; + case ttBool: return asTYPEID_BOOL; + case ttInt8: return asTYPEID_INT8; + case ttInt16: return asTYPEID_INT16; + case ttInt: return asTYPEID_INT32; + case ttInt64: return asTYPEID_INT64; + case ttUInt8: return asTYPEID_UINT8; + case ttUInt16: return asTYPEID_UINT16; + case ttUInt: return asTYPEID_UINT32; + case ttUInt64: return asTYPEID_UINT64; + case ttFloat: return asTYPEID_FLOAT; + case ttDouble: return asTYPEID_DOUBLE; + default: + // All types should be covered by the above. The variable type is not really a type + asASSERT(dtIn.GetTokenType() == ttQuestion); + return -1; + } + } + + int typeId = -1; + asCTypeInfo *ot = dtIn.GetTypeInfo(); + asASSERT(ot != &functionBehaviours); + // Object's hold the typeId themselves + typeId = ot->typeId; + + if( typeId == -1 ) + { + ACQUIREEXCLUSIVE(engineRWLock); + // Make sure another thread didn't determine the typeId while we were waiting for the lock + if( ot->typeId == -1 ) + { + typeId = typeIdSeqNbr++; + if( ot->flags & asOBJ_SCRIPT_OBJECT ) typeId |= asTYPEID_SCRIPTOBJECT; + else if( ot->flags & asOBJ_TEMPLATE ) typeId |= asTYPEID_TEMPLATE; + else if( ot->flags & asOBJ_ENUM ) {} // TODO: Should we have a specific bit for this? + else typeId |= asTYPEID_APPOBJECT; + + ot->typeId = typeId; + + mapTypeIdToTypeInfo.Insert(typeId, ot); + } + RELEASEEXCLUSIVE(engineRWLock); + } + + // Add flags according to the requested type + if( dtIn.GetTypeInfo() && !(dtIn.GetTypeInfo()->flags & asOBJ_ASHANDLE) ) + { + // The ASHANDLE types behave like handles, but are really + // value types so the typeId is never returned as a handle + if( dtIn.IsObjectHandle() ) + typeId |= asTYPEID_OBJHANDLE; + if( dtIn.IsHandleToConst() ) + typeId |= asTYPEID_HANDLETOCONST; + } + + return typeId; +} + +asCDataType asCScriptEngine::GetDataTypeFromTypeId(int typeId) const +{ + int baseId = typeId & (asTYPEID_MASK_OBJECT | asTYPEID_MASK_SEQNBR); + + if( typeId <= asTYPEID_DOUBLE ) + { + eTokenType type[] = {ttVoid, ttBool, ttInt8, ttInt16, ttInt, ttInt64, ttUInt8, ttUInt16, ttUInt, ttUInt64, ttFloat, ttDouble}; + return asCDataType::CreatePrimitive(type[typeId], false); + } + + // First check if the typeId is an object type + asCTypeInfo *ot = 0; + ACQUIRESHARED(engineRWLock); + asSMapNode *cursor = 0; + if( mapTypeIdToTypeInfo.MoveTo(&cursor, baseId) ) + ot = mapTypeIdToTypeInfo.GetValue(cursor); + RELEASESHARED(engineRWLock); + + if( ot ) + { + asCDataType dt = asCDataType::CreateType(ot, false); + if( typeId & asTYPEID_OBJHANDLE ) + dt.MakeHandle(true, true); + if( typeId & asTYPEID_HANDLETOCONST ) + dt.MakeHandleToConst(true); + + return dt; + } + + return asCDataType(); +} + +asCObjectType *asCScriptEngine::GetObjectTypeFromTypeId(int typeId) const +{ + asCDataType dt = GetDataTypeFromTypeId(typeId); + return CastToObjectType(dt.GetTypeInfo()); +} + +void asCScriptEngine::RemoveFromTypeIdMap(asCTypeInfo *type) +{ + ACQUIREEXCLUSIVE(engineRWLock); + asSMapNode *cursor = 0; + mapTypeIdToTypeInfo.MoveFirst(&cursor); + while( cursor ) + { + if(mapTypeIdToTypeInfo.GetValue(cursor) == type ) + { + mapTypeIdToTypeInfo.Erase(cursor); + break; + } + mapTypeIdToTypeInfo.MoveNext(&cursor, cursor); + } + RELEASEEXCLUSIVE(engineRWLock); +} + +// interface +asITypeInfo *asCScriptEngine::GetTypeInfoByDecl(const char *decl) const +{ + asCDataType dt; + // This cast is ok, because we are not changing anything in the engine + asCBuilder bld(const_cast(this), 0); + + // Don't write parser errors to the message callback + bld.silent = true; + + int r = bld.ParseDataType(decl, &dt, defaultNamespace); + if (r < 0) + return 0; + + return dt.GetTypeInfo(); +} + +// interface +int asCScriptEngine::GetTypeIdByDecl(const char *decl) const +{ + asCDataType dt; + // This cast is ok, because we are not changing anything in the engine + asCBuilder bld(const_cast(this), 0); + + // Don't write parser errors to the message callback + bld.silent = true; + + int r = bld.ParseDataType(decl, &dt, defaultNamespace); + if( r < 0 ) + return asINVALID_TYPE; + + return GetTypeIdFromDataType(dt); +} + +// interface +const char *asCScriptEngine::GetTypeDeclaration(int typeId, bool includeNamespace) const +{ + asCDataType dt = GetDataTypeFromTypeId(typeId); + + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = dt.Format(defaultNamespace, includeNamespace); + + return tempString->AddressOf(); +} + +// interface +int asCScriptEngine::GetSizeOfPrimitiveType(int typeId) const +{ + asCDataType dt = GetDataTypeFromTypeId(typeId); + if( !dt.IsPrimitive() ) return 0; + + return dt.GetSizeInMemoryBytes(); +} + +// interface +int asCScriptEngine::RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast) +{ + if( newPtr == 0 ) return asINVALID_ARG; + *newPtr = 0; + + if( fromType == 0 || toType == 0 ) return asINVALID_ARG; + + // A null-pointer can always be cast to another type, so it will always be successful + if( obj == 0 ) + return asSUCCESS; + + if( fromType == toType ) + { + *newPtr = obj; + AddRefScriptObject(*newPtr, toType); + return asSUCCESS; + } + + // Check for funcdefs + if ((fromType->GetFlags() & asOBJ_FUNCDEF) && (toType->GetFlags() & asOBJ_FUNCDEF)) + { + asCFuncdefType *fromFunc = CastToFuncdefType(reinterpret_cast(fromType)); + asCFuncdefType *toFunc = CastToFuncdefType(reinterpret_cast(toType)); + + if (fromFunc && toFunc && fromFunc->funcdef->IsSignatureExceptNameEqual(toFunc->funcdef)) + { + *newPtr = obj; + AddRefScriptObject(*newPtr, toType); + return asSUCCESS; + } + + return asSUCCESS; + } + + // Look for ref cast behaviours + asCScriptFunction *universalCastFunc = 0; + asCObjectType *from = reinterpret_cast(fromType); + for( asUINT n = 0; n < from->methods.GetLength(); n++ ) + { + asCScriptFunction *func = scriptFunctions[from->methods[n]]; + if( func->name == "opImplCast" || + (!useOnlyImplicitCast && func->name == "opCast") ) + { + if( func->returnType.GetTypeInfo() == toType ) + { + *newPtr = CallObjectMethodRetPtr(obj, func->id); + // The ref cast behaviour returns a handle with incremented + // ref counter, so there is no need to call AddRef explicitly + // unless the function is registered with autohandle + if( func->sysFuncIntf->returnAutoHandle ) + AddRefScriptObject(*newPtr, toType); + return asSUCCESS; + } + else if( func->returnType.GetTokenType() == ttVoid && + func->parameterTypes.GetLength() == 1 && + func->parameterTypes[0].GetTokenType() == ttQuestion ) + { + universalCastFunc = func; + } + } + } + + // One last chance if the object has a void opCast(?&out) behaviour + if( universalCastFunc ) + { + // TODO: Add proper error handling + asIScriptContext *ctx = RequestContext(); + ctx->Prepare(universalCastFunc); + ctx->SetObject(obj); + ctx->SetArgVarType(0, newPtr, toType->GetTypeId() | asTYPEID_OBJHANDLE); + ctx->Execute(); + ReturnContext(ctx); + + // The opCast(?&out) method already incremented the + // refCount so there is no need to do it manually + return asSUCCESS; + } + + // For script classes and interfaces there is a quick route + if( (fromType->GetFlags() & asOBJ_SCRIPT_OBJECT) && (toType->GetFlags() & asOBJ_SCRIPT_OBJECT) ) + { + if( fromType == toType ) + { + *newPtr = obj; + reinterpret_cast(*newPtr)->AddRef(); + return asSUCCESS; + } + + // Up casts to base class or interface can be done implicitly + if( fromType->DerivesFrom(toType) || + fromType->Implements(toType) ) + { + *newPtr = obj; + reinterpret_cast(*newPtr)->AddRef(); + return asSUCCESS; + } + // Down casts to derived class or from interface can only be done explicitly + if( !useOnlyImplicitCast ) + { + // Get the true type of the object so the explicit cast can evaluate all possibilities + asITypeInfo *trueType = reinterpret_cast(obj)->GetObjectType(); + if (trueType->DerivesFrom(toType) || + trueType->Implements(toType)) + { + *newPtr = obj; + reinterpret_cast(*newPtr)->AddRef(); + return asSUCCESS; + } + } + } + + // The cast is not available, but it is still a success + return asSUCCESS; +} + +// interface +void *asCScriptEngine::CreateScriptObject(const asITypeInfo *type) +{ + if( type == 0 ) return 0; + + asCObjectType *objType = const_cast(reinterpret_cast(type)); + void *ptr = 0; + + // Check that there is a default factory for ref types + if( objType->beh.factory == 0 && (objType->flags & asOBJ_REF) ) + { + // TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code? + // TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off +// asCString str; +// str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION); +// WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return 0; + } + + // Construct the object + if( objType->flags & asOBJ_SCRIPT_OBJECT ) + { + // Call the script class' default factory with a context + ptr = ScriptObjectFactory(objType, this); + } + else if( (objType->flags & asOBJ_TEMPLATE) && (objType->flags & asOBJ_REF) ) + { + // The registered factory that takes the object type is moved + // to the construct behaviour when the type is instantiated +#ifdef AS_NO_EXCEPTIONS + ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); +#else + try + { + ptr = CallGlobalFunctionRetPtr(objType->beh.construct, objType); + } + catch (...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if (ctx) + ctx->HandleAppException(); + } +#endif + } + else if( objType->flags & asOBJ_REF ) + { + // Call the default factory directly +#ifdef AS_NO_EXCEPTIONS + ptr = CallGlobalFunctionRetPtr(objType->beh.factory); +#else + try + { + ptr = CallGlobalFunctionRetPtr(objType->beh.factory); + } + catch(...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if( ctx ) + ctx->HandleAppException(); + } +#endif + } + else + { + // Make sure there is a default constructor or that it is a POD type + if( objType->beh.construct == 0 && !(objType->flags & asOBJ_POD) ) + { + // TODO: How to report the reason the object couldn't be created, without writing to the message callback? optional argument with return code? + // TODO: Warn about the invalid call to message callback. Make it an optional, so the warning can be turned off +// asCString str; +// str.Format(TXT_FAILED_IN_FUNC_s_s_d, "CreateScriptObject", errorNames[-asNO_FUNCTION], asNO_FUNCTION); +// WriteMessage("", 0, 0, asMSGTYPE_ERROR, str.AddressOf()); + return 0; + } + + // Manually allocate the memory, then call the default constructor + ptr = CallAlloc(objType); + int funcIndex = objType->beh.construct; + if (funcIndex) + { + if (objType->flags & asOBJ_TEMPLATE) + { + // Templates of value types create script functions as the constructors + CallScriptObjectMethod(ptr, funcIndex); + } + else + { +#ifdef AS_NO_EXCEPTIONS + CallObjectMethod(ptr, funcIndex); +#else + try + { + CallObjectMethod(ptr, funcIndex); + } + catch (...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if (ctx) + ctx->HandleAppException(); + + // Free the memory + CallFree(ptr); + ptr = 0; + } +#endif + } + } + } + + return ptr; +} + +// internal +int asCScriptEngine::CallScriptObjectMethod(void *obj, int funcId) +{ + asIScriptContext *ctx = 0; + int r = 0; + bool isNested = false; + + // Use nested call in the context if there is an active context + ctx = asGetActiveContext(); + if (ctx) + { + // It may not always be possible to reuse the current context, + // in which case we'll have to create a new one any way. + if (ctx->GetEngine() == this && ctx->PushState() == asSUCCESS) + isNested = true; + else + ctx = 0; + } + + if (ctx == 0) + { + // Request a context from the engine + ctx = RequestContext(); + if (ctx == 0) + { + // TODO: How to best report this failure? + return asERROR; + } + } + + r = ctx->Prepare(scriptFunctions[funcId]); + if (r < 0) + { + if (isNested) + ctx->PopState(); + else + ReturnContext(ctx); + // TODO: How to best report this failure? + return asERROR; + } + + // Set the object + ctx->SetObject(obj); + + for (;;) + { + r = ctx->Execute(); + + // We can't allow this execution to be suspended + // so resume the execution immediately + if (r != asEXECUTION_SUSPENDED) + break; + } + + if (r != asEXECUTION_FINISHED) + { + if (isNested) + { + ctx->PopState(); + + // If the execution was aborted or an exception occurred, + // then we should forward that to the outer execution. + if (r == asEXECUTION_EXCEPTION) + { + // TODO: How to improve this exception + ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); + } + else if (r == asEXECUTION_ABORTED) + ctx->Abort(); + } + else + ReturnContext(ctx); + + // TODO: How to best report the error? + return asERROR; + } + + if (isNested) + ctx->PopState(); + else + ReturnContext(ctx); + + return asSUCCESS; +} + +// interface +void *asCScriptEngine::CreateUninitializedScriptObject(const asITypeInfo *type) +{ + // This function only works for script classes. Registered types cannot be created this way. + if( type == 0 || !(type->GetFlags() & asOBJ_SCRIPT_OBJECT) ) + return 0; + + asCObjectType *objType = const_cast(reinterpret_cast(type)); + + // Construct the object, but do not call the actual constructor that initializes the members + // The initialization will be done by the application afterwards, e.g. through serialization. + asCScriptObject *obj = reinterpret_cast(CallAlloc(objType)); + + // Pre-initialize the memory so there are no invalid pointers + ScriptObject_ConstructUnitialized(objType, obj); + + return obj; +} + +// interface +void *asCScriptEngine::CreateScriptObjectCopy(void *origObj, const asITypeInfo *type) +{ + if( origObj == 0 || type == 0 ) return 0; + + void *newObj = 0; + + const asCObjectType *ot = reinterpret_cast(type); + if ((ot->flags & asOBJ_SCRIPT_OBJECT) && ot->beh.copyfactory) + { + // Call the script class' default factory with a context + newObj = ScriptObjectCopyFactory(ot, origObj, this); + } + else if (ot->beh.copyfactory) + { + // Call the copy factory which will allocate the memory then copy the original object +#ifdef AS_NO_EXCEPTIONS + newObj = CallGlobalFunctionRetPtr(ot->beh.copyfactory, origObj); +#else + try + { + newObj = CallGlobalFunctionRetPtr(ot->beh.copyfactory, origObj); + } + catch (...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if (ctx) + ctx->HandleAppException(); + } +#endif + } + else if( ot->beh.copyconstruct ) + { + // Manually allocate the memory, then call the copy constructor + newObj = CallAlloc(ot); +#ifdef AS_NO_EXCEPTIONS + CallObjectMethod(newObj, origObj, ot->beh.copyconstruct); +#else + try + { + CallObjectMethod(newObj, origObj, ot->beh.copyconstruct); + } + catch(...) + { + asCContext *ctx = reinterpret_cast(asGetActiveContext()); + if( ctx ) + ctx->HandleAppException(); + + // Free the memory + CallFree(newObj); + newObj = 0; + } +#endif + } + else + { + // Allocate the object and then do a value assign + newObj = CreateScriptObject(type); + if( newObj == 0 ) return 0; + + AssignScriptObject(newObj, origObj, type); + } + + return newObj; +} + +// internal +void asCScriptEngine::ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type) +{ + if( type == 0 || mem == 0 || obj == 0 ) return; + + // This function is only meant to be used for value types + asASSERT( type->flags & asOBJ_VALUE ); + + // Call the copy constructor if available, else call the default constructor followed by the opAssign + int funcIndex = type->beh.copyconstruct; + if( funcIndex ) + { + CallObjectMethod(mem, obj, funcIndex); + } + else + { + funcIndex = type->beh.construct; + if( funcIndex ) + CallObjectMethod(mem, funcIndex); + + AssignScriptObject(mem, obj, type); + } +} + +// interface +int asCScriptEngine::AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type) +{ + // TODO: Warn about invalid call in message stream (make it optional) + if( type == 0 || dstObj == 0 || srcObj == 0 ) return asINVALID_ARG; + + const asCObjectType *objType = reinterpret_cast(type); + + // If value assign for ref types has been disabled, then don't do anything if the type is a ref type + if (ep.disallowValueAssignForRefType && (objType->flags & asOBJ_REF) && !(objType->flags & asOBJ_SCOPED)) + { + asIScriptContext *ctx = asGetActiveContext(); + if (ctx) + ctx->SetException("Cannot do value assignment"); + return asNOT_SUPPORTED; + } + + // Must not copy if the opAssign is not available and the object is not a POD object + if( objType->beh.copy ) + { + asCScriptFunction *func = scriptFunctions[objType->beh.copy]; + if( func->funcType == asFUNC_SYSTEM ) + CallObjectMethod(dstObj, srcObj, objType->beh.copy); + else + { + // Call the script class' opAssign method + asASSERT( objType->flags & asOBJ_SCRIPT_OBJECT ); + reinterpret_cast(dstObj)->CopyFrom(reinterpret_cast(srcObj)); + } + } + else if( objType->size && (objType->flags & asOBJ_POD) ) + { + memcpy(dstObj, srcObj, objType->size); + } + + return asSUCCESS; +} + +// interface +void asCScriptEngine::AddRefScriptObject(void *obj, const asITypeInfo *type) +{ + // Make sure it is not a null pointer + if( obj == 0 || type == 0 ) return; + + const asCTypeInfo *ti = static_cast(type); + if (ti->flags & asOBJ_FUNCDEF) + { + CallObjectMethod(obj, functionBehaviours.beh.addref); + } + else + { + asCObjectType *objType = CastToObjectType(const_cast(ti)); + if (objType && objType->beh.addref) + { + // Call the addref behaviour + CallObjectMethod(obj, objType->beh.addref); + } + } +} + +// interface +void asCScriptEngine::ReleaseScriptObject(void *obj, const asITypeInfo *type) +{ + // Make sure it is not a null pointer + if( obj == 0 || type == 0 ) return; + + const asCTypeInfo *ti = static_cast(type); + if (ti->flags & asOBJ_FUNCDEF) + { + CallObjectMethod(obj, functionBehaviours.beh.release); + } + else + { + asCObjectType *objType = CastToObjectType(const_cast(ti)); + if (objType && objType->flags & asOBJ_REF) + { + asASSERT((objType->flags & asOBJ_NOCOUNT) || objType->beh.release); + if (objType->beh.release) + { + // Call the release behaviour + CallObjectMethod(obj, objType->beh.release); + } + } + else if( objType ) + { + // Call the destructor + if (objType->beh.destruct) + CallObjectMethod(obj, objType->beh.destruct); + else if (objType->flags & asOBJ_LIST_PATTERN) + DestroyList((asBYTE*)obj, objType); + + // We'll have to trust that the memory for the object was allocated with CallAlloc. + // This is true if the object was created in the context, or with CreateScriptObject. + + // Then free the memory + CallFree(obj); + } + } +} + +// interface +int asCScriptEngine::BeginConfigGroup(const char *groupName) +{ + // Make sure the group name doesn't already exist + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + if( configGroups[n]->groupName == groupName ) + return asNAME_TAKEN; + } + + if( currentGroup != &defaultGroup ) + return asNOT_SUPPORTED; + + asCConfigGroup *group = asNEW(asCConfigGroup)(); + if( group == 0 ) + return asOUT_OF_MEMORY; + + group->groupName = groupName; + + configGroups.PushLast(group); + currentGroup = group; + + return 0; +} + +// interface +int asCScriptEngine::EndConfigGroup() +{ + // Raise error if trying to end the default config + if( currentGroup == &defaultGroup ) + return asERROR; + + currentGroup = &defaultGroup; + + return 0; +} + +// interface +int asCScriptEngine::RemoveConfigGroup(const char *groupName) +{ + // It is not allowed to remove a group that is still in use. + + // It would be possible to change the code in such a way that + // the group could be removed even though it was still in use, + // but that would cause severe negative impact on runtime + // performance, since the VM would then have to be able handle + // situations where the types, functions, and global variables + // can be removed at any time. + + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + if( configGroups[n]->groupName == groupName ) + { + asCConfigGroup *group = configGroups[n]; + + // Remove any unused generated template instances + // before verifying if the config group is still in use. + // RemoveTemplateInstanceType() checks if the instance is in use + for( asUINT g = generatedTemplateTypes.GetLength(); g-- > 0; ) + RemoveTemplateInstanceType(generatedTemplateTypes[g]); + + // Make sure the group isn't referenced by anyone + if( group->refCount > 0 ) + return asCONFIG_GROUP_IS_IN_USE; + + // Verify if any objects registered in this group is still alive + if( group->HasLiveObjects() ) + return asCONFIG_GROUP_IS_IN_USE; + + // Remove the group from the list + if( n == configGroups.GetLength() - 1 ) + configGroups.PopLast(); + else + configGroups[n] = configGroups.PopLast(); + + // Remove the configurations registered with this group + group->RemoveConfiguration(this); + + asDELETE(group,asCConfigGroup); + } + } + + return 0; +} + +asCConfigGroup *asCScriptEngine::FindConfigGroupForFunction(int funcId) const +{ + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + // Check global functions + asUINT m; + for( m = 0; m < configGroups[n]->scriptFunctions.GetLength(); m++ ) + { + if( configGroups[n]->scriptFunctions[m]->id == funcId ) + return configGroups[n]; + } + } + + return 0; +} + + +asCConfigGroup *asCScriptEngine::FindConfigGroupForGlobalVar(int gvarId) const +{ + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + for( asUINT m = 0; m < configGroups[n]->globalProps.GetLength(); m++ ) + { + if( int(configGroups[n]->globalProps[m]->id) == gvarId ) + return configGroups[n]; + } + } + + return 0; +} + +asCConfigGroup *asCScriptEngine::FindConfigGroupForTypeInfo(const asCTypeInfo *objType) const +{ + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + for( asUINT m = 0; m < configGroups[n]->types.GetLength(); m++ ) + { + if( configGroups[n]->types[m] == objType ) + return configGroups[n]; + } + } + + return 0; +} + +asCConfigGroup *asCScriptEngine::FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const +{ + for( asUINT n = 0; n < configGroups.GetLength(); n++ ) + { + asCFuncdefType *f = const_cast(funcDef); + if( configGroups[n]->types.Exists(f) ) + return configGroups[n]; + } + + return 0; +} + +// interface +asDWORD asCScriptEngine::SetDefaultAccessMask(asDWORD defaultMask) +{ + asDWORD old = defaultAccessMask; + defaultAccessMask = defaultMask; + return old; +} + +int asCScriptEngine::GetNextScriptFunctionId() +{ + // This function only returns the next function id that + // should be used. It doesn't update the internal arrays. + if( freeScriptFunctionIds.GetLength() ) + return freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1]; + + return (int)scriptFunctions.GetLength(); +} + +void asCScriptEngine::AddScriptFunction(asCScriptFunction *func) +{ + // Update the internal arrays with the function id that is now used + if( freeScriptFunctionIds.GetLength() && freeScriptFunctionIds[freeScriptFunctionIds.GetLength()-1] == func->id ) + freeScriptFunctionIds.PopLast(); + + if( asUINT(func->id) == scriptFunctions.GetLength() ) + scriptFunctions.PushLast(func); + else + { + // The slot should be empty or already set with the function, which happens if an existing shared function is reused + asASSERT( scriptFunctions[func->id] == 0 || scriptFunctions[func->id] == func ); + scriptFunctions[func->id] = func; + } +} + +void asCScriptEngine::RemoveScriptFunction(asCScriptFunction *func) +{ + if( func == 0 || func->id < 0 ) return; + int id = func->id & ~FUNC_IMPORTED; + if( func->funcType == asFUNC_IMPORTED ) + { + if( id >= (int)importedFunctions.GetLength() ) return; + + if( importedFunctions[id] ) + { + // Remove the function from the list of script functions + if( id == (int)importedFunctions.GetLength() - 1 ) + { + importedFunctions.PopLast(); + } + else + { + importedFunctions[id] = 0; + freeImportedFunctionIdxs.PushLast(id); + } + } + } + else + { + if( id >= (int)scriptFunctions.GetLength() ) return; + asASSERT( func == scriptFunctions[id] ); + + if( scriptFunctions[id] ) + { + // Remove the function from the list of script functions + if( id == (int)scriptFunctions.GetLength() - 1 ) + { + scriptFunctions.PopLast(); + } + else + { + scriptFunctions[id] = 0; + freeScriptFunctionIds.PushLast(id); + } + + // Is the function used as signature id? + if( func->signatureId == id ) + { + // Remove the signature id + signatureIds.RemoveValue(func); + + // Update all functions using the signature id + int newSigId = 0; + for( asUINT n = 0; n < scriptFunctions.GetLength(); n++ ) + { + if( scriptFunctions[n] && scriptFunctions[n]->signatureId == id ) + { + if( newSigId == 0 ) + { + newSigId = scriptFunctions[n]->id; + signatureIds.PushLast(scriptFunctions[n]); + } + + scriptFunctions[n]->signatureId = newSigId; + } + } + } + } + } +} + +// internal +void asCScriptEngine::RemoveFuncdef(asCFuncdefType *funcdef) +{ + funcDefs.RemoveValue(funcdef); +} + +// interface +int asCScriptEngine::RegisterFuncdef(const char *decl) +{ + if( decl == 0 ) return ConfigError(asINVALID_ARG, "RegisterFuncdef", decl, 0); + + // Parse the function declaration + asCScriptFunction *func = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF); + if( func == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterFuncdef", decl, 0); + + asCBuilder bld(this, 0); + asCObjectType *parentClass = 0; + int r = bld.ParseFunctionDeclaration(0, decl, func, false, 0, 0, defaultNamespace, 0, &parentClass); + if( r < 0 ) + { + // Set as dummy function before deleting + func->funcType = asFUNC_DUMMY; + asDELETE(func,asCScriptFunction); + return ConfigError(asINVALID_DECLARATION, "RegisterFuncdef", decl, 0); + } + + // Check name conflicts + r = bld.CheckNameConflict(func->name.AddressOf(), 0, 0, defaultNamespace, true, false); + if( r < 0 ) + { + asDELETE(func,asCScriptFunction); + return ConfigError(asNAME_TAKEN, "RegisterFuncdef", decl, 0); + } + + func->id = GetNextScriptFunctionId(); + AddScriptFunction(func); + + asCFuncdefType *fdt = asNEW(asCFuncdefType)(this, func); + funcDefs.PushLast(fdt); // doesn't increase refcount + registeredFuncDefs.PushLast(fdt); // doesn't increase refcount + allRegisteredTypes.Insert(asSNameSpaceNamePair(fdt->nameSpace, fdt->name), fdt); // constructor already set the ref count to 1 + + currentGroup->types.PushLast(fdt); + if (parentClass) + { + parentClass->childFuncDefs.PushLast(fdt); + fdt->parentClass = parentClass; + + // Check if the method restricts that use of the template to value types or reference types + if (parentClass->flags & asOBJ_TEMPLATE) + { + r = SetTemplateRestrictions(parentClass, func, "RegisterFuncdef", decl); + if (r < 0) + return r; + } + } + + // If parameter type from other groups are used, add references + currentGroup->AddReferencesForFunc(this, func); + + // Return the type id as success + return GetTypeIdFromDataType(asCDataType::CreateType(fdt, false)); +} + +// interface +asUINT asCScriptEngine::GetFuncdefCount() const +{ + return asUINT(registeredFuncDefs.GetLength()); +} + +// interface +asITypeInfo *asCScriptEngine::GetFuncdefByIndex(asUINT index) const +{ + if( index >= registeredFuncDefs.GetLength() ) + return 0; + + return registeredFuncDefs[index]; +} + +// internal +asCFuncdefType *asCScriptEngine::FindMatchingFuncdef(asCScriptFunction *func, asCModule *module) +{ + asCFuncdefType *funcDef = func->funcdefType; + + if (funcDef == 0) + { + // Check if there is any matching funcdefs already in the engine that can be reused + for (asUINT n = 0; n < funcDefs.GetLength(); n++) + { + if (funcDefs[n]->funcdef->IsSignatureExceptNameEqual(func)) + { + if (func->IsShared() && !funcDefs[n]->funcdef->IsShared()) + continue; + funcDef = funcDefs[n]; + break; + } + } + } + + if (funcDef == 0) + { + // Create a matching funcdef + asCScriptFunction *fd = asNEW(asCScriptFunction)(this, 0, asFUNC_FUNCDEF); + fd->name = func->name; + fd->nameSpace = func->nameSpace; + fd->SetShared(func->IsShared()); + + fd->returnType = func->returnType; + fd->parameterTypes = func->parameterTypes; + fd->inOutFlags = func->inOutFlags; + + funcDef = asNEW(asCFuncdefType)(this, fd); + funcDefs.PushLast(funcDef); // doesn't increase the refCount + + fd->id = GetNextScriptFunctionId(); + AddScriptFunction(fd); + + if (module) + { + // Add the new funcdef to the module so it will + // be available when saving the bytecode + funcDef->module = module; + module->AddFuncDef(funcDef); // the refCount was already accounted for in the constructor + } + + // Observe, if the funcdef is created without informing a module a reference will be stored in the + // engine's funcDefs array, but it will not be owned by any module. This means that it will live on + // until the engine is released. + } + + if (funcDef && module && funcDef->module && funcDef->module != module) + { + // Unless this is a registered funcDef the returned funcDef must + // be stored as part of the module for saving/loading bytecode + if (!module->m_funcDefs.Exists(funcDef)) + { + module->AddFuncDef(funcDef); + funcDef->AddRefInternal(); + } + else + { + asASSERT(funcDef->IsShared()); + } + } + + return funcDef; +} + +// interface +// TODO: typedef: Accept complex types for the typedefs +int asCScriptEngine::RegisterTypedef(const char *type, const char *decl) +{ + if( type == 0 ) return ConfigError(asINVALID_NAME, "RegisterTypedef", type, decl); + + // Verify if the name has been registered as a type already + // TODO: Must check against registered funcdefs too + if( GetRegisteredType(type, defaultNamespace) ) + // Let the application recover from this error, for example if the same typedef is registered twice + return asALREADY_REGISTERED; + + // Grab the data type + size_t tokenLen; + eTokenType token; + asCDataType dataType; + + // Create the data type + token = tok.GetToken(decl, strlen(decl), &tokenLen); + switch(token) + { + case ttBool: + case ttInt: + case ttInt8: + case ttInt16: + case ttInt64: + case ttUInt: + case ttUInt8: + case ttUInt16: + case ttUInt64: + case ttFloat: + case ttDouble: + if( strlen(decl) != tokenLen ) + { + return ConfigError(asINVALID_TYPE, "RegisterTypedef", type, decl); + } + break; + + default: + return ConfigError(asINVALID_TYPE, "RegisterTypedef", type, decl); + } + + dataType = asCDataType::CreatePrimitive(token, false); + + // Make sure the name is not a reserved keyword + token = tok.GetToken(type, strlen(type), &tokenLen); + if( token != ttIdentifier || strlen(type) != tokenLen ) + return ConfigError(asINVALID_NAME, "RegisterTypedef", type, decl); + + asCBuilder bld(this, 0); + int r = bld.CheckNameConflict(type, 0, 0, defaultNamespace, true, false); + if( r < 0 ) + return ConfigError(asNAME_TAKEN, "RegisterTypedef", type, decl); + + // Don't have to check against members of object + // types as they are allowed to use the names + + // Put the data type in the list + asCTypedefType *td = asNEW(asCTypedefType)(this); + if( td == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterTypedef", type, decl); + + td->flags = asOBJ_TYPEDEF; + td->size = dataType.GetSizeInMemoryBytes(); + td->name = type; + td->nameSpace = defaultNamespace; + td->aliasForType = dataType; + + allRegisteredTypes.Insert(asSNameSpaceNamePair(td->nameSpace, td->name), td); + registeredTypeDefs.PushLast(td); + + currentGroup->types.PushLast(td); + + return GetTypeIdByDecl(type); +} + +// interface +asUINT asCScriptEngine::GetTypedefCount() const +{ + return asUINT(registeredTypeDefs.GetLength()); +} + +// interface +asITypeInfo *asCScriptEngine::GetTypedefByIndex(asUINT index) const +{ + if( index >= registeredTypeDefs.GetLength() ) + return 0; + + return registeredTypeDefs[index]; +} + +// interface +int asCScriptEngine::RegisterEnum(const char *name) +{ + // Check the name + if( NULL == name ) + return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0); + + // Verify if the name has been registered as a type already + if( GetRegisteredType(name, defaultNamespace) ) + return asALREADY_REGISTERED; + + // Use builder to parse the datatype + asCDataType dt; + asCBuilder bld(this, 0); + bool oldMsgCallback = msgCallback; msgCallback = false; + int r = bld.ParseDataType(name, &dt, defaultNamespace); + msgCallback = oldMsgCallback; + if( r >= 0 ) + { + // If it is not in the defaultNamespace then the type was successfully parsed because + // it is declared in a parent namespace which shouldn't be treated as an error + if( dt.GetTypeInfo() && dt.GetTypeInfo()->nameSpace == defaultNamespace ) + return ConfigError(asERROR, "RegisterEnum", name, 0); + } + + // Make sure the name is not a reserved keyword + size_t tokenLen; + int token = tok.GetToken(name, strlen(name), &tokenLen); + if( token != ttIdentifier || strlen(name) != tokenLen ) + return ConfigError(asINVALID_NAME, "RegisterEnum", name, 0); + + r = bld.CheckNameConflict(name, 0, 0, defaultNamespace, true, false); + if( r < 0 ) + return ConfigError(asNAME_TAKEN, "RegisterEnum", name, 0); + + asCEnumType *st = asNEW(asCEnumType)(this); + if( st == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterEnum", name, 0); + + asCDataType dataType; + dataType.CreatePrimitive(ttInt, false); + + st->flags = asOBJ_ENUM | asOBJ_SHARED; + st->size = 4; + st->name = name; + st->nameSpace = defaultNamespace; + + allRegisteredTypes.Insert(asSNameSpaceNamePair(st->nameSpace, st->name), st); + registeredEnums.PushLast(st); + + currentGroup->types.PushLast(st); + + return GetTypeIdByDecl(name); +} + +// interface +int asCScriptEngine::RegisterEnumValue(const char *typeName, const char *valueName, int value) +{ + // Verify that the correct config group is used + if( currentGroup->FindType(typeName) == 0 ) + return ConfigError(asWRONG_CONFIG_GROUP, "RegisterEnumValue", typeName, valueName); + + asCDataType dt; + int r; + asCBuilder bld(this, 0); + r = bld.ParseDataType(typeName, &dt, defaultNamespace); + if( r < 0 ) + return ConfigError(r, "RegisterEnumValue", typeName, valueName); + + // Store the enum value + asCEnumType *ot = CastToEnumType(dt.GetTypeInfo()); + if( ot == 0 ) + return ConfigError(asINVALID_TYPE, "RegisterEnumValue", typeName, valueName); + + if( NULL == valueName ) + return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName); + + asUINT tokenLen = 0; + asETokenClass tokenClass = ParseToken(valueName, 0, &tokenLen); + if( tokenClass != asTC_IDENTIFIER || tokenLen != strlen(valueName) ) + return ConfigError(asINVALID_NAME, "RegisterEnumValue", typeName, valueName); + + for( unsigned int n = 0; n < ot->enumValues.GetLength(); n++ ) + { + if( ot->enumValues[n]->name == valueName ) + return ConfigError(asALREADY_REGISTERED, "RegisterEnumValue", typeName, valueName); + } + + asSEnumValue *e = asNEW(asSEnumValue); + if( e == 0 ) + return ConfigError(asOUT_OF_MEMORY, "RegisterEnumValue", typeName, valueName); + + e->name = valueName; + e->value = value; + + ot->enumValues.PushLast(e); + + return asSUCCESS; +} + +// interface +asUINT asCScriptEngine::GetEnumCount() const +{ + return registeredEnums.GetLength(); +} + +// interface +asITypeInfo *asCScriptEngine::GetEnumByIndex(asUINT index) const +{ + if( index >= registeredEnums.GetLength() ) + return 0; + + return registeredEnums[index]; +} + +// interface +asUINT asCScriptEngine::GetObjectTypeCount() const +{ + return asUINT(registeredObjTypes.GetLength()); +} + +// interface +asITypeInfo *asCScriptEngine::GetObjectTypeByIndex(asUINT index) const +{ + if( index >= registeredObjTypes.GetLength() ) + return 0; + + return registeredObjTypes[index]; +} + +// interface +asITypeInfo *asCScriptEngine::GetTypeInfoByName(const char *in_name) const +{ + asCString name; + asSNameSpace *ns = 0; + if( DetermineNameAndNamespace(in_name, defaultNamespace, name, ns) < 0 ) + return 0; + + while (ns) + { + // Check the object types + for (asUINT n = 0; n < registeredObjTypes.GetLength(); n++) + { + if (registeredObjTypes[n]->name == name && + registeredObjTypes[n]->nameSpace == ns) + return registeredObjTypes[n]; + } + + // Perhaps it is a template type? In this case + // the returned type will be the generic type + for (asUINT n = 0; n < registeredTemplateTypes.GetLength(); n++) + { + if (registeredTemplateTypes[n]->name == name && + registeredTemplateTypes[n]->nameSpace == ns) + return registeredTemplateTypes[n]; + } + + // Check the enum types + for (asUINT n = 0; n < registeredEnums.GetLength(); n++) + { + if (registeredEnums[n]->name == name && + registeredEnums[n]->nameSpace == ns) + return registeredEnums[n]; + } + + // Check the typedefs + for (asUINT n = 0; n < registeredTypeDefs.GetLength();n++) + { + if (registeredTypeDefs[n]->name == name && + registeredTypeDefs[n]->nameSpace == ns) + return registeredTypeDefs[n]; + } + + // Recursively search parent namespace + ns = GetParentNameSpace(ns); + } + + return 0; +} + +// internal +int asCScriptEngine::DetermineNameAndNamespace(const char *in_name, asSNameSpace *implicitNs, asCString &out_name, asSNameSpace *&out_ns) const +{ + if( in_name == 0 ) + return asINVALID_ARG; + + asCString name = in_name; + asCString scope; + asSNameSpace *ns = implicitNs; + + // Check if the given name contains a scope + int pos = name.FindLast("::"); + if( pos >= 0 ) + { + scope = name.SubString(0, pos); + name = name.SubString(pos+2); + if( pos == 0 ) + { + // The scope is '::' so the search must start in the global namespace + ns = nameSpaces[0]; + } + else if( scope.SubString(0, 2) == "::" ) + { + // The scope starts with '::' so the given scope is fully qualified + ns = FindNameSpace(scope.SubString(2).AddressOf()); + } + else + { + // The scope doesn't start with '::' so it is relative to the current namespace + if( implicitNs->name == "" ) + ns = FindNameSpace(scope.AddressOf()); + else + ns = FindNameSpace((implicitNs->name + "::" + scope).AddressOf()); + } + } + + out_name = name; + out_ns = ns; + + return 0; +} + + +// interface +asITypeInfo *asCScriptEngine::GetTypeInfoById(int typeId) const +{ + asCDataType dt = GetDataTypeFromTypeId(typeId); + + // Is the type id valid? + if (!dt.IsValid()) return 0; + + return dt.GetTypeInfo(); +} + +// interface +asIScriptFunction *asCScriptEngine::GetFunctionById(int funcId) const +{ + return GetScriptFunction(funcId); +} + +// internal +bool asCScriptEngine::IsTemplateType(const char *name) const +{ + // Only look in the list of template types (not instance types) + for( unsigned int n = 0; n < registeredTemplateTypes.GetLength(); n++ ) + { + asCObjectType *type = registeredTemplateTypes[n]; + if( type && type->name == name ) + return true; + } + + return false; +} + +// internal +int asCScriptEngine::GetScriptSectionNameIndex(const char *name) +{ + ACQUIREEXCLUSIVE(engineRWLock); + + // TODO: These names are only released when the engine is freed. The assumption is that + // the same script section names will be reused instead of there always being new + // names. Is this assumption valid? Do we need to add reference counting? + + // Store the script section names for future reference + for( asUINT n = 0; n < scriptSectionNames.GetLength(); n++ ) + { + if( scriptSectionNames[n]->Compare(name) == 0 ) + { + RELEASEEXCLUSIVE(engineRWLock); + return n; + } + } + + asCString *str = asNEW(asCString)(name); + if( str ) + scriptSectionNames.PushLast(str); + int r = int(scriptSectionNames.GetLength()-1); + + RELEASEEXCLUSIVE(engineRWLock); + + return r; +} + +// interface +void asCScriptEngine::SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type) +{ + ACQUIREEXCLUSIVE(engineRWLock); + + for( asUINT n = 0; n < cleanEngineFuncs.GetLength(); n++ ) + { + if( cleanEngineFuncs[n].type == type ) + { + cleanEngineFuncs[n].cleanFunc = callback; + + RELEASEEXCLUSIVE(engineRWLock); + + return; + } + } + SEngineClean otc = {type, callback}; + cleanEngineFuncs.PushLast(otc); + + RELEASEEXCLUSIVE(engineRWLock); +} + +// interface +void asCScriptEngine::SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type) +{ + ACQUIREEXCLUSIVE(engineRWLock); + + for( asUINT n = 0; n < cleanModuleFuncs.GetLength(); n++ ) + { + if( cleanModuleFuncs[n].type == type ) + { + cleanModuleFuncs[n].cleanFunc = callback; + + RELEASEEXCLUSIVE(engineRWLock); + + return; + } + } + SModuleClean otc = {type, callback}; + cleanModuleFuncs.PushLast(otc); + + RELEASEEXCLUSIVE(engineRWLock); +} + +// interface +void asCScriptEngine::SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type) +{ + ACQUIREEXCLUSIVE(engineRWLock); + + for( asUINT n = 0; n < cleanContextFuncs.GetLength(); n++ ) + { + if( cleanContextFuncs[n].type == type ) + { + cleanContextFuncs[n].cleanFunc = callback; + + RELEASEEXCLUSIVE(engineRWLock); + + return; + } + } + SContextClean otc = {type, callback}; + cleanContextFuncs.PushLast(otc); + + RELEASEEXCLUSIVE(engineRWLock); +} + +// interface +void asCScriptEngine::SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type) +{ + ACQUIREEXCLUSIVE(engineRWLock); + + for( asUINT n = 0; n < cleanFunctionFuncs.GetLength(); n++ ) + { + if( cleanFunctionFuncs[n].type == type ) + { + cleanFunctionFuncs[n].cleanFunc = callback; + + RELEASEEXCLUSIVE(engineRWLock); + + return; + } + } + SFunctionClean otc = {type, callback}; + cleanFunctionFuncs.PushLast(otc); + + RELEASEEXCLUSIVE(engineRWLock); +} + +// interface +void asCScriptEngine::SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type) +{ + ACQUIREEXCLUSIVE(engineRWLock); + + for( asUINT n = 0; n < cleanTypeInfoFuncs.GetLength(); n++ ) + { + if( cleanTypeInfoFuncs[n].type == type ) + { + cleanTypeInfoFuncs[n].cleanFunc = callback; + + RELEASEEXCLUSIVE(engineRWLock); + + return; + } + } + STypeInfoClean otc = {type, callback}; + cleanTypeInfoFuncs.PushLast(otc); + + RELEASEEXCLUSIVE(engineRWLock); +} + +// interface +void asCScriptEngine::SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type) +{ + ACQUIREEXCLUSIVE(engineRWLock); + + for( asUINT n = 0; n < cleanScriptObjectFuncs.GetLength(); n++ ) + { + if( cleanScriptObjectFuncs[n].type == type ) + { + cleanScriptObjectFuncs[n].cleanFunc = callback; + + RELEASEEXCLUSIVE(engineRWLock); + + return; + } + } + SScriptObjClean soc = {type, callback}; + cleanScriptObjectFuncs.PushLast(soc); + + RELEASEEXCLUSIVE(engineRWLock); +} + +// interface +int asCScriptEngine::SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv) +{ +#ifdef AS_NO_EXCEPTIONS + return asNOT_SUPPORTED; +#else + if (callback.ptr.f.func == 0) + { + // Clear the callback + translateExceptionCallback = false; + return asSUCCESS; + } + + // Detect the new callback + translateExceptionCallback = true; + translateExceptionCallbackObj = param; + bool isObj = false; + if ((unsigned)callConv == asCALL_GENERIC || (unsigned)callConv == asCALL_THISCALL_OBJFIRST || (unsigned)callConv == asCALL_THISCALL_OBJLAST) + return asNOT_SUPPORTED; + if ((unsigned)callConv >= asCALL_THISCALL) + { + isObj = true; + if (param == 0) + { + translateExceptionCallback = false; + return asINVALID_ARG; + } + } + int r = DetectCallingConvention(isObj, callback, callConv, 0, &translateExceptionCallbackFunc); + if (r < 0) + translateExceptionCallback = false; + + return r; +#endif +} + +// internal +asCObjectType *asCScriptEngine::GetListPatternType(int listPatternFuncId) +{ + // Get the object type either from the constructor's object for value types + // or from the factory's return type for reference types + asCObjectType *ot = scriptFunctions[listPatternFuncId]->objectType; + if( ot == 0 ) + ot = CastToObjectType(scriptFunctions[listPatternFuncId]->returnType.GetTypeInfo()); + asASSERT( ot ); + + // Check if this object type already has a list pattern type + for( asUINT n = 0; n < listPatternTypes.GetLength(); n++ ) + { + if( listPatternTypes[n]->templateSubTypes[0].GetTypeInfo() == ot ) + return listPatternTypes[n]; + } + + // Create a new list pattern type for the given object type + asCObjectType *lpt = asNEW(asCObjectType)(this); + lpt->templateSubTypes.PushLast(asCDataType::CreateType(ot, false)); + lpt->flags = asOBJ_LIST_PATTERN; + listPatternTypes.PushLast(lpt); + + return lpt; +} + +// internal +void asCScriptEngine::DestroyList(asBYTE *buffer, const asCObjectType *listPatternType) +{ + asASSERT( listPatternType && (listPatternType->flags & asOBJ_LIST_PATTERN) ); + + // Get the list pattern from the listFactory function + // TODO: runtime optimize: Store the used list factory in the listPatternType itself + // TODO: runtime optimize: Keep a flag to indicate if there is really a need to free anything + asCObjectType *ot = CastToObjectType(listPatternType->templateSubTypes[0].GetTypeInfo()); + asCScriptFunction *listFactory = scriptFunctions[ot->beh.listFactory]; + asASSERT( listFactory ); + + asSListPatternNode *node = listFactory->listPattern; + DestroySubList(buffer, node); + + asASSERT( node->type == asLPT_END ); +} + +// internal +void asCScriptEngine::DestroySubList(asBYTE *&buffer, asSListPatternNode *&node) +{ + asASSERT( node->type == asLPT_START ); + + int count = 0; + + node = node->next; + while( node ) + { + if( node->type == asLPT_REPEAT || node->type == asLPT_REPEAT_SAME ) + { + // Align the offset to 4 bytes boundary + if( (asPWORD(buffer) & 0x3) ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + // Determine how many times the pattern repeat + count = *(asUINT*)buffer; + buffer += 4; + + if( count == 0 ) + { + // Skip the sub pattern that was expected to be repeated, otherwise + // we'll try to delete things that don't exist in the buffer + node = node->next; + if( node->type == asLPT_START ) + { + int subCount = 1; + do + { + node = node->next; + if( node->type == asLPT_START ) + subCount++; + else if( node->type == asLPT_END ) + subCount--; + } while( subCount > 0 ); + return; + } + } + } + else if( node->type == asLPT_TYPE ) + { + // If we're not in a repeat iteration, then only 1 value should be destroyed + if( count <= 0 ) + count = 1; + + asCDataType dt = reinterpret_cast(node)->dataType; + bool isVarType = dt.GetTokenType() == ttQuestion; + + while( count-- ) + { + if( isVarType ) + { + // Align the offset to 4 bytes boundary + if( (asPWORD(buffer) & 0x3) ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + int typeId = *(int*)buffer; + buffer += 4; + dt = GetDataTypeFromTypeId(typeId); + } + + asCTypeInfo *ti = dt.GetTypeInfo(); + if( ti && (ti->flags & asOBJ_ENUM) == 0 ) + { + // Free all instances of this type + if( ti->flags & asOBJ_VALUE ) + { + asUINT size = ti->GetSize(); + + // Align the offset to 4 bytes boundary + if( size >= 4 && (asPWORD(buffer) & 0x3) ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + asCObjectType *ot = CastToObjectType(ti); + if( ot && ot->beh.destruct ) + { + // Only call the destructor if the object has been created + // We'll assume the object has been created if any byte in + // the memory is different from 0. + // TODO: This is not really correct, as bytes may have been + // modified by the constructor, but then an exception + // thrown aborting the initialization. The engine + // really should be keeping track of which objects has + // been successfully initialized. + + for( asUINT n = 0; n < size; n++ ) + { + if( buffer[n] != 0 ) + { + void *ptr = (void*)buffer; + CallObjectMethod(ptr, ot->beh.destruct); + break; + } + } + } + + // Advance the pointer in the buffer + buffer += size; + } + else + { + // Align the offset to 4 bytes boundary + if( asPWORD(buffer) & 0x3 ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + // Call the release behaviour + void *ptr = *(void**)buffer; + if( ptr ) + ReleaseScriptObject(ptr, ti); + buffer += AS_PTR_SIZE*4; + } + } + else + { + asUINT size = dt.GetSizeInMemoryBytes(); + + // Align the offset to 4 bytes boundary + if( size >= 4 && (asPWORD(buffer) & 0x3) ) + buffer += 4 - (asPWORD(buffer) & 0x3); + + // Advance the buffer + buffer += size; + } + } + } + else if( node->type == asLPT_START ) + { + // If we're not in a repeat iteration, then only 1 value should be destroyed + if( count <= 0 ) + count = 1; + + while( count-- ) + { + asSListPatternNode *subList = node; + DestroySubList(buffer, subList); + + asASSERT( subList->type == asLPT_END ); + + if( count == 0 ) + node = subList; + } + } + else if( node->type == asLPT_END ) + { + return; + } + else + { + asASSERT( false ); + } + + node = node->next; + } +} + +// internal +asSNameSpace *asCScriptEngine::GetParentNameSpace(asSNameSpace *ns) const +{ + if( ns == 0 ) return 0; + if( ns == nameSpaces[0] ) return 0; + + asCString scope = ns->name; + int pos = scope.FindLast("::"); + if( pos >= 0 ) + { + scope = scope.SubString(0, pos); + return FindNameSpace(scope.AddressOf()); + } + + return nameSpaces[0]; +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_scriptengine.h b/angelscript/source/as_scriptengine.h new file mode 100644 index 0000000..fdfc568 --- /dev/null +++ b/angelscript/source/as_scriptengine.h @@ -0,0 +1,527 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptengine.h +// +// The implementation of the script engine interface +// + + + +#ifndef AS_SCRIPTENGINE_H +#define AS_SCRIPTENGINE_H + +#include "as_config.h" +#include "as_atomic.h" +#include "as_scriptfunction.h" +#include "as_array.h" +#include "as_datatype.h" +#include "as_objecttype.h" +#include "as_module.h" +#include "as_callfunc.h" +#include "as_configgroup.h" +#include "as_memory.h" +#include "as_gc.h" +#include "as_tokenizer.h" + +BEGIN_AS_NAMESPACE + +class asCBuilder; +class asCContext; + +// TODO: import: Remove this when import is removed +struct sBindInfo; + +class asCScriptEngine : public asIScriptEngine +{ +//============================================================= +// From asIScriptEngine +//============================================================= +public: + // Memory management + virtual int AddRef() const; + virtual int Release() const; + virtual int ShutDownAndRelease(); + + // Engine properties + virtual int SetEngineProperty(asEEngineProp property, asPWORD value); + virtual asPWORD GetEngineProperty(asEEngineProp property) const; + + // Compiler messages + virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv); + virtual int ClearMessageCallback(); + virtual int WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message); + + // JIT Compiler + virtual int SetJITCompiler(asIJITCompiler *compiler); + virtual asIJITCompiler *GetJITCompiler() const; + + // Global functions + virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0); + virtual asUINT GetGlobalFunctionCount() const; + virtual asIScriptFunction *GetGlobalFunctionByIndex(asUINT index) const; + virtual asIScriptFunction *GetGlobalFunctionByDecl(const char *declaration) const; + + // Global properties + virtual int RegisterGlobalProperty(const char *declaration, void *pointer); + virtual asUINT GetGlobalPropertyCount() const; + virtual int GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace = 0, int *typeId = 0, bool *isConst = 0, const char **configGroup = 0, void **pointer = 0, asDWORD *accessMask = 0) const; + virtual int GetGlobalPropertyIndexByName(const char *name) const; + virtual int GetGlobalPropertyIndexByDecl(const char *decl) const; + + // Type registration + virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags); + virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + virtual int RegisterInterface(const char *name); + virtual int RegisterInterfaceMethod(const char *intf, const char *declaration); + virtual asUINT GetObjectTypeCount() const; + virtual asITypeInfo *GetObjectTypeByIndex(asUINT index) const; + + // String factory + virtual int RegisterStringFactory(const char *datatype, asIStringFactory *factory); + virtual int GetStringFactoryReturnTypeId(asDWORD *flags) const; + + // Default array type + virtual int RegisterDefaultArrayType(const char *type); + virtual int GetDefaultArrayTypeId() const; + + // Enums + virtual int RegisterEnum(const char *type); + virtual int RegisterEnumValue(const char *type, const char *name, int value); + virtual asUINT GetEnumCount() const; + virtual asITypeInfo *GetEnumByIndex(asUINT index) const; + + // Funcdefs + virtual int RegisterFuncdef(const char *decl); + virtual asUINT GetFuncdefCount() const; + virtual asITypeInfo *GetFuncdefByIndex(asUINT index) const; + + // Typedefs + // TODO: interface: Should perhaps rename this to Alias, since it doesn't really create a new type + virtual int RegisterTypedef(const char *type, const char *decl); + virtual asUINT GetTypedefCount() const; + virtual asITypeInfo *GetTypedefByIndex(asUINT index) const; + + // Configuration groups + virtual int BeginConfigGroup(const char *groupName); + virtual int EndConfigGroup(); + virtual int RemoveConfigGroup(const char *groupName); + virtual asDWORD SetDefaultAccessMask(asDWORD defaultMask); + virtual int SetDefaultNamespace(const char *nameSpace); + virtual const char *GetDefaultNamespace() const; + + // Script modules + virtual asIScriptModule *GetModule(const char *module, asEGMFlags flag); + virtual int DiscardModule(const char *module); + virtual asUINT GetModuleCount() const; + virtual asIScriptModule *GetModuleByIndex(asUINT index) const; + + // Script functions + virtual asIScriptFunction *GetFunctionById(int funcId) const; + + // Type identification + virtual int GetTypeIdByDecl(const char *decl) const; + virtual const char *GetTypeDeclaration(int typeId, bool includeNamespace = false) const; + virtual int GetSizeOfPrimitiveType(int typeId) const; + virtual asITypeInfo *GetTypeInfoById(int typeId) const; + virtual asITypeInfo *GetTypeInfoByName(const char *name) const; + virtual asITypeInfo *GetTypeInfoByDecl(const char *decl) const; + + // Script execution + virtual asIScriptContext *CreateContext(); + virtual void *CreateScriptObject(const asITypeInfo *type); + virtual void *CreateScriptObjectCopy(void *obj, const asITypeInfo *type); + virtual void *CreateUninitializedScriptObject(const asITypeInfo *type); + virtual asIScriptFunction *CreateDelegate(asIScriptFunction *func, void *obj); + virtual int AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type); + virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type); + virtual void AddRefScriptObject(void *obj, const asITypeInfo *type); + virtual int RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast = false); + virtual asILockableSharedBool *GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const; + + // Context pooling + virtual asIScriptContext *RequestContext(); + virtual void ReturnContext(asIScriptContext *ctx); + virtual int SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param = 0); + + // String interpretation + virtual asETokenClass ParseToken(const char *string, size_t stringLength = 0, asUINT *tokenLength = 0) const; + + // Garbage collection + virtual int GarbageCollect(asDWORD flags = asGC_FULL_CYCLE, asUINT numIterations = 1); + virtual void GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed, asUINT *totalDetected, asUINT *newObjects, asUINT *totalNewDestroyed) const; + virtual int NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type); + virtual int GetObjectInGC(asUINT idx, asUINT *seqNbr, void **obj = 0, asITypeInfo **type = 0); + virtual void GCEnumCallback(void *reference); + virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type); + virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type); + virtual void SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param = 0); + + // User data + virtual void *SetUserData(void *data, asPWORD type); + virtual void *GetUserData(asPWORD type) const; + virtual void SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type); + virtual void SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type); + virtual void SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type); + virtual void SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type); + virtual void SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type); + virtual void SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type); + + // Exception handling + virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv); + +//=========================================================== +// internal methods +//=========================================================== +public: + asCScriptEngine(); + virtual ~asCScriptEngine(); + +//protected: + friend class asCBuilder; + friend class asCCompiler; + friend class asCContext; + friend class asCDataType; + friend class asCModule; + friend class asCRestore; + friend class asCByteCode; + friend int PrepareSystemFunction(asCScriptFunction *func, asSSystemFunctionInterface *internal, asCScriptEngine *engine); + + int RegisterMethodToObjectType(asCObjectType *objectType, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + int RegisterBehaviourToObjectType(asCObjectType *objectType, asEBehaviours behaviour, const char *decl, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary = 0, int compositeOffset = 0, bool isCompositeIndirect = false); + + int VerifyVarTypeNotInFunction(asCScriptFunction *func); + + void *CallAlloc(const asCObjectType *objType) const; + void CallFree(void *obj) const; + + void *CallGlobalFunctionRetPtr(int func) const; + void *CallGlobalFunctionRetPtr(int func, void *param1) const; + void *CallGlobalFunctionRetPtr(asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + void *CallGlobalFunctionRetPtr(asSSystemFunctionInterface *i, asCScriptFunction *s, void *param1) const; + void CallObjectMethod(void *obj, int func) const; + void CallObjectMethod(void *obj, void *param, int func) const; + void CallObjectMethod(void *obj, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + void CallObjectMethod(void *obj, void *param, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + bool CallObjectMethodRetBool(void *obj, int func) const; + int CallObjectMethodRetInt(void *obj, int func) const; + void *CallObjectMethodRetPtr(void *obj, int func) const; + void *CallObjectMethodRetPtr(void *obj, int param1, asCScriptFunction *func) const; + void CallGlobalFunction(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + bool CallGlobalFunctionRetBool(void *param1, void *param2, asSSystemFunctionInterface *func, asCScriptFunction *desc) const; + int CallScriptObjectMethod(void *obj, int func); + + void ConstructScriptObjectCopy(void *mem, void *obj, asCObjectType *type); + + void DeleteDiscardedModules(); + + void RemoveTemplateInstanceType(asCObjectType *t); + + asCConfigGroup *FindConfigGroupForFunction(int funcId) const; + asCConfigGroup *FindConfigGroupForGlobalVar(int gvarId) const; + asCConfigGroup *FindConfigGroupForTypeInfo(const asCTypeInfo *type) const; + asCConfigGroup *FindConfigGroupForFuncDef(const asCFuncdefType *funcDef) const; + + int RequestBuild(); + void BuildCompleted(); + + void PrepareEngine(); + bool isPrepared; + + int CreateContext(asIScriptContext **context, bool isInternal); + + asCTypeInfo *GetRegisteredType(const asCString &name, asSNameSpace *ns) const; + + asCObjectType *GetListPatternType(int listPatternFuncId); + void DestroyList(asBYTE *buffer, const asCObjectType *listPatternType); + void DestroySubList(asBYTE *&buffer, asSListPatternNode *&patternNode); + + int AddBehaviourFunction(asCScriptFunction &func, asSSystemFunctionInterface &internal); + + asCString GetFunctionDeclaration(int funcId); + + asCScriptFunction *GetScriptFunction(int funcId) const; + + asCModule *GetModule(const char *name, bool create); + asCModule *GetModuleFromFuncId(int funcId); + + int GetMethodIdByDecl(const asCObjectType *ot, const char *decl, asCModule *mod); + int GetFactoryIdByDecl(const asCObjectType *ot, const char *decl); + + int GetNextScriptFunctionId(); + void AddScriptFunction(asCScriptFunction *func); + void RemoveScriptFunction(asCScriptFunction *func); + void RemoveFuncdef(asCFuncdefType *func); + + int ConfigError(int err, const char *funcName, const char *arg1, const char *arg2); + + int GetTypeIdFromDataType(const asCDataType &dt) const; + asCDataType GetDataTypeFromTypeId(int typeId) const; + asCObjectType *GetObjectTypeFromTypeId(int typeId) const; + void RemoveFromTypeIdMap(asCTypeInfo *type); + + bool IsTemplateType(const char *name) const; + int SetTemplateRestrictions(asCObjectType *templateType, asCScriptFunction *func, const char *caller, const char *decl); + asCObjectType *GetTemplateInstanceType(asCObjectType *templateType, asCArray &subTypes, asCModule *requestingModule); + asCScriptFunction *GenerateTemplateFactoryStub(asCObjectType *templateType, asCObjectType *templateInstanceType, int origFactoryId); + bool GenerateNewTemplateFunction(asCObjectType *templateType, asCObjectType *templateInstanceType, asCScriptFunction *templateFunc, asCScriptFunction **newFunc); + asCFuncdefType *GenerateNewTemplateFuncdef(asCObjectType *templateType, asCObjectType *templateInstanceType, asCFuncdefType *templateFuncdef); + asCDataType DetermineTypeForTemplate(const asCDataType &orig, asCObjectType *tmpl, asCObjectType *ot); + bool RequireTypeReplacement(asCDataType &type, asCObjectType *templateType); + + asCModule *FindNewOwnerForSharedType(asCTypeInfo *type, asCModule *mod); + asCModule *FindNewOwnerForSharedFunc(asCScriptFunction *func, asCModule *mod); + + asCFuncdefType *FindMatchingFuncdef(asCScriptFunction *func, asCModule *mod); + + int DetermineNameAndNamespace(const char *in_name, asSNameSpace *implicitNs, asCString &out_name, asSNameSpace *&out_ns) const; + + // Global property management + asCGlobalProperty *AllocateGlobalProperty(); + void RemoveGlobalProperty(asCGlobalProperty *prop); + + int GetScriptSectionNameIndex(const char *name); + + // Namespace management + asSNameSpace *AddNameSpace(const char *name); + asSNameSpace *FindNameSpace(const char *name) const; + asSNameSpace *GetParentNameSpace(asSNameSpace *ns) const; + +//=========================================================== +// internal properties +//=========================================================== + asCMemoryMgr memoryMgr; + + asCObjectType *defaultArrayObjectType; + asCObjectType scriptTypeBehaviours; + asCObjectType functionBehaviours; + + // Registered interface + asCArray registeredObjTypes; // doesn't increase ref count + asCArray registeredTypeDefs; // doesn't increase ref count + asCArray registeredEnums; // doesn't increase ref count + // TODO: memory savings: Since there can be only one property with the same name a simpler symbol table should be used for global props + asCSymbolTable registeredGlobalProps; // increases ref count + asCSymbolTable registeredGlobalFuncs; + asCArray registeredFuncDefs; // doesn't increase ref count + asCArray registeredTemplateTypes; // doesn't increase ref count + asIStringFactory *stringFactory; + asCDataType stringType; + bool configFailed; + + // Stores all registered types + asCMap allRegisteredTypes; // increases ref count + + // Dummy types used to name the subtypes in the template objects + asCArray templateSubTypes; + + // Store information about template types + // This list will contain all instances of templates, both registered specialized + // types and those automacially instantiated from scripts + asCArray templateInstanceTypes; // increases ref count + + // Store information about list patterns + asCArray listPatternTypes; // increases ref count + + // Stores all global properties, both those registered by application, and those declared by scripts. + // The id of a global property is the index in this array. + asCArray globalProperties; // increases ref count + asCArray freeGlobalPropertyIds; + + // This map is used to quickly find a property by its memory address + // It is used principally during building, cleanup, and garbage detection for script functions + asCMap varAddressMap; // doesn't increase ref count + + // Stores all functions, i.e. registered functions, script functions, class methods, behaviours, etc. + asCArray scriptFunctions; // doesn't increase ref count + asCArray freeScriptFunctionIds; + asCArray signatureIds; + + // An array with all module imported functions + asCArray importedFunctions; // doesn't increase ref count + asCArray freeImportedFunctionIdxs; + + // Synchronized + mutable asCAtomic refCount; + // Synchronized with engineRWLock + // This array holds all live script modules + asCArray scriptModules; + // Synchronized with engineRWLock + // This is a pointer to the last module that was requested. It is used for performance + // improvement, since it is common that the same module is accessed many times in a row + asCModule *lastModule; + // Synchronized with engineRWLock + // This flag is true if a script is currently being compiled. It is used to prevent multiple + // threads from requesting builds at the same time (without blocking) + bool isBuilding; + // Synchronized with engineRWLock + // This array holds modules that have been discard (thus are no longer visible to the application) + // but cannot yet be deleted due to having external references to some of the entities in them + asCArray discardedModules; + // This flag is set to true during compilations of scripts (or loading pre-compiled scripts) + // to delay the validation of template types until the subtypes have been fully declared + bool deferValidationOfTemplateTypes; + + // Tokenizer is instantiated once to share resources + asCTokenizer tok; + + // Stores shared script declared types (classes, interfaces, enums) + asCArray sharedScriptTypes; // increases ref count + // This array stores the template instances types that have been automatically generated from template types + asCArray generatedTemplateTypes; + // Stores the funcdefs + // TODO: redesign: Only shared funcdefs should be stored here + // a funcdef becomes shared if all arguments and the return type are shared (or application registered) + asCArray funcDefs; // doesn't increases ref count + + // Stores the names of the script sections for debugging purposes + asCArray scriptSectionNames; + + // Type identifiers + mutable int typeIdSeqNbr; + mutable asCMap mapTypeIdToTypeInfo; + + // Garbage collector + asCGarbageCollector gc; + + // Dynamic groups + asCConfigGroup defaultGroup; + asCArray configGroups; + asCConfigGroup *currentGroup; + asDWORD defaultAccessMask; + asSNameSpace *defaultNamespace; + + // Message callback + bool msgCallback; + asSSystemFunctionInterface msgCallbackFunc; + void *msgCallbackObj; + struct preMessage_t + { + preMessage_t() { isSet = false; } + bool isSet; + asCString message; + asCString scriptname; + int r; + int c; + } preMessage; + + // JIt compilation + asIJITCompiler *jitCompiler; + + // Namespaces + // These are shared between all entities and are + // only deleted once the engine is destroyed + asCArray nameSpaces; + + // Callbacks for context pooling + asREQUESTCONTEXTFUNC_t requestCtxFunc; + asRETURNCONTEXTFUNC_t returnCtxFunc; + void *ctxCallbackParam; + + // User data + asCArray userData; + + struct SEngineClean { asPWORD type; asCLEANENGINEFUNC_t cleanFunc; }; + asCArray cleanEngineFuncs; + struct SModuleClean { asPWORD type; asCLEANMODULEFUNC_t cleanFunc; }; + asCArray cleanModuleFuncs; + struct SContextClean { asPWORD type; asCLEANCONTEXTFUNC_t cleanFunc; }; + asCArray cleanContextFuncs; + struct SFunctionClean { asPWORD type; asCLEANFUNCTIONFUNC_t cleanFunc; }; + asCArray cleanFunctionFuncs; + struct STypeInfoClean { asPWORD type; asCLEANTYPEINFOFUNC_t cleanFunc; }; + asCArray cleanTypeInfoFuncs; + struct SScriptObjClean { asPWORD type; asCLEANSCRIPTOBJECTFUNC_t cleanFunc; }; + asCArray cleanScriptObjectFuncs; + + // Synchronization for threads + DECLAREREADWRITELOCK(mutable engineRWLock) + + // Engine properties + struct + { + bool allowUnsafeReferences; + bool optimizeByteCode; + bool copyScriptSections; + asUINT maximumContextStackSize; + asUINT initContextStackSize; + bool useCharacterLiterals; + bool allowMultilineStrings; + bool allowImplicitHandleTypes; + bool buildWithoutLineCues; + bool initGlobalVarsAfterBuild; + bool requireEnumScope; + int scanner; + bool includeJitInstructions; + int stringEncoding; + int propertyAccessorMode; + bool expandDefaultArrayToTemplate; + bool autoGarbageCollect; + bool disallowGlobalVars; + bool alwaysImplDefaultConstruct; + int compilerWarnings; + bool disallowValueAssignForRefType; + // TODO: 3.0.0: Remove the alterSyntaxNamedArgs + int alterSyntaxNamedArgs; + bool disableIntegerDivision; + bool disallowEmptyListElements; + // TODO: 3.0.0: Remove the privatePropAsProtected + bool privatePropAsProtected; + bool allowUnicodeIdentifiers; + int heredocTrimMode; + asUINT maxNestedCalls; + asUINT genericCallMode; + asUINT initCallStackSize; + asUINT maxCallStackSize; + } ep; + + // Callbacks +#ifndef AS_NO_EXCEPTIONS + bool translateExceptionCallback; + asSSystemFunctionInterface translateExceptionCallbackFunc; + void * translateExceptionCallbackObj; +#endif + + // This flag is to allow a quicker shutdown when releasing the engine + bool shuttingDown; + + // This flag is set when the engine's destructor is called, this is to + // avoid recursive calls if an object happens to increment/decrement + // the ref counter during shutdown + bool inDestructor; +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_scriptfunction.cpp b/angelscript/source/as_scriptfunction.cpp new file mode 100644 index 0000000..2601454 --- /dev/null +++ b/angelscript/source/as_scriptfunction.cpp @@ -0,0 +1,1726 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptfunction.cpp +// +// A container for a compiled script function +// + + + +#include "as_config.h" +#include "as_scriptfunction.h" +#include "as_tokendef.h" +#include "as_scriptengine.h" +#include "as_callfunc.h" +#include "as_bytecode.h" +#include "as_texts.h" +#include "as_scriptnode.h" +#include "as_builder.h" +#include "as_scriptcode.h" + +#include // qsort + +BEGIN_AS_NAMESPACE + +#ifdef AS_MAX_PORTABILITY + +static void ScriptFunction_AddRef_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + self->AddRef(); +} + +static void ScriptFunction_Release_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + self->Release(); +} + +static void ScriptFunction_GetRefCount_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); +} + +static void ScriptFunction_SetFlag_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + self->SetFlag(); +} + +static void ScriptFunction_GetFlag_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); +} + +static void ScriptFunction_EnumReferences_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); +} + +static void ScriptFunction_ReleaseAllHandles_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *self = (asCScriptFunction*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); +} + +static void ScriptFunction_CreateDelegate_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *func = (asCScriptFunction*)gen->GetArgAddress(0); + void *obj = gen->GetArgAddress(1); + gen->SetReturnAddress(CreateDelegate(func, obj)); +} + +// TODO: operator== +/*static void ScriptFunction_opEquals_Generic(asIScriptGeneric *gen) +{ + asCScriptFunction *funcSelf = (asCScriptFunction*)gen->GetObject(); + asCScriptFunction *funcOther = (asCScriptFunction*)gen->GetArgAddress(0); + *(bool*)gen->GetAddressOfReturnLocation() = *funcSelf == *funcOther; +} +*/ + +#endif + + +void RegisterScriptFunction(asCScriptEngine *engine) +{ + // Register the gc behaviours for the script functions + int r = 0; + UNUSED_VAR(r); // It is only used in debug mode + engine->functionBehaviours.engine = engine; + engine->functionBehaviours.flags = asOBJ_REF | asOBJ_GC; + engine->functionBehaviours.name = "$func"; +#ifndef AS_MAX_PORTABILITY + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptFunction,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptFunction,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCScriptFunction,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCScriptFunction,SetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptFunction,GetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptFunction,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptFunction,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + // TODO: Need some way to allow the arg type to adapt when the funcdefs are instantiated +// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asMETHOD(asCScriptFunction,operator==), asCALL_THISCALL); asASSERT( r >= 0 ); +#else + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptFunction_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptFunction_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptFunction_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptFunction_SetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptFunction_GetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptFunction_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->functionBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptFunction_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); +// r = engine->RegisterMethodToObjectType(&engine->functionBehaviours, "bool opEquals(const int &in)", asFUNCTION(ScriptFunction_opEquals_Generic), asCALL_GENERIC); asASSERT( r >= 0 ); +#endif + + // Register the builtin function for creating delegates + // This function returns a handle to the delegate, but since the type is not known at this time it is + // registered to return a void then the return type is changed manually to the builtin function type + // The name of the function is an invalid identifier so it cannot be invoked accidentally from the script +#ifndef AS_MAX_PORTABILITY + r = engine->RegisterGlobalFunction("void f(int &in, int &in)", asFUNCTION(CreateDelegate), asCALL_CDECL); asASSERT( r >= 0 ); +#else + r = engine->RegisterGlobalFunction("void f(int &in, int &in)", asFUNCTION(ScriptFunction_CreateDelegate_Generic), asCALL_GENERIC); asASSERT( r >= 0 ); +#endif + + // Rename the function so that it cannot be called manually by the script + int idx = engine->registeredGlobalFuncs.GetIndex(engine->scriptFunctions[r]); + engine->registeredGlobalFuncs.Erase(idx); + engine->scriptFunctions[r]->name = DELEGATE_FACTORY; + engine->registeredGlobalFuncs.Put(engine->scriptFunctions[r]); + + // Change the return type so the VM will know the function really returns a handle + engine->scriptFunctions[r]->returnType = asCDataType::CreateType(&engine->functionBehaviours, false); + engine->scriptFunctions[r]->returnType.MakeHandle(true); +} + +asCScriptFunction *CreateDelegate(asCScriptFunction *func, void *obj) +{ + if( func == 0 || obj == 0 ) + { + // TODO: delegate: Should set script exception + return 0; + } + + // Create an instance of a asCScriptFunction with the type asFUNC_DELEGATE + // The delegate shouldn't have a function id and is not added to the engine->scriptFunctions + asCScriptFunction *delegate = asNEW(asCScriptFunction)(static_cast(func->GetEngine()), 0, asFUNC_DELEGATE); + if( delegate ) + delegate->MakeDelegate(func, obj); + + return delegate; +} + +// internal +void asCScriptFunction::MakeDelegate(asCScriptFunction *func, void *obj) +{ + // Increase the reference of the function and object + func->AddRef(); + funcForDelegate = func; + + func->GetEngine()->AddRefScriptObject(obj, func->GetObjectType()); + objForDelegate = obj; + + // The return type and parameters are copied from the delegated method to this object + // TODO: optimize: Do we really need to copy? Whenever requested the delegate can simply return the delegated methods' info directly + parameterTypes = func->parameterTypes; + returnType = func->returnType; + inOutFlags = func->inOutFlags; + + // The delegate doesn't own the parameters as it will only forward them to the real method + // so the exception handler must not clean up the parameters for the delegate + dontCleanUpOnException = true; +} + +// interface +void *asCScriptFunction::GetAuxiliary() const +{ + if (sysFuncIntf) + return sysFuncIntf->auxiliary; + + return 0; +} + +// interface +void *asCScriptFunction::GetDelegateObject() const +{ + return objForDelegate; +} + +// interface +asITypeInfo *asCScriptFunction::GetDelegateObjectType() const +{ + if( objForDelegate == 0 || funcForDelegate == 0 ) + return 0; + + return funcForDelegate->objectType; +} + +// interface +asIScriptFunction *asCScriptFunction::GetDelegateFunction() const +{ + return funcForDelegate; +} + +// TODO: operator== +/* +// internal +bool asCScriptFunction::operator==(const asCScriptFunction &other) const +{ + if( this == &other ) return true; + + if( this->funcType == asFUNC_DELEGATE && other.funcType == asFUNC_DELEGATE ) + { + if( this->objForDelegate == other.objForDelegate && + this->funcForDelegate == other.funcForDelegate ) + return true; + } + + return false; +} +*/ + +// internal +int asCScriptFunction::RegisterListPattern(const char *decl, asCScriptNode *listNodes) +{ + if( listNodes == 0 ) + return asINVALID_ARG; + + // Build the representation of the list pattern from the script nodes + asSListPatternNode *node; + listPattern = asNEW(asSListPatternNode)(asLPT_START); + node = listPattern; + + // Recursively parse the child + int r = ParseListPattern(node, decl, listNodes); + + node->next = asNEW(asSListPatternNode)(asLPT_END); + + return r; +} + +// internal +int asCScriptFunction::ParseListPattern(asSListPatternNode *&target, const char *decl, asCScriptNode *listNodes) +{ + asSListPatternNode *node = target; + + listNodes = listNodes->firstChild; + while( listNodes ) + { + if( listNodes->nodeType == snIdentifier ) + { + asCString token(&decl[listNodes->tokenPos], listNodes->tokenLength); + if( token == "repeat" ) + { + node->next = asNEW(asSListPatternNode)(asLPT_REPEAT); + node = node->next; + } + else if( token == "repeat_same" ) + { + // TODO: list: Should make sure this is a sub-list + node->next = asNEW(asSListPatternNode)(asLPT_REPEAT_SAME); + node = node->next; + } + else + { + // Shouldn't happen as the parser already reported the error + asASSERT(false); + } + } + else if( listNodes->nodeType == snDataType ) + { + asCDataType dt; + asCBuilder builder(engine, 0); + asCScriptCode code; + code.SetCode("", decl, 0, false); + dt = builder.CreateDataTypeFromNode(listNodes, &code, engine->defaultNamespace, false, CastToObjectType(returnType.GetTypeInfo())); + + node->next = asNEW(asSListPatternDataTypeNode)(dt); + node = node->next; + } + else if( listNodes->nodeType == snListPattern ) + { + node->next = asNEW(asSListPatternNode)(asLPT_START); + node = node->next; + + // Recursively parse the child + int r = ParseListPattern(node, decl, listNodes); + if( r < 0 ) + return r; + + node->next = asNEW(asSListPatternNode)(asLPT_END); + node = node->next; + } + else + { + // Unexpected token in the list, the parser shouldn't have allowed + asASSERT( false ); + return -1; + } + + listNodes = listNodes->next; + } + + target = node; + return 0; +} + +// internal +asCScriptFunction::asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType _funcType) +{ + funcType = _funcType; + if( funcType == asFUNC_DELEGATE ) + { + // Delegates behave like object instances, rather than script code + externalRefCount.set(1); + internalRefCount.set(0); + } + else + { + internalRefCount.set(1); + externalRefCount.set(0); + } + + this->engine = engine; + this->scriptData = 0; + module = mod; + objectType = 0; + name = ""; + sysFuncIntf = 0; + signatureId = 0; + dontCleanUpOnException = false; + vfTableIdx = -1; + gcFlag = false; + userData = 0; + id = 0; + accessMask = 0xFFFFFFFF; + nameSpace = engine->nameSpaces[0]; + objForDelegate = 0; + funcForDelegate = 0; + listPattern = 0; + funcdefType = 0; + + if( funcType == asFUNC_SCRIPT ) + AllocateScriptFunctionData(); + + // Notify the GC of delegates + if( funcType == asFUNC_DELEGATE ) + engine->gc.AddScriptObjectToGC(this, &engine->functionBehaviours); +} + +void asCScriptFunction::AllocateScriptFunctionData() +{ + if( scriptData ) return; + + scriptData = asNEW(ScriptFunctionData); + + scriptData->stackNeeded = 0; + scriptData->variableSpace = 0; + scriptData->scriptSectionIdx = -1; + scriptData->declaredAt = 0; + scriptData->jitFunction = 0; +} + +void asCScriptFunction::DeallocateScriptFunctionData() +{ + if( !scriptData ) return; + + for( asUINT n = 0; n < scriptData->variables.GetLength(); n++ ) + asDELETE(scriptData->variables[n],asSScriptVariable); + scriptData->variables.SetLength(0); + + asDELETE(scriptData, ScriptFunctionData); + scriptData = 0; +} + +// internal +asCScriptFunction::~asCScriptFunction() +{ + // Dummy functions that are allocated on the stack are not reference counted + asASSERT( funcType == asFUNC_DUMMY || + (externalRefCount.get() == 0 && internalRefCount.get() == 0) ); + + // Remove the script function from the engine's scriptFunctions array here + // Don't remove it before, because there may still be functions referring to it + // by index until now. If it was removed in DestroyInternal, those would not + // be able to release the refcount, thus causing memory leak. + if( engine && id != 0 && funcType != asFUNC_DUMMY ) + engine->RemoveScriptFunction(this); + + // If the engine pointer is 0, then DestroyInternal has already been called and there is nothing more to do + if( engine == 0 ) return; + + DestroyInternal(); + + // Finally set the engine pointer to 0 because it must not be accessed again + engine = 0; +} + +// internal +void asCScriptFunction::DestroyHalfCreated() +{ + asASSERT( externalRefCount.get() == 0 && internalRefCount.get() == 1 ); + + // Set the funcType to dummy so the destructor won't complain + funcType = asFUNC_DUMMY; + + // If the bytecode exist remove it before destroying, otherwise it + // will fail when the destructor releases the references as the bytecode + // is not fully constructed. + if( scriptData ) + scriptData->byteCode.SetLength(0); + + asDELETE(this, asCScriptFunction); +} + +// internal +void asCScriptFunction::DestroyInternal() +{ + // Clean up user data + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) + { + if( userData[n+1] ) + { + for( asUINT c = 0; c < engine->cleanFunctionFuncs.GetLength(); c++ ) + if( engine->cleanFunctionFuncs[c].type == userData[n] ) + engine->cleanFunctionFuncs[c].cleanFunc(this); + } + } + userData.SetLength(0); + + // Release all references the function holds to other objects + ReleaseReferences(); + parameterTypes.SetLength(0); + returnType = asCDataType::CreatePrimitive(ttVoid, false); + + for( asUINT p = 0; p < defaultArgs.GetLength(); p++ ) + if( defaultArgs[p] ) + asDELETE(defaultArgs[p], asCString); + defaultArgs.SetLength(0); + + if( sysFuncIntf ) + asDELETE(sysFuncIntf,asSSystemFunctionInterface); + sysFuncIntf = 0; + + if( objectType ) + { + objectType->ReleaseInternal(); + objectType = 0; + } + + DeallocateScriptFunctionData(); + + // Deallocate list pattern data + while( listPattern ) + { + asSListPatternNode *n = listPattern->next; + asDELETE(listPattern, asSListPatternNode); + listPattern = n; + } +} + +// interface +int asCScriptFunction::GetId() const +{ + return id; +} + +// interface +int asCScriptFunction::AddRef() const +{ + gcFlag = false; + return externalRefCount.atomicInc(); +} + +// interface +int asCScriptFunction::Release() const +{ + gcFlag = false; + int r = externalRefCount.atomicDec(); + if( r == 0 && + funcType != asFUNC_DUMMY ) // Dummy functions are allocated on the stack and cannot be deleted + { + // There are no more external references, if there are also no + // internal references then it is time to delete the function + if( internalRefCount.get() == 0 ) + { + // If there are no internal references, then no module is owning the function + // For example if the function was dynamically compiled without adding it to the scope of the module + asASSERT( module == 0 ); + + asDELETE(const_cast(this),asCScriptFunction); + } + } + + return r; +} + +// internal +int asCScriptFunction::AddRefInternal() +{ + return internalRefCount.atomicInc(); +} + +// internal +int asCScriptFunction::ReleaseInternal() +{ + int r = internalRefCount.atomicDec(); + if( r == 0 && + funcType != asFUNC_DUMMY ) + { + // There are no more internal references, if there are also no + // external references then it is time to delete the function + if( externalRefCount.get() == 0 ) + { + asDELETE(const_cast(this),asCScriptFunction); + } + } + + return r; +} + +// interface +int asCScriptFunction::GetTypeId() const +{ + // This const cast is ok, the object won't be modified + asCDataType dt = asCDataType::CreateType(engine->FindMatchingFuncdef(const_cast(this), 0), false); + return engine->GetTypeIdFromDataType(dt); +} + +// interface +bool asCScriptFunction::IsCompatibleWithTypeId(int typeId) const +{ + asCDataType dt = engine->GetDataTypeFromTypeId(typeId); + + // Make sure the type is a function + if (!dt.IsFuncdef()) + return false; + + asCScriptFunction *func = CastToFuncdefType(dt.GetTypeInfo())->funcdef; + if( !IsSignatureExceptNameEqual(func) ) + return false; + + // If this is a class method, then only return true if the object type is the same + if( objectType != func->objectType ) + return false; + + return true; +} + +// interface +const char *asCScriptFunction::GetModuleName() const +{ + if( module ) + return module->GetName(); + + return 0; +} + +// interface +asIScriptModule *asCScriptFunction::GetModule() const +{ + return module; +} + +// interface +asITypeInfo *asCScriptFunction::GetObjectType() const +{ + return objectType; +} + +// interface +const char *asCScriptFunction::GetObjectName() const +{ + if( objectType ) + return objectType->GetName(); + + return 0; +} + +// interface +const char *asCScriptFunction::GetName() const +{ + return name.AddressOf(); +} + +// interface +const char *asCScriptFunction::GetNamespace() const +{ + if (nameSpace) + return nameSpace->name.AddressOf(); + + return 0; +} + +// interface +bool asCScriptFunction::IsReadOnly() const +{ + return traits.GetTrait(asTRAIT_CONST); +} + +// interface +bool asCScriptFunction::IsPrivate() const +{ + return traits.GetTrait(asTRAIT_PRIVATE); +} + +// interface +bool asCScriptFunction::IsProtected() const +{ + return traits.GetTrait(asTRAIT_PROTECTED); +} + +// internal +int asCScriptFunction::GetSpaceNeededForArguments() +{ + // We need to check the size for each type + int s = 0; + for( asUINT n = 0; n < parameterTypes.GetLength(); n++ ) + s += parameterTypes[n].GetSizeOnStackDWords(); + + return s; +} + +// internal +int asCScriptFunction::GetSpaceNeededForReturnValue() +{ + return returnType.GetSizeOnStackDWords(); +} + +// internal +bool asCScriptFunction::DoesReturnOnStack() const +{ + if( returnType.GetTypeInfo() && + (returnType.GetTypeInfo()->flags & asOBJ_VALUE) && + !returnType.IsReference() ) + return true; + + return false; +} + +// internal +asCString asCScriptFunction::GetDeclarationStr(bool includeObjectName, bool includeNamespace, bool includeParamNames) const +{ + asCString str; + + // TODO: default arg: Make the declaration with the default args an option + + // Don't add the return type for constructors and destructors + if( !(returnType.GetTokenType() == ttVoid && + objectType && + (name == objectType->name || (name.GetLength() > 0 && name[0] == '~') || + name == "$beh0" || name == "$beh2")) ) + { + str = returnType.Format(nameSpace, includeNamespace); + str += " "; + } + if( objectType && includeObjectName ) + { + if( includeNamespace && objectType->nameSpace->name != "" ) + str += objectType->nameSpace->name + "::"; + + if( objectType->name != "" ) + str += objectType->name + "::"; + else + str += "_unnamed_type_::"; + } + else if (funcdefType && funcdefType->parentClass && includeObjectName) + { + if (includeNamespace && funcdefType->parentClass->nameSpace->name != "") + str += funcdefType->parentClass->nameSpace->name + "::"; + + if (funcdefType->parentClass->name != "") + str += funcdefType->parentClass->name + "::"; + else + str += "_unnamed_type_::"; + } + else if( includeNamespace && nameSpace->name != "" && !objectType ) + { + str += nameSpace->name + "::"; + } + if( name == "" ) + str += "_unnamed_function_("; + else if( name.SubString(0,4) == "$beh" && name.GetLength() == 5 ) + { + if( name[4] == '0' + asBEHAVE_CONSTRUCT ) + str += objectType->name + "("; + else if( name[4] == '0' + asBEHAVE_FACTORY ) + str += returnType.GetTypeInfo()->name + "("; + else if( name[4] == '0' + asBEHAVE_DESTRUCT ) + str += "~" + objectType->name + "("; + else + str += name + "("; + } + else + str += name + "("; + + if( parameterTypes.GetLength() > 0 ) + { + asUINT n; + for( n = 0; n < parameterTypes.GetLength() - 1; n++ ) + { + str += parameterTypes[n].Format(nameSpace, includeNamespace); + if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n ) + { + if( inOutFlags[n] == asTM_INREF ) str += "in"; + else if( inOutFlags[n] == asTM_OUTREF ) str += "out"; + else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout"; + } + + if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 ) + { + str += " "; + str += parameterNames[n]; + } + + if( defaultArgs.GetLength() > n && defaultArgs[n] ) + { + asCString tmp; + tmp.Format(" = %s", defaultArgs[n]->AddressOf()); + str += tmp; + } + + str += ", "; + } + + // Add the last parameter + str += parameterTypes[n].Format(nameSpace, includeNamespace); + if( parameterTypes[n].IsReference() && inOutFlags.GetLength() > n ) + { + if( inOutFlags[n] == asTM_INREF ) str += "in"; + else if( inOutFlags[n] == asTM_OUTREF ) str += "out"; + else if( inOutFlags[n] == asTM_INOUTREF ) str += "inout"; + } + + if( includeParamNames && n < parameterNames.GetLength() && parameterNames[n].GetLength() != 0 ) + { + str += " "; + str += parameterNames[n]; + } + + if( defaultArgs.GetLength() > n && defaultArgs[n] ) + { + asCString tmp; + tmp.Format(" = %s", defaultArgs[n]->AddressOf()); + str += tmp; + } + } + + str += ")"; + + if( IsReadOnly() ) + str += " const"; + + // Add the declaration of the list pattern + if( listPattern ) + { + asSListPatternNode *n = listPattern; + bool first = true; + while( n ) + { + if( n->type == asLPT_START ) + { + str += " {"; + first = true; + } + else if( n->type == asLPT_END ) + { + str += " }"; + first = false; + } + else if( n->type == asLPT_REPEAT ) + str += " repeat"; + else if( n->type == asLPT_REPEAT_SAME ) + str += " repeat_same"; + else if( n->type == asLPT_TYPE ) + { + if( first ) + { + str += " "; + first = false; + } + else + str += ", "; + str += reinterpret_cast(n)->dataType.Format(nameSpace, includeNamespace); + } + + n = n->next; + } + } + + return str; +} + +// interface +int asCScriptFunction::FindNextLineWithCode(int line) const +{ + if( scriptData == 0 ) return -1; + if( scriptData->lineNumbers.GetLength() == 0 ) return -1; + + // The line numbers for constructors are not in order due to the way + // class members can be initialized directly in the declaration + if( objectType && objectType->name == name ) + { + // Sort all line numbers before looking for the next + asCArray lineNbrs; + for( asUINT n = 1; n < scriptData->lineNumbers.GetLength(); n += 2 ) + lineNbrs.PushLast(scriptData->lineNumbers[n]&0xFFFFF); + + struct C + { + static int cmp(const void *a, const void *b) { return *(int*)a - *(int*)b; } + }; + std::qsort(&lineNbrs[0], lineNbrs.GetLength(), sizeof(int), C::cmp); + + if( line < lineNbrs[0] && line < (scriptData->declaredAt&0xFFFFF)) return -1; + if( line > lineNbrs[lineNbrs.GetLength()-1] ) return -1; + + // Find the line with code on or right after the input line + // TODO: optimize: Do binary search + for( asUINT n = 0; n < lineNbrs.GetLength(); n++ ) + if( line <= lineNbrs[n] ) + return lineNbrs[n]; + } + else + { + // Check if given line is outside function + if( line < (scriptData->declaredAt&0xFFFFF) ) return -1; + if( line > (scriptData->lineNumbers[scriptData->lineNumbers.GetLength()-1]&0xFFFFF) ) return -1; + + // Find the line with code on or right after the input line + // TODO: optimize: Do binary search instead + for( asUINT n = 1; n < scriptData->lineNumbers.GetLength(); n += 2 ) + { + if( line <= (scriptData->lineNumbers[n]&0xFFFFF) ) + return (scriptData->lineNumbers[n]&0xFFFFF); + } + } + + return -1; +} + +// internal +int asCScriptFunction::GetLineNumber(int programPosition, int *sectionIdx) +{ + asASSERT( scriptData ); + + if( sectionIdx ) *sectionIdx = scriptData->scriptSectionIdx; + if( scriptData->lineNumbers.GetLength() == 0 ) return 0; + + if( sectionIdx ) + { + // Find the correct section index if the function is compiled from multiple sections + // This array will be empty most of the time so we don't need a sofisticated algorithm to search it + for( asUINT n = 0; n < scriptData->sectionIdxs.GetLength(); n += 2 ) + { + if( scriptData->sectionIdxs[n] <= programPosition ) + *sectionIdx = scriptData->sectionIdxs[n+1]; + } + } + + // Do a binary search in the buffer + int max = (int)scriptData->lineNumbers.GetLength()/2 - 1; + int min = 0; + int i = max/2; + + for(;;) + { + if( scriptData->lineNumbers[i*2] < programPosition ) + { + // Have we found the largest number < programPosition? + if( max == i ) return scriptData->lineNumbers[i*2+1]; + if( scriptData->lineNumbers[i*2+2] > programPosition ) return scriptData->lineNumbers[i*2+1]; + + min = i + 1; + i = (max + min)/2; + } + else if( scriptData->lineNumbers[i*2] > programPosition ) + { + // Have we found the smallest number > programPosition? + if( min == i ) return scriptData->lineNumbers[i*2+1]; + + max = i - 1; + i = (max + min)/2; + } + else + { + // We found the exact position + return scriptData->lineNumbers[i*2+1]; + } + } +} + +// interface +asEFuncType asCScriptFunction::GetFuncType() const +{ + return funcType; +} + +// interface +asUINT asCScriptFunction::GetVarCount() const +{ + if( scriptData ) + return asUINT(scriptData->variables.GetLength()); + return 0; +} + +// interface +int asCScriptFunction::GetVar(asUINT index, const char **out_name, int *out_typeId) const +{ + if( scriptData == 0 ) + return asNOT_SUPPORTED; + if( index >= scriptData->variables.GetLength() ) + return asINVALID_ARG; + + if( out_name ) + *out_name = scriptData->variables[index]->name.AddressOf(); + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(scriptData->variables[index]->type); + + return asSUCCESS; +} + +// interface +const char *asCScriptFunction::GetVarDecl(asUINT index, bool includeNamespace) const +{ + if( scriptData == 0 || index >= scriptData->variables.GetLength() ) + return 0; + + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = scriptData->variables[index]->type.Format(nameSpace, includeNamespace); + *tempString += " " + scriptData->variables[index]->name; + + return tempString->AddressOf(); +} + +// internal +void asCScriptFunction::AddVariable(asCString &in_name, asCDataType &in_type, int in_stackOffset) +{ + asASSERT( scriptData ); + asSScriptVariable *var = asNEW(asSScriptVariable); + if( var == 0 ) + { + // Out of memory + return; + } + var->name = in_name; + var->type = in_type; + var->stackOffset = in_stackOffset; + var->declaredAtProgramPos = 0; + scriptData->variables.PushLast(var); +} + +// internal +asCTypeInfo *asCScriptFunction::GetTypeInfoOfLocalVar(short varOffset) +{ + asASSERT( scriptData ); + + for( asUINT n = 0; n < scriptData->objVariablePos.GetLength(); n++ ) + { + if( scriptData->objVariablePos[n] == varOffset ) + return scriptData->objVariableTypes[n]; + } + + return 0; +} + +// internal +void asCScriptFunction::ComputeSignatureId() +{ + // This function will compute the signatureId based on the + // function name, return type, and parameter types. The object + // type for methods is not used, so that class methods and + // interface methods match each other. + for( asUINT n = 0; n < engine->signatureIds.GetLength(); n++ ) + { + if( !IsSignatureEqual(engine->signatureIds[n]) ) continue; + + // We don't need to increment the reference counter here, because + // asCScriptEngine::FreeScriptFunctionId will maintain the signature + // id as the function is freed. + signatureId = engine->signatureIds[n]->signatureId; + return; + } + + signatureId = id; + engine->signatureIds.PushLast(this); +} + +// internal +bool asCScriptFunction::IsSignatureEqual(const asCScriptFunction *func) const +{ + if( name != func->name || !IsSignatureExceptNameEqual(func) ) return false; + + return true; +} + +// internal +bool asCScriptFunction::IsSignatureExceptNameEqual(const asCScriptFunction *func) const +{ + return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); +} + +// internal +bool asCScriptFunction::IsSignatureExceptNameEqual(const asCDataType &retType, const asCArray ¶mTypes, const asCArray ¶mInOut, const asCObjectType *objType, bool readOnly) const +{ + if( this->returnType != retType ) return false; + + return IsSignatureExceptNameAndReturnTypeEqual(paramTypes, paramInOut, objType, readOnly); +} + +// internal +bool asCScriptFunction::IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const +{ + return IsSignatureExceptNameEqual(func->returnType, func->parameterTypes, func->inOutFlags, objectType, IsReadOnly()); +} + +// internal +bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *func) const +{ + return IsSignatureExceptNameAndReturnTypeEqual(func->parameterTypes, func->inOutFlags, func->objectType, func->IsReadOnly()); +} + +// internal +bool asCScriptFunction::IsSignatureExceptNameAndReturnTypeEqual(const asCArray ¶mTypes, const asCArray ¶mInOut, const asCObjectType *objType, bool readOnly) const +{ + if( this->IsReadOnly() != readOnly ) return false; + if( (this->objectType != 0) != (objType != 0) ) return false; + if( this->inOutFlags != paramInOut ) return false; + if( this->parameterTypes != paramTypes ) return false; + + return true; +} + +// internal +void asCScriptFunction::AddReferences() +{ + // This array will be used to make sure we only add the reference to the same resource once + // This is especially important for global variables, as it expects the initialization function + // to hold only one reference to the variable. However, if the variable is initialized through + // the default constructor followed by the assignment operator we will have two references to + // the variable in the function. + asCArray ptrs; + + // Only count references if there is any bytecode + if( scriptData && scriptData->byteCode.GetLength() ) + { + if( returnType.GetTypeInfo() ) + { + returnType.GetTypeInfo()->AddRefInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); + if( group != 0 ) group->AddRef(); + } + + for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) + if( parameterTypes[p].GetTypeInfo() ) + { + parameterTypes[p].GetTypeInfo()->AddRefInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); + if( group != 0 ) group->AddRef(); + } + + for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ ) + if( scriptData->objVariableTypes[v] ) // The null handle is also stored, but it doesn't have an object type + { + scriptData->objVariableTypes[v]->AddRefInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); + if( group != 0 ) group->AddRef(); + } + + // Go through the byte code and add references to all resources used by the function + asCArray &bc = scriptData->byteCode; + for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] ) + { + switch( *(asBYTE*)&bc[n] ) + { + // Object types + case asBC_OBJTYPE: + case asBC_FREE: + case asBC_REFCPY: + case asBC_RefCpyV: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); + asASSERT( objType ); + if( objType ) + objType->AddRefInternal(); + } + break; + + // Object type and function + case asBC_ALLOC: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); + asASSERT( objType ); + if( objType ) + objType->AddRefInternal(); + + int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); + if( funcId ) + engine->scriptFunctions[funcId]->AddRefInternal(); + } + break; + + // Global variables + case asBC_PGA: + case asBC_PshGPtr: + case asBC_LDG: + case asBC_PshG4: + case asBC_LdGRdR4: + case asBC_CpyGtoV4: + case asBC_CpyVtoG4: + case asBC_SetG4: + // Need to increase the reference for each global variable + { + void *gvarPtr = (void*)asBC_PTRARG(&bc[n]); + if( !gvarPtr ) break; + asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr); + + if (!prop) + { + // The pointer is a string constant. In order to make sure the correct resource + // management is maintained we request a new string constant here, so the compiler + // or bytecode loader can release its copy afterwards. + asCString str; + asUINT length; + int r = engine->stringFactory->GetRawStringData(gvarPtr, 0, &length); + if (r >= 0) + { + str.SetLength(length); + engine->stringFactory->GetRawStringData(gvarPtr, str.AddressOf(), &length); + + // Get a new pointer (depending on the string factory implementation it may actually be the same) + gvarPtr = const_cast(engine->stringFactory->GetStringConstant(str.AddressOf(), length)); + asBC_PTRARG(&bc[n]) = (asPWORD)gvarPtr; + } + + // If we get an error from the string factory there is not + // anything we can do about it, except report a message. + // TODO: NEWSTRING: Write a message and then exit gracefully + asASSERT(r >= 0); + break; + } + + // Only addref the properties once + if( !ptrs.Exists(gvarPtr) ) + { + prop->AddRef(); + ptrs.PushLast(gvarPtr); + } + + asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id); + if( group != 0 ) group->AddRef(); + } + break; + + // System functions + case asBC_CALLSYS: + { + int funcId = asBC_INTARG(&bc[n]); + asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId); + if( group != 0 ) group->AddRef(); + + asASSERT( funcId > 0 ); + if( funcId > 0 ) + engine->scriptFunctions[funcId]->AddRefInternal(); + } + break; + + // Functions + case asBC_CALL: + case asBC_CALLINTF: + { + int funcId = asBC_INTARG(&bc[n]); + asASSERT( funcId > 0 ); + if( funcId > 0 ) + engine->scriptFunctions[funcId]->AddRefInternal(); + } + break; + + // Function pointers + case asBC_FuncPtr: + { + asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); + asASSERT( func ); + if( func ) + func->AddRefInternal(); + } + break; + } + } + } +} + +// internal +void asCScriptFunction::ReleaseReferences() +{ + asCArray ptrs; + + // Only count references if there is any bytecode + if( scriptData && scriptData->byteCode.GetLength() ) + { + if( returnType.GetTypeInfo() ) + { + returnType.GetTypeInfo()->ReleaseInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(returnType.GetTypeInfo()); + if( group != 0 ) group->Release(); + } + + for( asUINT p = 0; p < parameterTypes.GetLength(); p++ ) + if( parameterTypes[p].GetTypeInfo() ) + { + parameterTypes[p].GetTypeInfo()->ReleaseInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(parameterTypes[p].GetTypeInfo()); + if( group != 0 ) group->Release(); + } + + for( asUINT v = 0; v < scriptData->objVariableTypes.GetLength(); v++ ) + if( scriptData->objVariableTypes[v] ) // The null handle is also stored, but it doesn't have an object type + { + scriptData->objVariableTypes[v]->ReleaseInternal(); + + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(scriptData->objVariableTypes[v]); + if( group != 0 ) group->Release(); + } + + // Go through the byte code and release references to all resources used by the function + asCArray &bc = scriptData->byteCode; + for( asUINT n = 0; n < bc.GetLength(); n += asBCTypeSize[asBCInfo[*(asBYTE*)&bc[n]].type] ) + { + switch( *(asBYTE*)&bc[n] ) + { + // Object types + case asBC_OBJTYPE: + case asBC_FREE: + case asBC_REFCPY: + case asBC_RefCpyV: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); + if( objType ) + objType->ReleaseInternal(); + } + break; + + // Object type and function + case asBC_ALLOC: + { + asCObjectType *objType = (asCObjectType*)asBC_PTRARG(&bc[n]); + if( objType ) + objType->ReleaseInternal(); + + int funcId = asBC_INTARG(&bc[n]+AS_PTR_SIZE); + if( funcId > 0 ) + { + asCScriptFunction *fptr = engine->scriptFunctions[funcId]; + if( fptr ) + fptr->ReleaseInternal(); + + // The engine may have been forced to destroy the function internals early + // and this may will make it impossible to find the function by id anymore. + // This should only happen if the engine is released while the application + // is still keeping functions alive. + // TODO: Fix this possible memory leak + } + } + break; + + // Global variables + case asBC_PGA: + case asBC_PshGPtr: + case asBC_LDG: + case asBC_PshG4: + case asBC_LdGRdR4: + case asBC_CpyGtoV4: + case asBC_CpyVtoG4: + case asBC_SetG4: + // Need to increase the reference for each global variable + { + void *gvarPtr = (void*)asBC_PTRARG(&bc[n]); + if( !gvarPtr ) break; + asCGlobalProperty *prop = GetPropertyByGlobalVarPtr(gvarPtr); + + if (!prop) + { + // The pointer is a string constant, so it needs to be released by the string factory + int r = engine->stringFactory->ReleaseStringConstant(gvarPtr); + UNUSED_VAR(r); + + // If we get an error from the string factory there is not + // anything we can do about it, except report a message. + // TODO: Write a message showing that the string couldn't be + // released. Include the first 10 characters and the length + // to make it easier to identify which string it was + asASSERT(r >= 0); + break; + } + + // Only release the properties once + if( !ptrs.Exists(gvarPtr) ) + { + prop->Release(); + ptrs.PushLast(gvarPtr); + } + + asCConfigGroup *group = engine->FindConfigGroupForGlobalVar(prop->id); + if( group != 0 ) group->Release(); + } + break; + + // System functions + case asBC_CALLSYS: + { + int funcId = asBC_INTARG(&bc[n]); + asCConfigGroup *group = engine->FindConfigGroupForFunction(funcId); + if( group != 0 ) group->Release(); + + if( funcId ) + { + asCScriptFunction *fptr = engine->scriptFunctions[funcId]; + if( fptr ) + fptr->ReleaseInternal(); + } + } + break; + + // Functions + case asBC_CALL: + case asBC_CALLINTF: + { + int funcId = asBC_INTARG(&bc[n]); + if( funcId ) + { + asCScriptFunction *fptr = engine->scriptFunctions[funcId]; + if( fptr ) + fptr->ReleaseInternal(); + + // The engine may have been forced to destroy the function internals early + // and this may will make it impossible to find the function by id anymore. + // This should only happen if the engine is released while the application + // is still keeping functions alive. + // TODO: Fix this possible memory leak + } + } + break; + + // Function pointers + case asBC_FuncPtr: + { + asCScriptFunction *func = (asCScriptFunction*)asBC_PTRARG(&bc[n]); + if( func ) + func->ReleaseInternal(); + } + break; + } + } + + // Release the jit compiled function + if( scriptData->jitFunction ) + engine->jitCompiler->ReleaseJITFunction(scriptData->jitFunction); + scriptData->jitFunction = 0; + } + + // Delegate + if( objForDelegate ) + engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType()); + objForDelegate = 0; + if( funcForDelegate ) + funcForDelegate->Release(); + funcForDelegate = 0; +} + +// interface +int asCScriptFunction::GetReturnTypeId(asDWORD *flags) const +{ + if( flags ) + { + if( returnType.IsReference() ) + { + *flags = asTM_INOUTREF; + *flags |= returnType.IsReadOnly() ? asTM_CONST : 0; + } + else + *flags = asTM_NONE; + } + + return engine->GetTypeIdFromDataType(returnType); +} + +// interface +asUINT asCScriptFunction::GetParamCount() const +{ + return (asUINT)parameterTypes.GetLength(); +} + +// interface +int asCScriptFunction::GetParam(asUINT index, int *out_typeId, asDWORD *out_flags, const char **out_name, const char **out_defaultArg) const +{ + if( index >= parameterTypes.GetLength() ) + return asINVALID_ARG; + + if( out_typeId ) + *out_typeId = engine->GetTypeIdFromDataType(parameterTypes[index]); + + if( out_flags ) + { + *out_flags = inOutFlags[index]; + *out_flags |= parameterTypes[index].IsReadOnly() ? asTM_CONST : 0; + } + + if( out_name ) + { + // The parameter names are not stored if loading from bytecode without debug information + if( index < parameterNames.GetLength() ) + *out_name = parameterNames[index].AddressOf(); + else + *out_name = 0; + } + + if( out_defaultArg ) + { + if( index < defaultArgs.GetLength() && defaultArgs[index] ) + *out_defaultArg = defaultArgs[index]->AddressOf(); + else + *out_defaultArg = 0; + } + + return asSUCCESS; +} + +// interface +asIScriptEngine *asCScriptFunction::GetEngine() const +{ + return engine; +} + +// interface +const char *asCScriptFunction::GetDeclaration(bool includeObjectName, bool includeNamespace, bool includeParamNames) const +{ + asCString *tempString = &asCThreadManager::GetLocalData()->string; + *tempString = GetDeclarationStr(includeObjectName, includeNamespace, includeParamNames); + return tempString->AddressOf(); +} + +// interface +const char *asCScriptFunction::GetScriptSectionName() const +{ + if( scriptData && scriptData->scriptSectionIdx >= 0 ) + return engine->scriptSectionNames[scriptData->scriptSectionIdx]->AddressOf(); + + return 0; +} + +// interface +const char *asCScriptFunction::GetConfigGroup() const +{ + asCConfigGroup *group = 0; + if( funcType != asFUNC_FUNCDEF ) + group = engine->FindConfigGroupForFunction(id); + else + group = engine->FindConfigGroupForFuncDef(this->funcdefType); + + if( group == 0 ) + return 0; + + return group->groupName.AddressOf(); +} + +// interface +asDWORD asCScriptFunction::GetAccessMask() const +{ + return accessMask; +} + +// internal +void asCScriptFunction::JITCompile() +{ + if( funcType != asFUNC_SCRIPT ) + return; + + asASSERT( scriptData ); + + asIJITCompiler *jit = engine->GetJITCompiler(); + if( !jit ) + return; + + // Make sure the function has been compiled with JitEntry instructions + // For functions that has JitEntry this will be a quick test + asUINT length; + asDWORD *byteCode = GetByteCode(&length); + asDWORD *end = byteCode + length; + bool foundJitEntry = false; + while( byteCode < end ) + { + // Determine the instruction + asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode); + if( op == asBC_JitEntry ) + { + foundJitEntry = true; + break; + } + + // Move to next instruction + byteCode += asBCTypeSize[asBCInfo[op].type]; + } + + if( !foundJitEntry ) + { + asCString msg; + msg.Format(TXT_NO_JIT_IN_FUNC_s, GetDeclaration()); + engine->WriteMessage("", 0, 0, asMSGTYPE_WARNING, msg.AddressOf()); + } + + // Release the previous function, if any + if( scriptData->jitFunction ) + { + engine->jitCompiler->ReleaseJITFunction(scriptData->jitFunction); + scriptData->jitFunction = 0; + } + + // Compile for native system + int r = jit->CompileFunction(this, &scriptData->jitFunction); + if( r < 0 ) + asASSERT( scriptData->jitFunction == 0 ); +} + +// interface +asDWORD *asCScriptFunction::GetByteCode(asUINT *length) +{ + if( scriptData == 0 ) return 0; + + if( length ) + *length = (asUINT)scriptData->byteCode.GetLength(); + + if( scriptData->byteCode.GetLength() ) + return scriptData->byteCode.AddressOf(); + + return 0; +} + +// interface +void *asCScriptFunction::SetUserData(void *data, asPWORD type) +{ + // As a thread might add a new new user data at the same time as another + // it is necessary to protect both read and write access to the userData member + ACQUIREEXCLUSIVE(engine->engineRWLock); + + // It is not intended to store a lot of different types of userdata, + // so a more complex structure like a associative map would just have + // more overhead than a simple array. + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) + { + if( userData[n] == type ) + { + void *oldData = reinterpret_cast(userData[n+1]); + userData[n+1] = reinterpret_cast(data); + + RELEASEEXCLUSIVE(engine->engineRWLock); + + return oldData; + } + } + + userData.PushLast(type); + userData.PushLast(reinterpret_cast(data)); + + RELEASEEXCLUSIVE(engine->engineRWLock); + + return 0; +} + +// interface +void *asCScriptFunction::GetUserData(asPWORD type) const +{ + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + ACQUIRESHARED(engine->engineRWLock); + + for( asUINT n = 0; n < userData.GetLength(); n += 2 ) + { + if( userData[n] == type ) + { + RELEASESHARED(engine->engineRWLock); + return reinterpret_cast(userData[n+1]); + } + } + + RELEASESHARED(engine->engineRWLock); + + return 0; +} + +// internal +// TODO: cleanup: This method should probably be a member of the engine +asCGlobalProperty *asCScriptFunction::GetPropertyByGlobalVarPtr(void *gvarPtr) +{ + asSMapNode *node; + if( engine->varAddressMap.MoveTo(&node, gvarPtr) ) + { + asASSERT(gvarPtr == node->value->GetAddressOfValue()); + return node->value; + } + return 0; +} + +// internal +int asCScriptFunction::GetRefCount() +{ + asASSERT( funcType == asFUNC_DELEGATE ); + + return externalRefCount.get(); +} + +// internal +void asCScriptFunction::SetFlag() +{ + gcFlag = true; +} + +// internal +bool asCScriptFunction::GetFlag() +{ + return gcFlag; +} + +// internal +void asCScriptFunction::EnumReferences(asIScriptEngine *) +{ + asASSERT( funcType == asFUNC_DELEGATE ); + + // Delegate + if( objForDelegate ) + engine->GCEnumCallback(objForDelegate); +} + +// internal +void asCScriptFunction::ReleaseAllHandles(asIScriptEngine *) +{ + asASSERT( funcType == asFUNC_DELEGATE ); + + // Release paramaters + + // Delegate + if( objForDelegate ) + engine->ReleaseScriptObject(objForDelegate, funcForDelegate->GetObjectType()); + objForDelegate = 0; +} + +// interface +bool asCScriptFunction::IsShared() const +{ + // All system functions are shared + if( funcType == asFUNC_SYSTEM ) return true; + + // All class methods for shared classes are also shared + asASSERT( objectType == 0 || objectType->engine == engine || objectType->engine == 0 ); + if( objectType && (objectType->flags & asOBJ_SHARED) ) return true; + + // funcdefs that are registered by the application are shared + if (funcType == asFUNC_FUNCDEF && module == 0) return true; + + // Functions that have been specifically marked as shared are shared + return traits.GetTrait(asTRAIT_SHARED); +} + +// interface +bool asCScriptFunction::IsFinal() const +{ + return traits.GetTrait(asTRAIT_FINAL); +} + +// interface +bool asCScriptFunction::IsOverride() const +{ + return traits.GetTrait(asTRAIT_OVERRIDE); +} + +// interface +bool asCScriptFunction::IsExplicit() const +{ + return traits.GetTrait(asTRAIT_EXPLICIT); +} + +// interface +bool asCScriptFunction::IsProperty() const +{ + return traits.GetTrait(asTRAIT_PROPERTY); +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_scriptfunction.h b/angelscript/source/as_scriptfunction.h new file mode 100644 index 0000000..416f1d0 --- /dev/null +++ b/angelscript/source/as_scriptfunction.h @@ -0,0 +1,379 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptfunction.h +// +// A container for a compiled script function +// + + + +#ifndef AS_SCRIPTFUNCTION_H +#define AS_SCRIPTFUNCTION_H + +#include "as_config.h" +#include "as_string.h" +#include "as_array.h" +#include "as_datatype.h" +#include "as_atomic.h" + +BEGIN_AS_NAMESPACE + +class asCScriptEngine; +class asCModule; +class asCConfigGroup; +class asCGlobalProperty; +class asCScriptNode; +class asCFuncdefType; +struct asSNameSpace; + +struct asSScriptVariable +{ + asCString name; + asCDataType type; + int stackOffset; + asUINT declaredAtProgramPos; +}; + +enum asEListPatternNodeType +{ + asLPT_REPEAT, + asLPT_REPEAT_SAME, + asLPT_START, + asLPT_END, + asLPT_TYPE +}; + +struct asSListPatternNode +{ + asSListPatternNode(asEListPatternNodeType t) : type(t), next(0) {} + virtual ~asSListPatternNode() {}; + virtual asSListPatternNode *Duplicate() { return asNEW(asSListPatternNode)(type); } + asEListPatternNodeType type; + asSListPatternNode *next; +}; + +struct asSListPatternDataTypeNode : public asSListPatternNode +{ + asSListPatternDataTypeNode(const asCDataType &dt) : asSListPatternNode(asLPT_TYPE), dataType(dt) {} + asSListPatternNode *Duplicate() { return asNEW(asSListPatternDataTypeNode)(dataType); } + asCDataType dataType; +}; + +enum asEObjVarInfoOption +{ + asOBJ_UNINIT, // object is uninitialized/destroyed + asOBJ_INIT, // object is initialized + asBLOCK_BEGIN, // scope block begins + asBLOCK_END, // scope block ends + asOBJ_VARDECL // object variable is declared (but not necessarily initialized) +}; + +enum asEFuncTrait +{ + asTRAIT_CONSTRUCTOR = 1, + asTRAIT_DESTRUCTOR = 2, + asTRAIT_CONST = 4, + asTRAIT_PRIVATE = 8, + asTRAIT_PROTECTED = 16, + asTRAIT_FINAL = 32, + asTRAIT_OVERRIDE = 64, + asTRAIT_SHARED = 128, + asTRAIT_EXTERNAL = 256, + asTRAIT_EXPLICIT = 512, + asTRAIT_PROPERTY = 1024 +}; + +struct asSFunctionTraits +{ + asSFunctionTraits() : traits(0) {} + void SetTrait(asEFuncTrait trait, bool set) { if (set) traits |= trait; else traits &= ~trait; } + bool GetTrait(asEFuncTrait trait) const { return (traits & trait) ? true : false; } +protected: + asDWORD traits; +}; + +struct asSObjectVariableInfo +{ + asUINT programPos; + int variableOffset; + asEObjVarInfoOption option; +}; + +struct asSTryCatchInfo +{ + asUINT tryPos; + asUINT catchPos; +}; + +struct asSSystemFunctionInterface; + +// TODO: Might be interesting to allow enumeration of accessed global variables, and +// also functions/methods that are being called. This could be used to build a +// code database with call graphs, etc. + +void RegisterScriptFunction(asCScriptEngine *engine); + +class asCScriptFunction : public asIScriptFunction +{ +public: + // From asIScriptFunction + asIScriptEngine *GetEngine() const; + + // Memory management + int AddRef() const; + int Release() const; + + // Miscellaneous + int GetId() const; + asEFuncType GetFuncType() const; + const char *GetModuleName() const; + asIScriptModule *GetModule() const; + const char *GetScriptSectionName() const; + const char *GetConfigGroup() const; + asDWORD GetAccessMask() const; + void *GetAuxiliary() const; + + // Function signature + asITypeInfo *GetObjectType() const; + const char *GetObjectName() const; + const char *GetName() const; + const char *GetNamespace() const; + const char *GetDeclaration(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const; + bool IsReadOnly() const; + bool IsPrivate() const; + bool IsProtected() const; + bool IsFinal() const; + bool IsOverride() const; + bool IsShared() const; + bool IsExplicit() const; + bool IsProperty() const; + asUINT GetParamCount() const; + int GetParam(asUINT index, int *typeId, asDWORD *flags = 0, const char **name = 0, const char **defaultArg = 0) const; + int GetReturnTypeId(asDWORD *flags = 0) const; + + // Type id for function pointers + int GetTypeId() const; + bool IsCompatibleWithTypeId(int typeId) const; + + // Delegates + void *GetDelegateObject() const; + asITypeInfo *GetDelegateObjectType() const; + asIScriptFunction *GetDelegateFunction() const; + + // Debug information + asUINT GetVarCount() const; + int GetVar(asUINT index, const char **name, int *typeId = 0) const; + const char * GetVarDecl(asUINT index, bool includeNamespace = false) const; + int FindNextLineWithCode(int line) const; + + // For JIT compilation + asDWORD *GetByteCode(asUINT *length = 0); + + // User data + void *SetUserData(void *userData, asPWORD type); + void *GetUserData(asPWORD type) const; + +public: + //----------------------------------- + // Internal methods + + void SetShared(bool set) { traits.SetTrait(asTRAIT_SHARED, set); } + void SetReadOnly(bool set) { traits.SetTrait(asTRAIT_CONST, set); } + void SetFinal(bool set) { traits.SetTrait(asTRAIT_FINAL, set); } + void SetOverride(bool set) { traits.SetTrait(asTRAIT_OVERRIDE, set); } + void SetExplicit(bool set) { traits.SetTrait(asTRAIT_EXPLICIT, set); } + void SetProtected(bool set) { traits.SetTrait(asTRAIT_PROTECTED, set); } + void SetPrivate(bool set) { traits.SetTrait(asTRAIT_PRIVATE, set); } + void SetProperty(bool set) { traits.SetTrait(asTRAIT_PROPERTY, set); } + + asCScriptFunction(asCScriptEngine *engine, asCModule *mod, asEFuncType funcType); + ~asCScriptFunction(); + + // Keep an internal reference counter to separate references coming from + // application or script objects and references coming from the script code + int AddRefInternal(); + int ReleaseInternal(); + + void DestroyHalfCreated(); + + // TODO: operator== + // TODO: The asIScriptFunction should provide operator== and operator!= that should do a + // a value comparison. Two delegate objects that point to the same object and class method should compare as equal + // TODO: The operator== should also be provided in script as opEquals to allow the same comparison in script + // To do this we'll need some way to adapt the argtype for opEquals for each funcdef, preferrably without instantiating lots of different methods + // Perhaps reusing 'auto' to mean the same type as the object + //bool operator==(const asCScriptFunction &other) const; + + void DestroyInternal(); + + void AddVariable(asCString &name, asCDataType &type, int stackOffset); + + int GetSpaceNeededForArguments(); + int GetSpaceNeededForReturnValue(); + asCString GetDeclarationStr(bool includeObjectName = true, bool includeNamespace = false, bool includeParamNames = false) const; + int GetLineNumber(int programPosition, int *sectionIdx); + void ComputeSignatureId(); + bool IsSignatureEqual(const asCScriptFunction *func) const; + bool IsSignatureExceptNameEqual(const asCScriptFunction *func) const; + bool IsSignatureExceptNameEqual(const asCDataType &retType, const asCArray ¶mTypes, const asCArray &inOutFlags, const asCObjectType *type, bool isReadOnly) const; + bool IsSignatureExceptNameAndReturnTypeEqual(const asCScriptFunction *fun) const; + bool IsSignatureExceptNameAndReturnTypeEqual(const asCArray ¶mTypes, const asCArray &inOutFlags, const asCObjectType *type, bool isReadOnly) const; + bool IsSignatureExceptNameAndObjectTypeEqual(const asCScriptFunction *func) const; + + asCTypeInfo *GetTypeInfoOfLocalVar(short varOffset); + + void MakeDelegate(asCScriptFunction *func, void *obj); + + int RegisterListPattern(const char *decl, asCScriptNode *listPattern); + int ParseListPattern(asSListPatternNode *&target, const char *decl, asCScriptNode *listPattern); + + bool DoesReturnOnStack() const; + + void JITCompile(); + + void AddReferences(); + void ReleaseReferences(); + + void AllocateScriptFunctionData(); + void DeallocateScriptFunctionData(); + + asCGlobalProperty *GetPropertyByGlobalVarPtr(void *gvarPtr); + + // GC methods (for delegates) + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); + +public: + //----------------------------------- + // Properties + + mutable asCAtomic externalRefCount; // Used for external referneces + asCAtomic internalRefCount; // Used for internal references + mutable bool gcFlag; + asCScriptEngine *engine; + asCModule *module; + + asCArray userData; + + // Function signature + asCString name; + asCDataType returnType; + asCArray parameterTypes; + asCArray parameterNames; + asCArray inOutFlags; + asCArray defaultArgs; + asSFunctionTraits traits; + asCObjectType *objectType; + int signatureId; + + int id; + + asEFuncType funcType; + asDWORD accessMask; + + // Namespace will be null for funcdefs that are declared as child funcdefs + // of a class. In this case the namespace shall be taken from the parentClass + // in the funcdefType + asSNameSpace *nameSpace; + + asCFuncdefType *funcdefType; // Doesn't increase refCount + + // Used by asFUNC_DELEGATE + void *objForDelegate; + asCScriptFunction *funcForDelegate; + + // Used by list factory behaviour + asSListPatternNode *listPattern; + + // Used by asFUNC_SCRIPT + struct ScriptFunctionData + { + // Bytecode for the script function + asCArray byteCode; + + // The stack space needed for the local variables + asDWORD variableSpace; + + // These hold information on objects and function pointers, including temporary + // variables used by exception handler and when saving bytecode + asCArray objVariableTypes; + asCArray objVariablePos; // offset on stackframe + + // The first variables in above array are allocated on the heap, the rest on the stack. + // This variable shows how many are on the heap. + asUINT objVariablesOnHeap; + + // Holds information on scope for object variables on the stack + asCArray objVariableInfo; + + // Holds information on try/catch blocks for exception handling + asCArray tryCatchInfo; + + // The stack needed to execute the function + int stackNeeded; + + // JIT compiled code of this function + asJITFunction jitFunction; + + // Holds debug information on explicitly declared variables + asCArray variables; + // Store position, line number pairs for debug information + asCArray lineNumbers; + // Store the script section where the code was declared + int scriptSectionIdx; + // Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12) + int declaredAt; + // Store position/index pairs if the bytecode is compiled from multiple script sections + asCArray sectionIdxs; + }; + ScriptFunctionData *scriptData; + + // Stub functions and delegates don't own the object and parameters + bool dontCleanUpOnException; + + // Used by asFUNC_VIRTUAL + int vfTableIdx; + + // Used by asFUNC_SYSTEM + asSSystemFunctionInterface *sysFuncIntf; +}; + +const char * const DELEGATE_FACTORY = "$dlgte"; +asCScriptFunction *CreateDelegate(asCScriptFunction *func, void *obj); + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_scriptnode.cpp b/angelscript/source/as_scriptnode.cpp new file mode 100644 index 0000000..9bd9cfd --- /dev/null +++ b/angelscript/source/as_scriptnode.cpp @@ -0,0 +1,178 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptnode.cpp +// +// A node in the script tree built by the parser for compilation +// + + + +#include "as_scriptnode.h" +#include "as_scriptengine.h" + +BEGIN_AS_NAMESPACE + +asCScriptNode::asCScriptNode(eScriptNode type) +{ + nodeType = type; + tokenType = ttUnrecognizedToken; + tokenPos = 0; + tokenLength = 0; + + parent = 0; + next = 0; + prev = 0; + firstChild = 0; + lastChild = 0; +} + +void asCScriptNode::Destroy(asCScriptEngine *engine) +{ + // Destroy all children + asCScriptNode *node = firstChild; + asCScriptNode *nxt; + + while( node ) + { + nxt = node->next; + node->Destroy(engine); + node = nxt; + } + + // Return the memory to the memory manager + engine->memoryMgr.FreeScriptNode(this); +} + +asCScriptNode *asCScriptNode::CreateCopy(asCScriptEngine *engine) +{ + void *ptr = engine->memoryMgr.AllocScriptNode(); + if( ptr == 0 ) + { + // Out of memory + return 0; + } + + new(ptr) asCScriptNode(nodeType); + + asCScriptNode *node = reinterpret_cast(ptr); + node->tokenLength = tokenLength; + node->tokenPos = tokenPos; + node->tokenType = tokenType; + + asCScriptNode *child = firstChild; + while( child ) + { + node->AddChildLast(child->CreateCopy(engine)); + child = child->next; + } + + return node; +} + +void asCScriptNode::SetToken(sToken *token) +{ + tokenType = token->type; +} + +void asCScriptNode::UpdateSourcePos(size_t pos, size_t length) +{ + if( pos == 0 && length == 0 ) return; + + if( tokenPos == 0 && tokenLength == 0 ) + { + tokenPos = pos; + tokenLength = length; + } + else + { + if( tokenPos > pos ) + { + tokenLength = tokenPos + tokenLength - pos; + tokenPos = pos; + } + + if( pos + length > tokenPos + tokenLength ) + { + tokenLength = pos + length - tokenPos; + } + } +} + +void asCScriptNode::AddChildLast(asCScriptNode *node) +{ + // We might get a null pointer if the parser encounter an out-of-memory situation + if( node == 0 ) return; + + if( lastChild ) + { + lastChild->next = node; + node->next = 0; + node->prev = lastChild; + node->parent = this; + lastChild = node; + } + else + { + firstChild = node; + lastChild = node; + node->next = 0; + node->prev = 0; + node->parent = this; + } + + UpdateSourcePos(node->tokenPos, node->tokenLength); +} + +void asCScriptNode::DisconnectParent() +{ + if( parent ) + { + if( parent->firstChild == this ) + parent->firstChild = next; + if( parent->lastChild == this ) + parent->lastChild = prev; + } + + if( next ) + next->prev = prev; + + if( prev ) + prev->next = next; + + parent = 0; + next = 0; + prev = 0; +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_scriptnode.h b/angelscript/source/as_scriptnode.h new file mode 100644 index 0000000..e743f11 --- /dev/null +++ b/angelscript/source/as_scriptnode.h @@ -0,0 +1,138 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2018 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_scriptnode.h +// +// A node in the script tree built by the parser for compilation +// + + +#ifndef AS_SCRIPTNODE_H +#define AS_SCRIPTNODE_H + +#include "as_config.h" +#include "as_tokendef.h" + +BEGIN_AS_NAMESPACE + +enum eScriptNode +{ + snUndefined, + snScript, + snFunction, + snConstant, + snDataType, + snIdentifier, + snParameterList, + snStatementBlock, + snDeclaration, + snExpressionStatement, + snIf, + snFor, + snWhile, + snReturn, + snExpression, + snExprTerm, + snFunctionCall, + snConstructCall, + snArgList, + snExprPreOp, + snExprPostOp, + snExprOperator, + snExprValue, + snBreak, + snContinue, + snDoWhile, + snAssignment, + snCondition, + snSwitch, + snCase, + snImport, + snClass, + snInitList, + snInterface, + snEnum, + snTypedef, + snCast, + snVariableAccess, + snFuncDef, + snVirtualProperty, + snNamespace, + snMixin, + snListPattern, + snNamedArgument, + snScope, + snTryCatch +}; + +struct sToken +{ + eTokenType type; + size_t pos; + size_t length; +}; + +class asCScriptEngine; + +class asCScriptNode +{ +public: + asCScriptNode(eScriptNode nodeType); + + void Destroy(asCScriptEngine *engine); + asCScriptNode *CreateCopy(asCScriptEngine *engine); + + void SetToken(sToken *token); + void AddChildLast(asCScriptNode *node); + void DisconnectParent(); + + void UpdateSourcePos(size_t pos, size_t length); + + eScriptNode nodeType; + eTokenType tokenType; + size_t tokenPos; + size_t tokenLength; + + asCScriptNode *parent; + asCScriptNode *next; + asCScriptNode *prev; + asCScriptNode *firstChild; + asCScriptNode *lastChild; + +protected: + // Must call Destroy instead + ~asCScriptNode() {} +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_scriptobject.cpp b/angelscript/source/as_scriptobject.cpp new file mode 100644 index 0000000..260792e --- /dev/null +++ b/angelscript/source/as_scriptobject.cpp @@ -0,0 +1,1184 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +#include +#include "as_config.h" +#include "as_scriptengine.h" +#include "as_scriptobject.h" +#include "as_texts.h" + +BEGIN_AS_NAMESPACE + +// This helper function will call the default factory, that is a script function +asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngine *engine) +{ + asIScriptContext *ctx = 0; + int r = 0; + bool isNested = false; + + // Use nested call in the context if there is an active context + ctx = asGetActiveContext(); + if( ctx ) + { + // It may not always be possible to reuse the current context, + // in which case we'll have to create a new one any way. + if( ctx->GetEngine() == objType->GetEngine() && ctx->PushState() == asSUCCESS ) + isNested = true; + else + ctx = 0; + } + + if( ctx == 0 ) + { + // Request a context from the engine + ctx = engine->RequestContext(); + if( ctx == 0 ) + { + // TODO: How to best report this failure? + return 0; + } + } + + r = ctx->Prepare(engine->scriptFunctions[objType->beh.factory]); + if( r < 0 ) + { + if( isNested ) + ctx->PopState(); + else + engine->ReturnContext(ctx); + return 0; + } + + for(;;) + { + r = ctx->Execute(); + + // We can't allow this execution to be suspended + // so resume the execution immediately + if( r != asEXECUTION_SUSPENDED ) + break; + } + + if( r != asEXECUTION_FINISHED ) + { + if( isNested ) + { + ctx->PopState(); + + // If the execution was aborted or an exception occurred, + // then we should forward that to the outer execution. + if( r == asEXECUTION_EXCEPTION ) + { + // TODO: How to improve this exception + ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); + } + else if( r == asEXECUTION_ABORTED ) + ctx->Abort(); + } + else + engine->ReturnContext(ctx); + return 0; + } + + asIScriptObject *ptr = (asIScriptObject*)ctx->GetReturnAddress(); + + // Increase the reference, because the context will release its pointer + ptr->AddRef(); + + if( isNested ) + ctx->PopState(); + else + engine->ReturnContext(ctx); + + return ptr; +} + +// This helper function will call the copy factory, that is a script function +// TODO: Clean up: This function is almost identical to ScriptObjectFactory. Should make better use of the identical code. +asIScriptObject *ScriptObjectCopyFactory(const asCObjectType *objType, void *origObj, asCScriptEngine *engine) +{ + asIScriptContext *ctx = 0; + int r = 0; + bool isNested = false; + + // Use nested call in the context if there is an active context + ctx = asGetActiveContext(); + if (ctx) + { + // It may not always be possible to reuse the current context, + // in which case we'll have to create a new one any way. + if (ctx->GetEngine() == objType->GetEngine() && ctx->PushState() == asSUCCESS) + isNested = true; + else + ctx = 0; + } + + if (ctx == 0) + { + // Request a context from the engine + ctx = engine->RequestContext(); + if (ctx == 0) + { + // TODO: How to best report this failure? + return 0; + } + } + + r = ctx->Prepare(engine->scriptFunctions[objType->beh.copyfactory]); + if (r < 0) + { + if (isNested) + ctx->PopState(); + else + engine->ReturnContext(ctx); + return 0; + } + + // Let the context handle the case for argument by ref (&) or by handle (@) + ctx->SetArgObject(0, origObj); + + for (;;) + { + r = ctx->Execute(); + + // We can't allow this execution to be suspended + // so resume the execution immediately + if (r != asEXECUTION_SUSPENDED) + break; + } + + if (r != asEXECUTION_FINISHED) + { + if (isNested) + { + ctx->PopState(); + + // If the execution was aborted or an exception occurred, + // then we should forward that to the outer execution. + if (r == asEXECUTION_EXCEPTION) + { + // TODO: How to improve this exception + ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); + } + else if (r == asEXECUTION_ABORTED) + ctx->Abort(); + } + else + engine->ReturnContext(ctx); + return 0; + } + + asIScriptObject *ptr = (asIScriptObject*)ctx->GetReturnAddress(); + + // Increase the reference, because the context will release its pointer + ptr->AddRef(); + + if (isNested) + ctx->PopState(); + else + engine->ReturnContext(ctx); + + return ptr; +} + +#ifdef AS_MAX_PORTABILITY + +static void ScriptObject_AddRef_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + self->AddRef(); +} + +static void ScriptObject_Release_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + self->Release(); +} + +static void ScriptObject_GetRefCount_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + *(int*)gen->GetAddressOfReturnLocation() = self->GetRefCount(); +} + +static void ScriptObject_SetFlag_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + self->SetFlag(); +} + +static void ScriptObject_GetFlag_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + *(bool*)gen->GetAddressOfReturnLocation() = self->GetFlag(); +} + +static void ScriptObject_GetWeakRefFlag_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + *(asILockableSharedBool**)gen->GetAddressOfReturnLocation() = self->GetWeakRefFlag(); +} + +static void ScriptObject_EnumReferences_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->EnumReferences(engine); +} + +static void ScriptObject_ReleaseAllHandles_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + asIScriptEngine *engine = *(asIScriptEngine**)gen->GetAddressOfArg(0); + self->ReleaseAllHandles(engine); +} + +static void ScriptObject_Assignment_Generic(asIScriptGeneric *gen) +{ + asCScriptObject *other = *(asCScriptObject**)gen->GetAddressOfArg(0); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + + *self = *other; + + *(asCScriptObject**)gen->GetAddressOfReturnLocation() = self; +} + +static void ScriptObject_Construct_Generic(asIScriptGeneric *gen) +{ + asCObjectType *objType = *(asCObjectType**)gen->GetAddressOfArg(0); + asCScriptObject *self = (asCScriptObject*)gen->GetObject(); + + ScriptObject_Construct(objType, self); +} + +#endif + +void RegisterScriptObject(asCScriptEngine *engine) +{ + // Register the default script class behaviours + int r = 0; + UNUSED_VAR(r); // It is only used in debug mode + engine->scriptTypeBehaviours.engine = engine; + engine->scriptTypeBehaviours.flags = asOBJ_SCRIPT_OBJECT | asOBJ_REF | asOBJ_GC; + engine->scriptTypeBehaviours.name = "$obj"; +#ifndef AS_MAX_PORTABILITY + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct), asCALL_CDECL_OBJLAST, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asMETHOD(asCScriptObject,AddRef), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASE, "void f()", asMETHOD(asCScriptObject,Release), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterMethodToObjectType(&engine->scriptTypeBehaviours, "int &opAssign(int &in)", asFUNCTION(ScriptObject_Assignment), asCALL_CDECL_OBJLAST); asASSERT( r >= 0 ); + + // Weakref behaviours + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GET_WEAKREF_FLAG, "int &f()", asMETHOD(asCScriptObject,GetWeakRefFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(asCScriptObject,GetRefCount), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asMETHOD(asCScriptObject,SetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(asCScriptObject,GetFlag), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(asCScriptObject,EnumReferences), asCALL_THISCALL, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(asCScriptObject,ReleaseAllHandles), asCALL_THISCALL, 0); asASSERT( r >= 0 ); +#else + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTION(ScriptObject_Construct_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ADDREF, "void f()", asFUNCTION(ScriptObject_AddRef_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASE, "void f()", asFUNCTION(ScriptObject_Release_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterMethodToObjectType(&engine->scriptTypeBehaviours, "int &opAssign(int &in)", asFUNCTION(ScriptObject_Assignment_Generic), asCALL_GENERIC); asASSERT( r >= 0 ); + + // Weakref behaviours + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GET_WEAKREF_FLAG, "int &f()", asFUNCTION(ScriptObject_GetWeakRefFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + + // Register GC behaviours + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETREFCOUNT, "int f()", asFUNCTION(ScriptObject_GetRefCount_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_SETGCFLAG, "void f()", asFUNCTION(ScriptObject_SetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_GETGCFLAG, "bool f()", asFUNCTION(ScriptObject_GetFlag_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_ENUMREFS, "void f(int&in)", asFUNCTION(ScriptObject_EnumReferences_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); + r = engine->RegisterBehaviourToObjectType(&engine->scriptTypeBehaviours, asBEHAVE_RELEASEREFS, "void f(int&in)", asFUNCTION(ScriptObject_ReleaseAllHandles_Generic), asCALL_GENERIC, 0); asASSERT( r >= 0 ); +#endif +} + +void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self) +{ + new(self) asCScriptObject(objType); +} + +void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self) +{ + new(self) asCScriptObject(objType, false); +} + +asCScriptObject::asCScriptObject(asCObjectType *ot, bool doInitialize) +{ + refCount.set(1); + objType = ot; + objType->AddRef(); + isDestructCalled = false; + extra = 0; + hasRefCountReachedZero = false; + + // Notify the garbage collector of this object + if( objType->flags & asOBJ_GC ) + objType->engine->gc.AddScriptObjectToGC(this, objType); + + // Initialize members to zero. Technically we only need to zero the pointer + // members, but just the memset is faster than having to loop and check the datatypes + memset((void*)(this+1), 0, objType->size - sizeof(asCScriptObject)); + + if( doInitialize ) + { +#ifdef AS_NO_MEMBER_INIT + // When member initialization is disabled the constructor must make sure + // to allocate and initialize all members with the default constructor + for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = objType->properties[n]; + if( prop->type.IsObject() && !prop->type.IsObjectHandle() ) + { + if( prop->type.IsReference() || prop->type.GetTypeInfo()->flags & asOBJ_REF ) + { + asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); + if( prop->type.GetTypeInfo()->flags & asOBJ_SCRIPT_OBJECT ) + *ptr = (asPWORD)ScriptObjectFactory(prop->type.GetTypeInfo(), ot->engine); + else + *ptr = (asPWORD)AllocateUninitializedObject(prop->type.GetTypeInfo(), ot->engine); + } + } + } +#endif + } + else + { + // When the object is created without initialization, all non-handle members must be allocated, but not initialized + asCScriptEngine *engine = objType->engine; + for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = objType->properties[n]; + if( prop->type.IsObject() && !prop->type.IsObjectHandle() ) + { + if( prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF) ) + { + asPWORD *ptr = reinterpret_cast(reinterpret_cast(this) + prop->byteOffset); + *ptr = (asPWORD)AllocateUninitializedObject(CastToObjectType(prop->type.GetTypeInfo()), engine); + } + } + } + } +} + +void asCScriptObject::Destruct() +{ + // Call the destructor, which will also call the GCObject's destructor + this->~asCScriptObject(); + + // Free the memory +#ifndef WIP_16BYTE_ALIGN + userFree(this); +#else + // Script object memory is allocated through asCScriptEngine::CallAlloc() + // This free call must match the allocator used in CallAlloc(). + userFreeAligned(this); +#endif +} + +asCScriptObject::~asCScriptObject() +{ + if( extra ) + { + if( extra->weakRefFlag ) + { + extra->weakRefFlag->Release(); + extra->weakRefFlag = 0; + } + + if( objType->engine ) + { + // Clean the user data + for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 ) + { + if( extra->userData[n+1] ) + { + for( asUINT c = 0; c < objType->engine->cleanScriptObjectFuncs.GetLength(); c++ ) + if( objType->engine->cleanScriptObjectFuncs[c].type == extra->userData[n] ) + objType->engine->cleanScriptObjectFuncs[c].cleanFunc(this); + } + } + } + + asDELETE(extra, SExtra); + } + + // The engine pointer should be available from the objectType + asCScriptEngine *engine = objType->engine; + + // Destroy all properties + // In most cases the members are initialized in the order they have been declared, + // so it's safer to uninitialize them from last to first. The order may be different + // depending on the use of inheritance and or initialization in the declaration. + // TODO: Should the order of initialization be stored by the compiler so that the + // reverse order can be guaranteed during the destruction? + for( int n = (int)objType->properties.GetLength()-1; n >= 0; n-- ) + { + asCObjectProperty *prop = objType->properties[n]; + if( prop->type.IsObject() ) + { + // Destroy the object + asCObjectType *propType = CastToObjectType(prop->type.GetTypeInfo()); + if( prop->type.IsReference() || propType->flags & asOBJ_REF ) + { + void **ptr = (void**)(((char*)this) + prop->byteOffset); + if( *ptr ) + { + FreeObject(*ptr, propType, engine); + *(asDWORD*)ptr = 0; + } + } + else + { + // The object is allocated inline. As only POD objects may be allocated inline + // it is not a problem to call the destructor even if the object may never have + // been initialized, e.g. if an exception interrupted the constructor. + asASSERT( propType->flags & asOBJ_POD ); + + void *ptr = (void**)(((char*)this) + prop->byteOffset); + if( propType->beh.destruct ) + engine->CallObjectMethod(ptr, propType->beh.destruct); + } + } + else if( prop->type.IsFuncdef() ) + { + // Release the function descriptor + asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + (*ptr)->Release(); + *ptr = 0; + } + } + } + + objType->Release(); + objType = 0; + + // Something is really wrong if the refCount is not 0 by now + asASSERT( refCount.get() == 0 ); +} + +asILockableSharedBool *asCScriptObject::GetWeakRefFlag() const +{ + // If the object's refCount has already reached zero then the object is already + // about to be destroyed so it's ok to return null if the weakRefFlag doesn't already + // exist + if( (extra && extra->weakRefFlag) || hasRefCountReachedZero ) + return extra->weakRefFlag; + + // Lock globally so no other thread can attempt + // to create a shared bool at the same time. + // TODO: runtime optimize: Instead of locking globally, it would be possible to have + // a critical section per object type. This would reduce the + // chances of two threads lock on the same critical section. + asAcquireExclusiveLock(); + + // Make sure another thread didn't create the + // flag while we waited for the lock + if( !extra ) + extra = asNEW(SExtra); + if( !extra->weakRefFlag ) + extra->weakRefFlag = asNEW(asCLockableSharedBool); + + asReleaseExclusiveLock(); + + return extra->weakRefFlag; +} + +void *asCScriptObject::GetUserData(asPWORD type) const +{ + if( !extra ) + return 0; + + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + // TODO: runtime optimize: Would it be worth it to have a rwlock per object type? + asAcquireSharedLock(); + + for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 ) + { + if( extra->userData[n] == type ) + { + void *userData = reinterpret_cast(extra->userData[n+1]); + asReleaseSharedLock(); + return userData; + } + } + + asReleaseSharedLock(); + + return 0; +} + +void *asCScriptObject::SetUserData(void *data, asPWORD type) +{ + // Lock globally so no other thread can attempt + // to manipulate the extra data at the same time. + // TODO: runtime optimize: Instead of locking globally, it would be possible to have + // a critical section per object type. This would reduce the + // chances of two threads lock on the same critical section. + asAcquireExclusiveLock(); + + // Make sure another thread didn't create the + // flag while we waited for the lock + if( !extra ) + extra = asNEW(SExtra); + + // It is not intended to store a lot of different types of userdata, + // so a more complex structure like a associative map would just have + // more overhead than a simple array. + for( asUINT n = 0; n < extra->userData.GetLength(); n += 2 ) + { + if( extra->userData[n] == type ) + { + void *oldData = reinterpret_cast(extra->userData[n+1]); + extra->userData[n+1] = reinterpret_cast(data); + + asReleaseExclusiveLock(); + + return oldData; + } + } + + extra->userData.PushLast(type); + extra->userData.PushLast(reinterpret_cast(data)); + + asReleaseExclusiveLock(); + + return 0; +} + +asIScriptEngine *asCScriptObject::GetEngine() const +{ + return objType->engine; +} + +int asCScriptObject::AddRef() const +{ + // Warn in case the application tries to increase the refCount after it has reached zero. + // This may happen for example if the application calls a method on the class while it is + // being destroyed. The application shouldn't do this because it may cause application + // crashes if members that have already been destroyed are accessed accidentally. + if( hasRefCountReachedZero ) + { + if( objType && objType->engine ) + { + asCString msg; + msg.Format(TXT_RESURRECTING_SCRIPTOBJECT_s, objType->name.AddressOf()); + objType->engine->WriteMessage("", 0, 0, asMSGTYPE_ERROR, msg.AddressOf()); + } + } + + // Increase counter and clear flag set by GC + gcFlag = false; + return refCount.atomicInc(); +} + +int asCScriptObject::Release() const +{ + // Clear the flag set by the GC + gcFlag = false; + + // If the weak ref flag exists it is because someone held a weak ref + // and that someone may add a reference to the object at any time. It + // is ok to check the existance of the weakRefFlag without locking here + // because if the refCount is 1 then no other thread is currently + // creating the weakRefFlag. + if( refCount.get() == 1 && extra && extra->weakRefFlag ) + { + // Set the flag to tell others that the object is no longer alive + // We must do this before decreasing the refCount to 0 so we don't + // end up with a race condition between this thread attempting to + // destroy the object and the other that temporary added a strong + // ref from the weak ref. + extra->weakRefFlag->Set(true); + } + + // Call the script destructor behaviour if the reference counter is 1. + if( refCount.get() == 1 && !isDestructCalled ) + { + // This cast is OK since we are the last reference + const_cast(this)->CallDestructor(); + } + + // Now do the actual releasing + int r = refCount.atomicDec(); + if( r == 0 ) + { + // Flag this object as being destroyed so the application + // can be warned if the code attempts to resurrect the object + // during the destructor. This also avoids a recursive call + // to the destructor which would crash the application if it + // really does resurrect the object. + if( !hasRefCountReachedZero ) + { + hasRefCountReachedZero = true; + + // This cast is OK since we are the last reference + const_cast(this)->Destruct(); + } + return 0; + } + + return r; +} + +void asCScriptObject::CallDestructor() +{ + // Only allow the destructor to be called once + if( isDestructCalled ) return; + + asIScriptContext *ctx = 0; + bool isNested = false; + bool doAbort = false; + + // Make sure the destructor is called once only, even if the + // reference count is increased and then decreased again + isDestructCalled = true; + + // Call the destructor for this class and all the super classes + asCObjectType *ot = objType; + while( ot ) + { + int funcIndex = ot->beh.destruct; + if( funcIndex ) + { + if( ctx == 0 ) + { + // Check for active context first as it is quicker + // to reuse than to set up a new one. + ctx = asGetActiveContext(); + if( ctx ) + { + if( ctx->GetEngine() == objType->GetEngine() && ctx->PushState() == asSUCCESS ) + isNested = true; + else + ctx = 0; + } + + if( ctx == 0 ) + { + // Request a context from the engine + ctx = objType->engine->RequestContext(); + if( ctx == 0 ) + { + // TODO: How to best report this failure? + return; + } + } + } + + int r = ctx->Prepare(objType->engine->scriptFunctions[funcIndex]); + if( r >= 0 ) + { + ctx->SetObject(this); + + for(;;) + { + r = ctx->Execute(); + + // If the script tries to suspend itself just restart it + if( r != asEXECUTION_SUSPENDED ) + break; + } + + // Exceptions in the destructor will be ignored, as there is not much + // that can be done about them. However a request to abort the execution + // will be forwarded to the outer execution, in case of a nested call. + if( r == asEXECUTION_ABORTED ) + doAbort = true; + + // Observe, even though the current destructor was aborted or an exception + // occurred, we still try to execute the base class' destructor if available + // in order to free as many resources as possible. + } + } + + ot = ot->derivedFrom; + } + + if( ctx ) + { + if( isNested ) + { + ctx->PopState(); + + // Forward any request to abort the execution to the outer call + if( doAbort ) + ctx->Abort(); + } + else + { + // Return the context to engine + objType->engine->ReturnContext(ctx); + } + } +} + +asITypeInfo *asCScriptObject::GetObjectType() const +{ + return objType; +} + +int asCScriptObject::GetRefCount() +{ + return refCount.get(); +} + +void asCScriptObject::SetFlag() +{ + gcFlag = true; +} + +bool asCScriptObject::GetFlag() +{ + return gcFlag; +} + +// interface +int asCScriptObject::GetTypeId() const +{ + asCDataType dt = asCDataType::CreateType(objType, false); + return objType->engine->GetTypeIdFromDataType(dt); +} + +asUINT asCScriptObject::GetPropertyCount() const +{ + return asUINT(objType->properties.GetLength()); +} + +int asCScriptObject::GetPropertyTypeId(asUINT prop) const +{ + if( prop >= objType->properties.GetLength() ) + return asINVALID_ARG; + + return objType->engine->GetTypeIdFromDataType(objType->properties[prop]->type); +} + +const char *asCScriptObject::GetPropertyName(asUINT prop) const +{ + if( prop >= objType->properties.GetLength() ) + return 0; + + return objType->properties[prop]->name.AddressOf(); +} + +void *asCScriptObject::GetAddressOfProperty(asUINT prop) +{ + if( prop >= objType->properties.GetLength() ) + return 0; + + // Objects are stored by reference, so this must be dereferenced + asCDataType *dt = &objType->properties[prop]->type; + if( dt->IsObject() && !dt->IsObjectHandle() && + (dt->IsReference() || dt->GetTypeInfo()->flags & asOBJ_REF) ) + return *(void**)(((char*)this) + objType->properties[prop]->byteOffset); + + return (void*)(((char*)this) + objType->properties[prop]->byteOffset); +} + +void asCScriptObject::EnumReferences(asIScriptEngine *engine) +{ + // We'll notify the GC of all object handles that we're holding + for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = objType->properties[n]; + void *ptr = 0; + if (prop->type.IsObject()) + { + if (prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF)) + ptr = *(void**)(((char*)this) + prop->byteOffset); + else + ptr = (void*)(((char*)this) + prop->byteOffset); + + // The members of the value type needs to be enumerated + // too, since the value type may be holding a reference. + if ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && (prop->type.GetTypeInfo()->flags & asOBJ_GC)) + { + reinterpret_cast(engine)->CallObjectMethod(ptr, engine, CastToObjectType(prop->type.GetTypeInfo())->beh.gcEnumReferences); + } + } + else if (prop->type.IsFuncdef()) + ptr = *(void**)(((char*)this) + prop->byteOffset); + + if (ptr) + ((asCScriptEngine*)engine)->GCEnumCallback(ptr); + } +} + +void asCScriptObject::ReleaseAllHandles(asIScriptEngine *engine) +{ + for( asUINT n = 0; n < objType->properties.GetLength(); n++ ) + { + asCObjectProperty *prop = objType->properties[n]; + + if (prop->type.IsObject()) + { + if (prop->type.IsObjectHandle()) + { + void **ptr = (void**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + asASSERT((prop->type.GetTypeInfo()->flags & asOBJ_NOCOUNT) || prop->type.GetBehaviour()->release); + if (prop->type.GetBehaviour()->release) + ((asCScriptEngine*)engine)->CallObjectMethod(*ptr, prop->type.GetBehaviour()->release); + *ptr = 0; + } + } + else if ((prop->type.GetTypeInfo()->flags & asOBJ_VALUE) && (prop->type.GetTypeInfo()->flags & asOBJ_GC)) + { + // The members of the members needs to be released + // too, since they may be holding a reference. Even + // if the member is a value type. + void *ptr = 0; + if (prop->type.IsReference()) + ptr = *(void**)(((char*)this) + prop->byteOffset); + else + ptr = (void*)(((char*)this) + prop->byteOffset); + + reinterpret_cast(engine)->CallObjectMethod(ptr, engine, CastToObjectType(prop->type.GetTypeInfo())->beh.gcReleaseAllReferences); + } + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **ptr = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + if (*ptr) + { + (*ptr)->Release(); + *ptr = 0; + } + } + } +} + +asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self) +{ + return (*self = *other); +} + +asCScriptObject &asCScriptObject::operator=(const asCScriptObject &other) +{ + CopyFromAs(&other, objType); + return *this; +} + +// internal +int asCScriptObject::CopyFromAs(const asCScriptObject *other, asCObjectType *in_objType) +{ + if( other != this ) + { + if( !other->objType->DerivesFrom(in_objType) ) + { + // We cannot allow a value assignment from a type that isn't the same or + // derives from this type as the member properties may not have the same layout + asIScriptContext *ctx = asGetActiveContext(); + ctx->SetException(TXT_MISMATCH_IN_VALUE_ASSIGN); + return asERROR; + } + + // If the script class implements the opAssign method, it should be called + asCScriptEngine *engine = in_objType->engine; + asCScriptFunction *func = engine->scriptFunctions[in_objType->beh.copy]; + if( func->funcType == asFUNC_SYSTEM ) + { + // If derived, use the base class' assignment operator to copy the inherited + // properties. Then only copy new properties for the derived class + if( in_objType->derivedFrom ) + CopyFromAs(other, in_objType->derivedFrom); + + for( asUINT n = in_objType->derivedFrom ? in_objType->derivedFrom->properties.GetLength() : 0; + n < in_objType->properties.GetLength(); + n++ ) + { + asCObjectProperty *prop = in_objType->properties[n]; + if( prop->type.IsObject() ) + { + void **dst = (void**)(((char*)this) + prop->byteOffset); + void **src = (void**)(((char*)other) + prop->byteOffset); + if( !prop->type.IsObjectHandle() ) + { + if( prop->type.IsReference() || (prop->type.GetTypeInfo()->flags & asOBJ_REF) ) + CopyObject(*src, *dst, CastToObjectType(prop->type.GetTypeInfo()), engine); + else + CopyObject(src, dst, CastToObjectType(prop->type.GetTypeInfo()), engine); + } + else + CopyHandle((asPWORD*)src, (asPWORD*)dst, CastToObjectType(prop->type.GetTypeInfo()), engine); + } + else if (prop->type.IsFuncdef()) + { + asCScriptFunction **dst = (asCScriptFunction**)(((char*)this) + prop->byteOffset); + asCScriptFunction **src = (asCScriptFunction**)(((char*)other) + prop->byteOffset); + if (*dst) + (*dst)->Release(); + *dst = *src; + if (*dst) + (*dst)->AddRef(); + } + else + { + void *dst = ((char*)this) + prop->byteOffset; + void *src = ((char*)other) + prop->byteOffset; + memcpy(dst, src, prop->type.GetSizeInMemoryBytes()); + } + } + } + else + { + // Reuse the active context or create a new one to call the script class' opAssign method + asIScriptContext *ctx = 0; + int r = 0; + bool isNested = false; + + ctx = asGetActiveContext(); + if( ctx ) + { + if( ctx->GetEngine() == engine && ctx->PushState() == asSUCCESS ) + isNested = true; + else + ctx = 0; + } + + if( ctx == 0 ) + { + // Request a context from the engine + ctx = engine->RequestContext(); + if( ctx == 0 ) + return asERROR; + } + + r = ctx->Prepare(engine->scriptFunctions[in_objType->beh.copy]); + if( r < 0 ) + { + if( isNested ) + ctx->PopState(); + else + engine->ReturnContext(ctx); + return r; + } + + r = ctx->SetArgAddress(0, const_cast(other)); + asASSERT( r >= 0 ); + r = ctx->SetObject(this); + asASSERT( r >= 0 ); + + for(;;) + { + r = ctx->Execute(); + + // We can't allow this execution to be suspended + // so resume the execution immediately + if( r != asEXECUTION_SUSPENDED ) + break; + } + + if( r != asEXECUTION_FINISHED ) + { + if( isNested ) + { + ctx->PopState(); + + // If the execution was aborted or an exception occurred, + // then we should forward that to the outer execution. + if( r == asEXECUTION_EXCEPTION ) + { + // TODO: How to improve this exception + ctx->SetException(TXT_EXCEPTION_IN_NESTED_CALL); + } + else if( r == asEXECUTION_ABORTED ) + ctx->Abort(); + } + else + { + // Return the context to the engine + engine->ReturnContext(ctx); + } + return asERROR; + } + + if( isNested ) + ctx->PopState(); + else + { + // Return the context to the engine + engine->ReturnContext(ctx); + } + } + } + + return asSUCCESS; +} + +int asCScriptObject::CopyFrom(const asIScriptObject *other) +{ + if( other == 0 ) return asINVALID_ARG; + + if( GetTypeId() != other->GetTypeId() ) + return asINVALID_TYPE; + + *this = *(asCScriptObject*)other; + + return asSUCCESS; +} + +void *asCScriptObject::AllocateUninitializedObject(asCObjectType *in_objType, asCScriptEngine *engine) +{ + void *ptr = 0; + + if( in_objType->flags & asOBJ_SCRIPT_OBJECT ) + { + ptr = engine->CallAlloc(in_objType); + ScriptObject_ConstructUnitialized(in_objType, reinterpret_cast(ptr)); + } + else if( in_objType->flags & asOBJ_TEMPLATE ) + { + // Templates store the original factory that takes the object + // type as a hidden parameter in the construct behaviour + ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.construct, in_objType); + } + else if( in_objType->flags & asOBJ_REF ) + { + ptr = engine->CallGlobalFunctionRetPtr(in_objType->beh.factory); + } + else + { + ptr = engine->CallAlloc(in_objType); + int funcIndex = in_objType->beh.construct; + if( funcIndex ) + engine->CallObjectMethod(ptr, funcIndex); + } + + return ptr; +} + +void asCScriptObject::FreeObject(void *ptr, asCObjectType *in_objType, asCScriptEngine *engine) +{ + if( in_objType->flags & asOBJ_REF ) + { + asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || in_objType->beh.release ); + if(in_objType->beh.release ) + engine->CallObjectMethod(ptr, in_objType->beh.release); + } + else + { + if( in_objType->beh.destruct ) + engine->CallObjectMethod(ptr, in_objType->beh.destruct); + + engine->CallFree(ptr); + } +} + +void asCScriptObject::CopyObject(const void *src, void *dst, asCObjectType *in_objType, asCScriptEngine *engine) +{ + int funcIndex = in_objType->beh.copy; + if( funcIndex ) + { + asCScriptFunction *func = engine->scriptFunctions[in_objType->beh.copy]; + if( func->funcType == asFUNC_SYSTEM ) + engine->CallObjectMethod(dst, const_cast(src), funcIndex); + else + { + // Call the script class' opAssign method + asASSERT(in_objType->flags & asOBJ_SCRIPT_OBJECT ); + reinterpret_cast(dst)->CopyFrom(reinterpret_cast(src)); + } + } + else if( in_objType->size && (in_objType->flags & asOBJ_POD) ) + memcpy(dst, src, in_objType->size); +} + +void asCScriptObject::CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *in_objType, asCScriptEngine *engine) +{ + // asOBJ_NOCOUNT doesn't have addref or release behaviours + asASSERT( (in_objType->flags & asOBJ_NOCOUNT) || (in_objType->beh.release && in_objType->beh.addref) ); + + if( *dst && in_objType->beh.release ) + engine->CallObjectMethod(*(void**)dst, in_objType->beh.release); + *dst = *src; + if( *dst && in_objType->beh.addref ) + engine->CallObjectMethod(*(void**)dst, in_objType->beh.addref); +} + +// TODO: weak: Should move to its own file +asCLockableSharedBool::asCLockableSharedBool() : value(false) +{ + refCount.set(1); +} + +int asCLockableSharedBool::AddRef() const +{ + return refCount.atomicInc(); +} + +int asCLockableSharedBool::Release() const +{ + int r = refCount.atomicDec(); + if( r == 0 ) + asDELETE(const_cast(this), asCLockableSharedBool); + return r; +} + +bool asCLockableSharedBool::Get() const +{ + return value; +} + +void asCLockableSharedBool::Set(bool v) +{ + // Make sure the value is not changed while another thread + // is inspecting it and taking a decision on what to do. + Lock(); + value = v; + Unlock(); +} + +void asCLockableSharedBool::Lock() const +{ + ENTERCRITICALSECTION(lock); +} + +void asCLockableSharedBool::Unlock() const +{ + LEAVECRITICALSECTION(lock); +} + +// Interface +// Auxiliary function to allow applications to create shared +// booleans without having to implement the logic for them +AS_API asILockableSharedBool *asCreateLockableSharedBool() +{ + return asNEW(asCLockableSharedBool); +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_scriptobject.h b/angelscript/source/as_scriptobject.h new file mode 100644 index 0000000..77a435e --- /dev/null +++ b/angelscript/source/as_scriptobject.h @@ -0,0 +1,165 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_scriptobject.h +// +// A generic class for handling script declared structures +// + + + +#ifndef AS_SCRIPTOBJECT_H +#define AS_SCRIPTOBJECT_H + +#include "as_config.h" +#include "as_atomic.h" + +BEGIN_AS_NAMESPACE + +class asCObjectType; + +// TODO: Add const overload for GetAddressOfProperty + +// TODO: weak: Should move to its own file +class asCLockableSharedBool : public asILockableSharedBool +{ +public: + asCLockableSharedBool(); + int AddRef() const; + int Release() const; + + bool Get() const; + void Set(bool); + + void Lock() const; + void Unlock() const; + +protected: + mutable asCAtomic refCount; + bool value; + DECLARECRITICALSECTION(mutable lock) +}; + +class asCScriptObject : public asIScriptObject +{ +public: +//=================================== +// From asIScriptObject +//=================================== + + // Memory management + int AddRef() const; + int Release() const; + asILockableSharedBool *GetWeakRefFlag() const; + + // Type info + int GetTypeId() const; + asITypeInfo *GetObjectType() const; + + // Class properties + asUINT GetPropertyCount() const; + int GetPropertyTypeId(asUINT prop) const; + const char *GetPropertyName(asUINT prop) const; + void *GetAddressOfProperty(asUINT prop); + + // Miscellaneous + asIScriptEngine *GetEngine() const; + int CopyFrom(const asIScriptObject *other); + + // User data + void *SetUserData(void *data, asPWORD type = 0); + void *GetUserData(asPWORD type = 0) const; + +//==================================== +// Internal +//==================================== + asCScriptObject(asCObjectType *objType, bool doInitialize = true); + virtual ~asCScriptObject(); + + asCScriptObject &operator=(const asCScriptObject &other); + + // GC methods + void Destruct(); + int GetRefCount(); + void SetFlag(); + bool GetFlag(); + void EnumReferences(asIScriptEngine *engine); + void ReleaseAllHandles(asIScriptEngine *engine); + + // Used for properties + void *AllocateUninitializedObject(asCObjectType *objType, asCScriptEngine *engine); + void FreeObject(void *ptr, asCObjectType *objType, asCScriptEngine *engine); + void CopyObject(const void *src, void *dst, asCObjectType *objType, asCScriptEngine *engine); + void CopyHandle(asPWORD *src, asPWORD *dst, asCObjectType *objType, asCScriptEngine *engine); + int CopyFromAs(const asCScriptObject *other, asCObjectType *objType); + + void CallDestructor(); + +//============================================= +// Properties +//============================================= +protected: + friend class asCContext; + asCObjectType *objType; + + mutable asCAtomic refCount; + mutable asBYTE gcFlag:1; + mutable asBYTE hasRefCountReachedZero:1; + bool isDestructCalled; + + // Most script classes instances won't have neither the weakRefFlags nor + // userData so we only allocate this if requested. Even when used it is + // not something that will be accessed all the time so having the extra + // indirection will not affect the performance significantly. + struct SExtra + { + SExtra() : weakRefFlag(0) {}; + asCLockableSharedBool *weakRefFlag; + asCArray userData; + }; + mutable SExtra *extra; +}; + +void ScriptObject_Construct(asCObjectType *objType, asCScriptObject *self); +asCScriptObject &ScriptObject_Assignment(asCScriptObject *other, asCScriptObject *self); + +void ScriptObject_ConstructUnitialized(asCObjectType *objType, asCScriptObject *self); + +void RegisterScriptObject(asCScriptEngine *engine); + +asIScriptObject *ScriptObjectFactory(const asCObjectType *objType, asCScriptEngine *engine); +asIScriptObject *ScriptObjectCopyFactory(const asCObjectType *objType, void *origObj, asCScriptEngine *engine); + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_string.cpp b/angelscript/source/as_string.cpp new file mode 100644 index 0000000..8bd3edf --- /dev/null +++ b/angelscript/source/as_string.cpp @@ -0,0 +1,487 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +#include "as_config.h" + +#include // va_list, va_start(), etc +#include // strtod(), strtol() +#include // some compilers declare memcpy() here + +#if !defined(AS_NO_MEMORY_H) +#include +#endif + +#include "as_string.h" +#include "as_string_util.h" + +asCString::asCString() +{ + length = 0; + local[0] = 0; +} + +// Copy constructor +asCString::asCString(const asCString &str) +{ + length = 0; + local[0] = 0; + + Assign(str.AddressOf(), str.length); +} + +#ifdef AS_CAN_USE_CPP11 +asCString::asCString(asCString &&str) +{ + if( str.length <= 11 ) + { + length = str.length; + memcpy(local, str.local, length); + local[length] = 0; + } + else + { + dynamic = str.dynamic; + length = str.length; + } + + str.dynamic = 0; + str.length = 0; +} +#endif // c++11 + +asCString::asCString(const char *str, size_t len) +{ + length = 0; + local[0] = 0; + + Assign(str, len); +} + +asCString::asCString(const char *str) +{ + length = 0; + local[0] = 0; + + size_t len = strlen(str); + Assign(str, len); +} + +asCString::asCString(char ch) +{ + length = 0; + local[0] = 0; + + Assign(&ch, 1); +} + +asCString::~asCString() +{ + if( length > 11 && dynamic ) + { + asDELETEARRAY(dynamic); + } +} + +char *asCString::AddressOf() +{ + if( length <= 11 ) + return local; + else + return dynamic; +} + +const char *asCString::AddressOf() const +{ + if( length <= 11 ) + return local; + else + return dynamic; +} + +void asCString::SetLength(size_t len) +{ + Allocate(len, true); +} + +void asCString::Allocate(size_t len, bool keepData) +{ + // If we stored the capacity of the dynamically allocated buffer it would be possible + // to save some memory allocations if a string decreases in size then increases again, + // but this would require extra bytes in the string object itself, or a decrease of + // the static buffer, which in turn would mean extra memory is needed. I've tested each + // of these options, and it turned out that the current choice is what best balanced + // the number of allocations against the size of the allocations. + + if( len > 11 && len > length ) + { + // Allocate a new dynamic buffer if the new one is larger than the old + char *buf = asNEWARRAY(char,len+1); + if( buf == 0 ) + { + // Out of memory. Return without modifying anything + return; + } + + if( keepData ) + { + int l = (int)len < (int)length ? (int)len : (int)length; + memcpy(buf, AddressOf(), l); + } + + if( length > 11 ) + { + asDELETEARRAY(dynamic); + } + + dynamic = buf; + } + else if( len <= 11 && length > 11 ) + { + // Free the dynamic buffer, since it is no longer needed + char *buf = dynamic; + if( keepData ) + { + memcpy(&local, buf, len); + } + asDELETEARRAY(buf); + } + + length = (int)len; + + // Make sure the buffer is null terminated + AddressOf()[length] = 0; +} + +void asCString::Assign(const char *str, size_t len) +{ + Allocate(len, false); + + // Copy the string + memcpy(AddressOf(), str, length); + AddressOf()[length] = 0; +} + +asCString &asCString::operator =(const char *str) +{ + size_t len = str ? strlen(str) : 0; + Assign(str, len); + + return *this; +} + +asCString &asCString::operator =(const asCString &str) +{ + Assign(str.AddressOf(), str.length); + + return *this; +} + +#ifdef AS_CAN_USE_CPP11 +asCString &asCString::operator =(asCString &&str) +{ + if( this != &str ) + { + if( length > 11 && dynamic ) + { + asDELETEARRAY(dynamic); + } + + if ( str.length <= 11 ) + { + length = str.length; + + memcpy(local, str.local, length); + local[length] = 0; + } + else + { + dynamic = str.dynamic; + length = str.length; + } + + str.dynamic = 0; + str.length = 0; + } + + return *this; +} +#endif // c++11 + +asCString &asCString::operator =(char ch) +{ + Assign(&ch, 1); + + return *this; +} + +void asCString::Concatenate(const char *str, size_t len) +{ + asUINT oldLength = length; + SetLength(length + len); + + memcpy(AddressOf() + oldLength, str, len); + AddressOf()[length] = 0; +} + +asCString &asCString::operator +=(const char *str) +{ + size_t len = strlen(str); + Concatenate(str, len); + + return *this; +} + +asCString &asCString::operator +=(const asCString &str) +{ + Concatenate(str.AddressOf(), str.length); + + return *this; +} + +asCString &asCString::operator +=(char ch) +{ + Concatenate(&ch, 1); + + return *this; +} + +size_t asCString::GetLength() const +{ + return length; +} + +// Returns the length +size_t asCString::Format(const char *format, ...) +{ + va_list args; + va_start(args, format); + + const size_t startSize = 1024; + char tmp[startSize]; + int r = asVSNPRINTF(tmp, startSize-1, format, args); + + if( r > 0 && r < int(startSize) ) + { + Assign(tmp, r); + } + else + { + // TODO: For some reason this doesn't work properly on Linux. Perhaps the + // problem is related to vsnprintf not keeping the state of va_arg. + // Perhaps I need to rewrite this in some way to keep the state + size_t n = startSize*2; + asCString str; // Use temporary string in case the current buffer is a parameter + str.Allocate(n, false); + + while( (r = asVSNPRINTF(str.AddressOf(), n, format, args)) < 0 || r >= int(n) ) + { + n *= 2; + str.Allocate(n, false); + } + + Assign(str.AddressOf(), r); + } + + va_end(args); + + return length; +} + +char &asCString::operator [](size_t index) +{ + asASSERT(index < length); + + return AddressOf()[index]; +} + +const char &asCString::operator [](size_t index) const +{ + asASSERT(index < length); + + return AddressOf()[index]; +} + +asCString asCString::SubString(size_t in_start, size_t in_length) const +{ + if( in_start >= GetLength() || in_length == 0 ) + return asCString(""); + + if( in_length == (size_t)(-1) ) in_length = GetLength() - in_start; + + asCString tmp; + tmp.Assign(AddressOf() + in_start, in_length); + + return tmp; +} + +int asCString::Compare(const char *str) const +{ + return asCompareStrings(AddressOf(), length, str, strlen(str)); +} + +int asCString::Compare(const asCString &str) const +{ + return asCompareStrings(AddressOf(), length, str.AddressOf(), str.GetLength()); +} + +int asCString::Compare(const char *str, size_t len) const +{ + return asCompareStrings(AddressOf(), length, str, len); +} + +size_t asCString::RecalculateLength() +{ + SetLength(strlen(AddressOf())); + + return length; +} + +int asCString::FindLast(const char *str, int *count) const +{ + // There is no strstr that starts from the end, so + // we'll iterate until we find the last occurrance. + // This shouldn't cause a performance problem because + // it is not expected that this will be done very often, + // and then only on quite short strings anyway. + + if( count ) *count = 0; + + const char *last = 0; + const char *curr = AddressOf()-1; + while( (curr = strstr(curr+1, str)) != 0 ) + { + if( count ) (*count)++; + last = curr; + } + + if( last ) + return int(last - AddressOf()); + + return -1; +} + +//----------------------------------------------------------------------------- +// Helper functions + +bool operator ==(const asCString &a, const char *b) +{ + return a.Compare(b) == 0; +} + +bool operator !=(const asCString &a, const char *b) +{ + return a.Compare(b) != 0; +} + +bool operator ==(const asCString &a, const asCString &b) +{ + return a.Compare(b) == 0; +} + +bool operator !=(const asCString &a, const asCString &b) +{ + return a.Compare(b) != 0; +} + +bool operator ==(const char *a, const asCString &b) +{ + return b.Compare(a) == 0; +} + +bool operator !=(const char *a, const asCString &b) +{ + return b.Compare(a) != 0; +} + +bool operator <(const asCString &a, const asCString &b) +{ + return a.Compare(b) < 0; +} + +asCString operator +(const asCString &a, const asCString &b) +{ + asCString res = a; + res += b; + + return res; +} + +asCString operator +(const char *a, const asCString &b) +{ + asCString res = a; + res += b; + + return res; +} + +asCString operator +(const asCString &a, const char *b) +{ + asCString res = a; + res += b; + + return res; +} + +// wrapper class + +asCStringPointer::asCStringPointer() + : string(0), length(0), cstring(0) +{ +} + +asCStringPointer::asCStringPointer(const char *str, size_t len) + : string(str), length(len), cstring(0) +{ +} + +asCStringPointer::asCStringPointer(asCString *cstr) + : string(0), length(0), cstring(cstr) +{ +} + +const char *asCStringPointer::AddressOf() const +{ + return string ? string : cstring->AddressOf(); +} + +size_t asCStringPointer::GetLength() const +{ + return string ? length : cstring->GetLength(); +} + +bool asCStringPointer::operator==(const asCStringPointer& other) const +{ + return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) == 0; +} + +bool asCStringPointer::operator<(const asCStringPointer& other) const +{ + return asCompareStrings(AddressOf(), GetLength(), other.AddressOf(), other.GetLength()) < 0; +} diff --git a/angelscript/source/as_string.h b/angelscript/source/as_string.h new file mode 100644 index 0000000..0ee7469 --- /dev/null +++ b/angelscript/source/as_string.h @@ -0,0 +1,134 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2014 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + +// This class has been designed to be easy to use, but not necessarily efficiency. +// It doesn't use shared string memory, or reference counting. It keeps track of +// string length, memory size. It also makes sure that the string is null-terminated. + +#ifndef AS_STRING_H +#define AS_STRING_H + +#include +#include + +class asCString +{ +public: + asCString(); + ~asCString(); + +#ifdef AS_CAN_USE_CPP11 + asCString(asCString &&); + asCString &operator =(asCString &&); +#endif // c++11 + + asCString(const asCString &); + asCString(const char *); + asCString(const char *, size_t length); + explicit asCString(char); + + void Allocate(size_t len, bool keepData); + void SetLength(size_t len); + size_t GetLength() const; + + void Concatenate(const char *str, size_t length); + asCString &operator +=(const asCString &); + asCString &operator +=(const char *); + asCString &operator +=(char); + + void Assign(const char *str, size_t length); + asCString &operator =(const asCString &); + asCString &operator =(const char *); + asCString &operator =(char); + + asCString SubString(size_t start, size_t length = (size_t)(-1)) const; + + int FindLast(const char *str, int *count = 0) const; + + size_t Format(const char *fmt, ...); + + int Compare(const char *str) const; + int Compare(const asCString &str) const; + int Compare(const char *str, size_t length) const; + + char *AddressOf(); + const char *AddressOf() const; + char &operator [](size_t index); + const char &operator[](size_t index) const; + size_t RecalculateLength(); + +protected: + unsigned int length; + union + { + char *dynamic; + char local[12]; + }; +}; + +// Helper functions + +bool operator ==(const asCString &, const asCString &); +bool operator !=(const asCString &, const asCString &); + +bool operator ==(const asCString &, const char *); +bool operator !=(const asCString &, const char *); + +bool operator ==(const char *, const asCString &); +bool operator !=(const char *, const asCString &); + +bool operator <(const asCString &, const asCString &); + +asCString operator +(const asCString &, const char *); +asCString operator +(const char *, const asCString &); +asCString operator +(const asCString &, const asCString &); + +// a wrapper for using the pointer of asCString in asCMap +class asCStringPointer +{ +public: + asCStringPointer(); + asCStringPointer(const char *str, size_t len); + asCStringPointer(asCString *cstr); + + const char *AddressOf() const; + size_t GetLength() const; + + bool operator==(const asCStringPointer& other) const; + bool operator<(const asCStringPointer& other) const; + +private: + // Either string/length or cstring is stored + const char *string; + size_t length; + asCString *cstring; +}; + +#endif diff --git a/angelscript/source/as_string_util.cpp b/angelscript/source/as_string_util.cpp new file mode 100644 index 0000000..32edbed --- /dev/null +++ b/angelscript/source/as_string_util.cpp @@ -0,0 +1,383 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com + +*/ + +#include "as_config.h" + +#include // some compilers declare memcpy() here +#include // pow() + +#if !defined(AS_NO_MEMORY_H) +#include +#endif + +#include "as_string.h" +#include "as_string_util.h" + +BEGIN_AS_NAMESPACE + +int asCompareStrings(const char *str1, size_t len1, const char *str2, size_t len2) +{ + if( len1 == 0 ) + { + if( str2 == 0 || len2 == 0 ) return 0; // Equal + + return 1; // The other string is larger than this + } + + if( str2 == 0 ) + { + if( len1 == 0 ) + return 0; // Equal + + return -1; // The other string is smaller than this + } + + if( len2 < len1 ) + { + int result = memcmp(str1, str2, len2); + if( result == 0 ) return -1; // The other string is smaller than this + + return result; + } + + int result = memcmp(str1, str2, len1); + if( result == 0 && len1 < len2 ) return 1; // The other string is larger than this + + return result; +} + +double asStringScanDouble(const char *string, size_t *numScanned) +{ + // I decided to do my own implementation of strtod() because this function + // doesn't seem to be present on all systems. iOS 5 for example doesn't appear + // to include the function in the standard lib. + + // Another reason is that the standard implementation of strtod() is dependent + // on the locale on some systems, i.e. it may use comma instead of dot for + // the decimal indicator. This can be avoided by forcing the locale to "C" with + // setlocale(), but this is another thing that is highly platform dependent. + + double value = 0; + double fraction = 0.1; + int exponent = 0; + bool negativeExponent = false; + int c = 0; + + // The tokenizer separates the sign from the number in + // two tokens so we'll never have a sign to parse here + + // Parse the integer value + for( ;; ) + { + if( string[c] >= '0' && string[c] <= '9' ) + value = value*10 + double(string[c] - '0'); + else + break; + + c++; + } + + if( string[c] == '.' ) + { + c++; + + // Parse the fraction + for( ;; ) + { + if( string[c] >= '0' && string[c] <= '9' ) + value += fraction * double(string[c] - '0'); + else + break; + + c++; + fraction *= 0.1; + } + } + + if( string[c] == 'e' || string[c] == 'E' ) + { + c++; + + // Parse the sign of the exponent + if( string[c] == '-' ) + { + negativeExponent = true; + c++; + } + else if( string[c] == '+' ) + c++; + + // Parse the exponent value + for( ;; ) + { + if( string[c] >= '0' && string[c] <= '9' ) + exponent = exponent*10 + int(string[c] - '0'); + else + break; + + c++; + } + } + + if( exponent ) + { + if( negativeExponent ) + exponent = -exponent; + value *= pow(10.0, exponent); + } + + if( numScanned ) + *numScanned = c; + + return value; +} + +// Converts a character to the decimal number based on the radix +// Returns -1 if the character is not valid for the radix +static int asCharToNbr(char ch, int radix) +{ + if( ch >= '0' && ch <= '9' ) return ((ch -= '0') < radix ? ch : -1); + if( ch >= 'A' && ch <= 'Z' ) return ((ch -= 'A'-10) < radix ? ch : -1); + if( ch >= 'a' && ch <= 'z' ) return ((ch -= 'a'-10) < radix ? ch : -1); + return -1; +} + +// If base is 0 the string should be prefixed by 0x, 0d, 0o, or 0b to allow the function to automatically determine the radix +asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned, bool *overflow) +{ + asASSERT(base == 10 || base == 16 || base == 0); + + if (overflow) + *overflow = false; + + const char *end = string; + + static const asQWORD QWORD_MAX = (~asQWORD(0)); + + asQWORD res = 0; + if( base == 10 ) + { + while( *end >= '0' && *end <= '9' ) + { + if( overflow && ((res > QWORD_MAX / 10) || ((asUINT(*end - '0') > (QWORD_MAX - (QWORD_MAX / 10) * 10)) && res == QWORD_MAX / 10)) ) + *overflow = true; + res *= 10; + res += *end++ - '0'; + } + } + else + { + if( base == 0 && string[0] == '0') + { + // Determine the radix from the prefix + switch( string[1] ) + { + case 'b': case 'B': base = 2; break; + case 'o': case 'O': base = 8; break; + case 'd': case 'D': base = 10; break; + case 'x': case 'X': base = 16; break; + } + end += 2; + } + + asASSERT( base ); + + if( base ) + { + for (int nbr; (nbr = asCharToNbr(*end, base)) >= 0; end++) + { + if (overflow && ((res > QWORD_MAX / base) || ((asUINT(nbr) > (QWORD_MAX - (QWORD_MAX / base) * base)) && res == QWORD_MAX / base)) ) + *overflow = true; + + res = res * base + nbr; + } + } + } + + if( numScanned ) + *numScanned = end - string; + + return res; +} + +// +// The function will encode the unicode code point into the outEncodedBuffer, and then +// return the length of the encoded value. If the input value is not a valid unicode code +// point, then the function will return -1. +// +// This function is taken from the AngelCode ToolBox. +// +int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer) +{ + unsigned char *buf = (unsigned char*)outEncodedBuffer; + + int length = -1; + + if( value <= 0x7F ) + { + buf[0] = static_cast(value); + return 1; + } + else if( value >= 0x80 && value <= 0x7FF ) + { + // Encode it with 2 characters + buf[0] = static_cast(0xC0 + (value >> 6)); + length = 2; + } + else if( (value >= 0x800 && value <= 0xD7FF) || (value >= 0xE000 && value <= 0xFFFF) ) + { + // Note: Values 0xD800 to 0xDFFF are not valid unicode characters + buf[0] = static_cast(0xE0 + (value >> 12)); + length = 3; + } + else if( value >= 0x10000 && value <= 0x10FFFF ) + { + buf[0] = static_cast(0xF0 + (value >> 18)); + length = 4; + } + + int n = length-1; + for( ; n > 0; n-- ) + { + buf[n] = static_cast(0x80 + (value & 0x3F)); + value >>= 6; + } + + return length; +} + +// +// The function will decode an UTF8 character and return the unicode code point. +// outLength will receive the number of bytes that were decoded. +// +// This function is taken from the AngelCode ToolBox. +// +int asStringDecodeUTF8(const char *encodedBuffer, unsigned int *outLength) +{ + const unsigned char *buf = (const unsigned char*)encodedBuffer; + + int value = 0; + int length = -1; + unsigned char byte = buf[0]; + if( (byte & 0x80) == 0 ) + { + // This is the only byte + if( outLength ) *outLength = 1; + return byte; + } + else if( (byte & 0xE0) == 0xC0 ) + { + // There is one more byte + value = int(byte & 0x1F); + length = 2; + + // The value at this moment must not be less than 2, because + // that should have been encoded with one byte only. + if( value < 2 ) + length = -1; + } + else if( (byte & 0xF0) == 0xE0 ) + { + // There are two more bytes + value = int(byte & 0x0F); + length = 3; + } + else if( (byte & 0xF8) == 0xF0 ) + { + // There are three more bytes + value = int(byte & 0x07); + length = 4; + } + + int n = 1; + for( ; n < length; n++ ) + { + byte = buf[n]; + if( (byte & 0xC0) == 0x80 ) + value = (value << 6) + int(byte & 0x3F); + else + break; + } + + if( n == length ) + { + if( outLength ) *outLength = (unsigned)length; + return value; + } + + // The byte sequence isn't a valid UTF-8 byte sequence. + return -1; +} + +// +// The function will encode the unicode code point into the outEncodedBuffer, and then +// return the length of the encoded value. If the input value is not a valid unicode code +// point, then the function will return -1. +// +// This function is taken from the AngelCode ToolBox. +// +int asStringEncodeUTF16(unsigned int value, char *outEncodedBuffer) +{ + if( value < 0x10000 ) + { +#ifndef AS_BIG_ENDIAN + outEncodedBuffer[0] = (value & 0xFF); + outEncodedBuffer[1] = ((value >> 8) & 0xFF); +#else + outEncodedBuffer[1] = (value & 0xFF); + outEncodedBuffer[0] = ((value >> 8) & 0xFF); +#endif + return 2; + } + else + { + value -= 0x10000; + int surrogate1 = ((value >> 10) & 0x3FF) + 0xD800; + int surrogate2 = (value & 0x3FF) + 0xDC00; + +#ifndef AS_BIG_ENDIAN + outEncodedBuffer[0] = (surrogate1 & 0xFF); + outEncodedBuffer[1] = ((surrogate1 >> 8) & 0xFF); + outEncodedBuffer[2] = (surrogate2 & 0xFF); + outEncodedBuffer[3] = ((surrogate2 >> 8) & 0xFF); +#else + outEncodedBuffer[1] = (surrogate1 & 0xFF); + outEncodedBuffer[0] = ((surrogate1 >> 8) & 0xFF); + outEncodedBuffer[3] = (surrogate2 & 0xFF); + outEncodedBuffer[2] = ((surrogate2 >> 8) & 0xFF); +#endif + + return 4; + } +} + + +END_AS_NAMESPACE diff --git a/angelscript/source/as_string_util.h b/angelscript/source/as_string_util.h new file mode 100644 index 0000000..29174df --- /dev/null +++ b/angelscript/source/as_string_util.h @@ -0,0 +1,51 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2016 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +#ifndef AS_STRING_UTIL_H +#define AS_STRING_UTIL_H + +#include "as_config.h" + +BEGIN_AS_NAMESPACE + +int asCompareStrings(const char *str1, size_t len1, const char *str2, size_t len2); + +double asStringScanDouble(const char *string, size_t *numScanned); +asQWORD asStringScanUInt64(const char *string, int base, size_t *numScanned, bool *overflow); + +int asStringEncodeUTF8(unsigned int value, char *outEncodedBuffer); +int asStringDecodeUTF8(const char *encodedBuffer, unsigned int *outLength); + +int asStringEncodeUTF16(unsigned int value, char *outEncodedBuffer); + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_symboltable.h b/angelscript/source/as_symboltable.h new file mode 100644 index 0000000..11a7115 --- /dev/null +++ b/angelscript/source/as_symboltable.h @@ -0,0 +1,567 @@ +/* + AngelCode Scripting Library + Copyright (c) 2012-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_symboltable.h +// +// Created on: Jun 19, 2012 +// Author: Markus Lenger, a.k.a. mlengerx +// +// This class is used for fast symbol lookups while parsing or loading bytecode +// + +#ifndef AS_SYMBOLTABLE_H +#define AS_SYMBOLTABLE_H + +#include "as_config.h" +#include "as_memory.h" +#include "as_string.h" +#include "as_map.h" +#include "as_datatype.h" +#include "as_namespace.h" + + +BEGIN_AS_NAMESPACE + + + + + +// Interface to avoid nested templates which is not well supported by older compilers, e.g. MSVC6 +struct asIFilter +{ + virtual bool operator()(const void*) const = 0; + virtual ~asIFilter() {}; +}; + + + + +// forward declaration +template +class asCSymbolTable; + + + + +// Iterator that allows iterating in index order +template +class asCSymbolTableIterator +{ +public: + T2* operator*() const; + T2* operator->() const; + asCSymbolTableIterator& operator++(int); + asCSymbolTableIterator& operator--(int); + operator bool() const; + int GetIndex() const { return m_idx; } + +private: + friend class asCSymbolTable; + asCSymbolTableIterator(asCSymbolTable *table); + + void Next(); + void Previous(); + + asCSymbolTable* m_table; + unsigned int m_idx; +}; + + + + +// Symbol table mapping namespace + name to symbols +// The structure keeps the entries indexed in an array so the indices will not change +// There is also a map for a quick lookup. The map supports multiple entries with the same name +template +class asCSymbolTable +{ +public: + typedef asCSymbolTableIterator iterator; + typedef asCSymbolTableIterator const_iterator; + + asCSymbolTable(asUINT initialCapacity = 0); + + int GetFirstIndex(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const; + int GetFirstIndex(const asSNameSpace *ns, const asCString &name) const; + int GetLastIndex() const; + + int GetIndex(const T*) const; + + T* GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comparator) const; + T* GetFirst(const asSNameSpace *ns, const asCString &name); + const T* GetFirst(const asSNameSpace *ns, const asCString &name) const; + T* Get(asUINT index); + const T* Get(asUINT index) const; + T* GetLast(); + const T* GetLast() const; + + const asCArray &GetIndexes(const asSNameSpace *ns, const asCString &name) const; + + asUINT Put(T* entry); + + asUINT GetSize() const; + + void SwapWith(asCSymbolTable &other); + + void Clear(); + bool Erase(asUINT idx); + void Allocate(asUINT elem_cnt, bool keep_data); + + iterator List(); + const_iterator List() const; + +private: + // Don't allow assignment + asCSymbolTable& operator=(const asCSymbolTable &other) { return *this; } + + friend class asCSymbolTableIterator; + friend class asCSymbolTableIterator; + + void GetKey(const T *entry, asSNameSpaceNamePair &key) const; + bool CheckIdx(asUINT idx) const; + + asCMap > m_map; + asCArray m_entries; + unsigned int m_size; +}; + + + + +template +void asCSymbolTable::SwapWith(asCSymbolTable &other) +{ + m_map.SwapWith(other.m_map); + m_entries.SwapWith(other.m_entries); + + asUINT tmp = m_size; + m_size = other.m_size; + other.m_size = tmp; +} + + + + +// Constructor +// initialCapacity gives the number of entries to allocate in advance +template +asCSymbolTable::asCSymbolTable(asUINT initialCapacity) : m_entries(initialCapacity) +{ + m_size = 0; +} + + + +template +int asCSymbolTable::GetFirstIndex( + const asSNameSpace *ns, + const asCString &name, + const asIFilter &filter) const +{ + asSNameSpaceNamePair key(ns, name); + + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + { + const asCArray &arr = m_map.GetValue(cursor); + for( asUINT n = 0; n < arr.GetLength(); n++ ) + { + T *entry = m_entries[arr[n]]; + if( entry && filter(entry) ) + return arr[n]; + } + } + + return -1; +} + + + +template +const asCArray &asCSymbolTable::GetIndexes(const asSNameSpace *ns, const asCString &name) const +{ + asSNameSpaceNamePair key(ns, name); + + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + return m_map.GetValue(cursor); + + static asCArray dummy; + return dummy; +} + + + + +template +T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name, const asIFilter &comp) const +{ + int idx = GetFirstIndex(ns, name, comp); + if (idx != -1) return m_entries[idx]; + return 0; +} + + + + +template +int asCSymbolTable::GetFirstIndex(const asSNameSpace *ns, const asCString &name) const +{ + asSNameSpaceNamePair key(ns, name); + + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + return m_map.GetValue(cursor)[0]; + + return -1; +} + + + + +// Find the index of a certain symbol +// ATTENTION: this function has linear runtime complexity O(n)!! +template +int asCSymbolTable::GetIndex(const T* entry) const +{ + for( asUINT n = 0; n < m_entries.GetLength(); n++ ) + if( m_entries[n] == entry ) + return n; + + return -1; +} + + + + + + +template +T* asCSymbolTable::Get(asUINT idx) +{ + if( !CheckIdx(idx) ) + return 0; + + return m_entries[idx]; +} + +template +const T* asCSymbolTable::Get(asUINT idx) const +{ + return const_cast< asCSymbolTable* >(this)->Get(idx); +} + + + + + +template +T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name) +{ + int idx = GetFirstIndex(ns, name); + return Get(idx); +} + +template +const T* asCSymbolTable::GetFirst(const asSNameSpace *ns, const asCString &name) const +{ + return const_cast< asCSymbolTable* >(this)->GetFirst(ns, name); +} + + + + + +template +T* asCSymbolTable::GetLast() +{ + return Get(GetLastIndex()); +} + +template +const T* asCSymbolTable::GetLast() const +{ + return const_cast< asCSymbolTable* >(this)->GetLast(); +} + + + + + +// Clear the symbol table +// ATTENTION: The contained symbols are not rleased. This is up to the client +template +void asCSymbolTable::Clear() +{ + m_entries.SetLength(0); + m_map.EraseAll(); + m_size = 0; +} + + + + +// Pre-allocate slots for elemCnt entries +template +void asCSymbolTable::Allocate(asUINT elemCnt, bool keepData) +{ + asASSERT( elemCnt >= m_entries.GetLength() ); + m_entries.Allocate(elemCnt, keepData); + if( !keepData ) + m_map.EraseAll(); +} + + + +template +bool asCSymbolTable::Erase(asUINT idx) +{ + if( !CheckIdx(idx) ) + { + asASSERT(false); + return false; + } + + T *entry = m_entries[idx]; + asASSERT(entry); + if( !entry ) + return false; + + // Remove the symbol from the lookup map + asSNameSpaceNamePair key; + GetKey(entry, key); + + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + { + asCArray &arr = m_map.GetValue(cursor); + arr.RemoveValue(idx); + if( arr.GetLength() == 0 ) + m_map.Erase(cursor); + } + else + asASSERT(false); + + // Remove the symbol from the indexed array + if( idx == m_entries.GetLength() - 1 ) + m_entries.PopLast(); + else + { + // Must keep the array packed + int prevIdx = int(m_entries.GetLength()-1); + m_entries[idx] = m_entries.PopLast(); + + // Update the index in the lookup map + entry = m_entries[idx]; + GetKey(entry, key); + if( m_map.MoveTo(&cursor, key) ) + { + asCArray &arr = m_map.GetValue(cursor); + arr[arr.IndexOf(prevIdx)] = idx; + } + else + asASSERT(false); + } + m_size--; + + return true; +} + + + + +template +asUINT asCSymbolTable::Put(T *entry) +{ + asUINT idx = m_entries.GetLength(); + asSNameSpaceNamePair key; + GetKey(entry, key); + + asSMapNode > *cursor; + if( m_map.MoveTo(&cursor, key) ) + m_map.GetValue(cursor).PushLast(idx); + else + { + asCArray arr(1); + arr.PushLast(idx); + m_map.Insert(key, arr); + } + + m_entries.PushLast(entry); + m_size++; + return idx; +} + + + + +// Return key for specified symbol (namespace and name are used to generate the key) +template +void asCSymbolTable::GetKey(const T *entry, asSNameSpaceNamePair &key) const +{ + key = asSNameSpaceNamePair(entry->nameSpace, entry->name); +} + + + + +template +asUINT asCSymbolTable::GetSize() const +{ + return m_size; +} + + + + +template +bool asCSymbolTable::CheckIdx(asUINT idx) const +{ + return idx < m_entries.GetLength(); +} + + + + +template +int asCSymbolTable::GetLastIndex() const +{ + int idx = int(m_entries.GetLength()) - 1; + asASSERT( idx == -1 || m_entries[idx] ); + return idx; +} + + + + +template +asCSymbolTableIterator asCSymbolTable::List() +{ + return asCSymbolTableIterator(this); +} + + + + +template +typename asCSymbolTable::const_iterator asCSymbolTable::List() const +{ + return asCSymbolTableIterator(const_cast< asCSymbolTable *>(this)); +} + + +///////////////////////////////////////////////////////////////////////////////////////////////// +// Iterator + + +template +asCSymbolTableIterator::asCSymbolTableIterator(asCSymbolTable *table) : m_table(table), m_idx(0) +{ + asUINT sz = m_table->m_entries.GetLength(); + while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) + m_idx++; +} + + + +template +T2* asCSymbolTableIterator::operator*() const +{ + asASSERT(m_table->CheckIdx(m_idx)); + return m_table->m_entries[m_idx]; +} + + + +template +T2* asCSymbolTableIterator::operator->() const +{ + asASSERT(m_table->CheckIdx(m_idx)); + return m_table->m_entries[m_idx]; +} + + + +template +asCSymbolTableIterator& asCSymbolTableIterator::operator++(int) +{ + Next(); + return *this; +} + + + +// Return true if more elements are following +// ATTENTION: When deleting the object currently pointed to by this iterator this +// method returns false even though there might be more elements in the list +template +asCSymbolTableIterator::operator bool() const +{ + return m_idx < m_table->m_entries.GetLength() && m_table->m_entries[m_idx] != 0; +} + + + +template +void asCSymbolTableIterator::Next() +{ + asUINT sz = m_table->m_entries.GetLength(); + m_idx++; + while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) + m_idx++; +} + + + +template +void asCSymbolTableIterator::Previous() +{ + // overflow on stepping over first element + asUINT sz = m_table->m_entries.GetLength(); + m_idx--; + while( m_idx < sz && m_table->m_entries[m_idx] == 0 ) + m_idx--; +} + + + +template +asCSymbolTableIterator& asCSymbolTableIterator::operator--(int) +{ + Previous(); + return *this; +} + + +END_AS_NAMESPACE + +#endif // AS_SYMBOLTABLE_H diff --git a/angelscript/source/as_texts.h b/angelscript/source/as_texts.h new file mode 100644 index 0000000..8a7acc7 --- /dev/null +++ b/angelscript/source/as_texts.h @@ -0,0 +1,402 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_texts.h +// +// These are text strings used through out the library +// + + +#ifndef AS_TEXTS_H +#define AS_TEXTS_H + +// Compiler messages + +#define TXT_s_ALREADY_DECLARED "'%s' is already declared" +#define TXT_ABSTRACT_CLASS_s_CANNOT_BE_INSTANTIATED "Abstract class '%s' cannot be instantiated" +#define TXT_ACCESSING_PRIVATE_PROP_s "Accessing private property '%s' of parent class" +#define TXT_ARG_NOT_LVALUE "Output argument expression is not assignable" +#define TXT_ATTR_s_INFORMED_MULTIPLE_TIMES "Attribute '%s' informed multiple times" +#define TXT_AUTO_NOT_ALLOWED "Auto is not allowed here" + +#define TXT_BOTH_MUST_BE_SAME "Both expressions must have the same type" +#define TXT_BOTH_CONDITIONS_MUST_CALL_CONSTRUCTOR "Both conditions must call constructor" +#define TEXT_BASE_DOESNT_HAVE_DEF_CONSTR "Base class doesn't have default constructor. Make explicit call to base constructor" + +#define TXT_CANDIDATES_ARE "Candidates are:" +#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_LOOPS "Can't call a constructor in loops" +#define TXT_CANNOT_CALL_CONSTRUCTOR_IN_SWITCH "Can't call a constructor in switch" +#define TXT_CANNOT_CALL_CONSTRUCTOR_TWICE "Can't call a constructor multiple times" +#define TXT_CANNOT_CREATE_DELEGATE_FOR_NOREF_TYPES "Can't create delegate for types that do not support handles" +#define TXT_CANNOT_IMPLEMENT_SELF "Can't implement itself, or another interface that implements this interface" +#define TXT_CANNOT_INHERIT_FROM_s_FINAL "Can't inherit from class '%s' marked as final" +#define TXT_CANNOT_INHERIT_FROM_MULTIPLE_CLASSES "Can't inherit from multiple classes" +#define TXT_CANNOT_INHERIT_FROM_SELF "Can't inherit from itself, or another class that inherits from this class" +#define TXT_CANNOT_PASS_CLASS_METHOD_AS_ARG "Can't pass class method as arg directly. Use a delegate object instead" +#define TXT_CANNOT_RESOLVE_AUTO "Unable to resolve auto type" +#define TXT_CANNOT_ACCESS_NON_STATIC_MEMBER_s "Cannot access non-static member '%s' like this" +#define TXT_CANNOT_RETURN_REF_TO_LOCAL "Can't return reference to local value." +#define TXT_CANT_CONSTRUCT_s_USE_REF_CAST "Can't construct handle '%s'. Use ref cast instead" +#define TXT_CANT_IMPLICITLY_CONVERT_s_TO_s "Can't implicitly convert from '%s' to '%s'." +#define TXT_CANT_RETURN_VALUE "Can't return value when return type is 'void'" +#define TXT_CHANGE_SIGN "Implicit conversion changed sign of value" +#define TXT_CLASS_CANT_BE_FINAL_AND_ABSTRACT "A class cannot be both abstract and final" +#define TXT_COMPILING_s "Compiling %s" +#define TXT_COMPOUND_ASGN_ON_VALUE_TYPE "Compound assignments with property accessors on value types are not supported" +#define TXT_COMPOUND_ASGN_WITH_IDX_PROP "Compound assignments with indexed property accessors are not supported" +#define TXT_COMPOUND_ASGN_REQUIRE_GET_SET "Compound assignments with property accessors require both get and set accessors" +#define TXT_PROP_ACCESS_s_DOES_NOT_EXPECT_INDEX "Implemented property accessor '%s' does not expect index argument" +#define TXT_PROP_ACCESS_s_EXPECTS_INDEX "Implemented property accessor '%s' expects index argument" + +#define TXT_DATA_TYPE_CANT_BE_s "Data type can't be '%s'" +#define TXT_DECL_IN_SWITCH "Variables cannot be declared in switch cases, except inside statement blocks" +#define TXT_DEFAULT_MUST_BE_LAST "The default case must be the last one" +#define TXT_DEF_ARG_MISSING_IN_FUNC_s "All subsequent parameters after the first default value must have default values in function '%s'" +#define TXT_DEF_ARG_TYPE_DOESNT_MATCH "The type of the default argument expression doesn't match the function parameter type" +#define TXT_DUPLICATE_NAMED_ARG "Duplicate named argument" +#define TXT_DERIVED_METHOD_MUST_HAVE_SAME_RETTYPE_s "The method in the derived class must have the same return type as in the base class: '%s'" +#define TXT_DESTRUCTOR_MAY_NOT_HAVE_PARM "The destructor must not have any parameters" +#define TXT_DESTRUCTOR_s_s_NAME_ERROR "The name of the destructor '%s::~%s' must be the same as the class" +#define TXT_DISALLOW_ASSIGN_ON_REF_TYPE "Value assignment on reference types is not allowed. Did you mean to do a handle assignment?" +#define TXT_DISALLOW_COMPOUND_ASSIGN_ON_REF_TYPE "Compound assignment on reference types is not allowed" +#define TXT_DUPLICATE_SWITCH_CASE "Duplicate switch case" + +#define TXT_ELSE_WITH_EMPTY_STATEMENT "Else with empty statement" +#define TXT_EMPTY_LIST_ELEMENT_IS_NOT_ALLOWED "Empty list element is not allowed" +#define TXT_EMPTY_SWITCH "Empty switch statement" +#define TXT_EXPECTED_s "Expected '%s'" +#define TXT_EXPECTED_CONSTANT "Expected constant" +#define TXT_EXPECTED_DATA_TYPE "Expected data type" +#define TXT_EXPECTED_EXPRESSION_VALUE "Expected expression value" +#define TXT_EXPECTED_IDENTIFIER "Expected identifier" +#define TXT_EXPECTED_LIST "Expected a list enclosed by { } to match pattern" +#define TXT_EXPECTED_METHOD_OR_PROPERTY "Expected method or property" +#define TXT_EXPECTED_ONE_OF "Expected one of: " +#define TXT_EXPECTED_OPERATOR "Expected operator" +#define TXT_EXPECTED_s_OR_s "Expected '%s' or '%s'" +#define TXT_EXPECTED_POST_OPERATOR "Expected post operator" +#define TXT_EXPECTED_PRE_OPERATOR "Expected pre operator" +#define TXT_EXPECTED_STRING "Expected string" +#define TXT_EXPR_DOESNT_EVAL_TO_FUNC "Expression doesn't evaluate to a function" +#define TXT_EXPR_MUST_BE_BOOL "Expression must be of boolean type" +#define TXT_EXPR_s_IS_DATA_TYPE "Expression '%s' is a data type" +#define TXT_EXTERNAL_SHARED_s_NOT_FOUND "External shared entity '%s' not found" +#define TXT_EXTERNAL_SHARED_s_CANNOT_REDEF "External shared entity '%s' cannot redefine the original entity" + +#define TXT_FAILED_TO_COMPILE_DEF_ARG_d_IN_FUNC_s "Failed while compiling default arg for parameter %d in function '%s'" +#define TXT_FAILED_TO_CREATE_TEMP_OBJ "Previous error occurred while attempting to create a temporary copy of object" +#define TXT_FLOAT_CONV_TO_INT_CAUSE_TRUNC "Float value truncated in implicit conversion to integer" +#define TXT_FOUND_MULTIPLE_ENUM_VALUES "Found multiple matching enum values" +#define TXT_FUNCTION_ALREADY_EXIST "A function with the same name and parameters already exists" +#define TXT_FUNCTION_s_NOT_FOUND "Function '%s' not found" + +#define TXT_GET_SET_ACCESSOR_TYPE_MISMATCH_FOR_s "The property '%s' has mismatching types for the get and set accessors" +#define TXT_GLOBAL_VARS_NOT_ALLOWED "Global variables have been disabled by the application" + +#define TXT_HANDLE_ASSIGN_ON_NON_HANDLE_PROP "It is not allowed to perform a handle assignment on a non-handle property" +#define TXT_HANDLE_COMPARISON "The operand is implicitly converted to handle in order to compare them" +#define TXT_HANDLE_OF_HANDLE_IS_NOT_ALLOWED "Handle to handle is not allowed" +#define TXT_s_HIDES_VAR_IN_OUTER_SCOPE "Variable '%s' hides another variable of same name in outer scope" + +#define TXT_IDENTIFIER_s_NOT_DATA_TYPE "Identifier '%s' is not a data type" +#define TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_GLOBAL_NS "Identifier '%s' is not a data type in global namespace" +#define TXT_IDENTIFIER_s_NOT_DATA_TYPE_IN_NS_s "Identifier '%s' is not a data type in namespace '%s' or parent" +#define TXT_IF_WITH_EMPTY_STATEMENT "If with empty statement" +#define TXT_ILLEGAL_MEMBER_TYPE "Illegal member type" +// TODO: Should be TXT_ILLEGAL_OPERATION_ON_s +#define TXT_ILLEGAL_OPERATION "Illegal operation on this datatype" +#define TXT_ILLEGAL_OPERATION_ON_s "Illegal operation on '%s'" +#define TXT_ILLEGAL_TARGET_TYPE_FOR_REF_CAST "Illegal target type for reference cast" +#define TXT_ILLEGAL_VARIABLE_NAME_s "Illegal variable name '%s'." +#define TXT_INHERITED_PRIVATE_PROP_ACCESS_s "Illegal access to inherited private property '%s'" +#define TXT_INIT_LIST_CANNOT_BE_USED_WITH_s "Initialization lists cannot be used with '%s'" +#define TXT_INSTANCING_INVLD_TMPL_TYPE_s_s "Attempting to instantiate invalid template type '%s<%s>'" +#define TXT_INSTEAD_FOUND_s "Instead found '%s'" +#define TXT_INSTEAD_FOUND_IDENTIFIER_s "Instead found identifier '%s'" +#define TXT_INSTEAD_FOUND_KEYWORD_s "Instead found reserved keyword '%s'" +#define TXT_INTERFACE_s_CANNOT_BE_INSTANTIATED "Interface '%s' cannot be instantiated" +#define TXT_INTERFACE_CAN_ONLY_IMPLEMENT_INTERFACE "Interfaces can only implement other interfaces" +#define TXT_INVALID_BREAK "Invalid 'break'" +#define TXT_INVALID_CHAR_LITERAL "Invalid character literal" +#define TXT_INVALID_CONTINUE "Invalid 'continue'" +#define TXT_INVALID_ESCAPE_SEQUENCE "Invalid escape sequence" +#define TXT_INVALID_EXPRESSION_AMBIGUOUS_NAME "Invalid expression: ambiguous name" +#define TXT_INVALID_EXPRESSION_LAMBDA "Invalid expression: stand-alone anonymous function" +#define TXT_INVALID_OP_ON_METHOD "Invalid operation on method" +#define TXT_INVALID_REF_PROP_ACCESS "Invalid reference. Property accessors cannot be used in combined read/write operations" +#define TXT_INVALID_SCOPE "Invalid scope resolution" +#define TXT_INVALID_SIG_FOR_VIRTPROP "Invalid signature for virtual property" +#define TXT_INVALID_TYPE "Invalid type" +#define TXT_INVALID_UNICODE_FORMAT_EXPECTED_d "Invalid unicode escape sequence, expected %d hex digits" +#define TXT_INVALID_UNICODE_VALUE "Invalid unicode code point" +#define TXT_INVALID_UNICODE_SEQUENCE_IN_SRC "Invalid unicode sequence in source" +#define TXT_INVALID_USE_OF_NAMED_ARGS "Invalid use of named arguments" + +#define TXT_METHOD_CANNOT_OVERRIDE_s "Method '%s' declared as final and cannot be overridden" +#define TXT_METHOD_CANT_HAVE_NAME_OF_CLASS "The method cannot be named with the class name" +#define TXT_METHOD_s_DOES_NOT_OVERRIDE "Method '%s' marked as override but does not replace any base class or interface method" +#define TXT_METHOD_s_s_HAS_NO_RETURN_TYPE "Method '%s::%s' is missing the return type, nor is it the same name as object to be a constructor" +#define TXT_METHOD_s_NOT_PART_OF_OBJECT_s "Method '%s' is not part of object '%s'" +#define TXT_MISSING_IMPLEMENTATION_OF_s "Missing implementation of '%s'" +#define TXT_MISSING_DEFINITION_OF_s "Missing definition of '%s'" +#define TXT_MIXIN_CANNOT_BE_DECLARED_AS_s "Mixin class cannot be declared as '%s'" +#define TXT_MIXIN_CANNOT_HAVE_CONSTRUCTOR "Mixin classes cannot have constructors or destructors" +#define TXT_MIXIN_CLASS_CANNOT_INHERIT "Mixin class cannot inherit from classes" +#define TXT_MIXIN_CANNOT_HAVE_CHILD_TYPES "Mixin classes cannot have child types" +#define TXT_MORE_THAN_ONE_MATCHING_OP "Found more than one matching operator" +#define TXT_MULTIPLE_MATCHING_SIGNATURES_TO_s "Multiple matching signatures to '%s'" +#define TXT_MULTIPLE_PROP_GET_ACCESSOR_FOR_s "Found multiple get accessors for property '%s'" +#define TXT_MULTIPLE_PROP_SET_ACCESSOR_FOR_s "Found multiple set accessors for property '%s'" +#define TXT_MULTILINE_STRINGS_NOT_ALLOWED "Multiline strings are not allowed in this application" +#define TXT_MUST_BE_OBJECT "Only objects have constructors" +#define TXT_MUST_RETURN_VALUE "Must return a value" + +#define TXT_NAMESPACE_s_DOESNT_EXIST "Namespace '%s' doesn't exist." +#define TXT_NAME_CONFLICT_s_EXTENDED_TYPE "Name conflict. '%s' is an extended data type." +#define TXT_NAME_CONFLICT_s_GLOBAL_PROPERTY "Name conflict. '%s' is a global property." +#define TXT_NAME_CONFLICT_s_IS_NAMED_TYPE "Name conflict. '%s' is a named type." +#define TXT_NAME_CONFLICT_s_IS_FUNCDEF "Name conflict. '%s' is a funcdef." +#define TXT_NAME_CONFLICT_s_IS_FUNCTION "Name conflict. '%s' is a global function." +#define TXT_NAME_CONFLICT_s_IS_MIXIN "Name conflict. '%s' is a mixin class." +#define TXT_NAME_CONFLICT_s_IS_VIRTPROP "Name conflict. '%s' is a virtual property." +#define TXT_NAME_CONFLICT_s_STRUCT "Name conflict. '%s' is a class." +#define TXT_NAME_CONFLICT_s_OBJ_PROPERTY "Name conflict. '%s' is an object property." +#define TXT_NAME_CONFLICT_s_METHOD "Name conflict. '%s' is a class method." +#define TXT_NAME_CONFLICT_s_ALREADY_USED "Name conflict. '%s' is already used." +#define TXT_NAMED_ARGS_WITH_OLD_SYNTAX "Detected named argument with old syntax" +#define TXT_NO_APPROPRIATE_INDEX_OPERATOR "No appropriate indexing operator found" +#define TXT_NO_APPROPRIATE_OPHNDLASSIGN_s "No appropriate opHndlAssign method found in '%s' for handle assignment" +#define TXT_NO_APPROPRIATE_OPEQUALS "No appropriate opEquals method found" +#define TXT_NO_CONVERSION_s_TO_s "No conversion from '%s' to '%s' available." +#define TXT_NO_CONVERSION_s_TO_MATH_TYPE "No conversion from '%s' to math type available." +#define TXT_NO_DEFAULT_ARRAY_TYPE "The application doesn't support the default array type." +#define TXT_NO_DEFAULT_CONSTRUCTOR_FOR_s "No default constructor for object of type '%s'." +#define TXT_NO_DEFAULT_COPY_OP_FOR_s "No appropriate opAssign method found in '%s' for value assignment" +#define TXT_NO_COPY_CONSTRUCTOR_FOR_s "No copy constructor for object of type '%s'." +#define TXT_NO_MATCHING_SIGNATURES_TO_s "No matching signatures to '%s'" +#define TXT_NO_MATCHING_OP_FOUND_FOR_TYPE_s "No matching operator that takes the type '%s' found" +#define TXT_NO_MATCHING_OP_FOUND_FOR_TYPES_s_AND_s "No matching operator that takes the types '%s' and '%s' found" +#define TXT_NO_MATCHING_SYMBOL_s "No matching symbol '%s'" +#define TXT_NON_CONST_METHOD_ON_CONST_OBJ "Non-const method call on read-only object reference" +#define TXT_NONTERMINATED_STRING "Non-terminated string literal" +#define TXT_NOT_A_FUNC_s_IS_TYPE_s "Expression doesn't form a function call. '%s' evaluates to the non-function type '%s'" +#define TXT_NOT_ALL_PATHS_RETURN "Not all paths return a value" +#define TXT_NOT_ENOUGH_VALUES_FOR_LIST "Not enough values to match pattern" +#define TXT_s_NOT_DECLARED "'%s' is not declared" +#define TXT_NOT_EXACT "Implicit conversion of value is not exact" +#define TXT_s_NOT_INITIALIZED "'%s' is not initialized." +#define TXT_NOT_LVALUE "Expression is not an l-value" +#define TXT_s_NOT_MEMBER_OF_s "'%s' is not a member of '%s'" +#define TXT_NOT_VALID_REFERENCE "Not a valid reference" +#define TXT_NOT_VALID_LVALUE "Not a valid lvalue" +#define TXT_NOTHING_WAS_BUILT "Nothing was built in the module" + +#define TXT_OBJECT_DOESNT_SUPPORT_INDEX_OP "Type '%s' doesn't support the indexing operator" +#define TXT_OBJECT_HANDLE_NOT_SUPPORTED "Object handle is not supported for this type" +#define TXT_ONLY_OBJECTS_MAY_USE_REF_INOUT "Only object types that support object handles can use &inout. Use &in or &out instead" +#define TXT_ONLY_ONE_ARGUMENT_IN_CAST "A cast operator has one argument" +#define TXT_ONLY_ONE_FUNCTION_ALLOWED "The code must contain one and only one function" +#define TXT_ONLY_ONE_VARIABLE_ALLOWED "The code must contain one and only one global variable" +#define TXT_OPERANDS_MUST_BE_HANDLES "Both operands must be handles when comparing identity" +#define TXT_OVERLOAD_CONFLICTS_DUE_TO_DEFAULT_ARGS "The overloaded functions are identical on initial parameters without default arguments" + +#define TXT_PARAMETER_ALREADY_DECLARED "Parameter already declared" +#define TXT_PARAMETER_CANT_BE_s "Parameter type can't be '%s', because the type cannot be instantiated." +#define TXT_POS_ARG_AFTER_NAMED_ARG "Positional arguments cannot be passed after named arguments" +#define TXT_PREV_ERROR_WHILE_COMP_LIST_FOR_TYPE_s "Previous error occurred while attempting to compile initialization list for type '%s'" +#define TXT_PRIVATE_METHOD_CALL_s "Illegal call to private method '%s'" +#define TXT_PRIVATE_PROP_ACCESS_s "Illegal access to private property '%s'" +#define TXT_PROTECTED_METHOD_CALL_s "Illegal call to protected method '%s'" +#define TXT_PROTECTED_PROP_ACCESS_s "Illegal access to protected property '%s'" +#define TXT_PROP_ACCESS_WITH_INDEX_ONE_ARG "Property accessor with index must have 1 and only 1 index argument" +#define TXT_PROPERTY_ACCESSOR_DISABLED "Property accessors have been disabled by the application" +#define TXT_PROPERTY_ACCESSOR_MUST_BE_IMPLEMENTED "Property accessor must be implemented" +#define TXT_PROPERTY_CANT_BE_CONST "Class properties cannot be declared as const" +#define TXT_PROPERTY_HAS_NO_GET_ACCESSOR "The property has no get accessor" +#define TXT_PROPERTY_HAS_NO_SET_ACCESSOR "The property has no set accessor" +#define TXT_PROPERTY_WITHOUT_ACCESSOR "Virtual property must have at least one get or set accessor" + +#define TXT_REF_CANT_BE_TO_LOCAL_VAR "Resulting reference cannot be returned. Returned references must not refer to local variables." +#define TXT_REF_CANT_BE_RETURNED_DEFERRED_PARAM "Resulting reference cannot be returned. There are deferred arguments that may invalidate it." +#define TXT_REF_CANT_BE_RETURNED_LOCAL_VARS "Resulting reference cannot be returned. The expression uses objects that during cleanup may invalidate it." +#define TXT_REF_IS_READ_ONLY "Reference is read-only" +#define TXT_REF_IS_TEMP "Reference is temporary" +#define TXT_REF_TYPE_CANT_BE_PASSED_BY_VAL "Reference types cannot be passed by value in function parameters" +#define TXT_REF_TYPE_CANT_BE_RETURNED_BY_VAL "Reference types cannot be returned by value from functions" +#define TXT_RETURN_CANT_BE_s "Return type can't be '%s'" + +#define TXT_SHARED_CANNOT_ACCESS_NON_SHARED_VAR_s "Shared code cannot access non-shared global variable '%s'" +#define TXT_SHARED_CANNOT_CALL_NON_SHARED_FUNC_s "Shared code cannot call non-shared function '%s'" +#define TXT_SHARED_CANNOT_IMPLEMENT_NON_SHARED_s "Shared type cannot implement non-shared interface '%s'" +#define TXT_SHARED_CANNOT_INHERIT_FROM_NON_SHARED_s "Shared class cannot inherit from non-shared class '%s'" +#define TXT_SHARED_CANNOT_USE_NON_SHARED_TYPE_s "Shared code cannot use non-shared type '%s'" +#define TXT_SHARED_s_DOESNT_MATCH_ORIGINAL "Shared type '%s' doesn't match the original declaration in other module" +#define TXT_SECTION_IS_EMPTY "The script section is empty" +#define TXT_SIGNED_UNSIGNED_MISMATCH "Signed/Unsigned mismatch" +#define TXT_STRINGS_NOT_RECOGNIZED "Strings are not recognized by the application" +#define TXT_SWITCH_CASE_MUST_BE_CONSTANT "Case expressions must be constants" +#define TXT_SWITCH_MUST_BE_INTEGRAL "Switch expressions must be integral numbers" + +#define TXT_TMPL_s_EXPECTS_d_SUBTYPES "Template '%s' expects %d sub type(s)" +#define TXT_TMPL_SUBTYPE_MUST_NOT_BE_READ_ONLY "Template subtype must not be read-only" +#define TXT_TOO_MANY_JUMP_LABELS "The function has too many jump labels to handle. Split the function into smaller ones." +#define TXT_TOO_MANY_VALUES_FOR_LIST "Too many values to match pattern" +#define TXT_TYPE_s_CANNOT_BE_REFERENCE "Type '%s' cannot be a reference" +#define TXT_TYPE_s_NOT_AVAILABLE_FOR_MODULE "Type '%s' is not available for this module" +#define TXT_TYPE_s_NOT_TEMPLATE "Type '%s' is not a template type" + +#define TXT_UNEXPECTED_END_OF_FILE "Unexpected end of file" +#define TXT_UNEXPECTED_TOKEN_s "Unexpected token '%s'" +#define TXT_UNEXPECTED_VAR_DECL "Unexpected variable declaration" +#define TXT_UNINITIALIZED_GLOBAL_VAR_s "Use of uninitialized global variable '%s'." +#define TXT_UNKNOWN_SCOPE_s "Unknown scope '%s'" +#define TXT_UNREACHABLE_CODE "Unreachable code" +#define TXT_UNRECOGNIZED_VIRTUAL_PROPERTY_NODE "Virtual property contains unrecognized aspect" +#define TXT_UNUSED_SCRIPT_NODE "Unused script node" + +#define TXT_VALUE_TOO_LARGE_FOR_TYPE "Value is too large for data type" +#define TXT_VOID_CANT_BE_OPERAND "Void cannot be an operand in expressions" + +#define TXT_WARNINGS_TREATED_AS_ERROR "Warnings are treated as errors by the application" +#define TXT_WHERE_s_IS_s "Where '%s' is '%s'" +#define TXT_WHILE_PARSING_ARG_LIST "While parsing argument list" +#define TXT_WHILE_PARSING_EXPRESSION "While parsing expression" +#define TXT_WHILE_PARSING_INIT_LIST "While parsing initialization list" +#define TXT_WHILE_PARSING_NAMESPACE "While parsing namespace" +#define TXT_WHILE_PARSING_STATEMENT_BLOCK "While parsing statement block" +#define TXT_WHILE_INCLUDING_MIXIN "Previous error occurred while including mixin" + +// Global variable initialization + +#define TXT_FAILED_TO_INITIALIZE_s "Failed to initialize global variable '%s'" +#define TXT_EXCEPTION_s_IN_s "Exception '%s' in '%s'" + +// Engine message + +#define TXT_AUTOHANDLE_CANNOT_BE_USED_FOR_NOCOUNT "Autohandles cannot be used with types that have been registered with NOCOUNT" +#define TXT_FIRST_PARAM_MUST_BE_REF_FOR_TEMPLATE_FACTORY "First parameter to template factory must be a reference. This will be used to pass the object type of the template" +#define TXT_INVALID_CONFIGURATION "Invalid configuration. Verify the registered application interface." +#define TXT_VALUE_TYPE_MUST_HAVE_SIZE "A value type must be registered with a non-zero size" +#define TXT_TYPE_s_IS_MISSING_BEHAVIOURS "Type '%s' is missing behaviours" +#define TXT_ILLEGAL_BEHAVIOUR_FOR_TYPE "The behaviour is not compatible with the type" +#define TXT_GC_REQUIRE_ADD_REL_GC_BEHAVIOUR "A garbage collected ref type must have the addref, release, and all gc behaviours" +#define TXT_VALUE_GC_REQUIRE_GC_BEHAVIOUR "A garbage collected value type must have the gc enum references behaviour" +#define TXT_SCOPE_REQUIRE_REL_BEHAVIOUR "A scoped reference type must have the release behaviour" +#define TXT_REF_REQUIRE_ADD_REL_BEHAVIOUR "A reference type must have the addref and release behaviours" +#define TXT_NON_POD_REQUIRE_CONSTR_DESTR_BEHAVIOUR "A non-pod value type must have at least one constructor and the destructor behaviours" +#define TXT_CANNOT_PASS_TYPE_s_BY_VAL "Can't pass type '%s' by value unless the application type is informed in the registration" +#define TXT_CANNOT_RET_TYPE_s_BY_VAL "Can't return type '%s' by value unless the application type is informed in the registration" +// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to pass by value to application in native calling convention" +#define TXT_DONT_SUPPORT_TYPE_s_BY_VAL "Don't support passing type '%s' by value to application in native calling convention on this platform" +// TODO: Should be something like "This platform requires that AngelScript knows the exact content of the type '%s' in order to return by value from application in native calling convention" +#define TXT_DONT_SUPPORT_RET_TYPE_s_BY_VAL "Don't support returning type '%s' by value from application in native calling convention on this platform" +#define TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s "Object {%d}. GC cannot destroy an object of type '%s' as it doesn't know how many references to there are." +#define TXT_d_GC_CANNOT_FREE_OBJ_OF_TYPE_s_REF_COUNT_d "Object {%d}. GC cannot destroy an object of type '%s' as it can't see all references. Current ref count is %d." +#define TXT_OBJECT_TYPE_s_DOESNT_EXIST "Object type '%s' doesn't exist" +#define TXT_TEMPLATE_s_ALREADY_GENERATED_CANT_REGISTER "Cannot register. The template type instance '%s' has already been generated." +#define TXT_TEMPLATE_TYPE_s_DOESNT_EXIST "Template type '%s' doesn't exist" +#define TXT_TEMPLATE_SUBTYPE_s_DOESNT_EXIST "Template subtype '%s' doesn't exist" +#define TXT_TEMPLATE_LIST_FACTORY_EXPECTS_2_REF_PARAMS "Template list factory expects two reference parameters. The last is the pointer to the initialization buffer" +#define TXT_LIST_FACTORY_EXPECTS_1_REF_PARAM "List factory expects only one reference parameter. The pointer to the initialization buffer will be passed in this parameter" +#define TXT_FAILED_READ_SUBTYPE_OF_TEMPLATE_s "Failed to read subtype of template type '%s'" +#define TXT_FAILED_IN_FUNC_s_s_d "Failed in call to function '%s' (Code: %s, %d)" +#define TXT_FAILED_IN_FUNC_s_WITH_s_s_d "Failed in call to function '%s' with '%s' (Code: %s, %d)" +#define TXT_FAILED_IN_FUNC_s_WITH_s_AND_s_s_d "Failed in call to function '%s' with '%s' and '%s' (Code: %s, %d)" +#define TXT_GC_RECEIVED_NULL_PTR "AddScriptObjectToGC called with null pointer" +#define TXT_EXCEPTION_IN_NESTED_CALL "An exception occurred in a nested call" +#define TXT_TYPE_s_IS_STILL_USED_BY_FUNC_s "Type '%s' is still used by function '%s'" +#define TXT_PREV_TYPE_IS_NAMED_s "The builtin type in previous message is named '%s'" +#define TXT_PREV_FUNC_IS_NAMED_s_TYPE_IS_d "The function in previous message is named '%s'. The func type is %d" +#define TXT_RESURRECTING_SCRIPTOBJECT_s "The script object of type '%s' is being resurrected illegally during destruction" +#define TXT_INVALID_BYTECODE_d "LoadByteCode failed. The bytecode is invalid. Number of bytes read from stream: %d" +#define TXT_NO_JIT_IN_FUNC_s "Function '%s' appears to have been compiled without JIT entry points" +#define TXT_ENGINE_REF_COUNT_ERROR_DURING_SHUTDOWN "Uh oh! The engine's reference count is increasing while it is being destroyed. Make sure references needed for clean-up are immediately released" +#define TXT_MODULE_IS_IN_USE "The module is still in use and cannot be rebuilt. Discard it and request another module" +#define TXT_EXTRNL_REF_TO_MODULE_s "There is an external reference to an object in module '%s', preventing it from being deleted" + +// Internal names + +#define TXT_PROPERTY "Property" +#define TXT_SYSTEM_FUNCTION "System function" +#define TXT_VARIABLE_DECL "Variable declaration" + +// Exceptions + +#define TXT_STACK_OVERFLOW "Stack overflow" +#define TXT_NULL_POINTER_ACCESS "Null pointer access" +#define TXT_DIVIDE_BY_ZERO "Divide by zero" +#define TXT_DIVIDE_OVERFLOW "Overflow in integer division" +#define TXT_POW_OVERFLOW "Overflow in exponent operation" +#define TXT_UNRECOGNIZED_BYTE_CODE "Unrecognized byte code" +#define TXT_INVALID_CALLING_CONVENTION "Invalid calling convention" +#define TXT_UNBOUND_FUNCTION "Unbound function called" +#define TXT_OUT_OF_BOUNDS "Out of range" +#define TXT_EXCEPTION_CAUGHT "Caught an exception from the application" +#define TXT_MISMATCH_IN_VALUE_ASSIGN "Mismatching types in value assignment" +#define TXT_TOO_MANY_NESTED_CALLS "Too many nested calls" + +// Error codes +#define ERROR_NAME(x) #x +static const char*const errorNames[] = +{ + ERROR_NAME(asSUCCESS), + ERROR_NAME(asERROR), + ERROR_NAME(asCONTEXT_ACTIVE), + ERROR_NAME(asCONTEXT_NOT_FINISHED), + ERROR_NAME(asCONTEXT_NOT_PREPARED), + ERROR_NAME(asINVALID_ARG), + ERROR_NAME(asNO_FUNCTION), + ERROR_NAME(asNOT_SUPPORTED), + ERROR_NAME(asINVALID_NAME), + ERROR_NAME(asNAME_TAKEN), + ERROR_NAME(asINVALID_DECLARATION), + ERROR_NAME(asINVALID_OBJECT), + ERROR_NAME(asINVALID_TYPE), + ERROR_NAME(asALREADY_REGISTERED), + ERROR_NAME(asMULTIPLE_FUNCTIONS), + ERROR_NAME(asNO_MODULE), + ERROR_NAME(asNO_GLOBAL_VAR), + ERROR_NAME(asINVALID_CONFIGURATION), + ERROR_NAME(asINVALID_INTERFACE), + ERROR_NAME(asCANT_BIND_ALL_FUNCTIONS), + ERROR_NAME(asLOWER_ARRAY_DIMENSION_NOT_REGISTERED), + ERROR_NAME(asWRONG_CONFIG_GROUP), + ERROR_NAME(asCONFIG_GROUP_IS_IN_USE), + ERROR_NAME(asILLEGAL_BEHAVIOUR_FOR_TYPE), + ERROR_NAME(asWRONG_CALLING_CONV), + ERROR_NAME(asBUILD_IN_PROGRESS), + ERROR_NAME(asINIT_GLOBAL_VARS_FAILED), + ERROR_NAME(asOUT_OF_MEMORY), + ERROR_NAME(asMODULE_IS_IN_USE) +}; + +#endif diff --git a/angelscript/source/as_thread.cpp b/angelscript/source/as_thread.cpp new file mode 100644 index 0000000..63ab15e --- /dev/null +++ b/angelscript/source/as_thread.cpp @@ -0,0 +1,468 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2014 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_thread.cpp +// +// Functions for multi threading support +// + +#include "as_config.h" +#include "as_thread.h" +#include "as_atomic.h" + +BEGIN_AS_NAMESPACE + +//======================================================================= + +// Singleton +static asCThreadManager *threadManager = 0; + +//====================================================================== + +// Global API functions +extern "C" +{ + +AS_API int asThreadCleanup() +{ + return asCThreadManager::CleanupLocalData(); +} + +AS_API asIThreadManager *asGetThreadManager() +{ + return threadManager; +} + +AS_API int asPrepareMultithread(asIThreadManager *externalThreadMgr) +{ + return asCThreadManager::Prepare(externalThreadMgr); +} + +AS_API void asUnprepareMultithread() +{ + asCThreadManager::Unprepare(); +} + +AS_API void asAcquireExclusiveLock() +{ + if( threadManager ) + { + ACQUIREEXCLUSIVE(threadManager->appRWLock); + } +} + +AS_API void asReleaseExclusiveLock() +{ + if( threadManager ) + { + RELEASEEXCLUSIVE(threadManager->appRWLock); + } +} + +AS_API void asAcquireSharedLock() +{ + if( threadManager ) + { + ACQUIRESHARED(threadManager->appRWLock); + } +} + +AS_API void asReleaseSharedLock() +{ + if( threadManager ) + { + RELEASESHARED(threadManager->appRWLock); + } +} + +} + +//====================================================================== + +#if !defined(AS_NO_THREADS) && defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) +__declspec(thread) asCThreadLocalData *asCThreadManager::tld = 0; +#endif + +asCThreadManager::asCThreadManager() +{ + // We're already in the critical section when this function is called + +#ifdef AS_NO_THREADS + tld = 0; +#else + // Allocate the thread local storage + #if defined AS_POSIX_THREADS + pthread_key_t pKey; + pthread_key_create(&pKey, 0); + tlsKey = (asDWORD)pKey; + #elif defined AS_WINDOWS_THREADS + #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + tld = 0; + #else + tlsKey = (asDWORD)TlsAlloc(); + #endif + #endif +#endif + refCount = 1; +} + +int asCThreadManager::Prepare(asIThreadManager *externalThreadMgr) +{ + // Don't allow an external thread manager if there + // is already a thread manager defined + if( externalThreadMgr && threadManager ) + return asINVALID_ARG; + + // The critical section cannot be declared globally, as there is no + // guarantee for the order in which global variables are initialized + // or uninitialized. + + // For this reason it's not possible to prevent two threads from calling + // AddRef at the same time, so there is a chance for a race condition here. + + // To avoid the race condition when the thread manager is first created, + // the application must make sure to call the global asPrepareForMultiThread() + // in the main thread before any other thread creates a script engine. + if( threadManager == 0 && externalThreadMgr == 0 ) + threadManager = asNEW(asCThreadManager); + else + { + // If an application uses different dlls each dll will get it's own memory + // space for global variables. If multiple dlls then uses AngelScript's + // global thread support functions it is then best to share the thread + // manager to make sure all dlls use the same critical section. + if( externalThreadMgr ) + threadManager = reinterpret_cast(externalThreadMgr); + + ENTERCRITICALSECTION(threadManager->criticalSection); + threadManager->refCount++; + LEAVECRITICALSECTION(threadManager->criticalSection); + } + + // Success + return 0; +} + +void asCThreadManager::Unprepare() +{ + asASSERT(threadManager); + + if( threadManager == 0 ) + return; + + // It's necessary to protect this section so no + // other thread attempts to call AddRef or Release + // while clean up is in progress. + ENTERCRITICALSECTION(threadManager->criticalSection); + if( --threadManager->refCount == 0 ) + { + // Make sure the local data is destroyed, at least for the current thread + CleanupLocalData(); + + // As the critical section will be destroyed together + // with the thread manager we must first clear the global + // variable in case a new thread manager needs to be created; + asCThreadManager *mgr = threadManager; + threadManager = 0; + + // Leave the critical section before it is destroyed + LEAVECRITICALSECTION(mgr->criticalSection); + + asDELETE(mgr,asCThreadManager); + } + else + LEAVECRITICALSECTION(threadManager->criticalSection); +} + +asCThreadManager::~asCThreadManager() +{ +#ifndef AS_NO_THREADS + // Deallocate the thread local storage + #if defined AS_POSIX_THREADS + pthread_key_delete((pthread_key_t)tlsKey); + #elif defined AS_WINDOWS_THREADS + #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + tld = 0; + #else + TlsFree((DWORD)tlsKey); + #endif + #endif +#else + if( tld ) + { + asDELETE(tld,asCThreadLocalData); + } + tld = 0; +#endif +} + +int asCThreadManager::CleanupLocalData() +{ + if( threadManager == 0 ) + return 0; + +#ifndef AS_NO_THREADS +#if defined AS_POSIX_THREADS + asCThreadLocalData *tld = (asCThreadLocalData*)pthread_getspecific((pthread_key_t)threadManager->tlsKey); +#elif defined AS_WINDOWS_THREADS + #if !defined(_MSC_VER) || !(WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + asCThreadLocalData *tld = (asCThreadLocalData*)TlsGetValue((DWORD)threadManager->tlsKey); + #endif +#endif + + if( tld == 0 ) + return 0; + + if( tld->activeContexts.GetLength() == 0 ) + { + asDELETE(tld,asCThreadLocalData); + #if defined AS_POSIX_THREADS + pthread_setspecific((pthread_key_t)threadManager->tlsKey, 0); + #elif defined AS_WINDOWS_THREADS + #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + tld = 0; + #else + TlsSetValue((DWORD)threadManager->tlsKey, 0); + #endif + #endif + return 0; + } + else + return asCONTEXT_ACTIVE; + +#else + if( threadManager->tld ) + { + if( threadManager->tld->activeContexts.GetLength() == 0 ) + { + asDELETE(threadManager->tld,asCThreadLocalData); + threadManager->tld = 0; + } + else + return asCONTEXT_ACTIVE; + } + return 0; +#endif +} + +asCThreadLocalData *asCThreadManager::GetLocalData() +{ + if( threadManager == 0 ) + return 0; + +#ifndef AS_NO_THREADS +#if defined AS_POSIX_THREADS + asCThreadLocalData *tld = (asCThreadLocalData*)pthread_getspecific((pthread_key_t)threadManager->tlsKey); + if( tld == 0 ) + { + tld = asNEW(asCThreadLocalData)(); + pthread_setspecific((pthread_key_t)threadManager->tlsKey, tld); + } +#elif defined AS_WINDOWS_THREADS + #if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + if( tld == 0 ) + tld = asNEW(asCThreadLocalData)(); + #else + asCThreadLocalData *tld = (asCThreadLocalData*)TlsGetValue((DWORD)threadManager->tlsKey); + if( tld == 0 ) + { + tld = asNEW(asCThreadLocalData)(); + TlsSetValue((DWORD)threadManager->tlsKey, tld); + } + #endif +#endif + + return tld; +#else + if( threadManager->tld == 0 ) + threadManager->tld = asNEW(asCThreadLocalData)(); + + return threadManager->tld; +#endif +} + +//========================================================================= + +asCThreadLocalData::asCThreadLocalData() +{ +} + +asCThreadLocalData::~asCThreadLocalData() +{ +} + +//========================================================================= + +#ifndef AS_NO_THREADS +asCThreadCriticalSection::asCThreadCriticalSection() +{ +#if defined AS_POSIX_THREADS + pthread_mutex_init(&cs, 0); +#elif defined AS_WINDOWS_THREADS +#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + // Only the Ex version is available on Windows Store + InitializeCriticalSectionEx(&cs, 4000, 0); +#else + // Only the non-Ex version is available on WinXP and older + // MinGW also only defines this version + InitializeCriticalSection(&cs); +#endif +#endif +} + +asCThreadCriticalSection::~asCThreadCriticalSection() +{ +#if defined AS_POSIX_THREADS + pthread_mutex_destroy(&cs); +#elif defined AS_WINDOWS_THREADS + DeleteCriticalSection(&cs); +#endif +} + +void asCThreadCriticalSection::Enter() +{ +#if defined AS_POSIX_THREADS + pthread_mutex_lock(&cs); +#elif defined AS_WINDOWS_THREADS + EnterCriticalSection(&cs); +#endif +} + +void asCThreadCriticalSection::Leave() +{ +#if defined AS_POSIX_THREADS + pthread_mutex_unlock(&cs); +#elif defined AS_WINDOWS_THREADS + LeaveCriticalSection(&cs); +#endif +} + +bool asCThreadCriticalSection::TryEnter() +{ +#if defined AS_POSIX_THREADS + return !pthread_mutex_trylock(&cs); +#elif defined AS_WINDOWS_THREADS + return TryEnterCriticalSection(&cs) ? true : false; +#else + return true; +#endif +} + +asCThreadReadWriteLock::asCThreadReadWriteLock() +{ +#if defined AS_POSIX_THREADS + int r = pthread_rwlock_init(&lock, 0); + asASSERT( r == 0 ); + UNUSED_VAR(r); +#elif defined AS_WINDOWS_THREADS +#if defined(_MSC_VER) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + // Only the Ex versions are available on Windows Store + + // Create a semaphore to allow up to maxReaders simultaneous readers + readLocks = CreateSemaphoreExW(NULL, maxReaders, maxReaders, 0, 0, 0); + // Create a critical section to synchronize writers + InitializeCriticalSectionEx(&writeLock, 4000, 0); +#else + readLocks = CreateSemaphoreW(NULL, maxReaders, maxReaders, 0); + InitializeCriticalSection(&writeLock); +#endif +#endif +} + +asCThreadReadWriteLock::~asCThreadReadWriteLock() +{ +#if defined AS_POSIX_THREADS + pthread_rwlock_destroy(&lock); +#elif defined AS_WINDOWS_THREADS + DeleteCriticalSection(&writeLock); + CloseHandle(readLocks); +#endif +} + +void asCThreadReadWriteLock::AcquireExclusive() +{ +#if defined AS_POSIX_THREADS + pthread_rwlock_wrlock(&lock); +#elif defined AS_WINDOWS_THREADS + // Synchronize writers, so only one tries to lock out the readers + EnterCriticalSection(&writeLock); + + // Lock all reader out from the semaphore. Do this one by one, + // so the lock doesn't have to wait until there are no readers at all. + // If we try to lock all at once it is quite possible the writer will + // never succeed. + for( asUINT n = 0; n < maxReaders; n++ ) + WaitForSingleObjectEx(readLocks, INFINITE, FALSE); + + // Allow another writer to lock. It will only be able to + // lock the readers when this writer releases them anyway. + LeaveCriticalSection(&writeLock); +#endif +} + +void asCThreadReadWriteLock::ReleaseExclusive() +{ +#if defined AS_POSIX_THREADS + pthread_rwlock_unlock(&lock); +#elif defined AS_WINDOWS_THREADS + // Release all readers at once + ReleaseSemaphore(readLocks, maxReaders, 0); +#endif +} + +void asCThreadReadWriteLock::AcquireShared() +{ +#if defined AS_POSIX_THREADS + pthread_rwlock_rdlock(&lock); +#elif defined AS_WINDOWS_THREADS + // Lock a reader slot + WaitForSingleObjectEx(readLocks, INFINITE, FALSE); +#endif +} + +void asCThreadReadWriteLock::ReleaseShared() +{ +#if defined AS_POSIX_THREADS + pthread_rwlock_unlock(&lock); +#elif defined AS_WINDOWS_THREADS + // Release the reader slot + ReleaseSemaphore(readLocks, 1, 0); +#endif +} + +#endif + +//======================================================================== + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_thread.h b/angelscript/source/as_thread.h new file mode 100644 index 0000000..813d4c0 --- /dev/null +++ b/angelscript/source/as_thread.h @@ -0,0 +1,108 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + + +// +// as_thread.h +// +// Classes for multi threading support +// + +#ifndef AS_THREAD_H +#define AS_THREAD_H + +#include "as_config.h" +#include "as_string.h" +#include "as_array.h" +#include "as_map.h" +#include "as_criticalsection.h" + +BEGIN_AS_NAMESPACE + +class asCThreadLocalData; + +class asCThreadManager : public asIThreadManager +{ +public: + static asCThreadLocalData *GetLocalData(); + static int CleanupLocalData(); + + static int Prepare(asIThreadManager *externalThreadMgr); + static void Unprepare(); + + // This read/write lock can be used by the application to provide simple synchronization + DECLAREREADWRITELOCK(appRWLock) + +protected: + asCThreadManager(); + ~asCThreadManager(); + + // No need to use the atomic int here, as it will only be + // updated within the thread manager's critical section + int refCount; + +#ifndef AS_NO_THREADS +#if defined(_MSC_VER) && defined(AS_WINDOWS_THREADS) && (WINAPI_FAMILY & WINAPI_FAMILY_PHONE_APP) + // On Windows Store we must use MSVC specific thread variables for thread + // local storage, as the TLS API isn't available. On desktop we can't use + // this as it may cause problems if the library is used in a dll. + // ref: http://msdn.microsoft.com/en-us/library/2s9wt68x.aspx + // ref: http://msdn.microsoft.com/en-us/library/9w1sdazb.aspx + __declspec(thread) static asCThreadLocalData *tld; +#else + asDWORD tlsKey; +#endif + DECLARECRITICALSECTION(criticalSection) +#else + asCThreadLocalData *tld; +#endif +}; + +//====================================================================== + +class asIScriptContext; + +class asCThreadLocalData +{ +public: + asCArray activeContexts; + asCString string; + +protected: + friend class asCThreadManager; + + asCThreadLocalData(); + ~asCThreadLocalData(); +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_tokendef.h b/angelscript/source/as_tokendef.h new file mode 100644 index 0000000..ed24ab5 --- /dev/null +++ b/angelscript/source/as_tokendef.h @@ -0,0 +1,326 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2019 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_tokendef.h +// +// Definitions for tokens identifiable by the tokenizer +// + + +#ifndef AS_TOKENDEF_H +#define AS_TOKENDEF_H + +#include "as_config.h" + +BEGIN_AS_NAMESPACE + +enum eTokenType +{ + ttUnrecognizedToken, + + ttEnd, // End of file + + // White space and comments + ttWhiteSpace, // ' ', '\t', '\r', '\n', UTF8 byte-order-mark + ttOnelineComment, // // \n + ttMultilineComment, // /* */ + + // Atoms + ttIdentifier, // abc123 + ttIntConstant, // 1234 + ttFloatConstant, // 12.34e56f + ttDoubleConstant, // 12.34e56 + ttStringConstant, // "123" + ttMultilineStringConstant, // + ttHeredocStringConstant, // """text""" + ttNonTerminatedStringConstant, // "123 + ttBitsConstant, // 0xFFFF + + // Math operators + ttPlus, // + + ttMinus, // - + ttStar, // * + ttSlash, // / + ttPercent, // % + ttStarStar, // ** + + ttHandle, // @ + + ttAddAssign, // += + ttSubAssign, // -= + ttMulAssign, // *= + ttDivAssign, // /= + ttModAssign, // %= + ttPowAssign, // **= + + ttOrAssign, // |= + ttAndAssign, // &= + ttXorAssign, // ^= + ttShiftLeftAssign, // <<= + ttShiftRightLAssign, // >>= + ttShiftRightAAssign, // >>>= + + ttInc, // ++ + ttDec, // -- + + ttDot, // . + ttScope, // :: + + // Statement tokens + ttAssignment, // = + ttEndStatement, // ; + ttListSeparator, // , + ttStartStatementBlock, // { + ttEndStatementBlock, // } + ttOpenParanthesis, // ( + ttCloseParanthesis, // ) + ttOpenBracket, // [ + ttCloseBracket, // ] + ttAmp, // & + + // Bitwise operators + ttBitOr, // | + ttBitNot, // ~ + ttBitXor, // ^ + ttBitShiftLeft, // << + ttBitShiftRight, // >> // TODO: In Java this is the arithmetical shift + ttBitShiftRightArith, // >>> // TODO: In Java this is the logical shift + + // Compare operators + ttEqual, // == + ttNotEqual, // != + ttLessThan, // < + ttGreaterThan, // > + ttLessThanOrEqual, // <= + ttGreaterThanOrEqual, // >= + + ttQuestion, // ? + ttColon, // : + + // Reserved keywords + ttIf, // if + ttElse, // else + ttFor, // for + ttWhile, // while + ttBool, // bool + ttFuncDef, // funcdef + ttImport, // import + ttInt, // int + ttInt8, // int8 + ttInt16, // int16 + ttInt64, // int64 + ttInterface, // interface + ttIs, // is + ttNotIs, // !is + ttUInt, // uint + ttUInt8, // uint8 + ttUInt16, // uint16 + ttUInt64, // uint64 + ttFloat, // float + ttVoid, // void + ttTrue, // true + ttFalse, // false + ttReturn, // return + ttNot, // not + ttAnd, // and, && + ttOr, // or, || + ttXor, // xor, ^^ + ttBreak, // break + ttContinue, // continue + ttConst, // const + ttDo, // do + ttDouble, // double + ttSwitch, // switch + ttCase, // case + ttDefault, // default + ttIn, // in + ttOut, // out + ttInOut, // inout + ttNull, // null + ttClass, // class + ttTypedef, // typedef + ttEnum, // enum + ttCast, // cast + ttPrivate, // private + ttProtected, // protected + ttNamespace, // namespace + ttMixin, // mixin + ttAuto, // auto + ttTry, // try + ttCatch // catch +}; + +struct sTokenWord +{ + const char *word; + size_t wordLength; + eTokenType tokenType; +}; + +#define asTokenDef(str, tok) {str, sizeof(str)-1, tok} + +sTokenWord const tokenWords[] = +{ + asTokenDef("+" , ttPlus), + asTokenDef("+=" , ttAddAssign), + asTokenDef("++" , ttInc), + asTokenDef("-" , ttMinus), + asTokenDef("-=" , ttSubAssign), + asTokenDef("--" , ttDec), + asTokenDef("*" , ttStar), + asTokenDef("*=" , ttMulAssign), + asTokenDef("/" , ttSlash), + asTokenDef("/=" , ttDivAssign), + asTokenDef("%" , ttPercent), + asTokenDef("%=" , ttModAssign), + asTokenDef("**" , ttStarStar), + asTokenDef("**=" , ttPowAssign), + asTokenDef("=" , ttAssignment), + asTokenDef("==" , ttEqual), + asTokenDef("." , ttDot), + asTokenDef("|" , ttBitOr), + asTokenDef("|=" , ttOrAssign), + asTokenDef("||" , ttOr), + asTokenDef("&" , ttAmp), + asTokenDef("&=" , ttAndAssign), + asTokenDef("&&" , ttAnd), + asTokenDef("^" , ttBitXor), + asTokenDef("^=" , ttXorAssign), + asTokenDef("^^" , ttXor), + asTokenDef("<" , ttLessThan), + asTokenDef("<=" , ttLessThanOrEqual), + asTokenDef("<<" , ttBitShiftLeft), + asTokenDef("<<=" , ttShiftLeftAssign), + asTokenDef(">" , ttGreaterThan), + asTokenDef(">=" , ttGreaterThanOrEqual), + asTokenDef(">>" , ttBitShiftRight), + asTokenDef(">>=" , ttShiftRightLAssign), + asTokenDef(">>>" , ttBitShiftRightArith), + asTokenDef(">>>=" , ttShiftRightAAssign), + asTokenDef("~" , ttBitNot), + asTokenDef(";" , ttEndStatement), + asTokenDef("," , ttListSeparator), + asTokenDef("{" , ttStartStatementBlock), + asTokenDef("}" , ttEndStatementBlock), + asTokenDef("(" , ttOpenParanthesis), + asTokenDef(")" , ttCloseParanthesis), + asTokenDef("[" , ttOpenBracket), + asTokenDef("]" , ttCloseBracket), + asTokenDef("?" , ttQuestion), + asTokenDef(":" , ttColon), + asTokenDef("::" , ttScope), + asTokenDef("!" , ttNot), + asTokenDef("!=" , ttNotEqual), + asTokenDef("!is" , ttNotIs), + asTokenDef("@" , ttHandle), + asTokenDef("and" , ttAnd), + asTokenDef("auto" , ttAuto), + asTokenDef("bool" , ttBool), + asTokenDef("break" , ttBreak), + asTokenDef("case" , ttCase), + asTokenDef("cast" , ttCast), + asTokenDef("catch" , ttCatch), + asTokenDef("class" , ttClass), + asTokenDef("const" , ttConst), + asTokenDef("continue" , ttContinue), + asTokenDef("default" , ttDefault), + asTokenDef("do" , ttDo), +#ifdef AS_USE_DOUBLE_AS_FLOAT + asTokenDef("double" , ttFloat), +#else + asTokenDef("double" , ttDouble), +#endif + asTokenDef("else" , ttElse), + asTokenDef("enum" , ttEnum), + asTokenDef("false" , ttFalse), + asTokenDef("float" , ttFloat), + asTokenDef("for" , ttFor), + asTokenDef("funcdef" , ttFuncDef), + asTokenDef("if" , ttIf), + asTokenDef("import" , ttImport), + asTokenDef("in" , ttIn), + asTokenDef("inout" , ttInOut), + asTokenDef("int" , ttInt), + asTokenDef("int8" , ttInt8), + asTokenDef("int16" , ttInt16), + asTokenDef("int32" , ttInt), + asTokenDef("int64" , ttInt64), + asTokenDef("interface" , ttInterface), + asTokenDef("is" , ttIs), + asTokenDef("mixin" , ttMixin), + asTokenDef("namespace" , ttNamespace), + asTokenDef("not" , ttNot), + asTokenDef("null" , ttNull), + asTokenDef("or" , ttOr), + asTokenDef("out" , ttOut), + asTokenDef("private" , ttPrivate), + asTokenDef("protected" , ttProtected), + asTokenDef("return" , ttReturn), + asTokenDef("switch" , ttSwitch), + asTokenDef("true" , ttTrue), + asTokenDef("try" , ttTry), + asTokenDef("typedef" , ttTypedef), + asTokenDef("uint" , ttUInt), + asTokenDef("uint8" , ttUInt8), + asTokenDef("uint16" , ttUInt16), + asTokenDef("uint32" , ttUInt), + asTokenDef("uint64" , ttUInt64), + asTokenDef("void" , ttVoid), + asTokenDef("while" , ttWhile), + asTokenDef("xor" , ttXor), +}; + +const unsigned int numTokenWords = sizeof(tokenWords)/sizeof(sTokenWord); + +const char * const whiteSpace = " \t\r\n"; + +// Some keywords that are not considered tokens by the parser +// These only have meaning in specific situations. Outside these +// situations they are treated as normal identifiers. +const char * const THIS_TOKEN = "this"; +const char * const FROM_TOKEN = "from"; +const char * const SUPER_TOKEN = "super"; +const char * const SHARED_TOKEN = "shared"; +const char * const FINAL_TOKEN = "final"; +const char * const OVERRIDE_TOKEN = "override"; +const char * const GET_TOKEN = "get"; +const char * const SET_TOKEN = "set"; +const char * const ABSTRACT_TOKEN = "abstract"; +const char * const FUNCTION_TOKEN = "function"; +const char * const IF_HANDLE_TOKEN = "if_handle_then_const"; +const char * const EXTERNAL_TOKEN = "external"; +const char * const EXPLICIT_TOKEN = "explicit"; +const char * const PROPERTY_TOKEN = "property"; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_tokenizer.cpp b/angelscript/source/as_tokenizer.cpp new file mode 100644 index 0000000..2017a12 --- /dev/null +++ b/angelscript/source/as_tokenizer.cpp @@ -0,0 +1,475 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2015 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_tokenizer.cpp +// +// This class identifies tokens from the script code +// + +#include "as_config.h" +#include "as_scriptengine.h" +#include "as_tokenizer.h" +#include "as_tokendef.h" + +#if !defined(AS_NO_MEMORY_H) +#include +#endif +#include // strcmp() + +BEGIN_AS_NAMESPACE + +asCTokenizer::asCTokenizer() +{ + engine = 0; + memset(keywordTable, 0, sizeof(keywordTable)); + + // Initialize the jump table + for( asUINT n = 0; n < numTokenWords; n++ ) + { + const sTokenWord& current = tokenWords[n]; + unsigned char start = current.word[0]; + + // Create new jump table entry if none exists + if( !keywordTable[start] ) + { + // Surely there won't ever be more than 32 keywords starting with + // the same character. Right? + keywordTable[start] = asNEWARRAY(const sTokenWord*, 32); + memset(keywordTable[start], 0, sizeof(sTokenWord*)*32); + } + + // Add the token sorted from longest to shortest so + // we check keywords greedily. + const sTokenWord** tok = keywordTable[start]; + unsigned insert = 0, index = 0; + while( tok[index] ) + { + if(tok[index]->wordLength >= current.wordLength) + ++insert; + ++index; + } + + while( index > insert ) + { + tok[index] = tok[index - 1]; + --index; + } + + tok[insert] = ¤t; + } +} + +asCTokenizer::~asCTokenizer() +{ + // Deallocate the jump table + for( asUINT n = 0; n < 256; n++ ) + { + if( keywordTable[n] ) + asDELETEARRAY(keywordTable[n]); + } +} + +// static +const char *asCTokenizer::GetDefinition(int tokenType) +{ + if( tokenType == ttUnrecognizedToken ) return ""; + if( tokenType == ttEnd ) return ""; + if( tokenType == ttWhiteSpace ) return ""; + if( tokenType == ttOnelineComment ) return ""; + if( tokenType == ttMultilineComment ) return ""; + if( tokenType == ttIdentifier ) return ""; + if( tokenType == ttIntConstant ) return ""; + if( tokenType == ttFloatConstant ) return ""; + if( tokenType == ttDoubleConstant ) return ""; + if( tokenType == ttStringConstant ) return ""; + if( tokenType == ttMultilineStringConstant ) return ""; + if( tokenType == ttNonTerminatedStringConstant ) return ""; + if( tokenType == ttBitsConstant ) return ""; + if( tokenType == ttHeredocStringConstant ) return ""; + + for( asUINT n = 0; n < numTokenWords; n++ ) + if( tokenWords[n].tokenType == tokenType ) + return tokenWords[n].word; + + return 0; +} + +bool asCTokenizer::IsDigitInRadix(char ch, int radix) const +{ + if( ch >= '0' && ch <= '9' ) return (ch -= '0') < radix; + if( ch >= 'A' && ch <= 'Z' ) return (ch -= 'A'-10) < radix; + if( ch >= 'a' && ch <= 'z' ) return (ch -= 'a'-10) < radix; + return false; +} + +eTokenType asCTokenizer::GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc) const +{ + asASSERT(source != 0); + asASSERT(tokenLength != 0); + + eTokenType tokenType; + size_t tlen; + asETokenClass t = ParseToken(source, sourceLength, tlen, tokenType); + if( tc ) *tc = t; + if( tokenLength ) *tokenLength = tlen; + + return tokenType; +} + +asETokenClass asCTokenizer::ParseToken(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const +{ + if( IsWhiteSpace(source, sourceLength, tokenLength, tokenType) ) return asTC_WHITESPACE; + if( IsComment(source, sourceLength, tokenLength, tokenType) ) return asTC_COMMENT; + if( IsConstant(source, sourceLength, tokenLength, tokenType) ) return asTC_VALUE; + if( IsIdentifier(source, sourceLength, tokenLength, tokenType) ) return asTC_IDENTIFIER; + if( IsKeyWord(source, sourceLength, tokenLength, tokenType) ) return asTC_KEYWORD; + + // If none of the above this is an unrecognized token + // We can find the length of the token by advancing + // one step and trying to identify a token there + tokenType = ttUnrecognizedToken; + tokenLength = 1; + + return asTC_UNKNOWN; +} + +bool asCTokenizer::IsWhiteSpace(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const +{ + // Treat UTF8 byte-order-mark (EF BB BF) as whitespace + if( sourceLength >= 3 && + asBYTE(source[0]) == 0xEFu && + asBYTE(source[1]) == 0xBBu && + asBYTE(source[2]) == 0xBFu ) + { + tokenType = ttWhiteSpace; + tokenLength = 3; + return true; + } + + // Group all other white space characters into one + size_t n; + int numWsChars = (int)strlen(whiteSpace); + for( n = 0; n < sourceLength; n++ ) + { + bool isWhiteSpace = false; + for( int w = 0; w < numWsChars; w++ ) + { + if( source[n] == whiteSpace[w] ) + { + isWhiteSpace = true; + break; + } + } + if( !isWhiteSpace ) break; + } + + if( n > 0 ) + { + tokenType = ttWhiteSpace; + tokenLength = n; + return true; + } + + return false; +} + +bool asCTokenizer::IsComment(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const +{ + if( sourceLength < 2 ) + return false; + + if( source[0] != '/' ) + return false; + + if( source[1] == '/' ) + { + // One-line comment + + // Find the length + size_t n; + for( n = 2; n < sourceLength; n++ ) + { + if( source[n] == '\n' ) + break; + } + + tokenType = ttOnelineComment; + tokenLength = n < sourceLength ? n+1 : n; + + return true; + } + + if( source[1] == '*' ) + { + // Multi-line comment + + // Find the length + size_t n; + for( n = 2; n < sourceLength-1; ) + { + if( source[n++] == '*' && source[n] == '/' ) + break; + } + + tokenType = ttMultilineComment; + tokenLength = n+1; + + return true; + } + + return false; +} + +bool asCTokenizer::IsConstant(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const +{ + // Starting with number + if( (source[0] >= '0' && source[0] <= '9') || (source[0] == '.' && sourceLength > 1 && source[1] >= '0' && source[1] <= '9') ) + { + // Is it a based number? + if( source[0] == '0' && sourceLength > 1 ) + { + // Determine the radix for the constant + int radix = 0; + switch( source[1] ) + { + case 'b': case 'B': radix = 2; break; + case 'o': case 'O': radix = 8; break; + case 'd': case 'D': radix = 10; break; + case 'x': case 'X': radix = 16; break; + } + + if( radix ) + { + size_t n; + for( n = 2; n < sourceLength; n++ ) + if( !IsDigitInRadix(source[n], radix) ) + break; + + tokenType = ttBitsConstant; + tokenLength = n; + return true; + } + } + + size_t n; + for( n = 0; n < sourceLength; n++ ) + { + if( source[n] < '0' || source[n] > '9' ) + break; + } + + if( n < sourceLength && (source[n] == '.' || source[n] == 'e' || source[n] == 'E') ) + { + if( source[n] == '.' ) + { + n++; + for( ; n < sourceLength; n++ ) + { + if( source[n] < '0' || source[n] > '9' ) + break; + } + } + + if( n < sourceLength && (source[n] == 'e' || source[n] == 'E') ) + { + n++; + if( n < sourceLength && (source[n] == '-' || source[n] == '+') ) + n++; + + for( ; n < sourceLength; n++ ) + { + if( source[n] < '0' || source[n] > '9' ) + break; + } + } + + if( n < sourceLength && (source[n] == 'f' || source[n] == 'F') ) + { + tokenType = ttFloatConstant; + tokenLength = n + 1; + } + else + { +#ifdef AS_USE_DOUBLE_AS_FLOAT + tokenType = ttFloatConstant; +#else + tokenType = ttDoubleConstant; +#endif + tokenLength = n; + } + return true; + } + + tokenType = ttIntConstant; + tokenLength = n; + return true; + } + + // String constant between double or single quotes + if( source[0] == '"' || source[0] == '\'' ) + { + // Is it a normal string constant or a heredoc string constant? + if( sourceLength >= 6 && source[0] == '"' && source[1] == '"' && source[2] == '"' ) + { + // Heredoc string constant (spans multiple lines, no escape sequences) + + // Find the length + size_t n; + for( n = 3; n < sourceLength-2; n++ ) + { + if( source[n] == '"' && source[n+1] == '"' && source[n+2] == '"' ) + break; + } + + tokenType = ttHeredocStringConstant; + tokenLength = n+3; + } + else + { + // Normal string constant + tokenType = ttStringConstant; + char quote = source[0]; + bool evenSlashes = true; + size_t n; + for( n = 1; n < sourceLength; n++ ) + { +#ifdef AS_DOUBLEBYTE_CHARSET + // Double-byte characters are only allowed for ASCII + if( (source[n] & 0x80) && engine->ep.scanner == 0 ) + { + // This is a leading character in a double byte character, + // include both in the string and continue processing. + n++; + continue; + } +#endif + + if( source[n] == '\n' ) + tokenType = ttMultilineStringConstant; + if( source[n] == quote && evenSlashes ) + { + tokenLength = n+1; + return true; + } + if( source[n] == '\\' ) evenSlashes = !evenSlashes; else evenSlashes = true; + } + + tokenType = ttNonTerminatedStringConstant; + tokenLength = n; + } + + return true; + } + + return false; +} + +bool asCTokenizer::IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const +{ + // char is unsigned by default on some architectures, e.g. ppc and arm + // Make sure the value is always treated as signed in the below comparisons + signed char c = source[0]; + + // Starting with letter or underscore + if( (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + c == '_' || + (c < 0 && engine->ep.allowUnicodeIdentifiers) ) + { + tokenType = ttIdentifier; + tokenLength = 1; + + for( size_t n = 1; n < sourceLength; n++ ) + { + c = source[n]; + if( (c >= 'a' && c <= 'z') || + (c >= 'A' && c <= 'Z') || + (c >= '0' && c <= '9') || + c == '_' || + (c < 0 && engine->ep.allowUnicodeIdentifiers) ) + tokenLength++; + else + break; + } + + // Make sure the identifier isn't a reserved keyword + if( IsKeyWord(source, tokenLength, tokenLength, tokenType) ) + return false; + + return true; + } + + return false; +} + +bool asCTokenizer::IsKeyWord(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const +{ + unsigned char start = source[0]; + const sTokenWord **ptr = keywordTable[start]; + + if( !ptr ) + return false; + + for( ; *ptr; ++ptr ) + { + size_t wlen = (*ptr)->wordLength; + if( sourceLength >= wlen && strncmp(source, (*ptr)->word, wlen) == 0 ) + { + // Tokens that end with a character that can be part of an + // identifier require an extra verification to guarantee that + // we don't split an identifier token, e.g. the "!is" token + // and the tokens "!" and "isTrue" in the "!isTrue" expression. + if( wlen < sourceLength && + ((source[wlen-1] >= 'a' && source[wlen-1] <= 'z') || + (source[wlen-1] >= 'A' && source[wlen-1] <= 'Z') || + (source[wlen-1] >= '0' && source[wlen-1] <= '9')) && + ((source[wlen] >= 'a' && source[wlen] <= 'z') || + (source[wlen] >= 'A' && source[wlen] <= 'Z') || + (source[wlen] >= '0' && source[wlen] <= '9') || + (source[wlen] == '_')) ) + { + // The token doesn't really match, even though + // the start of the source matches the token + continue; + } + + tokenType = (*ptr)->tokenType; + tokenLength = wlen; + return true; + } + } + + return false; +} + +END_AS_NAMESPACE + diff --git a/angelscript/source/as_tokenizer.h b/angelscript/source/as_tokenizer.h new file mode 100644 index 0000000..38a08c1 --- /dev/null +++ b/angelscript/source/as_tokenizer.h @@ -0,0 +1,79 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2013 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_tokenizer.cpp +// +// This class identifies tokens from the script code +// + + + +#ifndef AS_TOKENIZER_H +#define AS_TOKENIZER_H + +#include "as_config.h" +#include "as_tokendef.h" +#include "as_map.h" +#include "as_string.h" + +BEGIN_AS_NAMESPACE + +class asCTokenizer +{ +public: + eTokenType GetToken(const char *source, size_t sourceLength, size_t *tokenLength, asETokenClass *tc = 0) const; + + static const char *GetDefinition(int tokenType); + +protected: + friend class asCScriptEngine; + + asCTokenizer(); + ~asCTokenizer(); + + asETokenClass ParseToken(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; + bool IsWhiteSpace(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; + bool IsComment(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; + bool IsConstant(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; + bool IsKeyWord(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; + bool IsIdentifier(const char *source, size_t sourceLength, size_t &tokenLength, eTokenType &tokenType) const; + bool IsDigitInRadix(char ch, int radix) const; + + const asCScriptEngine *engine; + + const sTokenWord **keywordTable[256]; +}; + +END_AS_NAMESPACE + +#endif + diff --git a/angelscript/source/as_typeinfo.cpp b/angelscript/source/as_typeinfo.cpp new file mode 100644 index 0000000..04f240d --- /dev/null +++ b/angelscript/source/as_typeinfo.cpp @@ -0,0 +1,476 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2020 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_typeinfo.cpp +// + + +#include "as_config.h" +#include "as_typeinfo.h" +#include "as_scriptengine.h" + +BEGIN_AS_NAMESPACE + +asCTypeInfo::asCTypeInfo() +{ + externalRefCount.set(0); + internalRefCount.set(1); // start with one internal ref-count + engine = 0; + module = 0; + size = 0; + flags = 0; + typeId = -1; // start as -1 to signal that it hasn't been defined + + scriptSectionIdx = -1; + declaredAt = 0; + + accessMask = 0xFFFFFFFF; + nameSpace = 0; +} + +asCTypeInfo::asCTypeInfo(asCScriptEngine *in_engine) +{ + externalRefCount.set(0); + internalRefCount.set(1); // start with one internal ref count + engine = in_engine; + module = 0; + size = 0; + flags = 0; + typeId = -1; // start as -1 to signal that it hasn't been defined + + scriptSectionIdx = -1; + declaredAt = 0; + + accessMask = 0xFFFFFFFF; + nameSpace = engine->nameSpaces[0]; +} + +asCTypeInfo::~asCTypeInfo() +{ +} + +// interface +int asCTypeInfo::AddRef() const +{ + return externalRefCount.atomicInc(); +} + +// interface +int asCTypeInfo::Release() const +{ + int r = externalRefCount.atomicDec(); + + if (r == 0) + { + // There are no more external references, if there are also no + // internal references then it is time to delete the object type + if (internalRefCount.get() == 0) + { + // If the engine is no longer set, then it has already been + // released and we must take care of the deletion ourselves + asDELETE(const_cast(this), asCTypeInfo); + } + } + + return r; +} + +int asCTypeInfo::AddRefInternal() +{ + return internalRefCount.atomicInc(); +} + +int asCTypeInfo::ReleaseInternal() +{ + int r = internalRefCount.atomicDec(); + + if (r == 0) + { + // There are no more internal references, if there are also no + // external references then it is time to delete the object type + if (externalRefCount.get() == 0) + { + // If the engine is no longer set, then it has already been + // released and we must take care of the deletion ourselves + asDELETE(const_cast(this), asCTypeInfo); + } + } + + return r; +} + +// interface +asIScriptModule *asCTypeInfo::GetModule() const +{ + return module; +} + +void *asCTypeInfo::SetUserData(void *data, asPWORD type) +{ + // As a thread might add a new new user data at the same time as another + // it is necessary to protect both read and write access to the userData member + ACQUIREEXCLUSIVE(engine->engineRWLock); + + // It is not intended to store a lot of different types of userdata, + // so a more complex structure like a associative map would just have + // more overhead than a simple array. + for (asUINT n = 0; n < userData.GetLength(); n += 2) + { + if (userData[n] == type) + { + void *oldData = reinterpret_cast(userData[n + 1]); + userData[n + 1] = reinterpret_cast(data); + + RELEASEEXCLUSIVE(engine->engineRWLock); + + return oldData; + } + } + + userData.PushLast(type); + userData.PushLast(reinterpret_cast(data)); + + RELEASEEXCLUSIVE(engine->engineRWLock); + + return 0; +} + +void *asCTypeInfo::GetUserData(asPWORD type) const +{ + // There may be multiple threads reading, but when + // setting the user data nobody must be reading. + ACQUIRESHARED(engine->engineRWLock); + + for (asUINT n = 0; n < userData.GetLength(); n += 2) + { + if (userData[n] == type) + { + RELEASESHARED(engine->engineRWLock); + return reinterpret_cast(userData[n + 1]); + } + } + + RELEASESHARED(engine->engineRWLock); + + return 0; +} + +// interface +const char *asCTypeInfo::GetName() const +{ + return name.AddressOf(); +} + +// interface +const char *asCTypeInfo::GetNamespace() const +{ + if( nameSpace ) + return nameSpace->name.AddressOf(); + + return 0; +} + +// interface +asDWORD asCTypeInfo::GetFlags() const +{ + return flags; +} + +// interface +asUINT asCTypeInfo::GetSize() const +{ + return size; +} + +// interface +int asCTypeInfo::GetTypeId() const +{ + if (typeId == -1) + { + // We need a non const pointer to create the asCDataType object. + // We're not breaking anything here because this function is not + // modifying the object, so this const cast is safe. + asCTypeInfo *ot = const_cast(this); + + // The engine will define the typeId for this object type + engine->GetTypeIdFromDataType(asCDataType::CreateType(ot, false)); + } + + return typeId; +} + +// interface +asIScriptEngine *asCTypeInfo::GetEngine() const +{ + return engine; +} + +// interface +const char *asCTypeInfo::GetConfigGroup() const +{ + asCConfigGroup *group = engine->FindConfigGroupForTypeInfo(this); + if (group == 0) + return 0; + + return group->groupName.AddressOf(); +} + +// interface +asDWORD asCTypeInfo::GetAccessMask() const +{ + return accessMask; +} + +// interface +int asCTypeInfo::GetProperty(asUINT index, const char **out_name, int *out_typeId, bool *out_isPrivate, bool *out_isProtected, int *out_offset, bool *out_isReference, asDWORD *out_accessMask, int *out_compositeOffset, bool *out_isCompositeIndirect) const +{ + UNUSED_VAR(index); + if (out_name) *out_name = 0; + if (out_typeId) *out_typeId = 0; + if (out_isPrivate) *out_isPrivate = false; + if (out_isProtected) *out_isProtected = false; + if (out_offset) *out_offset = 0; + if (out_isReference) *out_isReference = false; + if (out_accessMask) *out_accessMask = 0; + if (out_compositeOffset) *out_compositeOffset = 0; + if (out_isCompositeIndirect) *out_isCompositeIndirect = false; + return -1; +} + +// internal +asCObjectType *CastToObjectType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + // TODO: type: Should List pattern have its own type class? + if ((ti->flags & (asOBJ_VALUE | asOBJ_REF | asOBJ_LIST_PATTERN)) && !(ti->flags & asOBJ_FUNCDEF)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +asCEnumType *CastToEnumType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + if (ti->flags & (asOBJ_ENUM)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +asCTypedefType *CastToTypedefType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + if (ti->flags & (asOBJ_TYPEDEF)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +asCFuncdefType *CastToFuncdefType(asCTypeInfo *ti) +{ + // Allow call on null pointer + if (ti == 0) return 0; + + if (ti->flags & (asOBJ_FUNCDEF)) + return reinterpret_cast(ti); + + return 0; +} + +// internal +void asCTypeInfo::CleanUserData() +{ + asASSERT(engine); + for (asUINT n = 0; n < userData.GetLength(); n += 2) + { + if (userData[n + 1]) + { + for (asUINT c = 0; c < engine->cleanTypeInfoFuncs.GetLength(); c++) + if (engine->cleanTypeInfoFuncs[c].type == userData[n]) + engine->cleanTypeInfoFuncs[c].cleanFunc(this); + } + } + userData.SetLength(0); +} + +// internal +bool asCTypeInfo::IsShared() const +{ + // Types that can be declared by scripts need to have the explicit flag asOBJ_SHARED + if (flags & (asOBJ_SCRIPT_OBJECT | asOBJ_ENUM)) return flags & asOBJ_SHARED ? true : false; + + // Otherwise we assume the type to be shared + return true; +} + +//////////////////////////////////////////////////////////////////////////////////////// + +asCEnumType::~asCEnumType() +{ + asUINT n; + for (n = 0; n < enumValues.GetLength(); n++) + { + if (enumValues[n]) + asDELETE(enumValues[n], asSEnumValue); + } + enumValues.SetLength(0); +} + +// interface +asUINT asCEnumType::GetEnumValueCount() const +{ + return enumValues.GetLength(); +} + +// interface +const char *asCEnumType::GetEnumValueByIndex(asUINT index, int *outValue) const +{ + if (outValue) + *outValue = 0; + + if (index >= enumValues.GetLength()) + return 0; + + if (outValue) + *outValue = enumValues[index]->value; + + return enumValues[index]->name.AddressOf(); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +asCTypedefType::~asCTypedefType() +{ + DestroyInternal(); +} + +void asCTypedefType::DestroyInternal() +{ + if (engine == 0) return; + + // Release the object types held by the alias + if (aliasForType.GetTypeInfo()) + aliasForType.GetTypeInfo()->ReleaseInternal(); + + aliasForType = asCDataType::CreatePrimitive(ttVoid, false); + + CleanUserData(); + + // Remove the type from the engine + if (typeId != -1) + engine->RemoveFromTypeIdMap(this); + + // Clear the engine pointer to mark the object type as invalid + engine = 0; +} + +// interface +int asCTypedefType::GetTypedefTypeId() const +{ + return engine->GetTypeIdFromDataType(aliasForType); +} + +////////////////////////////////////////////////////////////////////////////////////////// + +asCFuncdefType::asCFuncdefType(asCScriptEngine *en, asCScriptFunction *func) : asCTypeInfo(en) +{ + asASSERT(func->funcType == asFUNC_FUNCDEF); + asASSERT(func->funcdefType == 0); + + // A function pointer is special kind of reference type + // It must be possible to garbage collect, as funcdefs can form circular references if used as delegates + flags = asOBJ_REF | asOBJ_GC | asOBJ_FUNCDEF | (func->IsShared() ? asOBJ_SHARED : 0); + name = func->name; + nameSpace = func->nameSpace; + module = func->module; + accessMask = func->accessMask; + funcdef = func; // reference already counted by the asCScriptFunction constructor + parentClass = 0; + + func->funcdefType = this; +} + +asCFuncdefType::~asCFuncdefType() +{ + DestroyInternal(); +} + +void asCFuncdefType::DestroyInternal() +{ + if (engine == 0) return; + + // Release the funcdef + if( funcdef ) + funcdef->ReleaseInternal(); + funcdef = 0; + + // Detach from parent class + if (parentClass) + { + parentClass->childFuncDefs.RemoveValue(this); + parentClass = 0; + } + + CleanUserData(); + + // Remove the type from the engine + if (typeId != -1) + engine->RemoveFromTypeIdMap(this); + + // Clear the engine pointer to mark the object type as invalid + engine = 0; +} + +// interface +asIScriptFunction *asCFuncdefType::GetFuncdefSignature() const +{ + return funcdef; +} + +// interface +asITypeInfo *asCFuncdefType::GetParentType() const +{ + return parentClass; +} + +END_AS_NAMESPACE + + diff --git a/angelscript/source/as_typeinfo.h b/angelscript/source/as_typeinfo.h new file mode 100644 index 0000000..a5643dd --- /dev/null +++ b/angelscript/source/as_typeinfo.h @@ -0,0 +1,242 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2017 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_typeinfo.h +// + + + +#ifndef AS_TYPEINFO_H +#define AS_TYPEINFO_H + +#include "as_config.h" +#include "as_string.h" +#include "as_atomic.h" +#include "as_datatype.h" + +BEGIN_AS_NAMESPACE + +class asCScriptEngine; +class asCModule; +class asCObjectType; +class asCEnumType; +class asCTypedefType; +class asCFuncdefType; +struct asSNameSpace; + +// TODO: type: asCPrimitiveType shall be implemented to represent primitives (void, int, double, etc) + +// TODO: type: asCTypeInfo should have an internal virtual method GetBehaviours. For asCObjectType it +// should return the beh member. For asCFuncdefType it should return the beh member of +// engine->functionBehaviours. This will allow the code that needs the behaviour to handle +// both object types and funcdefs the same way + +class asCTypeInfo : public asITypeInfo +{ +public: + //===================================== + // From asITypeInfo + //===================================== + asIScriptEngine *GetEngine() const; + const char *GetConfigGroup() const; + asDWORD GetAccessMask() const; + asIScriptModule *GetModule() const; + + // Memory management + int AddRef() const; + int Release() const; + + // Type info + const char *GetName() const; + const char *GetNamespace() const; + asITypeInfo *GetBaseType() const { return 0; } + bool DerivesFrom(const asITypeInfo *objType) const { UNUSED_VAR(objType); return 0; } + asDWORD GetFlags() const; + asUINT GetSize() const; + int GetTypeId() const; + int GetSubTypeId(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return -1; } + asITypeInfo *GetSubType(asUINT subtypeIndex = 0) const { UNUSED_VAR(subtypeIndex); return 0; } + asUINT GetSubTypeCount() const { return 0; } + + // Interfaces + asUINT GetInterfaceCount() const { return 0; } + asITypeInfo *GetInterface(asUINT index) const { UNUSED_VAR(index); return 0; } + bool Implements(const asITypeInfo *objType) const { UNUSED_VAR(objType); return false; } + + // Factories + asUINT GetFactoryCount() const { return 0; } + asIScriptFunction *GetFactoryByIndex(asUINT index) const { UNUSED_VAR(index); return 0; } + asIScriptFunction *GetFactoryByDecl(const char *decl) const { UNUSED_VAR(decl); return 0; } + + // Methods + asUINT GetMethodCount() const { return 0; } + asIScriptFunction *GetMethodByIndex(asUINT index, bool getVirtual) const { UNUSED_VAR(index); UNUSED_VAR(getVirtual); return 0; } + asIScriptFunction *GetMethodByName(const char *in_name, bool getVirtual) const { UNUSED_VAR(in_name); UNUSED_VAR(getVirtual); return 0; } + asIScriptFunction *GetMethodByDecl(const char *decl, bool getVirtual) const { UNUSED_VAR(decl); UNUSED_VAR(getVirtual); return 0; } + + // Properties + asUINT GetPropertyCount() const { return 0; } + int GetProperty(asUINT index, const char **name, int *typeId, bool *isPrivate, bool *isProtected, int *offset, bool *isReference, asDWORD *accessMask, int *compositeOffset, bool *isCompositeIndirect) const; + const char *GetPropertyDeclaration(asUINT index, bool includeNamespace = false) const { UNUSED_VAR(index); UNUSED_VAR(includeNamespace); return 0; } + + // Behaviours + asUINT GetBehaviourCount() const { return 0; } + asIScriptFunction *GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const { UNUSED_VAR(index); UNUSED_VAR(outBehaviour); return 0; } + + // Child types + asUINT GetChildFuncdefCount() const { return 0; } + asITypeInfo *GetChildFuncdef(asUINT index) const { UNUSED_VAR(index); return 0; } + asITypeInfo *GetParentType() const { return 0; } + + // Enums + virtual asUINT GetEnumValueCount() const { return 0; } + virtual const char *GetEnumValueByIndex(asUINT index, int *outValue) const { UNUSED_VAR(index); if (outValue) *outValue = 0; return 0; } + + // Typedef + virtual int GetTypedefTypeId() const { return asERROR; } + + // Funcdef + virtual asIScriptFunction *GetFuncdefSignature() const { return 0; } + + // User data + void *SetUserData(void *data, asPWORD type); + void *GetUserData(asPWORD type) const; + + //=========================================== + // Internal + //=========================================== +public: + asCTypeInfo(asCScriptEngine *engine); + virtual ~asCTypeInfo(); + + // Keep an internal reference counter to separate references coming from + // application or script objects and references coming from the script code + virtual int AddRefInternal(); + virtual int ReleaseInternal(); + + virtual void DestroyInternal() {} + + void CleanUserData(); + + bool IsShared() const; + + // These can be safely used on null pointers (which will return null) + friend asCObjectType *CastToObjectType(asCTypeInfo *); + friend asCEnumType *CastToEnumType(asCTypeInfo *); + friend asCTypedefType *CastToTypedefType(asCTypeInfo *); + friend asCFuncdefType *CastToFuncdefType(asCTypeInfo *); + + + asCString name; + asSNameSpace *nameSpace; + int size; + mutable int typeId; + asDWORD flags; + asDWORD accessMask; + + // Store the script section where the code was declared + int scriptSectionIdx; + // Store the location where the function was declared (row in the lower 20 bits, and column in the upper 12) + int declaredAt; + + asCScriptEngine *engine; + asCModule *module; + asCArray userData; + +protected: + friend class asCScriptEngine; + friend class asCConfigGroup; + friend class asCModule; + friend class asCObjectType; + asCTypeInfo(); + + mutable asCAtomic externalRefCount; + asCAtomic internalRefCount; +}; + +struct asSEnumValue +{ + asCString name; + int value; +}; + +class asCEnumType : public asCTypeInfo +{ +public: + asCEnumType(asCScriptEngine *engine) : asCTypeInfo(engine) {} + ~asCEnumType(); + + asCArray enumValues; + + asUINT GetEnumValueCount() const; + const char *GetEnumValueByIndex(asUINT index, int *outValue) const; + +protected: + asCEnumType() : asCTypeInfo() {} +}; + +class asCTypedefType : public asCTypeInfo +{ +public: + asCTypedefType(asCScriptEngine *engine) : asCTypeInfo(engine) {} + ~asCTypedefType(); + + void DestroyInternal(); + + asCDataType aliasForType; // increase refCount for typeinfo inside datatype + + int GetTypedefTypeId() const; + +protected: + asCTypedefType() : asCTypeInfo() {} +}; + +class asCFuncdefType : public asCTypeInfo +{ +public: + asCFuncdefType(asCScriptEngine *engine, asCScriptFunction *func); + ~asCFuncdefType(); + + asIScriptFunction *GetFuncdefSignature() const; + asITypeInfo *GetParentType() const; + + void DestroyInternal(); + asCScriptFunction *funcdef; // increases refCount + asCObjectType *parentClass; // doesn't increase refCount + +protected: + asCFuncdefType() : asCTypeInfo(), funcdef(0), parentClass(0) {} +}; + +END_AS_NAMESPACE + +#endif diff --git a/angelscript/source/as_variablescope.cpp b/angelscript/source/as_variablescope.cpp new file mode 100644 index 0000000..aca36da --- /dev/null +++ b/angelscript/source/as_variablescope.cpp @@ -0,0 +1,142 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2012 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_variablescope.cpp +// +// A manager class for variable declarations +// + + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_variablescope.h" + +BEGIN_AS_NAMESPACE + +asCVariableScope::asCVariableScope(asCVariableScope *parent) +{ + this->parent = parent; + Reset(); +} + +asCVariableScope::~asCVariableScope() +{ + Reset(); +} + +void asCVariableScope::Reset() +{ + isBreakScope = false; + isContinueScope = false; + + for( asUINT n = 0; n < variables.GetLength(); n++ ) + if( variables[n] ) + { + asDELETE(variables[n],sVariable); + } + variables.SetLength(0); +} + +int asCVariableScope::DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool onHeap) +{ + // TODO: optimize: Improve linear search + // See if the variable is already declared + if( strcmp(name, "") != 0 ) + { + for( asUINT n = 0; n < variables.GetLength(); n++ ) + { + if( variables[n]->name == name ) + return -1; + } + } + + sVariable *var = asNEW(sVariable); + if( var == 0 ) + { + // Out of memory. Return without allocating the var + return -2; + } + var->name = name; + var->type = type; + var->stackOffset = stackOffset; + var->isInitialized = false; + var->isPureConstant = false; + var->onHeap = onHeap; + + // Parameters are initialized + if( stackOffset <= 0 ) + var->isInitialized = true; + + variables.PushLast(var); + + return 0; +} + +sVariable *asCVariableScope::GetVariable(const char *name) +{ + // TODO: optimize: Improve linear search + // Find the variable + for( asUINT n = 0; n < variables.GetLength(); n++ ) + { + if( variables[n]->name == name ) + return variables[n]; + } + + if( parent ) + return parent->GetVariable(name); + + return 0; +} + +sVariable *asCVariableScope::GetVariableByOffset(int offset) +{ + // TODO: optimize: Improve linear search + // Find the variable + for( asUINT n = 0; n < variables.GetLength(); n++ ) + { + if( variables[n]->stackOffset == offset ) + return variables[n]; + } + + if( parent ) + return parent->GetVariableByOffset(offset); + + return 0; +} + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + + diff --git a/angelscript/source/as_variablescope.h b/angelscript/source/as_variablescope.h new file mode 100644 index 0000000..d4b220a --- /dev/null +++ b/angelscript/source/as_variablescope.h @@ -0,0 +1,87 @@ +/* + AngelCode Scripting Library + Copyright (c) 2003-2012 Andreas Jonsson + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any + damages arising from the use of this software. + + Permission is granted to anyone to use this software for any + purpose, including commercial applications, and to alter it and + redistribute it freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you + must not claim that you wrote the original software. If you use + this software in a product, an acknowledgment in the product + documentation would be appreciated but is not required. + + 2. Altered source versions must be plainly marked as such, and + must not be misrepresented as being the original software. + + 3. This notice may not be removed or altered from any source + distribution. + + The original version of this library can be located at: + http://www.angelcode.com/angelscript/ + + Andreas Jonsson + andreas@angelcode.com +*/ + + +// +// as_variablescope.h +// +// A manager class for variable declarations +// + + +#ifndef AS_VARIABLESCOPE_H +#define AS_VARIABLESCOPE_H + +#include "as_config.h" + +#ifndef AS_NO_COMPILER + +#include "as_array.h" +#include "as_string.h" +#include "as_datatype.h" + +BEGIN_AS_NAMESPACE + +struct sVariable +{ + asCString name; + asCDataType type; + int stackOffset; + bool isInitialized; + bool isPureConstant; + asQWORD constantValue; + bool onHeap; +}; + +class asCVariableScope +{ +public: + asCVariableScope(asCVariableScope *parent); + ~asCVariableScope(); + + void Reset(); + + int DeclareVariable(const char *name, const asCDataType &type, int stackOffset, bool isObjectOnHeap); + sVariable *GetVariable(const char *name); + sVariable *GetVariableByOffset(int offset); + + asCVariableScope *parent; + + bool isBreakScope; + bool isContinueScope; + + asCArray variables; +}; + +END_AS_NAMESPACE + +#endif // AS_NO_COMPILER + +#endif diff --git a/docs/articles/changes0.html b/docs/articles/changes0.html new file mode 100644 index 0000000..f5e7c8d --- /dev/null +++ b/docs/articles/changes0.html @@ -0,0 +1,206 @@ + + +AngelScript - Changes + + + + + + + +

AngelScript Change Log

+ +

Version 0.95 - 2003/06/17

+ +
    +
  • Fixed bug in constant declaration +
  • Improved byte code for string manipulation +
  • Added data type: bits +
  • new operators: ~ | & ^ << >> >>> |= &= ^= <<= >>= >>>= +
  • added bits constants: 0xFFA +
  • Fixed a bug in the call stack +
+ +

Version 0.85 - 2003/06/04

+ +
    +
  • stack positions are re-used when variables goes out of scope +
  • bstr is now copied instead of reference counted +
  • concatenation operators for bstr: + += +
  • comparison operators for bstr: == != < > <= >= +
  • If script is aborted or an exception occurs the engine cleans up the stack +
  • Engine now executes until finished or until aborted +
  • Arguments can now be sent by reference instead of by value +
+ +

Version 0.7 - 2003/05/28

+ +
    +
  • Added ?: operator +
  • Added compound assignments: += -= *= /= %= +
  • New data type: bstr (byte string) +
  • Added support for string constants +
  • Character sequences: \n \r \0 \\ \" \x00 +
+ +

Version 0.55 - 2003/05/19

+ +
    +
  • removed include from AngelScript +
  • AngelScript no longer loads the scriptcode from disk +
  • the host application can add several pieces of code that will be compiled as one +
+ +

Version 0.5 - 2003/05/15

+ +
    +
  • declaration of global constants through directive: const +
  • added do-while statement +
  • fixed bug in AngelScript +
+ +

Version 0.4 - 2003/05/09

+ +
    +
  • AngelScript now allows for application defined datatypes +
  • fixed potential bug in AngelScript +
+ +

Version 0.3 - 2003/04/23

+ +
    +
  • Modulo operator % +
  • minor changes in the virtual machine +
  • fixed bug in compiler +
+ +

Version 0.25 - 2003/04/15

+ +
    +
  • Added ++ -- +
  • Boolean expressions are no longer fully evaluated +
  • Added break continue +
+ +

Version 0.2 - 2003/04/09

+ +
    +
  • using cdecl calling convention +
+ +

Version 0.1 - 2003/03/28

+ +
    +
  • Simple scripting with int float +
+ + + \ No newline at end of file diff --git a/docs/articles/changes1.html b/docs/articles/changes1.html new file mode 100644 index 0000000..d24a379 --- /dev/null +++ b/docs/articles/changes1.html @@ -0,0 +1,898 @@ + + +AngelScript - Changes + + + + + + + +

AngelScript Change Log

+ +

Version 1.10.1d - 2005/01/21

+ +
    +
  • Bug fixes +
      +
    • asGetActiveContext() now returns 0 if there are no active contexts +
    • It is now possible to overload arrays of registered types +
    • Removed an assert failure when compiling math operator on non-math types +
    • On GCC/Linux all classes/structs are always returned in memory regardless of size and complexity +
    • Some compilers complained about the negative array size in the template code that is never instanciated. The code was commented. +
    • Fixed an assert failure when trying to use a unregistered object type (thanks Alain "abrken" Bridel) +
    +
+ +

Version 1.10.1c - 2004/12/19

+ +
    +
  • Bug fixes +
      +
    • ExecuteString() could sometimes return an invalid context pointer when an error occurred. +
    • Application functions that returned float or double failed on GNUC based compilers with optimizations turned on. (thanks Marcin "Szpak" Zajaczkowski) +
    • Prepare() could crash if the function id was incorrect. +
    +
+ +

Version 1.10.1b - 2004/12/01

+ +
    +
  • Bug fixes +
      +
    • Temporary objects created explicitly by calling the object's constructor weren't properly handled by the exception handler (thanks Alain "abrken" Bridel) +
    • Values were not implicitly converted to the parameter type when sent as function arguments +
    +
+ +

Version 1.10.1a - 2004/11/26

+ +
    +
  • Bug fixes +
      +
    • The tokenizer wasn't able to handle string constants that ended with two backslashes (thanks Scott "waheyluggage" Newby) +
    • The calling convention asCALL_CDECL_OBJFIRST wasn't working for functions with parameters +
    • rvalue was not verified to be initialized in assignments +
    +
+ +

Version 1.10.1 - 2004/11/21

+ +
    +
  • Bug fixes +
      +
    • The -> operator didn't compile correctly (thanks Adrian Licu) +
    • If the ?: operator returned literal constants there was an assert failure (thanks Alain "abrken" Bridel) +
    • Arrays of pointers were wrongly reported as uninitialized by the compiler +
    • Dereferencing temporary variables didn't release the variable +
    • Multidimensional arrays weren't working on GNUC based compilers +
    • Arrays of pointers to objects where causing problems (thanks Dan "Aggrav8d" Royer) +
    • Conversions to and from double failed in the VM (thanks Jetro Lauha) +
    • CALLBND didn't work in the ASM vm +
    • ExecuteStep() still didn't work as before with BUILD_WITH_LINE_CUES (thanks Josh Passenger) +
    • ++ and -- failed in ASM VM for float values +
    • Temporary variables where at times prematurely released (thanks Jetro Lauha) +
    + +
  • Library interface +
      +
    • asIScriptContext::Prepare() can now be called with the argument asPREPARE_PREVIOUS to prepare a context for calling the same function that was previously called. +
    + +
  • Script language +
      +
    • All number types are now implicitly converted for assignments and function arguments +
    • When evaluating math operations of two different number types the types are first implicitly converted to the largest type +
    • bits datatype is implicitly converted to and from uint/int +
    + +
  • Virtual machine +
      +
    • Optimized the ASM VM +
    + +
  • Compiler +
      +
    • Greatly improved build times +
    + +
  • Multithreading +
      +
    • Multithreading support is off by default, to add the support define the flag USE_THREADS +
    • The flag NO_THREADS no longer have any effect +
    + +
  • Project files +
      +
    • Added as_typeinfo.h and as_typeinfo.cpp +
    +
+ +

Version 1.10.0 - 2004/11/02

+ +
    +
  • Virtual machine +
      +
    • Optimized the C++ VM +
    • Jumps no longer suspend the VM +
    • New byte code BC_END, only used by exception handler. +
    • Added a new module as_context_x86.cpp with an optimized VM using assembly. Compile with the flag USE_ASM_VM to utilize this new VM. (contribution by Andres "Lioric" Carrera) NOTE: This is currently slightly slower than the C++ VM, but will be optimized further in future releases. +
    • Removed the NOP instructions as they are no longer needed for alignment +
    • Added the SUSPEND bytecode again. It's used to guarantee that the host application always can suspend a context, i.e. all loops have a SUSPEND instruction. +
    + +
  • Bug fixes +
      +
    • Exception handler would continue the execution +
    • Temporary variables were not always freed after compiling a function call +
    • Constants were not always successfully converted to reference when making function calls (thanks Anthony "Deyja" Casteel) +
    • The switch case didn't treat 8 and 16 bit integer types correctly (thanks Alain "abrken" Bridel) +
    • The exception handler failed when objects where returned by reference +
    • There was a memory leak when adding script sections but not actually building them (thanks Alain "abrken" Bridel) +
    + +
  • Script language +
      +
    • Added the operator 'xor' for boolean types. Alias '^^' (suggestion by Thomas Suter) +
    • Added native support for arrays +
    + +
  • Library interface +
      +
    • Changed the parameter type for callConv to asDWORD in the interface +
    • If the configuration is wrong the engine writes the message "Invalid configuration" to the outstream if available. People keep forgetting to verify the return code, this may help them understand why the build isn't done. +
    • RegisterObjectBehaviour() should only be used for object behaviours. Global behaviours should be registered with RegisterGlobalBehaviour(). +
    • GetFunctionName(), GetFunctionDeclaration(), GetGlobalVarName(), GetGlobalVarDeclaration(), GetImportedFunctionDeclaration(), and GetExceptionString() have changed to return a pointer to the string, so it is no longer necessary to pass a buffer to them. +
    • GetImportedFunctionSourceModule() and GetModuleNameFromIndex() now return the length as well. +
    • New global function asThreadCleanup() (see multithreading) + +
    • Fixed ExecuteStep() to work as before +
        +
      • By default ExecuteStep() is guaranteed to suspend execution at least once per loop +
      • Added the compile flag BUILD_WITH_LINE_CUES, which makes the script compiler add extra bytecodes that allow ExecuteStep() to return after each statement. +
      + +
    • Improved ExecuteString() +
        +
      • Calls to ExecuteString() can now be nested. +
      • ExecuteString() now takes an extra parameter, which allow the application to receive the context pointer directly, or even pass its own context by using the flag asEXECSTRING_USE_MY_CONTEXT. +
      • GetContextForExecuteString() is deprecated. +
      • ExecuteString() now reports build errors with line and column number starting with the passed string. +
      + +
    • Overridable array objects +
        +
      • It is now possible to register array objects, overriding the native array object +
      • New error code: asLOWER_ARRAY_DIMENSION_NOT_REGISTERED +
      • The library now returns asAPP_CANT_INTERFACE_DEFAULT_ARRAY if the application tries to register a function that uses arrays that haven't been registered by the application. +
      +
    + +
  • Multithreading +
      +
    • Added support for multithreading (can be disabled by defining NO_THREADS) +
    • Multithreading should now work with both MSVC and MinGW. Still only for Windows though. +
    • asGetActiveContext() is now thread safe +
    • Reference counting is thread safe +
    • The engine now deletes all unused modules when Discard() is called, this simplifies the context's interaction with the modules making the engine more stable for multithreading +
    • Created the global function asThreadCleanup() that will allow AngelScript to cleanup some thread local data. Should be called before exiting any extra threads that access AngelScript. +
    + +
  • Miscellaneous +
      +
    • Added the module as_thread.cpp that abstract the OS's thread functions +
    • New module as_arrayobject.cpp for the default array implementation +
    • Added as_debug.h +
    • Made minor code changes to make compilation on Linux smoother (thanks Johannes Plass) +
    • Changed MSVC projects to output to a different file when in debugmode (thanks Dan "Aggrav8d" Royer) +
    • Added std::vector binding code to the library download (thanks Anthony "Deyja" Casteel) +
    • as_compiler_expression.cpp was merged with as_compiler.cpp +
    + +
+ +

Version 1.9.2a - 2004/10/12

+ +
    +
  • Bug fixes +
      +
    • Subtraction was optimized as if it was associative (thanks Lennart Denninger) +
    • SetArguments() failed for script functions that returns registered object types by value. (thanks Thomas Suter) +
    • The application would crash if an exception was raised in ExecuteString() (thanks Joe "Desdemona" Wright) +
    • GetFunctionName() and GetFunctionDeclaration() now works for the ExecuteString() function id as well. +
    • The compiler didn't warn when passing uninitialized variables to function parameters (thanks Alain "abrken" Bridel) +
    • Constructors with parameters could cause assertion failure in GenerateExceptionHandler(). (thanks Alain "abrken" Bridel) +
    +
+ +

Version 1.9.2 - 2004/09/30

+ +
    +
  • Library interface +
      +
    • The interface now uses default argument value where applicable to make it easier to use +
    +
  • Script language +
      +
    • Added support for global objects using constructors with parameters (contribution by Andres Carrera) +
    • Improved constructors with parameters to work with local objects as well +
    • Constructors can now be used in expressions to create temporary objects +
    +
  • Virtual Machine +
      +
    • Removed the bytecode EID, which speeds up execution when there are objects in the scripts +
    • The exception ID is found by looking in a separate array +
    • Added the bytecodes RDGA4 and MOVGA4 for faster access to global variables +
    • Removed the bytecodes SET1 and PSP +
    • Added the bytecodes ADDIi, SUBIi, ADDIf, SUBIf, CMPIf +
    +
+ +

Version 1.9.1 - 2004/09/21

+ +
    +
  • Bug fixes +
      +
    • Switch-case didn't work correctly if the cases were not ordered in ascending order (thanks Dmitry "RCL" Rekman) +
    • The ternary operator ?: didn't release temporary variables as it should, causing an assert failure in the debug version (thanks Dmitry "RCL" Rekman) +
    • Passing string constants to condition operator would cause an assertion failure. (thanks Joe "Desdemona" Wright) +
    • Implicit conversion of pointer to a reference to a pointer caused assert failure (thanks Joe "Desdemona" Wright) +
    • The ternary operator ?: still wasn't working ok (thanks Joe "Desdemona" Wright) +
    +
  • Virtual Machine +
      +
    • Added 4 new conditional jump byte codes JS, JNS, JP, and JNP +
    • Renamed JMP0 and JMP1 to JZ and JNZ respectively +
    • Added the bytecodes CMPIi and CMPIui +
    • Removed the bytecodes LINE and SUSPEND. +
    • Line numbers are now stored in a separate array for the functions that need them +
    • Added bytecode CALLSYS for calling system functions and CALLBND for calling bound functions +
    • RET now pops the function arguments +
    +
  • Script language +
      +
    • String constants are now concatenated by the compiler if only whitespace separate them +
    • If the first case in the ternary operator ?: is a constant 0 it's type will be converted to the type of the second case. +
    +
  • Compiler +
      +
    • Added many optimizations +
    • Code that can't be reached is now removed by the compiler +
    • If statements that have constant expressions are optimized to go directly to the correct case +
    • If there are no objects in the function the exception handler will only have a return instruction +
    +
  • Library interface +
      +
    • ExecuteStep() no longer suspends execution after each statement because of the remove bytecodes LINE and SUSPEND. +
    • Added support for asCALL_CDECL_OBJFIRST (thanks Tristan "Kurioes" Hartskeerl) +
    • The value of boolean true can now be configured in as_config.h (the default is set to 1) +
    +
+ +

Version 1.9.0 - 2004/09/02

+ +
    +
  • Library interface +
      +
    • Renamed RegisterTypeBehaviour() to RegisterObjectBehaviour() +
    • Removed the flags asCALL_RETURNBYVAL and asCALL_RETURNBYREF +
    • Removed the flags asOBJ_IS_COMPLEX and asOBJ_IS_NOT_COMPLEX +
    • Included support for saving and loading compiled bytecode (thanks Dennis Bollyn) +
    • Removed the need to pass stack size when calling Prepare() or ExecuteString() +
    • Added the method SetDefaultContextStackSize() +
    • New error message asINVALID_CONFIGURATION, which is returned by Build() if the configuration failed +
    • Removed AS_CALL from the interface. This changes the exported function names. +
    • Added new methods for binding module functions from different modules. +
    • Removed GetModuleID() +
    • Added GetModuleIndex(), and GetModuleNameFromIndex() +
    • Added GetFunctionIDByIndex() and GetGlobalVarIDByIndex() +
    • Added functions for automatically binding all functions imported in a module. New error code asCANT_BIND_ALL_FUNCTIONS +
    • Added the lineOffset parameter to AddScriptSection() +
    +
  • Compiler +
      +
    • Compiler no longer outputs unecessary messages, such as "Building..." +
    • Each error message now follows a standard format: {section name} ({row}, {col}) : {Error or Warning} : {Message} +
    +
  • Virtual machine +
      +
    • The context stack now dynamically grows as needed +
    • New byte code BC_STR, that pushes the constant string address and length on the stack. The direct memory address is no longer stored in the compiled byte code +
    +
  • Script language +
      +
    • Added the global statement 'import FUNC_DEF from "MODULE NAME";'. 'import' is a reserved keyword, but 'from' isn't. +
    +
  • Miscellaneous +
      +
    • Renamed acCString to asCString and acCArray to asCArray +
    • Minor code improvements and potential bug fixes (thanks Wade Brainerd) +
    +
  • Bug fixes +
      +
    • Returning complex objects in script functions didn't work as expected. (thanks Joe "Desdemona" Wright) +
    • An assert failed in GenerateExceptionHandler() when returning large types. +
    • The macros asFUNCTIONP() and asFUNCTIONPR() wasn't working (thanks Joe "Desdemona" Wright) +
    • When a Build() fails, the module is cleaned up so that ExecuteString() can't call half compiled functions +
    +
+ +

Version 1.8.3 - 2004/08/31

+ +
    +
  • bug fix: An object with asBEHAVE_ASSIGNMENT registered could be assigned even though it was declared as const (thanks Lee "_MrC_" Clark) +
  • bug fix: Two functions with the same name and parameters would cause an assertion failure in compiler (thanks Alain "abrken" Bridel) +
  • bug fix: Discarding a module with Discard() could sometimes cause the module object to be deleted twice (thanks Alain "abrken" Bridel) +
  • bug fix: There was a typo in macro asMETHODPR() (thanks Joe "Desdemona" Wright) +
  • bug fix: An unclosed statement block could lead to assert failure in the parser (thanks Alain "abrken" Bridel) +
+ +

Version 1.8.2 - 2004/08/13

+ +
    +
  • Methods from classes with multiple inheritance are now supported +
  • Changed how the byte code references script functions, so that they are now local to each module, i.e. independent of module ID +
  • BC_PGA now takes an int instead of a dword +
  • Changed so that registered global properties are referenced by index instead of their memory address +
  • Global script variables are referenced by their local index, i.e. independent of module ID +
  • Added support for switch case statements (thanks Jeff White) +
  • Added support for the negative operator behaviour. The new flag is asBEHAVE_NEGATE +
+ +

Version 1.8.1 - 2004/08/13

+ +
    +
  • Changed debug output to be put in subdirectory AS_DEBUG +
  • bug fix: Some errors were always reported on line 1 column 1, no matter where they were located +
  • bug fix: An assertion failed when a function call used a temporary variable and the function wasn't found (thanks Jakub "krajzega" Wasilewski) +
  • bug fix: Non-complex objects with 2 DWORDs in size is now correctly returned from system functions +
  • bug fix: Objects returned in memory is now correctly handled by MinGW for cdecl calling convention +
  • bug fix: Objects registered with asOBJ_IS_COMPLEX was not treated correctly by MinGW +
  • bug fix: BC_PGA didn't mask out the module ID when retrieving the address of the global variable. (thanks Anders "Dentoid" Stenberg) +
  • bug fix: Class methods can now return objects in MSVC +
  • bug fix: Local variables in the top statement block could be destroyed at return even though they were declared after the return statement. (thanks Anders "Dentoid" Stenberg) +
  • bug fix: Class methods can now return objects in memory on MinGW +
  • bug fix: ExecuteString() could cause a crash when executed on a script compiled for the second time using the same module name. (thanks Jakub "krajzega" Wasilewski) +
  • Registering methods from classes with multiple inheritance are detected and reported as not supported +
  • Registering methods from classes with virtual inheritance are detected and reported as not supported on MSVC. Can't be detected on GNUC +
  • Cleaned up as_callfunc_x86.cpp +
  • Added support for virtual methods in GNUC +
  • New flags for RegisterObjectType(): asOBJ_CLASS, asOBJ_CLASS_CONSTRUCTOR, asOBJ_CLASS_DESTRUCTOR, asOBJ_CLASS_ASSIGNMENT, asOBJ_PRIMITIVE, asOBJ_FLOAT +
  • The flags asCALL_RETURNBYREF and asCALL_RETURNBYVAL no longer have any effect, and will be removed in a future version +
+ +

Version 1.8.0c - 2004/07/19

+ +
    +
  • bug fix: When creating a module its ID wasn't set correctly if another module had previously been released (thanks Lennart Denninger) +
  • bug fix: An assert failed when calling function in global variable initialization (thanks Lennart Denninger) +
+ +

Version 1.8.0b - 2004/07/17

+ +
    +
  • bug fix: Overloaded functions in multiple modules didn't compile correctly (thanks Anders "Dentoid" Stenberg) +
  • bug fix: MinGW reported duplicate labels when compiling as_callfunc_x86.cpp (thanks Jakub "krajzega" Wasilewski) +
+ +

Version 1.8.0a - 2004/07/12

+ +
    +
  • bug fix: asOBJ_IS_NOT_COMPLEX incorrectly identified objects smaller than or equal to 8 bytes (thanks Lennart Denninger) +
  • bug fix: Function calls in a second module didn't compile correctly (thanks Lennart Denninger) +
+ +

Version 1.8.0 - 2004/07/10

+ +
    +
  • Removed the flags parameter from RegisterGlobalProperty() and RegisterObjectProperty() +
  • Added RegisterStringFactory() +
  • Removed the bstr type from the library +
  • Added new behaviour flags for assignment operators, changing the values of the others +
  • Overloading assignment operator and compound assignment operators now work +
  • Added changes to remove level 4 warnings for MSVC .NET (thanks Ricard) +
  • Added C++ code alternative to the assembler code (thanks Eric Love) +
  • Changed the way function pointers and method pointers are registered. Use as asFUNCTION(f) and asMETHOD(c, m) macros. +
  • bug fix: Object method calls didn't free the object if it was temporary. (thanks Peter Marshall) +
  • Support for compilation of scripts into separate modules have been implemented. +
  • BC_PGA now takes a DWORD instead of a WORD +
  • @init() and @exit() are no longer reported by GetFunction...() +
  • Added support for STDCALL (contribution by Adam Hoult) +
  • bug fix: Functions with arguments of object types sent by value didn't pop all the arguments from the stack (thanks Adam Hoult) +
  • Added the method Discard() which allows the application to discard a module when it is no longer needed +
  • Added the method GetModuleID() which can be used to enumerate script functions in modules +
  • RegisterObjectType() should now use the new flags asOBJ_IS_COMPLEX and asOBJ_IS_NOT_COMPLEX +
  • ExecuteString() now take the name of the module in which it is to be executed +
  • Added support for enumeration of global script variables +
  • Added new macros to make it easier to take the pointer of overloaded functions and methods +
+ +

Version 1.7.1a - 2004/06/10

+ +
    +
  • bug fix: Arguments received by reference was erronously destroyed (thanks Peter Marshall) +
  • bug fix: MSVC++.Net 2003 crashed when compiling scripts. (thanks Fredrik Malmer) +
  • bug fix: Unnamed parameters wasn't treated by the exception handler +
  • bug fix: Some temporary variables wasn't correctly freed, leading to memory leakage +
+ +

Version 1.7.1 - 2004/05/27

+ +
    +
  • bstr has become an internally registered type +
  • bstr.length() is now a method instead of a property +
  • Removed the byte code STRMKE +
  • RegisterObjectType() now accepts the flags asCALL_RETURNBYVAL and asCALL_RETURNBYREF +
  • bug fix: Prepare() should no longer crash when receiving invalid function id (thanks Xavier "meink" Shay) +
  • The unexpected token message now shows what token was found +
  • It is now possible to use function overloads for scripted functions as well +
  • GetFunctionIDByName() returns asMULTIPLE_FUNCTIONS if more than one function with the same name exists +
  • GetFunctionIDByDecl() is now supported +
  • bug fix: The -> operator now works with direct pointers as well as pointer references (thanks Joe "Desdemona" Wright) +
  • bug fix: multiple variables per global declaration statement now works again (thanks Lennart Denninger) +
  • bug fix: scripts with errors in global variables could crash the application if no output stream was specified (thanks Fredrik Ehnbom) +
  • bug fix: calling ExecuteString() without first building a script didn't work (thanks Fredrik Ehnbom) +
  • ExecuteStep(asEXEC_STEP_OVER) is now supported +
  • Added support for the indexing operator +
  • The asBEHAVE_INDEX flag is used to register the overloaded indexing operator +
  • bstr[int] returns a reference to the indexed byte +
  • The library is now working on the Dreamcast (thanks Fredrik Ehnbom) +
  • bug fix: When compiling function calls the compiler didn't discard alternatives with more parameters than used arguments (thanks Lennart Denninger) +
+ +

Version 1.7.0 - 2004/05/03

+ +
    +
  • Included the makefile for Linux compilers (thanks Stefan Diepenbrock) +
  • Added the methods ExecuteString() and GetContextForExecuteString() to the engine interface +
  • ExecuteStep() now takes a parameter that defines how to execute, only asEXEC_STEP_INTO is supported at the moment +
  • ExecuteString() is able to work with compiled script +
  • ExecuteString() now takes a flag that can be either 0 or asEXECSTRING_ONLY_PREPARE (thanks Joe "Desdemona" Wright) +
  • Removed the concept of global constants, they are instead global variables that are read-only +
  • bug fix: global variables ignored any type modifiers, thus global pointers were not possible (thanks Gunder Wulde) +
  • condition operator can be used when initializing global variables +
  • Global variables can now be initialized with expressions using other global variables, not just constants +
  • When finding the matching overloaded function, a conversion between signed and unsigned integers are given priority over conversion between integer and float (thanks Joe "Desdemona" Wright) +
  • bug fix: A pointer with an assignment behaviour can now be assigned a null pointer. +
  • Changed the library license from LGPL to the zLib license +
+ +

Version 1.6.1b - 2004/03/30

+ +
    +
  • bug fix: Declaring multiple global variables in the same statement resulted in compiler error (thanks Jayanth) +
  • Added the tokens &&, ||, and ! as aliases to 'and', 'or', and 'not' +
+ +

Version 1.6.1a - 2004/03/23

+ +
    +
  • Removed compilation warning for VSC++ .NET 2003 (thanks Daniel Krenn) +
  • bug fix: When reading booleans as object properties the compiler failed to mask out value (thanks Joe "Desdemona" Wright) +
+ +

Version 1.6.1 - 2004/03/21

+ +
    +
  • bug fix: There was a memory leak in the tokenizer (thanks Philip Love) +
  • bug fix: An exception occured when compiling method calls with objects as parameters (thanks Bartosz "Hans" Czuba) +
  • More code cleaned up +
  • BCONSTR and BDESTR are no longer used, instead BC_CALL is used +
  • BCONSTR, BDESTR, BCOPY, STRDEL, STRCPY, STRMOV, STRCAT, STRCMP and STRWRT has been removed +
  • bug fix: break, continue, and return sometimes caused GenerateExceptionHandler() to fail since objects were destroyed more than once +
  • Added support for the for-loop (thanks Erik J Baran) +
  • Return values are now returned in a special register instead of on the stack +
  • Added bytecodes SRET4, SRET8, RRET4, RRET8 for managing the return register +
  • Added the calling convention asCALL_CDECL_OBJLAST for object methods. This calls the method as a normal C function with the object reference as the last parameter +
  • The asMETHOD and asFUNCTION types are now defined macros instead +
  • Type behaviours must be registered as either asCALL_THISCALL or asCDECL_OBJLAST +
  • Pointers can now be compared with other pointers of the same type and level, or with 0 for null pointer tests +
  • It is now possible to register overloaded operators for all dual operators, except assignment operators +
  • bstr is now handled with operator overloads +
  • bug fix: booleans are now 1 byte large, just as for C++ (thanks Josh "nihlist" Passenger for spotting the bug). +
  • Cleaned up the code that compiles overloaded operators and function calls +
  • Changed all the JMP instructions to use a 4 byte offset +
  • Function overloading for registered functions and object methods is now supported +
  • bug fix: When converting a constant to another type the value would become 0 +
+ +

Version 1.6.0 - 2004/02/18

+ +
    +
  • Added parameter flags for RegisterObjectType, but should be set to 0 +
  • The flag asCALL_WITHCONTEXT is no longer available, use asGetActiveContext() to retrieve context instead +
  • GetFunctionCount() can now be used to obtain the number of script functions compiled +
  • The way type behaviours are registered have been changed to allow more flexibility +
  • Cleaned up the code +
  • bug fix: RegisterObjectMethod() didn't accept asCALL_RETURNBYVAL and asCALL_RETURNBYREF flags +
  • If any of the engine configuration methods fail the engine object will no longer let the application build scripts. +
  • Function parameters and variables can now be declared as const +
  • The flag asPROPERTY_READONLY has been removed, use const in declaration instead +
  • bug fix: exceptionID wasn't initialized to zero in Prepare() and the program could crash at an exception +
  • Lot's of changes to allow compilation with DJGPP (thanks Eric Love) +
  • Added as_config.h that may be used to configure some aspects of the compilation to acomodate for compiler differences +
  • Improved the angelscript.h by allowing the user to define exactly the way AngelScript is linked +
  • bug fix: Equality comparison between bits types didn't work (thanks Bartosz "Hans" Czuba) +
+ +

Version 1.5.2 - 2004/01/30

+ +
    +
  • bug fix: When sending objects with behaviours by value in function arguments the exception handler didn't correctly destroy the objects +
  • bug fix: Pointers now work correctly with behaviours +
  • Added the flags asCALL_RETURNBYVAL and asCALL_RETURNBYREF that can be used to register how a system function returns if the engine isn't able to correctly determine it +
  • Cleaned up the method CallSystemFunction() giving about 10% performance improvement +
+ +

Version 1.5.1 - 2004/01/26

+ +
    +
  • bug fix: The compiler no longer crashes when an object method name is not found (thanks Lennart Denninger) +
  • Changed where and when objects are constructed and destructed +
  • Changed bstr to use behaviour functions for construct, destruct, and copy +
  • Changed the STRMKE and the STRCAT byte codes +
  • STRDEL, STRCPY, STRMOV, and STRWRT are no longer used +
  • Added bytecodes JMPP, EID, and PEID +
  • Completely remade the way the script engine cleans up the stack in case of exceptions +
  • It is now allowed to register behaviours for pointers to objects +
  • Exceptions may be thrown in the construct and copy behaviour functions +
+ +

Version 1.5.0 - 2004/01/19

+ +
    +
  • When registering object types the name is checked against all other names registered +
  • It is no longer possible to register two object members with the same name +
  • Contexts now hold a reference to the engine object +
  • Added RegisterTypeBehaviour() that allows the application to register helper function that will be call when a script variable is initialized, uninitialized, and copied +
  • Added bytecodes BC_BCONSTR, BC_BDESTR, and BC_BCOPY +
  • Objects with behaviour cannot be sent by value +
  • Returning objects with behaviour requires special care for system functions +
+ +

Version 1.4.1 - 2004/01/14

+ +
    +
  • bug fix: SetArguments() and GetReturnValue() didn't work +
  • Change the message for when implicit conversion is not possible to a more descriptive one +
  • Added int32 as alias to int, uint32 to uint, and bits32 to bits +
+ +

Version 1.4.0 - 2004/01/12

+ +
    +
  • Created the asIScriptContext interface for communicating directly with the contexts +
  • Context::Prepare() now takes a function ID instead of a string, making it faster for repeated preparations with the same function +
  • Get/SetStackData() has been renamed to GetReturnValue() and SetArguments() +
  • GetReturnValue() and SetArguments() now takes an array of dwords instead of a single dword +
  • System functions now receive a pointer to the context instead of the engine +
  • Added RegisterGlobalProperty() giving the script engine access to variables in the host application +
  • bug fix: properties are now properly treated as read only if the flag is set +
+ +

Version 1.3.9 - 2004/01/06

+ +
    +
  • bug fix: the compiler determined the size of the returned value incorrectly for large types +
  • bug fix: the script engine crashed the program when calling system functions that returned large types +
  • warnings and errors during compilation of constants are now correctly shown +
  • Improved performance for repetetive execution of the same script function by caching some values +
+ +

Version 1.3.8 - 2003/12/10

+ +
    +
  • Explicit conversions no longer generate warnings about precision +
  • bug fix: global constants of type double didn't hold the correct value +
  • float constants can now be declared explicitly by including the f modifier after the number +
+ +

Version 1.3.7 - 2003/11/27

+ +
    +
  • Added datatype double +
  • lots of new byte codes to handle the double data type +
  • Added missing conversions bits -> bits8, bits16 -> bits8, bits -> bits16 +
  • bug fix: Conversions in constant expressions now work +
  • bug fix: bits constants are now correctly parsed +
+ +

Version 1.3.6 - 2003/11/07

+ +
    +
  • Fixed a memory leak +
  • Multiple global constants of the same type can now be declared in the same statement +
  • Conversion on constants now continue being constants if possible +
  • Constant declarations now correctly report error if expression type is wrong +
  • Constant expressions are now implicitly converted to correct type for constant declarations +
  • Global variables can now be declared and initialized with constant expressions +
  • Added byte code PGA (Push Global Address) used to access global variables +
+ +

Version 1.3.5 - 2003/09/23

+ +
    +
  • Fixed a bug with returning a pointer to a float from a system function +
  • Fixed bug in CleanStack, that crashed program on an exception +
  • bstr.length is now uint +
  • Changed data types for functions asCreateScriptEngine, asBStrAlloc, and asBStrLength +
  • Improved speed of object method calls with almost 10% +
  • Added new bytecode PUSHZERO improving speed about 3% +
  • Added new bytecode COPY for copying memory blocks +
  • Simple structs are now supported, those that don't need special treatment for construction, destruction and assignments +
  • Added bytecode PSP (again) +
  • Fixed a bug that sometimes crashed the program if a system function declaration was wrong +
+ +

Version 1.3.4 - 2003/09/16

+ +
    +
  • Added data types: int8, int16, uint8, uint16, bits8, bits16 +
  • Bitwise shift operators now takes an unsigned integer to the right +
  • bits, int, and uint can be implicitly converted to a larger type but never to a smaller +
  • Added byte codes BC_SB, BC_SW, BC_UB, BC_UW, BC_WRT1, BC_WRT2, BC_INCi16, BC_INCi8, BC_DECi16, BC_DECi8 +
  • Implemented ++, -- for uint type (missing from last version) +
+ +

Version 1.3.3 - 2003/09/10

+ +
    +
  • Added data type: uint +
  • Integer constants are now uint +
  • Added byte codes BC_UI2F, BC_F2UI, BC_CMPui +
  • Fixed a bug that affected unary operations on constant values +
+ +

Version 1.3.2 - 2003/09/02

+ +
    +
  • Separated texts from the code for easier maintenance +
  • Separated library code from Windows DLL code +
  • Library code is now following the ANSI standard +
  • Fixed bug that at crashed program when the engine was destroyed +
  • System functions may now returns references that the script engine can write to +
+ +

Version 1.3.1 - 2003/08/22

+ +
    +
  • RegisterObjectMethod() is now supported for non virtual object methods +
+ +

Version 1.3.0 - 2003/08/19

+ +
    +
  • Reduced windows .dll size 10% by using the linker option /OPT:NOWIN98 +
  • Reduced size another 20% by turning off exception handling (something that can't safely be used in a dll anyway as other compilers don't implement it the same way) +
  • Interface functions and methods are now explicitly declared as _stdcall +
  • The script language now allows the use of pointer declarations, although no pointer arithmetic +
  • Added the -> operator to access members from pointers +
  • Changed the RegisterObjectProperty() parameters +
  • RegisterObjectType() now takes an object size as property as well (although, only 0 is supported) +
+ +

Version 1.2.1 - 2003/08/12

+ +
    +
  • Registered object types are checked already when registering them +
  • Registered global functions are checked at inclusion +
  • Fixed bug, a script exception could sometimes crash the app +
  • Object properties can now be registered by the application. +
+ +

Version 1.2.0 - 2003/08/05

+ +
    +
  • The engine now supports multiple contexts for executing several script functions in parallel +
  • The application can now set a script exception in system functions +
  • The application can query the current function and line number being executed +
  • Changed the status codes returned by Execute() +
  • It is now possible to suspend a context +
  • The last context executed is returned with GetLastContextExecuted() +
  • EnumerateContexts() enumerates all existing context IDs. +
  • PrepareContext() uses an existing context created with CreateContext() to improve performance of execution +
  • A pointer to the scripting engine is sent as the last parameter to the system functions +
  • Improved error codes for interface methods +
  • ExecuteStep() allows the application to step through the script. +
+ +

Version 1.1.2 - 2003/07/31

+ +
    +
  • Added the access operator . for object properties +
  • Added length property to the bstr type +
  • Added ADDOFF that adds an offset to a pointer in a variable +
  • Fixed a bug in CompileDeclaration() +
  • Fixed a bug in Execute() where it returned 1 when finished succesfully +
  • Fixed bug in CallCDeclFunction(), where printf() and OutputDebugString() didn't work in the called function +
  • asCDataType now allows references to be marked as read-only +
+ +

Version 1.1.1 - 2003/07/25

+ +
    +
  • Cleaned up the code for the instruction set +
  • Added instruction set statistics +
  • Removed NOP, PSP, END +
  • Added MOVSF4, SWAP4, STORE4, RECALL4 +
  • Improved performance of the switch case in asCThread::ExecuteNext() +
  • Improved performance for compound assignments +
  • Fixed a bug in CompileConversion() +
+ +

Version 1.1.0 - 2003/07/18

+ +
    +
  • The thread now reserves space on the stack for arguments and return value +
  • It is now possible to send arguments and retrieve return value +
  • The declarations of the script functions can be retrieved for verification +
  • Compiler error on divide by zero with constant +
  • Throws divide-by-zero on DIVi, MODi, DIVf, MODf +
  • Added byte code LINE that the thread uses to report on which line an exception ocurred +
  • The output stream is now only used during build. +
  • Made the string methods global because the memory is shared anyway +
  • Information about exceptions ocurred can now be retrieved from the engine +
  • The engine interface now uses reference counting to control memory deallocation +
  • Changed the name of the thread functions, as they create the misconceptions that multiple threads are allowed +
  • The output stream is now sent with the Build() method, as it is only used during build. +
+ +

Version 1.0.4 - 2003/07/16

+ +
    +
  • Improved compiler code to be easier to maintain +
  • Improved the implicit conversion to include assignment and return expressions. +
  • Improved compiler message output, doesn't write "Parsing..." or "Compiling..." unless there is an error or warning. +
  • Improved verification of extended types and system functions +
+ +

Version 1.0.3 - 2003/07/08

+ +
    +
  • Undeclared variables are only reported once +
  • Doesn't give assert failed when lvalue is a temporary variable (gives a compile error instead) +
  • A warning is now given if a variable is used before being assigned a value +
  • Added implicit conversion between int and float for constant values +
  • Constant expressions are evaluated into a single constant +
  • Constant declarations may now take constant expressions +
  • Constants can only be declared one per statement. +
+ +

Version 1.0.2 - 2003/07/03

+ +
    +
  • Fixed minor error where the script engine treated the argument to STRMKE as short instead of WORD as it should. +
  • Added an extra SUSPEND in both while and do-while loops to make sure that at least one exist in every loop. +
  • Fixed a bug where assigning a string to a variable breaks the code. +
  • Added post compile optimizations +
  • Added byte code RDSF4 that the optimizer puts in the place of PSF followed by RD4 +
  • Added asGetLibraryVersion() to the API +
+ +

Version 1.0.1 - 2003/06/30

+ +
    +
  • Corrected the missing return type for operator = in asCDataType (thanks Marc Fascia for spotting that) +
  • Fixed a bug where the script engine crashed when initializing variables with a declared bstr constant. +
  • Improved version check so that it is backwards compatible for changes in build version (bug fixes) +
+ +

Version 1.0.0 - 2003/06/25

+ +
    +
  • Improved temporary variable reutilization +
  • Removed bug in release version +
  • Cleaned up the code for public release +
  • Prepared for compilation as DLL +
+ + + \ No newline at end of file diff --git a/docs/articles/changes2.html b/docs/articles/changes2.html new file mode 100644 index 0000000..aca7cbe --- /dev/null +++ b/docs/articles/changes2.html @@ -0,0 +1,3795 @@ + + +AngelScript - Changes + + + + + + + +

AngelScript Change Log

+ +

Version 2.35.0 - 2020/12/05

+ +
    +
  • Bug fixes +
      +
    • asIScriptModule::GetGlobalVar was returning asSUCCESS when the given index was out of range +
    • Compiler would give an error when compiling functions returning a reference to a type that cannot be instantiated +
    • Fixed problem with LoadByteCode and shared classes (Thanks MrFloat) +
    • Fixed crash when using copy constructor declared as taking the object by value (Thanks Miss) +
    • Fixed memory invasion in compiler when compiling initialization lists with expressions using default arguments (Thanks jsd1982) +
    • Fixed memory invasion in compiler when compiling default arguments +
    • Fixed an issue in compiler with auto type and constness (Thanks Polyák István) +
    • Fixed symbol lookup of child type from within class method while compiling a construct call (Thanks Polyák István) +
    • Fixed crash after a discarding a module that compiled a shared object type that continues to be used by other modules (Thanks MrFloat) +
    • Funcdefs are marked with asOBJ_GC as they can form circular references when used with delegates (Thanks cmann) +
    • Fixed memory leak when using CompileGlobalVar to add a variable to a module with an object type (Thanks gmp3) +
    • Fixed error when loading bytecode that is using a list constructor for a value type (Thanks Phong Ba) +
    • Fixed memory invasion in compiler when compiling default argument after an argument with index operator (Thanks Phong Ba) +
    +
  • Library +
      +
    • asIScriptModule::GetFunctionByName now supports informing the scope in the name (Thanks Boost113) +
    • asIScriptModule::GetGlobalVarByName and GetTypeInfoByName also support informing the scope in the name +
    • asIScriptEngine::GetTypeInfoByName and GetGlobalPropertyIndexByName also support informing the scope in the name +
    • The default opAssign implementation for script classes will use the base class' opAssign method to copy inherited properties (Thanks hiago desena) +
    • Added config for 64bit x86 CPU on Haiku OS (Thanks Panagiotis Vasilopoulos) +
    • Added flag asOBJ_APP_CLASS_MORE_CONSTRUCTORS to inform when a class with defaulted constructors has additional non-trivial constructors (Thanks Miss) +
    • Added support for native calling conventions on Linux with ARM64 (Thanks Max Waine) +
    • Minor code changes to make the library buildable on DragonFly BSD (Thanks David Carlier) +
    • Improved time for compilation and loading pre-compiled bytecode for scripts with lots of type definitions (Thanks Len Deuel) +
    • Added config to make the library buildable for Linux with Elbrus 2000 CPU (Thanks Sattarov Ramil) +
    +
  • Library interface +
      +
    • asIScriptObject::CopyFrom now takes a const pointer +
    • RegisterGlobalProperty and RegisterObjectProperty now return the index of the property upon success (Thanks Marc Oude Kotte) +
    +
  • Virtual machine +
      +
    • asBC_Thiscall1 bytecode instruction is now capable of catching and translating C++ exceptions to script exceptions (Thanks Quentin Cosendey) +
    +
  • Add-ons & Samples +
      +
    • Implemented to-string debug callback for datetime in asrun +
    • Fixed a problem due to daylight time when initializing a datetime object with specific date +
    • debugger add-on handles incorrect user commands better +
    • Implemented a version of exec for asrun sample that captures the standard output from the system command into a string +
    • Implemented getCreateDateTime and getModifyDateTime on the filesystem add-on +
    • Improved performance on array sort for arrays holding object types +
    • Fixed registration of the virtual property accessors in the game sample (Thanks Marc Oude Kotte) +
    • Fixed compilation error in scriptstdstring.cpp with AS_USE_NAMESPACE (Thanks Wipe) +
    • Added mingw makefile for console sample +
    • Registered the script array add-on in the console sample +
    • Added generic calling convention bindings for datetime and filesystem add-ons (Thanks gjl) +
    +
  • Project +
      +
    • Added option to the cmake project to allow linking statically with CRT on MSVC (Thanks Ilya) +
    • Added MSVC2019 project files +
    • Fixed cmake project for MSVC2019 (Thanks Wipe) +
    • Fixed gnuc makefile to detect arm target and add a compiler flag to accept implicit IT constructs in thumb mode (Thanks Maya Posch) +
    +
+ +

Version 2.34.0 - 2019/09/22

+ +
    +
  • Bug fixes +
      +
    • Fixed problem in compiler with bool property returned as reference in conditions (Thanks Miss) +
    • Fixed problem with catching exceptions in functions with multiple try-catch blocks (Thanks johannesg) +
    • Fixed read from unallocated memory in compiler when compiling default args (Thanks Patrick Jeeves) +
    • Fixed problem with doing a value assign from array holding handles (Thanks Aaron Baker) +
    • Fixed crash in compiler when there are multiple matching global functions for set accessors (Thanks Aaron Baker) +
    • Fixed crash that could happen when loading bytecode with shared classes that doesn't match current declared shared classes (Thanks MrFloat) +
    • Fixed assert failure when compiling a construct call with an anonymous initialization list (Thanks perost86) +
    • Fixed incorrect bytecode sequence when doing value assignment from handles for script classes using default assignment operator (Thanks Aaron Baker) +
    • Fixed problem with default arg not being able to access members in expression (Thanks Aaron Baker) +
    • Fixed crash when releasing engine with template specialization containing child funcdefs (Thanks BertS) +
    • Fixed asCALL_THISCALL_ASGLOBAL to function correctly with multiple inheritance (Thanks stalker#3829) +
    • Compiler now identifies match for functions taking object as inout ref when passing anonymous init list (Thanks Max Waine) +
    • Compiler now interrupts compilation after identifying error while compiling use of get property accessor (Thanks Patric Jeeves) +
    • Compiler no longer identifies global script functions as property accessors when this is turned off with asEP_PROPERTY_ACCESSOR_MODE (Thanks Aaron Baker) +
    • Fixed config for FreeBSD on non-x86 64bit targets (Thanks Greg V) +
    +
  • Library +
      +
    • asEP_PROPERTY_ACCESSOR_MODE has a new mode (3) to require property accessors to be flagged with 'property' +
    • Property accessors are validated upon declaration when flagged with 'property' +
    • asEP_PROPERTY_ACCESSOR_MODE is now set to 3 by default +
    +
  • Script language +
      +
    • Handles can now be declared read-only (Thanks Max Waine) +
    • Functions and methods intended to be used as virtual property should now be declared with a 'property' decorator +
    • Added non-reserved keyword 'property' +
    +
  • Library interface +
      +
    • Added asIScriptFunction::IsProperty +
    +
  • Add-ons & Samples +
      +
    • Removed an invalid assert() statement in ExecuteString (Thanks Pto) +
    • Debugger commands 'n' and 'o' no longer prints 'No script is running' when used as first command +
    • Debugger command 'p' prints 'Invalid expression. No matching symbol' when the symbol doesn't exist in the current context +
    • Fixed missing check for failed memory allocation in CScriptArray::Precache (Thanks Zelerin) +
    • The string factory in the std::string add-on is now thread safe +
    • Enabled Virtual Terminal Processing in asrun for colored text on Windows console +
    +
+ +

Version 2.33.0 - 2018/12/22

+ +
    +
  • Bug fixes +
      +
    • Fixed crash when compiling is null comparison with ASHANDLE object without any opEquals operator (Thanks Boost113) +
    • Fixed bug with anonymous initialization lists when used to initialize value type passed by value to function (Thanks Patrick Jeeves) +
    • Loading bytecode that included use of template value types with a template type as argument crashed +
    • Compiler would crash on compiling ternary operator with anonymous list in one of the conditions (Thanks doctorgester) +
    • Fixed error when saving bytecode for scripts containing interfaces that derives from interfaces (Thanks y18a) +
    • Saving bytecode for a never returning function would cause assert failure (Thanks y18a) +
    • Fixed an error when compiling a class method call as post-op and the name matches a type name (Thanks y18a) +
    • Template types are now properly identified in separate namespaces (Thanks ASBai) +
    • Fixed memory build-up due to delayed cleanup when discarding modules with shared entities (Thanks y18a) +
    • opImplCast with variable type won't be used for non-ref types +
    • Fixed compiler error when both opConv and opImplConv are implemented (Thanks Ali Gerami) +
    • Fixed bug when loading bytecode containing shared interfaces with inheritance (Thanks Zakhar) +
    • auto declarations now works correctly with implicit handle types (Thanks y18a) +
    • Initializing an ASHANDLE type with overloaded opHndlAssign taking a var type as a handle wasn't done correctly +
    • Fixed loading byte code that uses external shared classes in namespace (Thanks y18a) +
    • The bytecode for external shared entities is no longer saved in the module when inherited from (Thanks y18a) +
    • Bytecode with external shared classes with virtual methods failed to load from bytecode (Thanks y18a) +
    • Fixed assert failure on call to opCast(?&out) with a non-variable expression (Thanks Miss) +
    • Passing a string literal to function expecting &out will now give compiler error (Thanks Jordan Verner) +
    • Fixed problem in compiler that didn't release a temporary variable when passing anonymous object to function expecting ?&in (Thanks y18a) +
    • Fixed a bug when loading bytecode having identical shared functions in different namespaces (Thanks y18a) +
    • Compiler will now detect name conflict between property and function +
    • asIScriptFunction::GetDeclaration(false, true) no longer includes the namespace before the function name for class methods (Thanks IronHawk) +
    • Fixed assert failure in asIScriptEngine::RefCastObject when object has multiple opCast methods (Thanks gjl) +
    • Compiler no longer accepts primitives in the right hand expression for handle assignments (Thanks gjl) +
    • Fixed compiler warning with use of asOFFSET on 64bit platforms (Thanks Miss) +
    • Fixed crash caused by CreateScriptObjectCopy when script class' constructor takes argument by handle (Thanks Boost113) +
    • Child funcdefs in templates will no longer convert parameter types to @const& (Thanks Dinkleberg) +
    • Fixed problem when compiling anonymous initialization list from default arg (Thanks Dinkleberg) +
    • Ownership of shared template instances wasn't correctly transferred when discarding modules (Thanks Jason Goepel) +
    • Fixed crash in compiler when matching anonymous list to function taking funcdef (Thanks Miss) +
    • Fixed assert failure in builder when compiling external shared interfaces with inheritance (Thanks Chisser98) +
    • Fixed crash in compiler when invalid script has inheritance from class with duplicate methods (Thanks Miss) +
    +
  • Library +
      +
    • Changed the compiler to do less copies of objects and especially string constants +
    • Engine error messages now include the symbol name for the error code for easier interpretation +
    • All methods for template instances now get unique functions to show the template instance as the object type (Thanks Miss) +
    • Template types can now be registered with methods taking parameters as &inout (Thanks ASBai) +
    • Implemented engine property asEP_GENERIC_CALL_MODE to make the generic calling convention treat handles the same way that the native calling convention do +
    • By default asEP_GENERIC_CALL_MODE is set to use the new behaviour +
    • Registered value types can now register GC behaviours to solve circular references involving these types +
    • Reduced the size of the saved byte code, especially when there are lots of functions without parameters +
    • AssignScriptObject will now set a script exception for ref types if asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE is used +
    • The copy constructor of script classes are now used properly by the compiler (Thanks MrFloat) +
    • Refactored how he compiler does symbol lookups to better handle namespace hierarchies and child types. (Thanks y18a) +
    • Added engine property asEP_INIT_STACK_SIZE to set the initial data stack size for contexts (Thanks Karoly Pinter) +
    • Added engine properties asEP_INIT_CALL_STACK_SIZE and asEP_MAX_CALL_STACK_SIZE to set initial and max call stack size for nested calls (Thanks Karoly Pinter) +
    • asIScriptContext::PushState will return an error if the call stack is already too big +
    • context's GetExceptionString, GetExceptionFunction, GetExceptionLineNumber will now return the last exception even if it has been caught +
    • CreateScriptObject no longer writes to the message callback if the object type doesn't have constructor/factory +
    +
  • Library interface +
      +
    • Implemented a callback to allow application to translate C++ exceptions thrown by registered functions (Thanks Boost113) +
    • Added the engine methods ForwardGCEnumReferences and ForwardGCReleaseAllReferences +
    • Included SetCircularRefDetectedCallback to allow application developers to easier identify the origin of circular references (Thanks baiyang) +
    • SetException now has an optional argument to allow exception to be caught or not +
    • Added WillExceptionBeCaught that the exception callback can use while inspecting the exception +
    • Added IsExplicit to asIScriptFunction +
    +
  • Script language +
      +
    • Now it is possible to resolve ambiguity with lambda functions by explicitly specifying the parameter types (Thanks Miss) +
    • The compiler will now give an error on bitwise operator with floats instead of silently converting to integer (Thanks Jason Goepel) +
    • Class constructors can now be declared with private and protected too (Thanks noizex) +
    • The correct resolution is now done for types implementing both opCast and opImplCast and the const overloads. The same for opConv and opImplConv +
    • Initialization lists will implicitly assume objects by handle if asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE is used (Thanks y18a) +
    • When unsafe references is allowed the stream operator (<<) can now be implemented on value types with correct behaviour for chained expressions (Thanks ASBai) +
    • Virtual property accessors must not have the same name as real property or function in the same scope +
    • Namespace and class with the same name must not have name conflicts between members as it would cause ambiguity in the symbol lookup (Thanks Phong Ba) +
    • Added support for try/catch statements +
    • Implemented support for flagging constructors as explicit +
    • Factories for ref types with only one argument can now be used for implicit type conversion too +
    • 'auto' declarations will now always prefer handle if the type allows it (Thanks Miss) +
    +
  • Virtual machine +
      +
    • The asBC_REFCPY and asBC_RefCpyV instructions can now be used with value types too +
    +
  • Add-ons & Samples +
      +
    • Added the methods isLink and getSize to filesystem add-on +
    • Added methods setDate and setTime to datetime add-on and operators to add seconds, compare, and determine difference in seconds +
    • The asrun sample now waits for user input before closing on any error when executed from file explorer on Windows +
    • filesystem's changeCurrentPath doesn't modify anything if the new path is invalid +
    • Implemented the methods makeDir, removeDir, deleteFile, copyFile, and move on the filesystem add-on +
    • Changed the clean-up of the string factory in the stdstring add-on to avoid crash if the script engine is stored in global singleton (Thanks howie_007) +
    • Fixed incorrect use of setlocale in parseFloat (Thanks Miss) +
    • Implemented a #pragma callback in the builder add-on +
    • asrun can now turn on debugging with #pragma debug (works the same as -d command arg) +
    • Fixed crash in debugger add-on when printing call stack in template function +
    • weakref now properly identifies different object instance when the address is the same as the previously freed object (Thanks y18a) +
    • meta data is now correctly extracted for class methods with decorators (Thanks Patrick Jeeves) +
    • CScriptBuilder now supports having multiple meta data blocks for each entity (Thanks noizex) +
    • CScriptHandle registers the ENUMREFS and RELEASEREFS gc behaviours +
    • CScriptArray, CScriptDictionary, CScriptGrid, and CScriptAny now support forwarding gc enum callbacks to value types with gc behaviour +
    • The array's and string's length property accessors is now only registered if AS_USE_ACCESSORS is defined to avoid conflict with the length() method +
    • Implemented the functions throw() and getExceptionInfo() that can be registered with RegisterExceptionRoutines +
    • dictionary add-on is better prepared to work with string type registered as reference type (Thanks Wracky) +
    • dictionary get method didn't always return true/false to indicate success or failure (Thanks Miss) +
    • Fixed a problem in filesystem's CopyFile on non-Windows platforms (Thanks cvet) +
    • Fixed string's findLastNotOf +
    • The datetime add-on now has a constructor to initialize date and time directly +
    • dictionary raises script exception if it cannot create a copy of a value being assigned +
    • array::less will now take const handles when T is a handle +
    +
  • Project +
      +
    • Updated the cmake project for better usability (Thanks Solokiller) +
    • Added MSVC 2017 projects +
    +
+ +

Version 2.32.0 - 2017/12/16

+ +
    +
  • Bug fixes +
      +
    • Registered funcdefs can now be used by shared script functions (Thanks Sir Ementaler) +
    • Fixed compiler error on MSVC2008 due to missing stdint.h (Thanks Friggle) +
    • Fixed a problem where the use of a get accessor could incorrectly reuse temporary variables (Thanks Phong Ba) +
    • Fixed the symbol search order so class name with same name as type is properly handled (Thanks Ansjh) +
    • Fixed compiler error in asFUNCTIONPR on MSVC2017 (Thanks Farbod) +
    • Fixed problem that could happen when saving bytecode that used shared functions (Thanks Phong Ba) +
    • Fixed problem with calling function expecting @&in where the argument was itself a & argument (Thanks Alexander Orefkov) +
    • Fixed crash when compiling expression using opIndex property accessor without arguments (Thanks Aaron Baker) +
    • Fixed compiler warning in assert (Thanks David Binderman) +
    • Fixed a couple of bugs on platforms with 4 byte booleans (Thanks Joseph Tilley) +
    • Fixed bug in parser that would produce misleading error message on invalid code (Thanks Kirill Artemov) +
    • Fixed assert failure when compiling ref cast and multiple matching cast operators are found (Thanks Jordan Verner) +
    • Template instances now correctly replaces child funcdefs +
    • Fixed bug where compiler didn't allow default arguments to be name of global functions (Thanks Aaron Baker) +
    • as_callfunc_x64_gcc.cpp now compiles correctly with address sanitize on g++ 5 (Thanks a light breeze) +
    • Fixed memory leak in RemoveGlobalProperty as the property wasn't uninitialized before it was removed (Thanks Quentin Cosendey) +
    • Fixed bug in compiler that would in complex expressions overwrite a temporary variable before it was used (Thanks Aaron Baker) +
    • Handles received by reference is now properly treated when passed to function expecting variant type (Thanks Quentin Cosendey) +
    • Fixed compiler error in derecated IsHandleCompatibleWithObject when using AS_DEPRECATED (Thanks Asu) +
    • Fixed assert failure when compiling comparison expressions with primitives smaller than 32bit (Thanks Asu) +
    • Fixed crash in compiler when compiling type conversion with invalid use of named arguments (Thanks Adrian Bibby Walther) +
    • Fixed assert failure when compiling expression with anonymous initialization list (Thanks Patrick Jeeves) +
    • Explicitly creating a copy of a const object to get a non-const handle would give a compiler error +
    • Value type without opAssign but with a copy constructor can now be implicitly copied in type conversions +
    • Saved byte code with scripts that used child funcdefs couldn't be loaded (Thanks Quentin Cosendey) +
    • Compiler was allowing to pass a const object by reference to a parameter expecting a non-const when using unsafe references +
    • Fixed buffer overflow when formatting error message with very long tokens +
    • RefCastObject was allowing explicit cast from base class to derived class even though the true type was of the base class (Thanks Miss) +
    +
  • Library interface +
      +
    • RegisterFuncdef, RegisterInterface, RegisterTypedef, RegisterEnum now returns the type id on success +
    • Added asEP_MAX_NESTED_CALLS to control the maximum number of nested calls that should be allowed +
    • Both Read and Write in asIBinaryStream can now return an error code to signal failure +
    • Added a new interface asIStringFactory to allow the application to hold the string constants in native format +
    • The RegisterStringFactory now takes a pointer to asIStringFactory instead of a function callback +
    • Removed deprecated code from previous versions +
    • Added support for registering class methods for composite objects without wrappers (Thanks Patrick Jeeves) +
    • Object properties can also be registered for composite objects +
    +
  • Library +
      +
    • Handles explicitly initialized with null in declarations no longer produce any bytecode (Thanks Solokiller) +
    • Saved bytecode now takes advantage of shared entities declared as external and includes less bytes +
    • The VM now raises an exception when application performs too many nested calls (Thanks Jordan Verner) +
    • Improved compiler error message when identifier before parenthesis doesn't evaluate to a function (Thanks Patrick Jeeves) +
    • Objects that rely on asGetActiveContext during clean-up can now do so even during exception handling +
    • String constants are now evaluated at compile time and a pointer to the application native format is kept in the bytecode +
    +
  • Virtual machine +
      +
    • The asBC_STR instruction no longer has any use and will be deprecated +
    +
  • Script language +
      +
    • Added the keyword 'external' +
    • shared enum can now be declared as external to explicitly include a shared enum from previously compiled module +
    • shared interfaces, classes, functions, and funcdefs can also be declared as external +
    • funcdefs can now be explicitly declared as shared +
    • Implemented support for typeless anonymous initialization lists (Thanks Patrick Jeeves) +
    • The compiler will implicitly convert string literals to local variables if a non-const reference is needed +
    +
  • Add-ons +
      +
    • Fixed bug in CScriptArray::RemoveRange (Thanks Michael Cohen) +
    • ScriptBuilder add-on now support metadata for enums too +
    • ScriptBuilder add-on properly handles 'external' and 'shared' keywords when parsing metadata +
    • WriteConfigToStream now resets the namespace for the string factory (Thanks Solokiller) +
    • Implemented sort in CScriptArray that takes as input a script function to compare two elements +
    • Dictionary storing a const handle now allows retrieving by value +
    • ConfigEngineFromStream takes an optional pointer to asIStringFactory +
    • scriptstdstring add-on implements a string factory for asIStringFactory with a cache +
    • WriteConfigToStream and ConfigEngineFromStream properly handles composite properties +
    • Debugger is capable of inspecting value of composite properties +
    +
+ +

Version 2.31.2 - 2016/12/18

+ +
    +
  • Bug fixes +
      +
    • Fixed compiler warning about missing GNU-stack on gentoo Linux (Thanks James Le Cuirot) +
    • Fixed asGetTypeTraits on clang 3.8 (Thanks Ansjh) +
    • Fixed big endian errors in the compiler related to enum values (Thanks rfonseca) +
    • CreateScriptObject crashed when called for template value types (Thanks noizex) +
    • Fixed crash when discarding modules containing shared funcdefs (Thanks Violet CLM) +
    • Fixed big endian errors in the compiler related to implicit conversions of constants (Thanks rfonseca) +
    • Fixed bug with saved byte code not being portable between 32bit and 64bit platforms when including ChkNullS instruction (Thanks cvet) +
    • Fixed assert failure in compiler when compiling invalid switch case (Thanks Jordan Verner) +
    • Fixed bug in compiler when passing a @& argument to a function (Thanks IronHawk) +
    • Fixed bug when compiling get property accessor returning a registered type that is then implicitly converted to another (Thanks Phong Ba) +
    • Fixed assert failure when compiling boolean not operator on constant (Thanks gkfkdk404) +
    • Fixed incorrect compiler warning about too large value when assigning negative value to const int8/int16 (Thanks gkfkdk404) +
    • Compiler emits warnings if 64bit integer constants cannot fit when implicitly converted to smaller types (Thanks Sir Ementaler) +
    • Compiler didn't support implicitly converting constant uint64 values to uint32 values +
    • Fixed compiler error on Linux with non-x86 64bit platforms, e.g. arm64, mips, and s390x architectures (Thanks deveee) +
    • Fixed assert failure when compiling comparison operator on boolean constant (Thanks Autious) +
    • Fixed bug in bytecode serialization when adjusting pointer sizes for calls using asBC_ALLOC (Thanks Autious) +
    • Fixed problem with registering types using the asOBJ_IMPLICIT_HANDLE flag (Thanks cvet) +
    • Fixed assert failure on implicit conversion from 8/16 bit uint constant to integer (Thanks Sir Ementaler) +
    • opCast(?&out) on null handle now works without raising null pointer exceptions (Thanks Ansjh) +
    • Corrected as_config.h so Linux for 64bit ARM doesn't try to compile as_callfunc_x64_gcc.cpp (Thanks Igor Gnatenko) +
    • Fixed crash on GCC 6 due to CastToObjectType accepting this == null (Thanks Anjsh) +
    +
  • Library +
      +
    • Introduced a new keyword 'if_handle_then_const' that is used to tell template that a handle should be to const object +
    • Compiler now emits an error if an integer constant is larger than 2^64-1 +
    • Non-pod value types are now allowed to be registered without default constructor, as long as at least one constructor is registered (Thanks Phong Ba) +
    • Reduced the number of calls to addref and release that the compiler includes in the bytecode in some cases (Thanks Thomas Grip) +
    • Non-assignment dual operators, e.g. +, now evaluates left to right even when using overloaded operators (Thanks Scott Bean) +
    +
  • Add-ons & Samples +
      +
    • Fixed a minor bug in ExecuteString that could cause problem in rare cases (Thanks Solokiller) +
    • Fixed a bug in asrun example where the context was returned to the pool before being unprepared (Thanks noizex) +
    • Registered the opAssign method for weakref to allow value assignments for this type (Thanks noizex) +
    • Array add-on uses 'if_handle_then_const' on find methods (Thanks IronHawk) +
    • Fixed bug in script builder for meta data on functions with default arguments (Thanks Thomas Grip) +
    +
+ +

Version 2.31.1 - 2016/06/26

+ +
    +
  • Bug fixes +
      +
    • Fixed assert failure in compiler when attempting to implicitly convert primitive to function pointer (Thanks Sir Ementaler) +
    • Fixed compiler bug when passing funcdef by reference to a function (Thanks Sir Ementaler) +
    • The auxiliary pointer wasn't stored with object methods registered with the asCALL_GENERIC calling convention (Thanks Phong Ba) +
    • Fixed null pointer access crash in asBC_Thiscall1 when calling opIndex on a null pointer (Thanks gjl) +
    • The generic calling convention wasn't properly handling funcdefs in arguments or return type (Thanks Ansjh) +
    • Fixed null pointer access crash in compiler when compiling invalid script with value assign of function pointer (Thanks Phong Ba) +
    • Expressions like (expr ? null : null) is now compiled correctly (Thanks Sir Ementaler) +
    • auto var = null; no longer causes a crash in the compiler (Thanks Sir Ementaler) +
    • Compiler wasn't giving an error on 'void &' (Thanks Sir Ementaler) +
    • Fixed error when discarding a module if a context was still holding a reference to global var (Thanks GuyWithBeard) +
    • Offset for bytecode ClrVPtr wasn't adjusted correctly when saving/loading bytecode when the referred to variable was a null pointer (Thanks _Engine_) +
    • Fixed assert failure in compiler with AS_DEBUG when compiling anonymous function from class method (Thanks Phong Ba) +
    • Fixed crash in compiler when compiling 'null();' (Thanks Nikola Stojsic) +
    • Incorrect constructor could be used when declaring variable of object type and the initialization expression was of the same type but type had no copy constructor (Thanks loboWu) +
    • Returning a function pointer from a registered function wasn't working properly (Thanks Sir Ementaler) +
    • Function pointers in initialization lists would crash the application (Thanks Sir Ementaler) +
    • opCast can now be used on types registered with asOBJ_NOHANDLE too without crashing +
    • Function pointers wasn't properly handled in context's SetArg and GetReturn methods +
    • Fixed some big endian compatibility issues in compiler (Thanks rfonseca) +
    +
  • Script language +
      +
    • Enum to int32 conversion is now preferred over enum to int of other sizes in function overload resolution (Thanks Sir Ementaler) +
    • Anonymous objects initialized with initialization lists are now parsed as expression terms, rather than expressions by themselves +
    +
  • Library +
      +
    • Added asEP_HEREDOC_TRIM_MODE to allow application to decide how/if heredoc strings should be trimmed +
    +
  • Add-ons +
      +
    • Implemented parseUInt, findFirstOf, findLastOf, findFirstNotOf, findLastNotOf, insert, and erase for the string add-on +
    • Implemented removeRange for the array add-on +
    • Implemented insertAt for the array add-on that inserts all the elements from another array +
    • Fixed big endian compatility problems in script dictionary (Thanks rfonseca) +
    • Fixed compiler error in datetime add-on on gnuc (Thanks rfonseca) +
    +
+ +

Version 2.31.0 - 2016/02/26

+ +
    +
  • Bug fixes +
      +
    • Compiler no longer crashes when assigning anonymous function to variable declared with auto type (Thanks glcolor) +
    • Compiler will no longer match funcdefs for datatype if the namespace is not the correct one +
    • Fixed bug with template value types and loading bytecode (Thanks glcolor) +
    • Fixed bug with namespace and class member initialization (Thanks Solokiller) +
    • Ternary condition can now return function pointers (Thanks Sir Ementaler) +
    • Fixed problem with named args and registered behaviours (Thanks Solokiller) +
    • Linux with PPC64 Little Endian is now working with AS_MAX_PORTABILITY (Thanks Rafael Fonseca) +
    • Functions with generic calling conventions now catch application exceptions (Thanks Jason Goepel) +
    • Fixed a bug in compiler with calling function with const reference and the function expected non-const reference (Thanks cvet) +
    • Fixed compiler error in as_memory.cpp on OpenBSD (Thanks David Carlier) +
    • Fixes for Big Endian CPUs (Thanks Rafael Fonseca) +
    • Fixed crash on Linux 32bit when application threw C++ exception and library had been compiled with optimizations +
    • Fixed bug in compiler when passing a handle from function argument to copy constructor (Thanks GGLucas) +
    • Compiler properly resolves namespace when calling base classes method and the base class is declared in a different namespace (Thanks Ansjh) +
    +
  • Library interface +
      +
    • Added GetAuxiliary to asIScriptGeneric and asIScriptFunction for retrieving the auxiliary object registered with the function (Thanks cvet) +
    • Added GetChildFuncdefCount and GetChildFuncdef to asIObjectType +
    • Renamed GetFuncDefFromTypeId to GetFuncdefFromTypeId for consistency +
    • It is now possible to register child funcdefs with RegisterFuncdef too +
    • Renamed asIObjectType to asITypeInfo +
    • Renamed asCLEANOBJECTTYPEFUNC_t to asCLEANTYPEINFOFUNC_t +
    • Implemented GetTypeInfoByDecl, GetTypeInfoByName, and GetTypeInfoById +
    • Implemented SetTypeInfoUserDataCleanupCallback +
    • Implemented asITypeInfo::GetEnumValueCount and GetEnumValueByIndex +
    • Deprecated GetObjectTypeByName/Decl, GetEnumValueCount/ByIndex, GetObjectTypeById, SetObjectTypeUserDataCleanupCallback in engine +
    • Deprecated GetObjectTypeByName/Decl, GetEnumValueCount/ByIndex in module +
    • Deprecated asIObjectType +
    • Changed GetEnumByIndex and GetTypedefByIndex to return an asITypeInfo and removed all the output parameters +
    • Implemented GetTypedefTypeId in asITypeInfo +
    • GetChildFuncdef now returns an asITypeInfo instead of asIScriptFunction +
    • Added GetFuncdefSignature to asITypeInfo +
    • Deprecated GetFuncdefFromTypeId +
    • Implemented GetParentType in asITypeInfo to allow querying the parent type for child funcdefs +
    +
  • Library +
      +
    • The asCALL_GENERIC calling convention now also supports storing an auxiliary pointer during registration (Thanks cvet) +
    • Improved parser error message when finding unexpected token to inform if the token is reserved or not (Thanks Solokiller) +
    • Implemented asEP_ALLOW_UNICODE_IDENTIFIERS (Thanks Alexander Orefkov) +
    • Added configuration in as_config.h to identify GNUC+Linux+PPC64 (Thanks Rafael Fonseca) +
    • Access mask in the engine now defaults to all bits set to make sure built-in functions are available to all modules (Thanks Solokiller) +
    • Included the asOBJ_FUNCDEF value to allow asITypeInfo to represent funcdefs too +
    • asOBJ_SCRIPT_FUNCTION has been removed +
    • RefCastObject can now be used for function pointers too +
    • Refactored the code with regards to how types are stored, specifically funcdefs, resulting in more unified code and less memory use +
    • Clang is now recognized in angelscript.h as supporting C++11 features (Thanks Derric McGarrah) +
    +
  • Script language +
      +
    • It is now possible to declare funcdefs as members of script classes +
    • Partially specializing the scope as the enum type when referring to enums in namespaces is now possible (Thanks cvet) +
    +
  • Add-ons & Samples +
      +
    • Fixed compiler error in scriptstdstring.h when using AS_USE_NAMESPACE (Thanks Sami Vuorela) +
    • Fixed compiler error in aswrappedcall.h when using AS_USE_NAMESPACE +
    • WriteConfigToStream and ConfigEngineFromStream is properly handling child funcdefs +
    • Fixed problem in CScriptAny with constructing any object from primitive (Thanks gjl) +
    • ScriptHandle and Dictionary no longer need special code for function pointers +
    • Implemented CScriptDictionary::find for easier lookup of key/value pairs from application side +
    • dictionary::delete now returns a bool to indicate if the delete was successful or not +
    • Implemented CDateTime as a basic way of getting the time in scripts +
    • The asrun sample exposes the CDateTime add-on to scripts +
    • Implemented getInput in the asrun sample to allow it to get user input from standard input +
    • CScriptAny released asITypeInfo that it didn't own when a null handle was stored in it (Thanks GGLucas) +
    • CScriptBuilder incorrectly replaced /./ in include paths with nothing (Thanks Solokiller) +
    +
  • Project +
      +
    • Fixed cmake project files so library can be built as stand-alone without including the game sample (Thanks Wipe) +
    • Corrected the name of the shared object filename in the gnuc makefile (Thanks hasufell) +
    +
+ +

Version 2.30.2 - 2015/08/30

+ +
    +
  • Bug fixes +
      +
    • Throwing exception from application code would cause a crash if the library had been built without optimizations on 64bit GNUC (Thanks dkrusu) +
    • Fixed crash with asCALL_THISCALL_ASGLOBAL and objects passed by value in argument (Thanks justin12343) +
    • Fixed bug in parser related to virtual properties and datatypes in namespaces (Thanks dkrusu) +
    • Fixed compiler bug with nested namespaces, when the outer namespace has not been explicitly registered (Thanks BasicMind) +
    • Fixed a bug with SaveByteCode on 64bit platforms when the script called constructor with primitive arg before object arg (Thanks Idarion) +
    +
  • Library +
      +
    • Built-in function names and object types are now prefixed with $ to make it quicker to identify them while loading bytecode +
    • Optimized logic for finding registered function/method in LoadByteCode (Thanks _Engine_) +
    • Reduced size of pre-compiled bytecode +
    • Optimized logic for determining typeId for object types, which can improve compile time and LoadByteCode for applications with a lot of different object types +
    • Improved thread safety to support multiple threads querying typeIds simultaneously +
    • Improved performance for saving bytecode that uses lots of global properties +
    • Improved the compiler to generate less temporary copies of objects +
    • Optimized some byte code sequences generated by the compiler +
    +
  • Script language +
      +
    • Added the non-reserved keyword 'function' that will be used to declare anonymous functions +
    • Anonymous functions can now be declared as part of expressions +
    • Initialization lists can be used to initialize variables declared as handles too (Thanks Peter Jensen) +
    +
  • Add-ons +
      +
    • ConfigEngineFromStream appropriately treats names of behaviour functions before registering them since they are now prefixed with $ in WriteConfigToStream +
    • Fixed compiler error in as_scriptbuilder.h on MinGW (Thanks DarkPizzaX) +
    • Minor code changes to CScriptDictionary (Thanks Sir Ementaler) +
    • The options argument in formatInt, UInt, and Float now has a default argument of an empty string +
    • On C++11 enabled compilers the string pool is now using the unordered_map container for faster look-up +
    • CScriptDictionary now uses a typedef for the key type to make it easier for applications that uses custom string types (Thanks Solokiller) +
    • Changed to use std::unordered_map in CScriptDictionary when C++11 is used +
    • The CScriptDictionary now caches its object type to avoid looking it up in the engine for each instance +
    +
+ +

Version 2.30.1 - 2015/07/03

+ +
    +
  • Bug fixes +
      +
    • Fixed bug in compiler when using compound assignment on virtual property on temporary variable (Thanks Violet CLM) +
    • Compiler no longer gives error when access global variable in global namespace from class in namespace (Thanks Sir Ementaler) +
    • Fixed bug with compiler accepting null handle in initialization lists that didn't support it (Thanks Phong Ba) +
    • Parser properly handles template type and non-template type of same name in different namespaces (Thanks Polyák István) +
    • Fixed problem with ternary conditions returning references to global variables (Thanks Jonathan Sandusky) +
    • Fixed bug with opIndex when global variable had same name as datatype in a different namespace (Thanks dkrusu) +
    • Saving bytecode that used templates with multiple subtypes is now working properly (Thanks Phong Ba) +
    • Fixed assert failure in compiler when creating delegate from temporary object (Thanks Solokiller) +
    • Fixed crash on Win64 when calling native function that takes object by value that requires clean-up after call and the function also return an object by value (Thanks Jason Goepel) +
    • Fixed a bug with native calling conventions on Win32 when using Clang with MinGW 4.7+ (Thanks Joshua Cearley) +
    • Fixed a null pointer access failure that could happen in asGetActiveContext (Thanks Gwinnell) +
    • Fixed compiler warnings in asGetTypeTraits on gnuc 5.1 (Thanks Boost113) +
    • Fixed a possible null pointer access while releasing a script function (Thanks Andreas Fobian) +
    • Fixed some compiler errors on Linux with ARM (Thanks Vincent Cheng and James Cowgill) +
    • Fixed compiler bug when using construct call for a reftype on an object with opConv(?&out) (Thanks dkrusu) +
    • Fixed compiler bug that allowed class method handle to be converted to primitive (Thanks Solokiller) +
    +
  • Library +
      +
    • It is now possible to register member properties as references if the member should be dereferenced before access (Thanks cvet) +
    • Added supported for native calling conventions on Linux and Android with MIPS +
    • Improved performance for loading saved byte code (Thanks _Engine_) +
    • XBox 360 now supports 64bit integer arguments in native functions (Thanks Anthony Clark) +
    +
  • Virtual machine +
      +
    • Implemented asBC_Thiscall1 for faster calls to class methods that take an int argument and return a reference +
    +
  • Script language +
      +
    • for-loops now support multiple increment expressions separated by , (Thanks dkrusu) +
    +
  • Add-ons & Samples +
      +
    • Fixed memory leak in serializer when using extra objects +
    • Fixed bug in serializer with incorrect refcount on registered types when restoring the script object that references them +
    • Serializer attempted to backup non-pod types that had no user type registered with bitwise copy potentially causing errors +
    • Added GetBuffer to the CScriptArray object (Thanks Solokiller) +
    • Added GetRef to the CScriptHandle (Thanks zerochen) +
    • Added formatUInt for strings (Thanks iraxef) +
    • Included asserts in CScriptAny to detect improper usage from application (Thanks Solokiller) +
    • Script array is now constructed even if the current script context has a script exception set (Thanks iraxef) +
    • Fixed a compiler problem in asrun when C++11 support is not available (Thanks Anthony Clark) +
    • Implemented GetAddressOfValue in the dictionary value and iterator to simplify inspecting the content with the debugger +
    • Added a Set/GetEngine to the CDebugger to hold an engine pointer that can be used by the callbacks +
    • The debugger's ToString method and Callbacks now take a expand members recursively +
    • Implemented DictionaryToString debugger callback in asrun sample (Thanks Anthony Clark) +
    • CScriptBuilder now does case insensitive compares for duplicate include files on Windows (Thanks Solokiller) +
    +
  • Project +
      +
    • Added meson project files (Thanks Igor Gnatenko) +
    • Improved the android project files +
    +
+ +

Version 2.30.0 - 2015/02/22

+ +
    +
  • Bug fixes +
      +
    • Fixed bug with use of scoped reference types declared in global variables (Thanks ic0de) +
    • Fixed bug when comparing two handles and one is a handle to a read-only object (Thanks mbwac) +
    • Compiler will now give error if there is an overflow when evaluating power-of in constant expression (Thanks ThyReaper) +
    • Funcdefs can now have template types with script classes as subtypes (Thanks Sir Ementaler) +
    • Fixed an incorrect error code when registering a template specialization and the template type instance already existed (Thanks glcolor) +
    • Template specialization failed to remove generated template instances that has been created as a consequence (Thanks Sami Vuorela) +
    • Engine detects if application attempts to register method or property for generated template instances (Thanks glcolor) +
    • Fixed bug with asOBJ_APP_ARRAY in arm and ppc64 calling conventions (Thanks Brandon Bare) +
    • Fixed bug in Linux arm hardfloat ABI (Thanks Brandon Bare) +
    • Fixed an assert failure in the compiler when compiling an assignment with non-temporary deferred arguments (Thanks iraxef) +
    • The constructor stubs for value template types didn't pop the object pointer from the stack (Thanks iraxef) +
    • GetFunctionByDecl wasn't able to find the global function if the name was prefixed with :: (Thanks Ser Ementaler) +
    • The compiler was producing wrong bytecode when calling asBEHAVE_IMPLICIT_REF_CAST on value type +
    • Fixed crash when script class contained value template type as member +
    • Class method can refer to base class' method with fully specified namespace (Thanks iraxef) +
    • It is possible to register an enum with the same name in a namespace after it has been registered in the global namespace (Simon Geilfus) +
    • No more memory build-up when the script has circular references between classes and templates (Thanks iraxef) +
    • Private class properties are not accessible from derived classes (Thanks iraxef) +
    • Fixed bug in compiler where default argument could use temp var used in previous arguments (Thanks Solokiller) +
    • Compiler didn't properly check the access masks for registered class methods (Thanks Solokiller) +
    • Directly calling a funcdef retrieved from member property accessor would get wrong arguments (Thanks Solokiller) +
    • Methods declared in mixins in namespaces weren't compiled with the correct namespace (Thanks Sir Ementaler) +
    • Fixed problem with compiler not detecting incorrect type when passing class method as argument to constructor (Thanks Polyák István) +
    • Fixed bug in asBC_u64TOd and asBC_u64TOf on non-MSVC compilers (Thanks Turo Lamminen) +
    • Fixed crash on iOS/arm64 with thiscall callback functions (Thanks _Engine_) +
    • Fixed incorrect compiler warning about converting to handle after get accessor (Thanks agentprog) +
    +
  • Library interface +
      +
    • Deprecated asBEHAVE_VALUE_CAST and asBEHAVE_IMPLICIT_VALUE_CAST +
    • asIScriptEngine::AssignScriptObject now returns an int with the success or error code +
    • The tokenLength arg for ParseToken is changed to asUINT +
    • Added asIScriptObject::GetWeakRefFlag +
    • Implemented asIScriptEngine::RefCastObject +
    • Deprecated asIScriptEngine::IsHandleCompatibleWithObject +
    • Implemented SetArgVarType to the context for calling functions with variable argument types +
    • Added ShutDownAndRelease to explicitly tell when the engine should be shut down, compared to simply releasing the reference +
    • Implemented support for user data in script object instances +
    • Included asIScriptFunction::IsProtected +
    • asIObjectType::GetProperty has an additional parameter to return if the property is protected +
    • Deprecated asBEHAVE_REF_CAST and asBEHAVE_IMPLICIT_REF_CAST +
    • Added engine property asEP_PRIVATE_PROP_AS_PROTECTED +
    +
  • Library +
      +
    • Improved the algorithm for verifying if script classes require garbage collection +
    • Added support for native calling conventions on PS Vita (Thanks Brandon Bare) +
    • GetModule and DiscardModule are now thread-safe (Thanks Brandon Bare) +
    • Returned declarations with namespaces no longer prefix symbols with :: when declared in the global namespace (Thanks iraxef) +
    • When compiling a default argument expression the namespace of the called function is used as default (Thanks iraxef) +
    • Implemented asEP_DISALLOW_EMPTY_LIST_ELEMENTS to allow application to disable empty elements in initialization lists (Thanks theoutfield) +
    • Application can now register types with asOBJ_IMPLICIT_HANDLE if this option is turned on +
    • Improved some compiler error messages +
    • Updated gnuc makefile to automatically retrieve version number from angelscript.h for the shared library file name (Thanks Cody Ferguson) +
    • Minor runtime optimizations have been made +
    • Changed SetLineCallback so that it is safe to call it from a second thread while the context is running (Thanks ziomau) +
    • Completely re-factored the way the memory management for the internal script code is done +
    • Discarding modules is much faster, and doesn't burden the garbage collector (Thanks ziomau) +
    • Compiler no longer warns on empty sections since this may be a valid situation (Thanks iraxef) +
    • When formatting type declarations for messages the namespace will always be included if different than the current namespace (Thanks Solokiller) +
    • Included check to avoid modifying template types registration after a template instance has already been generated +
    • module's GetFunctionByName/Decl, GetGlobalVarIndexByName/Decl, GetObjectTypeByName recursively search parent namespaces +
    • engine's GetGlobalPropertyIndexByName/Decl, GetGlobalFunctionByDecl, GetObjectTypeByName recursively search parent namespaces +
    +
  • Script language +
      +
    • The ternary condition operator can now be used as lvalue if both options are lvalues of the same type (Thanks Polyák István) +
    • opImplConv can now be used to allow implicit conversion to bool for registered value types +
    • imported functions can now be placed in namespaces too (Thanks cvet) +
    • Compound assignment operators can now be used with virtual properties +
    • Included 'protected' as reserved keyword +
    • Class members can now be declared as protected +
    • Script classes can now implement opCast and opImplCast to provide custom ref cast behaviours +
    +
  • Add-ons & Samples +
      +
    • The script array and grid add-ons avoid flagging themselves as garbage collected for handle subtypes that are known not to be garbage collected +
    • CScriptHandle, CScriptAny, and CScriptDictionary use the new RefCastObject to properly cast to all supported types of the contained handle +
    • The dictionaryValue was missing a copy opAssign method so it wasn't possible to directly assign one dictionaryValue to another (Thanks iraxef) +
    • The weakref is now a value template type +
    • The syntax for using weakref in script is much more like a normal handles +
    • Implemented a CScriptFileSystem add-on to complement the CScriptFile add-on +
    • Changed ContextMgr::AddContext to allow application to tell manager that it want to keep the context after execution +
    • Added ContextMgr::DoneWithContext to return the context after the application has retrieved what it wants from it +
    • Fixed the asrun sample so now returns the status from the script again +
    • Improved asrun to support international languages better when writing to the console on Windows +
    • Changed CScriptFile::ReadLine and ReadString to return the string by value instead of as an output parameter +
    • Fixed some compiler warnings on gnuc in the add-ons (Thanks Bertram25) +
    • dictionaryValue has better support for boolean values +
    • Added support for asrun to execute system commands +
    • Debugger now accepts namespace for printing variables +
    • CScriptBuilder expands relative paths to absolute paths before verifying if the include file is duplicate (Thanks cuipeng) +
    • Fixed WriteConfigToStream/ConfigEngineFromStream to keep the valid object type flags and properly handle namespaces (Thanks Solokiller) +
    • Fixed ScriptArrayIsEmpty_Generic that didn't set the return value (Thanks _Engine_) +
    • Improved WriteConfigToStream so that template types are fully registered before other types (Thanks Solokiller) +
    • Prepared CContextMgr for use with AS_MAX_PORTABILITY +
    • Fixed bug in dictionary's opIndex when generic calling convention was used +
    • Fixed bug in CScriptHandle when AS_MAX_PORTABILITY was used +
    +
+ +

Version 2.29.2 - 2014/10/21

+ +
    +
  • Bug fixes +
      +
    • Fixed bug when compiling expressions using opCall on objects returned by reference from previous call (Thanks Sir Ementaler) +
    • Empty initialization lists are now properly working where a repeat pattern is expected (Thanks cvet) +
    • Fixed bug when global variable expression had casts between script classes (Thanks cvet) +
    • Fixed incorrect warning on literal -9223372036854775808 (Thanks iraxef) +
    • Compiler was incorrectly accepting syntax as object@(expr) (Thanks iraxef) +
    • Taking the address of an imported function now works as it should (Thanks Wipe) +
    • Fixed crash in compiler when compiling initialization lists with 'null' as one of the elements (Thanks iraxef) +
    • Identity comparison on handle received as parameter by reference wasn't working (Thanks iraxef) +
    • Application no longer crashes if an asIObjectType is released after the engine has been released +
    • Template instances now receive the member properties that were registered for the template (Thanks Samichama) +
    • Template types can now use other template types as method arguments where the sub-types are shared (Thanks Samichama) +
    • Fixed bug in compiler with use of implicit value conversion and temporary variables (Thanks Jason Goepel) +
    +
  • Library interface +
      +
    • Improved compiler compatibility of asGetTypeTraits to support Xcode/Clang (Thanks PhilCK) +
    • Script interfaces now return the module that owns them with GetModule (Thanks cvet) +
    +
  • Library +
      +
    • Added asEP_DISABLE_INTEGER_DIVISION that makes all divisions with integer values result in doubles (Thanks Jason Goepel) +
    • Improved performance of shutting down the engine (Thanks ThyReaper) +
    • Compiler warns when variable in inner scope hides variable of same name in outer scope (Thanks carew) +
    • Compiler warns when overloading inherited class method and default args in the methods cause conflicts (Thanks Aaron Baker) +
    • Compiler automatically resolves ambiguous enum values on comparisons (Thanks Jason Goepel) +
    +
  • Script language +
      +
    • Script classes can now implement opConv and opImplConv to support type conversions +
    • Passing a non-lvalue expression to a &out argument will now yield compiler error instead of warning +
    +
  • Virtual machine +
      +
    • Updated asBC_CALLBND so that imported functions can now be bound to application registered functions too (Thanks gjl) +
    +
  • Add-ons +
      +
    • The array and grid add-ons no longer set a script exception if the initialization list is empty +
    • Fixed problem with storing/retrieving enum values from the dictionary (Thanks iraxef) +
    • Concatenation with integers and string now properly supports 64bit types (Thanks iraxef) +
    • dictionary::get now supports retrieving stored handle by value if type is compatible (Thanks iraxef) +
    • CScriptBuilder::AddSectionFromMemory now has an optional lineOffset argument (Thanks Boost113) +
    • CScriptBuilder will report the correct path to the include files that fails to load (Thanks gjl) +
    • Fixed bug in CScriptFile when reading ints for least significant byte first (Thanks gjl) +
    +
+ +

Version 2.29.1 - 2014/07/20

+ +
    +
  • Bug fixes +
      +
    • Fixed compiler assert failure with unsafe references and deferred arguments (Thanks AgentC) +
    • Fixed problem with enumerating entities after removing a config group (Thanks Robert42) +
    • Fixed buffer overflow problem when Prepare() with virtual script function near the end of the stack memory (Thanks GGLucas) +
    • Fixed parser bug when local variable had the same name as a type in different namespace (Thanks cvet) +
    • Fixed errors with saved bytecode when using template types declared in namespace (Thanks cvet) +
    +
  • Library +
      +
    • Improved compiler error messages +
    • The module's ResetGlobalVars uses the context callbacks to support debugging initialization of global variables without informing a pre-created context +
    • The context callbacks are disabled before destroying the engine to avoid creation of new contexts while cleaning up objects +
    • Added asEP_ALTER_SYNTAX_NAMED_ARGS to optionally support the previous syntax for named args +
    • asOBJ_TEMPLATE can now be used with value types too +
    +
  • Library interface +
      +
    • Added asGetTypeTraits<T>() as part of the official interface +
    +
  • Script language +
      +
    • Changed the syntax for named arguments to "arg: expr" to avoid confusion when local variable has the same name as the argument (Thanks Kevin Ingwersen) +
    • Added support for declaring classes as abstract to prevent instantiation (Thanks Scott Bean) +
    +
  • Add-ons & Samples +
      +
    • Added null-pointer check in CDebugger::ToString and fixed some compiler warnings (Thanks Dominique Dumont) +
    • Array elements are initialized to zero by default (Thanks cvet) +
    • Fixed null pointer access bug in grid add-on (Thanks Bitsauce) +
    • GetTypeTraits<T>() has been removed from the helper add-on +
    • Replaced the helper function PrintException with GetExceptionInfo that returns the information in a string +
    • The asrun sample is now using the ContextMgr add-on to support co-routines +
    • The ContextMgr uses the RequestContext instead of CreateContext to take advantage of the context callbacks +
    • Fixed bug in closeTo math function when one of the arguments was 0 +
    +
+ +

Version 2.29.0 - 2014/06/09

+ +
    +
  • Bug fixes +
      +
    • Function handles were incorrectly treated as handles in value assignment +
    • Fixed RWX section in as_callfunc_arm_gcc.S (Thanks Julian Ospald) +
    • Fixed assert failure with implicit cast and get accessor (Thanks Amer Koleci) +
    • Fixed opCall on global variable (Thanks gjl) +
    • Fixed crash when calling opCall on a property accessor on a global variable (Thanks gjl) +
    • Fixed bug in compiler where temporary variable could be overwritten when calling overloaded operators (Thanks Jason Goepel) +
    • Fixed bug in tokenizer for one line comments on the last line of a script (Thanks Jason Goepel) +
    • Fixed bug with explicit construct call and reference types (Thanks Roel Binnendijk) +
    • Fixed bug in GetDeclaration when returning the list pattern (Thanks agentprog) +
    • GetSubTypeId and GetSubType now works for registered template specializations too (Thanks Jason Goepel) +
    • Loading bytecode with funcdefs declared from script wasn't working identical to building from source (Thanks cvet) +
    • GarbageCollect(asGC_FULL_CYCLE | asGC_DESTROY_GARBAGE) will now properly destroy the garbage in the new generation too (Thanks Maciej Biedrzycki) +
    • Stack unwinding now works on Linux 64bit with native calling conventions +
    • Fixed bug in compiler that allowed expression with name of function without doing anything with it (Thanks iraxef) +
    • Engine no longer silently accept registering template methods where the template subtype is passed by value +
    • Mixin classes in parent namespace can now be properly included in a class (Thanks cvet) +
    • Compiler now gives an error when script declares handle to handle (Thanks iraxef) +
    +
  • Library +
      +
    • Added the flag asOBJ_APP_ARRAY to support registering types that are really C arrays +
    • The parameter names from the declaration are now stored in the functions (Thanks GGLucas) +
    • The parameter names are stored with the saved bytecode, unless debug information is stripped +
    • Improved C++ exception handling to avoid deleting object that was never returned (Thanks Polyák István) +
    • CreateScriptObject will return null if the object constructor throws C++ exception +
    • The template callback can now write error messages to facilitate the understanding of why a template cannot be instantiated (Thanks JaviCervera) +
    • Compiling the library with Sun CC for SPARC is now possible, though without native calling conventions (Thanks Andrey Bergman) +
    • Improved error message when trying to pass class method as argument (Thanks Grimshaw) +
    • Types registered with asOBJ_ASHANDLE should now provide the opHndlAssign method to support handle assignments +
    • Types registered with asOBJ_ASHANDLE can also register the opAssign method to support value assignments +
    • CreateScriptObjectCopy now uses the copy constructor for value types, if available +
    • The asBEHAVE_VALUE_CAST behaviour now supports the generic form 'void f(?&out)' +
    • Improved runtime performance by avoiding increasing/decreasing refcount of script object in class methods (Thanks GGLucas) +
    +
  • Library interface +
      +
    • asIScriptFunction::GetDeclaration has an optional argument to include the parameter names (Thanks GGLucas) +
    • Added asIScriptFunction::GetParam that can optionally return both the name and default argument in addition to the type id +
    • Deprecated asIScriptFunction::GetParamTypeId +
    • Added GetObjectTypeByDecl to both engine and module +
    • Removed old deprecated methods +
    • Modules, contexts, and functions now also support multiple user data +
    • Added the global functions asAllocMem and asFreeMem that call the registered custom memory functions +
    • Added RequestContext, ReturnContext, SetContextCallbacks to engine +
    • Added the argument numIterations to GarbageCollect to support multiple iterations without having to call the method multiple times +
    • GetStringFactoryReturnTypeId now has an optional argument to return information on the reference (Thanks agentprog) +
    • Added support for registering functor objects as class methods with asCALL_THISCALL_OBJLAST and asCALL_THISCALL_OBJFIRST (Thanks Jordi Oliveras) +
    +
  • Script language +
      +
    • Named arguments in function calls are now supported (Thanks GGLucas) +
    • auto can now be used to tell the compiler to resolve the type of a variable from the initialization expression (Thanks GGLucas) +
    +
  • Add-ons +
      +
    • The GetTypeTraits<T>() helper function automatically detects when to use asOBJ_APP_ARRAY +
    • Added default factory and resize method to the grid +
    • Array and grid properly handle exceptions while constructing elements (Thanks Polyák István) +
    • Fixed compilation error with xcode 5.1 in dictionary (Thanks Jordi Oliveras Rovira) +
    • The array and grid addons use the asAllocMem and asFreeMem as default memory routines +
    • CScriptHandle implements the opHndlAssign instead of the opAssign +
    • Dictionary now has the opIndex that can be used to directly assign and retrieve values without using the set/get methods +
    • Dictionary uses asAllocMem and asFreeMem, and has factory functions to create instances +
    • The context manager now uses funcdefs and dictionary to create co-routines +
    • WriteConfigToFile wasn't saving the return type for the string factory correctly (Thanks agentprog) +
    • Added helper functions WriteConfigToStream and ConfigEngineFromStream +
    • Fixed compilation error with CScriptArray in asrun +
    +
+ +

Version 2.28.2 - 2014/03/18

+ +
    +
  • Bug fixes +
      +
    • The Library can now be compiled for WinXP with multithread support again (Thanks carnalis) +
    • Fixed crash after loading bytecode with initialization lists holding ref types by value (Thanks loboWu) +
    • Fixed bug with saved bytecode and initialization lists that skip values +
    • Tokenizer was splitting identifiers that started with keywords that ended with numbers, e.g. int8 (Thanks loboWu) +
    • GetObjectTypeById crashed if the typeId represented a template instance type that had already been released (Thanks iraxef) +
    • Corrected some compiler warnings (Thanks arpeggiodragon) +
    • Fixed crash when returning primitive value implicitly cast from global handle (Thanks Jason Goepel) +
    • Fixed assert failure in compiler when using opAssign that returns a value instead of a reference (Thanks simong) +
    • Fixed memory leak with registered cast behaviours on template types (Thanks Jason Goepel) +
    • Fixed bug with missing implicit ref cast when passing object to parameter as inout reference (Thanks Jason Goepel) +
    • Fixed bug when passing 'null' or 'void' to var type argument +
    +
  • Library +
      +
    • It's now possible to use repeat_same in list pattern to tell compiler that all lines must be of the same length +
    • The compiler will warn if JIT compiler is used and script is built without JIT entry points (Thanks gjl) +
    • Compiler no longer warns on sign change for bitwise operator with negative enum value (Thanks _Vicious_) +
    • Reduced size of saved bytecode +
    • Changed GarbageCollect so that it can now be executed for a full cycle in a parallel thread +
    • Implemented C++11 move operators for the internal asCString type (Thanks iraxef) +
    • Compiler now casts to common base class when comparing two handles (Thanks Aaron Baker) +
    • When unsafe references is turned on the compiler allows passing literal constants to const references (Thanks Jason Goepel) +
    • Improved implicit cast of object to primitive in math expressions (Thanks Jason Goepel) +
    • Optimization to use the copy constructor instead of the assignment when preparing temp object for func argument +
    • Optimization to avoid copy when passing ref type to const &in parameter (Thanks Jason Goepel) +
    +
  • Script language +
      +
    • Anonymous objects can now be initialized in expressions with lists +
    • The opIndex operator overload now supports multiple arguments +
    • Functor objects can now be implemented by implementing opCall methods in the class (Thanks gjl) +
    +
  • Add-ons +
      +
    • Implemented closeTo() in the math add-on (Thanks haegarr) +
    • GetTypeTraits() no longer incorrectly identifies C++ arrays as asOBJ_APP_CLASS (Thanks eezstreet) +
    • The script array now supports user defined memory routines (Thanks FDsagizi) +
    • The script array should be allocated with factory functions instead of directly with new (Thanks iraxef) +
    • Added GetTypeId to the dictionary to retrieve the type id of the stored value (Thanks iraxef) +
    • The dictionary now has an iterator on the C++ side that supports C++ range-for loops (Thanks iraxef) +
    • Implemented the grid template add-on +
    +
+ +

Version 2.28.1 - 2014/01/31

+ +
    +
  • Bug fixes +
      +
    • Fixed improper warning of used types when releasing engine and having circular references between registered types (Thanks Jason Goepel) +
    • Fixed memory leak on registering opAssign twice for the same object type (Thanks Jason Goepel) +
    • Compiler will not used enum values from registered enum types if the module doesn't have access to it +
    • Fixed assert failure in Execute when forgetting to set the object on a class method call (Thanks simps) +
    • Compiler now uses the default args declared in derived methods instead of the default args in base method (Thanks Aaron Baker) +
    • Fixed the position reported for errors while compiling global variables +
    • Compiler wasn't searching parent namespaces when resolving the symbol for class inheritance (Thanks Agnis) +
    • Fixed linker error on Windows RT with ARM due to misaligned code in as_callfunc_arm_msvc.asm (Thanks NiteLordz) +
    • Fixed crash with THISCALL_ASGLOBAL and virtual methods (Thanks Macobyte) +
    • Implicit cast didn't work in initialization of global vars (Thanks Jason Goepel) +
    • Incorrect bytecode sequence when compiling initialization list for dictionary containing values from global string variables (Thanks Jordi Oliveras Rovira) +
    • Compiler was incorrectly converting both results to const in ?: if one of the expressions was null (Thanks FDsagizi) +
    • Fixed memory leak on iOS when passing complex object by value to registered function (Thanks FDsagizi) +
    • Fixed intermittent crash with registered object properties of template instance types (Thanks aliascc) +
    • Fixed crash when attempting to assign a script object to another of another type (Thanks Philip Bennefall) +
    • Fixed crash when registering two or more methods for an object type uses template instance types in parameters or return value (Thanks iraxef) +
    +
  • Library +
      +
    • Defined default arg for asSFuncPtr constructor to allow trivial instanciation (Thanks _Vicious_) +
    • Added verification to avoid use of context from a different engine to call functions (Thanks GGLucas) +
    • Removed some more unused code in AS_NO_COMPILER mode +
    • Optimized compiler performance with faster lookups (Thanks GGLucas) +
    • Added check against attempts to register multiple list factories (Thanks Jason Goepel) +
    • Compiler is able to resolve ambiguous enum values if it can determine the enum type from the destination (Thanks Jason Goepel) +
    • Slightly reduced memory consumption as virtual functions no longer store the default args +
    • Linux with ARM now supports native calling conventions for both soft-float ABI and hard-float ABI +
    • Compiler is capable of using constructors with default args as default constructor (Thanks Sir Ementaler) +
    • An error will now be returned when building an empty script +
    • Saving bytecode for an empty module will now return an error +
    • The overhead for calling interface methods is reduced by adding the methods in the virtual function table (Thanks GGLucas) +
    • asIScriptEngine::GetObjectTypeByName can now return template types too +
    • POD value types are now allocated inline when members of script classes (Thanks GGLucas) +
    • Ternary condition operator now converts either case to const @ if the other is const @ (Thanks _Vicious_) +
    • Multithreading is now supported on Windows Store Apps too +
    • Slightly reduced size of saved bytecode +
    • Improved error messages when loading invalid bytecode +
    +
  • Script language +
      +
    • Added the operators ** and **= for exponent math operations (Thanks Jason Goepel) +
    • The methods opPow and opPow_r can be used to overload the exponent math operator (Thanks Jason Goepel) +
    +
  • Virtual machine +
      +
    • Added the instructions POWi, POWu, POWf, POWd, POWdi, POWi64, POWu64 (Thanks Jason Goepel) +
    +
  • Add-ons & samples +
      +
    • WriteConfigToFile now writes the engine properties too +
    • asbuild sample updated to set the engine properties as informed in config file +
    • Added GetTypeId to the script handle to make it easier to work with function pointers (Thanks Ava Skoog) +
    • Implemented FindByRef in the script array (Thanks Marcus L) +
    • CDebugger now has a RegisterToStringCallback to allow custom conversion of types to strings for the debug output +
    • Fixed assert failure in CScriptWeakRef (Thanks Squared'D) +
    • WriteConfigToFile escapes quote characters in default arg expressions (Thanks alraz.exe) +
    • asbuild sample updated to treat the escaped quote characters properly (Thanks alraz.exe) +
    • CScriptHandle will hold a reference to engine to avoid crash if engine is released before the contained reference (Thanks Samuel Villarreal) +
    +
+ +

Version 2.28.0 - 2013/11/02

+ +
    +
  • Bug fixes +
      +
    • The GET_WEAKREF_FLAG behaviour is now registered for the script types in AS_MAX_PORTABILITY too (Thanks orimoto) +
    • Fixed stack alignment problem with native calling convention for Linux and ARM (Thanks loboWu) +
    • Fixed null pointer access during compilation if JIT compiler is used (Thanks Andrew Ackermann) +
    • Fixed null pointer access when calling GetMethodByDecl on template instance type (Thanks Jason Goepel) +
    • Fixed memory leak with default args and shared functions (Thanks thd.MM) +
    • Fixed crash on registering function with autohandles for unknown type (Thanks Jason Goepel) +
    • Fixed crash on registering template specialization twice (Thanks Jason Goepel) +
    • Fixed bug with passing handle to ?& arg with unsafe references (Thanks FDsagizi) +
    • opEquals with funcdef works again (Thanks Violet CLM) +
    • Fixed bug with implicit casts of large integer constants and uint64 (Thanks Apmyp) +
    • Fixed bug in IsNested when called with parameter (Thanks Jordi Oliveras Rovira) +
    • Fixed crash in compiler when resolving function pointers with namespace (Thanks Violet CLM) +
    • Conditional operator ?: implicitly converts 0 to the type of the other expression again (Thanks FDsagizi) +
    • Reusing existing module without discarding it no longer accumulates memory in engine (Thanks Scott Bean) +
    • The object type for script classes that formed circular reference with base class wasn't resolved by gc (Thanks Scott Bean) +
    • FindNextLineWithCode() works properly for class constructors where class has non-primitive members too (Thanks Scott Bean) +
    • GetTypeDeclaration now work correctly for registered template specializations (Thanks zexee) +
    • Fixed crash with chained handle assignments (Thanks FDsagizi) +
    • Fixed compiler errors with Borland (Thanks Viacheslav Polyakov) +
    • Fixed assert failure in compiler on explicit ref cast of void expression (Thanks AgentC) +
    +
  • Library +
      +
    • The list factory behaviour now receives a pointer to a buffer with all values instead of just the expected length +
    • Engine now properly supports use of autohandles in template factories +
    • Assembler code for Linux + ARM is now unified to support both normal and thumb mode (Thanks loboWu) +
    • The engine uses the registered list pattern to dynamically determine the elements in the list buffer +
    • Optimized tokenizer with the use of jump tables (Thanks GGLucas) +
    • Added compiler warning on implicit conversion from float to integer (Thanks FDsagizi) +
    • FindNextLineWithCode() is able to find the first line with code from where the function has been declared +
    • Added code to detect and warn instead of crashing if application attempts to resurrect script object during its destruction (Thanks Tuukka Pensala) +
    • The function declaration for constructors and destructors now show the object type name instead of _beh_x_ (Thanks Jason Goepel) +
    • Added support for atomics and posix threads with Android 2.3+ (Thanks Jordi Oliveras Rovira) +
    • The engine no longer writes parser errors to message callback in the GetByDecl methods (Thanks kaveldun) +
    • Updated config to correctly identify iOS with 64bit arm (Thanks taliska) +
    +
  • Library interface +
      +
    • Added GetModuleCount and GetModuleByIndex for enumerating existing modules (Thanks Vitaly Akimov) +
    • asBEHAVE_LIST_FACTORY must declare the expected pattern for the initialization list +
    • Added asBEHAVE_LIST_CONSTRUCT to allow value types to be initialized with lists too +
    • GetVarDecl and GetPropertyDeclaration now take an optional includeNamespace argument (Thanks zexee) +
    +
  • Virtual machine +
      +
    • Implemented the bytecodes asBC_AllocMem, asBC_SetListSize, asBC_SetListType and asBC_PshListElmnt for handling initialization lists +
    • asBC_FREE has been enhanced to allow it to destroy the content of an initialization list +
    +
  • Add-ons +
      +
    • The script array add-on uses the new form for the initialization list +
    • The weakref add-on now works properly in AS_MAX_PORTABILITY too +
    • Fixed bug in script array resize() method that could cause a crash if reserving too much memory (Thanks Philip Bennefall) +
    • Fixed compiler error in CDebugger add-on when using the AngelScript namespace (Thanks Jordi Oliveras Rovira) +
    • The dictionary add-on now supports initialization lists +
    • The Complex math add-on now supports initialization lists +
    +
+ +

Version 2.27.1 - 2013/08/16

+ +
    +
  • Bug fixes +
      +
    • Engine no longer accepts registering template factory with autohandles +
    • Implicit conversion to ASHANDLE type will not copy the value any longer +
    • Fixed 64bit bug in asBC_SwapPtr (Thanks Colin Didier) +
    • Fixed bug in the compiler when dealing with opAssign that returns anything else than a reference (Thanks neorej16) +
    • Compiler was incorrectly reusing temporary variables in some expressions with ternary condition operator (Thanks neorej16) +
    • Compiler was incorrectly making a copy of the object in some cases for explicit ref casts +
    +
  • Library +
      +
    • Reduced memory footprint for applications with a lot of registered functions +
    +
  • Script language +
      +
    • For consistency @null is now a valid expression +
    • Default arguments can be used with anonymous parameters (Thanks Sir Ementaler) +
    • void is a legal expression and can be used to ignore output parameters +
    +
  • Add-ons & samples +
      +
    • Fixed bug in CScriptBuilder with loading an empty file (Thanks Piotr Kosek) +
    • Implemented a different ExecuteString that can return a value of variable type +
    +
+ +

Version 2.27.0 - 2013/07/28

+ +
    +
  • Bug fixes +
      +
    • Compiler would call a script class' opAssign method as if it was a system function in a specific situation causing a crash (Thanks Polyák István) +
    • A compound assignment to a class member could be compiled incorrectly if the lvalue had deferred parameters in expression (Thanks Polyák István) +
    • GetExceptionLineNumber would crash if the exception had been raised in a generated function (Thanks Polyák István) +
    • Fixed compiler error on FreeBSD (Thanks Veniamin Gvozdikov) +
    • Compiler didn't detect ambigious enum values when compiling initialization of global variables +
    • Nested calls in context could overwrite value in register (Thanks Philip Bennefall) +
    • Fixed bug with max portability and delegates (Thanks Andris Jaunzeikars) +
    • Fixed memory leak in compiler with shared classes and virtual properties (Thanks Xifos) +
    • Function pointers for global functions in namespaces wasn't resolving properly (Thanks Violet CLM) +
    • Registered value types that didn't have size evenly divisable of 4 weren't allocated with enough space (Thanks Hermann Noll) +
    • Class methods with default args using parenthesis failed to parse (Thanks Aaron Baker) +
    • Template arguments declared as const T@ will keep the handle-to-const attribute in template instances +
    +
  • Library interface +
      +
    • Removed previously deprecated methods +
    • Added GetModule method to the asIScriptFunction and asIObjectType interfaces +
    • Added Discard to the asIScriptModule interface, that does the same as asIScriptEngine::DiscardModule +
    • Added GetDelegateObject and GetDelegateFunction to asIScriptFunction +
    • Added CreateDelegate to asIScriptEngine +
    • RegisterObjectBehaviour and RegisterStringFactory now accepts asCALL_THISCALL_ASGLOBAL +
    • Added type modifier asTM_CONST to indicate parameters and return types that are const references (Thanks Polyák István) +
    • GetArgTypeId and GetReturnTypeId now have optional parameter to retrieve the type modifier flags +
    • Added GetFuncDefFromTypeId to allow getting the asIScriptFunction for a function definition (Thanks Polyák István) +
    • NotifyGarbageCollectorOfNewObject will return the sequence number attributed to the object +
    • Added GetObjectInGC to allow inspecting objects that are currently known by the GC +
    • The new behaviour asBEHAVE_GET_WEAKREF_FLAG was added to support weak references (Thanks vroad) +
    • Added the interface asILockableSharedBool for the weak ref flag +
    • Global asCreateLockableSharedBool can be used by application classes to create instances of shared booleans +
    • CreateScriptObject, CreateScriptObjectCopy and CreateUnitializedScriptObject now takes an asIObjectType instead of type id +
    • AssignScriptObject also takes an asIObjectType instead of type id +
    • Deprecated AddRefScriptObject and ReleaseScriptObject that takes type id +
    +
  • Library +
      +
    • Improved performance of thread manager and with that reduced the overhead of script calls (Thanks Andrew Ackermann) +
    • GC now gives an id for each object from a sequence and reports this when it cannot destroy an object +
    • GC will call script class destructor before breaking circular references (Thanks hupsilardee) +
    • Engine no longer silently accepts modifications to built-in types by the application (Thanks Violet CLM) +
    • Added support for weak references (Thanks vroad) +
    +
  • Script language +
      +
    • Literal float and double constants accept the format 1e5 (Thanks Jason Goepel) +
    • Template subtypes can no longer be declared as read-only +
    • Derived classes can no longer override base methods with different return types (Thanks Philip Bennefall) +
    +
  • Add-ons & samples +
      +
    • Script array add-on can now sort arrays of handles by calling the opCmp on the objects (Thanks Polyák István) +
    • Script array does a better search for matching opCmp and opEquals (Thanks Polyák István) +
    • Fixed compilation error with has_trivial_destructor on g++ 4.8 in GetTypeTraits (Thanks Craig Soutar) +
    • Added the weakref add-on (Thanks vroad) +
    • The game sample uses the weakref add-on +
    +
+ +

Version 2.26.3 - 2013/05/08

+ +
    +
  • Bug fixes +
      +
    • Compiler was generating invalid bytecode when compiling var declaration with initialization using void opAssign (Thanks Andrew Ackermann) +
    • RegisterObjectProperty() will now return an error if the offset is larger than a signed 16bit value which is what the VM supports (Thanks Adrian Bibby Walther) +
    • Fixed bug in compiler where the class constructor could become invalid if two classes with the same name was declared in different namespaces (Thanks loverlin) +
    • A null pointer access error could happen when compiling a script with enums after discarding a script with global variables (Thanks Robert Weitzel) +
    • The context could in some situations attempt to destroy objects on the stack that had never been initialized upon cleanup (Thanks Philip Bennefall) +
    • Multi-template types where both subtypes are of the same script class no longer crash the GC (Thanks Polyák István) +
    +
  • Library interface +
      +
    • The new enum asFUNC_DELEGATE is used to identify function objects that are delegates +
    • The engine property asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE disables value assignments for reference types +
    +
  • Script language +
      +
    • Delegates can now be instantiated with a construct call for a funcdef with the class method as argument +
    • Function handles for overloaded functions are now implicitly resolved by the compiler by deferring the choice of the function until its used +
    • Parent namespaces are now searched recursively for matching entities +
    +
  • Add-ons +
      +
    • Script array add-on will not allow subtypes of reference types unless they are handles if asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE is turned on (Thanks Polyák István) +
    • Added methods GetSectionCount() and GetSectionName() to builder for enumerating the included script sections +
    • Added fpToIEEE and fpFromIEEE to the math addon. These allow platform agnostic conversion between floating point and IEEE 754 representation (Thanks Maarten van Berkel) +
    +
+ +

Version 2.26.2 - 2013/03/31

+ +
    +
  • Bug fixes +
      +
    • Fixed bug in compiler when compiling implicit cast of global variable of ref type to a primitive value (Thanks jrick) +
    • Fixed crash that could happen on releasing the engine if some garbage collected object was still kept alive by application (Thanks thd.MM) +
    • Fixed the native calling conventions on Android (Thanks Grimshaw) +
    • Fixed problem with shared global functions being recompiled in all modules and thus causing memory leaks (Thanks thd.MM) +
    • Fixed crash with native calling conventions on Linux 64bit (Thanks darthvolvo) +
    • The compiler wasn't giving error when default arg expression didn't match the parameter type (Thanks Philip Bennefall) +
    • Evaluating -2147483648 / -1 is now treated properly with a script exception (Thanks TyRoXx) +
    • Initializing class member in declaration with a non-default constructor produced invalid bytecode (Thanks fanwars) +
    • Fixed the native calling conventions on MinGW64 4.7 (Thanks Neuntoter) +
    +
  • Library +
      +
    • Improved garbage collector to give better error messages when it can't release all objects +
    • Added engine property asEP_COMPILER_WARNINGS to allow applications to turn off warnings +
    • Changed the code back to emit a warning instead of an error on unreachable code as it was often used by developers to temporarily skip parts of the code during testing +
    • Increased maximum limit of number of functions in the engine from 65535 to approximately 10^9 (Thanks TheAtom) +
    +
  • Script language +
      +
    • Integer constants are now considered signed by default (Thanks cellulose) +
    +
  • Add-ons +
      +
    • Implemented helper function GetTypeTraits<T> to aid in the registration of value types. Relies on C++11 features (Thanks Heuristics) +
    +
  • Project +
      +
    • Updated the Android makefile to make sure the library is compiled with thumb mode turned off (Thanks quarnster) +
    • Modified the gnuc makefile to make it easier for Linux package maintainers (Thanks Michael Shigorin) +
    • Updated trolltech makefile to allow it to compile as_callfunc_x64_msvc_asm.asm on 64bit Windows (Thanks Markus Mönig) +
    +
+ +

Version 2.26.1 - 2013/03/02

+ +
    +
  • Bug fixes +
      +
    • Fixed compiler error on Mac OS X in with the atomic functions (Thanks thd.MM) +
    • Fixed segfault in GetGlobalVarIndexByDecl on passing invalid declaration (Thanks Nate Kent) +
    • AssignScriptObject and CopyFrom wasn't using the script class' opAssign method (Thanks Polyák István) +
    • Fixed bug in compiler with complex expressions in default args (Thanks Philip Bennefall) +
    • Fixed the line numbers for for-loops (Thanks FDsagizi) +
    • Fixed bug with the allocation of function ids, which could cause random behaviour for very large scripts (Thanks TheAtom) +
    • Fixed bug with loading bytecode that used registered value types that could cause unexpected behaviour (Thanks TheAtom) +
    • The compiler wasn't considering the correct namespace when parsing methods of classes and interfaces within namespaces (Thanks Wipe) +
    • Interfaces that inherited other interfaces didn't expose the inherited methods (Thanks Wipe) +
    • Fixed assert failure in compiler with use of copy constructor for value type with unsafe reference (Thanks FDsagizi) +
    • Fixed assert failure in compiler with nested access to virtual property accessors (Thanks AgentC) +
    • Fixed null pointer access in compiler when compiling default constructor for a class with invalid member initialization expressions (Thanks FDsagizi) +
    • Fixed crash in compiler when compiling call to imported function with default arguments (Thanks Wipe) +
    • Compiler no longer emits warnings on implementing the same interface multiple times (Thanks Wipe) +
    • Compiler generated invalid bytecode when compiling expression that called function pointer returned from virtual property accessor (Thanks Wipe) +
    • Fixed crash in GetLineNumber after loading module from bytecode (Thanks FDsagizi) +
    • Fixed memory leak that could happen upon script exception (Thanks Wipe) +
    +
  • Library +
      +
    • Improved error message from CreateScriptObject when called for type that doesn't have default constructor (Thanks izackp) +
    • Parser doesn't complain with empty declaration, i.e. a single ;, in classes (Thanks FDsagizi) +
    • Improved error message when encountering non-terminated string literals (Thanks FDsagizi) +
    • Templates now support multiple subtypes (Thanks Amer Koleci) +
    • Added support for native calling conventions on Linux with ARM and gnuc compiler (Thanks Carlos Luna) +
    • Compiler will report error if virtual property in shared interface doesn't match first declaration of the interface (Thanks Wipe) +
    • Funcdefs are now automatically shared between modules if they are identical (Thanks Wipe) +
    +
  • Script language +
      +
    • Primitives can now be implicitly cast to value types via a call to the appropriate constructor +
    • Added support for octal and binary constants with prefixes 0o and 0b respectively (Thanks ketmar) +
    • Heredoc strings keep the last linebreak (Thanks Scott Bean) +
    +
  • Add-ons +
      +
    • Script any, dictionary, and file add-ons now uses asAtomicInc/Dec to provide threadsafe reference counting +
    • Implicit casts from primitives to the complex math type can be done with the new constructor +
    +
+ +

Version 2.26.0 - 2013/02/03

+ +
    +
  • Bug fixes +
      +
    • Fixed rare crash after an object type had been deleted prematurely by the engine +
    • Fixed incorrect static_cast on MSVC when attempting to register method for class with virtual inheritance (Thanks David Rosen) +
    • Fixed compiler warnings when compiling with AS_NO_THREADS (Thanks Papirosnik) +
    • Namespaces are now properly considered when compiler searches for property accessors (Thanks Violet CLM) +
    • Fixed crash that occurred when using asCALL_GENERIC with asBEHAVE_TEMPLATE_CALLBACK (Thanks Andre Santee) +
    • Fixed problem with saving/loading bytecode that passed function pointers in a function parameter (Thanks Andre Santee) +
    • Fixed global variables of scoped reference types +
    • Fixed bug in XBox 360 native calling convention code when returning simple objects by value (Thanks Jason Dorie) +
    • Fixed compiler errors on Wii U (Thanks virious) +
    • Shared types would get the implemented interfaces duplicated if compiled in multiple modules (Thanks Andrew Ackermann) +
    • Fixed bug in compiler with passing temp handle to function taking inout ref to object (Thanks kozec) +
    • RegisterObjectType no longer accepts combination of asOBJ_VALUE and asOBJ_NOHANDLE (Thanks Paril101) +
    • Compiler wasn't considering the correct implicit namespace when looking up datatypes (Thanks Paril101) +
    • Loading bytecode always failed if global variables had been disabled, even if the saved bytecode didn't have any global variables (Thanks Paril101) +
    • Constructor with const &inout is now recognized as copy constructor with asEP_ALLOW_UNSAFE_REFERENCES (Thanks FDsagizi) +
    • Fixed parser error when function declaration had default argument that used paranthesis (Thanks Thomas Grip) +
    • Fixed null pointer access in GetLineNumber() if called on function without debug info (Thanks ketmar) +
    • Fixed crash that could happen discarding a module and the garbage collector held a reference to an object declared in the module (Thanks Thomas Grip) +
    • Script arrays could be falsely marked as non-garbage collected as the asOBJ_GC flag wasn't set when the template callback was invoked +
    • Fixed bug where a script class could be incorrectly marked as non-garbage collected when including a garbage collected member by value +
    +
  • Library interface +
      +
    • Added asCALL_THISCALL_ASGLOBAL for registering a class method as a global function +
    • RegisterGlobalFunction() now takes an optional object pointer to be used with THISCALL_ASGLOBAL (Thanks zerochen) +
    • asPrepareMultithread now takes an optional argument for using a shared thread manager in multiple dlls (Thanks Damien French) +
    • asGetThreadManager and asIThreadManager for retrieving an existing thread manager (Thanks Damien French) +
    • Added GetDefaultNamespace to engine and module (Thanks dkrusu) +
    • Prepared asIObjectType for future implementation of templates with multiple subtypes +
    • Added asAtomicInc and asAtomicDec as global functions to aid in development of portable and threadsafe add-ons +
    +
  • Library +
      +
    • Unreachable code in script functions is now considered an error by the compiler, instead of just a warning +
    • Compiler avoids misleading error message about not all paths having a return value after encountering unreachable code (Thanks zerochen) +
    • Marmalade is now identified as an OS with its own ABI (Thanks Braden MacDonald) +
    • Added configuration for compiling the library with gnuc on Linux with mips. Though only with AS_MAX_PORTABILITY (Thanks Andris Jaunzeikars) +
    • Added compile time option AS_NO_MEMBER_INIT to disable member initialization for backwards compatibility (Thanks Andrew Ackermann) +
    • Reduced size of executable by avoiding code inlining in templated functions for taking function pointers (Thanks AgentC) +
    • Slight reduction on overhead of calling system functions (Thanks Andrew Ackermann) +
    • Improved algorithm in compiler for determining if objects needs to be garbage collected or not by taking advantage of the 'final' flag (Thanks Andrew Ackermann) +
    +
  • Script language +
      +
    • It is now possible to initialize class members directly in the declaration +
    +
  • Add-ons +
      +
    • Implemented the generic calling convention wrappers for the missing methods in the script array add-on +
    • Implemented the generic calling convention wrappers for the script handle add-on +
    • Implemented the generic calling convention wrappers for the missing methods in the std::string add-on +
    • Fixed bug in script array when comparing two arrays for equality and only opCmp had been implemented in the element type (Thanks virious) +
    • Fixed fopen_s compiler error on Marmalade in the scriptfile and scripthelper add-ons (Thanks Braden MacDonald) +
    • CScriptBuilder::AddSectionFromMemory() now requires a name and an optional length for the buffer in case it is not null terminated (Thanks Paril101) +
    • Fixed null pointer access in CDebugger when stepping over a function without debug info (Thanks ketmar) +
    • Script array's reference counter is now threadsafe by using the global functions asAtomicInc and asAtomicDec +
    +
+ +

Version 2.25.2 - 2012/11/24

+ +
    +
  • Bug fixes +
      +
    • Problem with template types when non-default factory was registered before the default factory (Thanks zeta945) +
    • import functions can now be declared with default arguments without crashing (Thanks Wipe) +
    • Fixed bug in IsNested() that could sometimes give false positives +
    • Fixed incorrect error messages for mismatching property accessors when this had been disabled by application (Thanks Philip Bennefall) +
    +
  • Library +
      +
    • Changed to localized bytecode optimizations for greatly enhanced compilation speeds in large complex functions +
    • Added new bytecode optimizations for improved runtime performance +
    • Script functions are now only added to the GC when the owning module releases them +
    • Some more unused methods in the code are excluded when compiling with AS_NO_COMPILER +
    • Global properties are also only added to the GC when the owning module releases them +
    • Object types are no longer added to the GC while the module still references them +
    • Changed style of comments in as_callfunc_arm_gcc.S to avoid compiler errors with Marmalade (Thanks Papirosnik) +
    +
  • Script language +
      +
    • Mixin classes can now implement interfaces +
    +
  • Add-ons & Samples +
      +
    • Fixed some compiler errors with gnuc in the sample projects (Thanks Aapo Rantalainen) +
    • ScriptBuilder now supports metadata for entities in namespaces (Thanks Chase W) +
    • Changed the code in the string factory to avoid confusing the Marmalade memory leak detector (Thanks Papirosnik) +
    +
+ +

Version 2.25.1 - 2012/10/28

+ +
    +
  • Bug fixes +
      +
    • Fixed including mixin from a different script section (Thanks Nick Robinson) +
    • Registering template specializations for templates without default constructor is now working (Thanks slicer4ever) +
    • Fixed compiler assert on unary negate operator on void expression (Thanks FDsagizi) +
    • Fixed bug with NOCOUNT object when copying script class members (Thanks FDsagizi) +
    • Problem with exception handling after loading pre-compiled bytecode when class constructor takes object in argument (Thanks FDsagizi) +
    • GetLineNumber() could crash when called for nested context calls (Thanks saejox) +
    • Compiler would incorrectly find global functions when compiling function calls as post ops (Thanks FDsagizi) +
    • Fixed bug in compiler when compiling property get expression that returned a reference to an object, but the reference wasn't used (Thanks Eero Tanskanen) +
    • Fixed bug with virtual methods returning objects in memory on ARM platforms (Thanks Cordan) +
    • Fixed compiler bug when compiling function that takes out reference of a type where opAssign returned a value (Thanks _Engine_) +
    • Compiler wasn't showing error for virtual properties without any accessor (Thanks FDsagizi) +
    • Shared enums in pre-compiled bytecode were not treated as shared when loading (Thanks _Engine_) +
    • Shared classes will now validate that declared members exist in the original declaration during compilation (Thanks _Engine_) +
    +
  • Library +
      +
    • Implemented an inline profiler to get better understanding of bottlenecks in the code +
    • Added support for the new ABI in MinGW32 4.7 (Thanks Heuristics) +
    • Improved error messages when loading bytecode with shared types that doesn't match existing shared types +
    • The context's line callback is now invoked one extra time just before leaving the Execute() method to allow listeners to catch state changes (Thanks saejox) +
    • Made some improvements towards compatibility with Marmalade +
    • Added validation against duplicate registration of global functions or class methods (Thanks Jason Dorie) +
    +
  • Script language +
      +
    • Class properties of the same type can now be declared together separated by , +
    • Interfaces can now inherit from other interfaces +
    • Improved the way function overloads are matched against arguments so least conversion cost for all arguments wins (Thanks Adam Hoult) +
    +
  • Add-ons +
      +
    • Slight optimization in the string pool when a string is inserted for the first time (Thanks thewavelength) +
    • Fixed bug in script builder add-on with parsing metadata for invalid script (Thanks FDsagizi) +
    +
+ +

Version 2.25.0 - 2012/09/17

+ +
    +
  • Bug fixes +
      +
    • GetEnumByIndex and GetTypedefByIndex wasn't returning a valid typeId when the type was not in the default namespace (Thanks Polyák István) +
    • Inheriting from a class or interface in a different namespace didn't work (Thanks Polyák István) +
    • Functions and class methods didn't accept the scope operator in the return type (Thanks Polyák István) +
    • Compiler missed adding a validation for a null pointer when compiling a return statement for a function returning object by value (Thanks Philip Bennefall) +
    • Fixed crash when cleaning up after a script exception in a function that returns a value object by value (Thanks Philip Bennefall) +
    • Fixed memory leak when compiling script that declares interface with virtual properties (Thanks brumi) +
    • Functions that take 64bit types as arguments now work with Android native calling conventions (Thanks Fredrik Ehnbom) +
    • Fixed bug in compiler when assigning value from property accessor to array element (Thanks Philip Bennefall) +
    • Fixed crash in garbage collector when using automatic collections (Thanks Polyák István) +
    • Compiler failed to compile default argument expression that accessed an index in global array (Thanks Philip Bennefall) +
    • Avoid temporary copy of script object without explicit opAssign method when assigned from global variable (Thanks Andrew Ackermann) +
    • Duplicate class methods are now detected at their declaration (Thanks FDsagizi) +
    • Local function pointers variables now properly take precedence over class methods of the same name (Thanks cellulose) +
    • Serializing bytecode that called funcions with variable arguments didn't work properly (Thanks Markus Lenger) +
    • Construct calls in expressions are now parsed properly when the type is preceeded with the namespace (Thanks Andrew Ackermann) +
    • Compiler gave error when compiling non-const methods that returned const references to members (Thanks Polyák István) +
    +
  • Library +
      +
    • The VM will catch C++ exceptions thrown by the registered functions and set a script exception. This can be turned off by AS_NO_EXCEPTIONS if exception handling is not supported (Thanks Polyák István) +
    • Loading large precompiled bytecode files will now be significantly faster. Performance should now be similar to pre 2.23.0 (Thanks loboWu) +
    • Improved build performance of tokenizer for large initialization lists (Thanks Markus Lenger) +
    • Improved build performance of parser for scripts with a lot of statements +
    • Improved build performance of searching for global properties by name (Thanks Markus Lenger) +
    • Improved build performance of searching for global script functions (Thanks Markus Lenger) +
    • Compiler will now implicitly convert rvalue to handle when doing a handle assignment to ASHANDLE type +
    • Types registered with asOBJ_APP_PRIMITIVE or asOBJ_APP_FLOAT can now be passed by value in native calling convention on 64bit Linux and Mac (Thanks Cordan) +
    • Error message now includes the error code when an improper call to an engine function is made +
    • Improved error message when parser encounters unexpected end of file (Thanks Philip Bennefall) +
    • Improved build performance when optimizing bytecode with a large amount of conditions +
    +
  • Virtual Machine +
      +
    • float and double comparisons in the VM now properly handle infinity (Thanks GGLucas) +
    +
  • Library interface +
      +
    • Added asOBJ_APP_CLASS_ALIGN8 used to inform AngelScript that a type may need to be aligned on 8byte boundaries (Thanks Fredrik Ehnbom) +
    • The template callback behaviour now take a second argument to allow the application to tell the engine if an instance shouldn't be garbage collected +
    • Added asOBJ_SCRIPT_FUNCTION flag to identify the object type that represents script functions +
    • Added asIScriptFunction::IsCompatibleWithTypeId() and GetTypeId() to work with function pointers as generic types +
    • Added an optional argument to asIScriptModule::SaveByteCode to strip the debug info +
    • Added an optional argument to asIScriptModule::LoadByteCode to determine if the bytecode contains debug info or not +
    +
  • Script language +
      +
    • Added keyword 'mixin' +
    • mixin classes can now be declared with default implementations to be included into a class +
    +
  • Add-ons +
      +
    • The script array is no longer garbage collected if the type cannot form circular references (Thanks Philip Bennefall) +
    • Implemented the C++ copy constructor for the CScriptArray +
    • Added GetType() to CScriptHandle +
    • CScriptHandle::Cast() properly handles function pointers +
    • Fixed bug in CScriptArray::SetValue() when replacing a handle in an element (Thanks Andrew Ackermann) +
    • Added wrapper for std::string::operator== to fix compile error on gcc 4.7 (Thanks Piotr Rak) +
    • Fixed bug in CSerializer related to extra objects (Thanks FDsagizi) +
    +
+ +

Version 2.24.1 - 2012/08/07

+ +
    +
  • Bug fixes +
      +
    • Parser now recognizes declarations where the type is declared in a different namespace (Thanks alraz) +
    • Parser can now parse templates where the subtype is in a different namespace (Thanks sylexer) +
    • Stack pointer wasn't restored correctly when reusing context, which lead to memory invasions (Thanks virious) +
    • Fixed problem with loading bytecode that contained arrays of function pointers (Thanks TheAtom) +
    • GetFunctionByDecl() failed to find functions with parameters when they were declared in a namespace (Thanks alraz) +
    • The scope operator can now be used in the inheritance list when a class is deriving from a class in another namespace (Thanks alraz) +
    • IsVarInScope() and GetAddressOfVar() now works properly even before Execute() (Thanks Friggle) +
    • The garbage collector could enter an infinite recursive loop if invoked while calling a class destructor (Thanks Philip Bennefall) +
    • Aborting a nested script call could cause a crash in the VM (Thanks Philip Bennefall) +
    • AS_64BIT_PTR is now defined in angelscript.h instead of in as_config.h (Thanks quarnster) +
    • Saving bytecode with functions that take enums by value could fail on 64bit platforms (Thanks m4ttbush) +
    • asIScriptContext::GetLineNumber() will now return the line where the function call was made from (Thanks quarnster) +
    • Registering object properties when both object and property type is in a namespace is now working properly (Thanks Starfox) +
    • Fixed memory invasion when script allocated script class that had other script classes as members (Thanks Andrew Ackermann) +
    • Registering global properties with a type from another namespace failed (Thanks _Engine_) +
    • Fixed 64bit bug when saving bytecode (Thanks quarnster) +
    +
  • Library +
      +
    • Removed functionality where interfaces would be automatically shared if the declaration was identical. This was already deprecated in version 2.23.0 +
    • Improved internal handling of namespaces +
    • Reduced the size of saved bytecode by not storing the namespace of class methods +
    • Bytecode optimizer exchanges some more sequences with shorter ones for better performance +
    • When the engine receives a request to abort a script in a nested call it will now forward the request to the outer call, after aborting the inner call (Thanks Philip Bennefall) +
    • Reduced recursiveness in compiler to allow it to compile extremely long expressions without stack overflow (Thanks Philip Bennefall) +
    • Added JitEntry instructions in the factory stub functions and generated default constructor +
    +
  • Script language +
      +
    • Function pointers can now be invoked from arbitrary expressions without first assigning them to a variable (Thanks TheAtom) +
    +
  • Virtual machine +
      +
    • Each call to Execute() will now tell the GC to process at least one step unless automatic garbage collection is turned off +
    +
  • Add-ons +
      +
    • Corrected the implementation of Complex::operator/() to calculate the proper result (Thanks CMRM) +
    • Fixed compilation error in scriptbuilder.cpp on XCode 4.3 with CLang++ 3.1 (Thanks Ricky C) +
    • The script array will forward requests to abort a script to the outer call when performing comparisons, which uses nested calls (Thanks Philip Bennefall) +
    • Fixed linker error in scriptstdstring.cpp on XCode 4.3 with CLang++ 3.1 (Thanks Ricky C) +
    • Fixed crash in script array when the array was created with a very large initial size (Thanks Philip Bennefall) +
    +
+ +

Version 2.24.0 - 2012/06/24

+ +
    +
  • Bug fixes +
      +
    • Fixed a potential crash if context is prepared but never executed (Thanks Andrew Ackermann) +
    • Fixed crash with release of the thread manager if the last engine was released as part of destructor in global variable (Thanks Friggle) +
    • Accessing entitites in global scope from a function in a namespace didn't work (Thanks _Vicious_) +
    • Fixed assert failure on compiling unary plus operator on non-primitive (Thanks FDsagizi) +
    • Fixed error in compiler with index operator on a value returned by a property index accessor (Thanks Andrew Ackermann) +
    • Fixed error in compiler when compiling function call with @& parameter and asEP_ALLOW_UNSAFE_REFERENCES (Thanks FDsagizi) +
    • Fixed problem in parsing enum declarations where unexpected tokens might get ignored (Thanks virious) +
    • Fixed crash on 64bit Mac OS X when calling native function that receives and returns large objects by value (Thanks Markus Mönig) +
    • Namespaces are now properly considered for registered types as well (Thanks Ricky C and adam4813) +
    • Improved compatibility with native calling convention on Android with gnuc (Thanks Lasse Öörni) +
    • SaveByteCode() was crashing when the script contained assignment of POD types without explicit opAssign method (Thanks Andrew Price) +
    • Fixed crash with releasing a suspended context when a function was returning a value type by value (Thanks Andrew Price) +
    • The engine allowed to register multiple ref cast behaviours to the same type, which would cause assert failure in compiler (Thanks Andrew Ackermann) +
    • Improved compatibility with native calling conventions on iOS (Thanks Lasse Öörni) +
    • Templates with const subtypes are now properly handled (Thanks Andrew Ackermann) +
    • Fixed SegV with gnuc when using a virtual method for the message callback (Thanks Tzarls) +
    • Fixed problem with calling registered functions with more than 8 parameters on XBox 360 (Thanks virious) +
    • Fixed problem with returning float/double on XBox 360 when the library is compiled with optimizations (Thanks virious) +
    • Fixed bug with virtual property access with index and variable type argument (Thanks virious) +
    • IsHandleCompatibleWithObject() was ignoring inheritance for script objects (Thanks saejox) +
    • Fixed bug in compiler when compiling a cast on temporary ASHANDLE object (Thanks saejox) +
    +
  • Library interface +
      +
    • Added the global functions asPrepareMultithread() and asUnprepareMultithread() +
    • The engine and object type can now hold multiple different user data +
    • Added the global functions asAcquireExclusiveLock(), asReleaseExclusiveLock(), asAcquireSharedLock() and asReleaseSharedLock() +
    • Deprecated engine::GetGlobalFunctionIdByIndex() +
    • Deprecated module::GetFunctionIdBy...() and module::RemoveFunction(funcId) +
    • Changed asIScriptContext::GetAddressOfVar() to dereference parameter references to make it easier to use (Thanks virious) +
    • Changed BindImportedFunction to take a asIScriptFunction pointer +
    • Deprecated context::Prepare(int id) +
    • Deprecated generic::GetFunctionId() and GetFunctionUserData() +
    • Deprecated objecttype::GetFactoryId...() and GetMethodId...() +
    • Changed objecttype::GetBehaviourByIndex() to return asIScriptFunction* +
    • Added the method engine::CreateUninitializedScriptObject() that will create an object without calling the constructor +
    • Added module::GetObjectTypeByName() +
    • Renamed engine::CopyScriptObject() to AssignScriptObject() to avoid common confusion with the intent of the method +
    • Added PushState(), PopState(), and IsNested() to the context that can be used to reuse an active context in a system call +
    +
  • Library +
      +
    • Improved stability in out-of-memory conditions to allow graceful exits (Thanks Zylann) +
    • Improved error handling when loading incorrect bytecode (Thanks Andrew Price) +
    • Improved thread safety in XBox 360 native code +
    +
  • Add-ons & Samples +
      +
    • SetValue is now a public method in the CScriptArray (Thanks saejox) +
    • The array add-on takes advantage of the multiple user data types to share its cache between arrays of the same type +
    • The array uses the new global functions to create the shared cache in a thread safe manner +
    • CScriptBuilder::GetMetadataStringForFunc() and GetMetadataStringForTypeMethod() now takes a asIScriptFunction* +
    • The string pool is now threadsafe and supports multiple engines +
    • CSerializer now works when script class constructors modify global variables too (Thanks FDsagizi) +
    • Added method AddExtraObjectToStore on CSerializer to allow serializing objects not referenced by global variables in module (Thanks FDsagizi) +
    • Improved C++ interface for the CScriptHandle class to make it easier to use from application +
    • The CScriptHandle is now capable of casting to inherited script classes or implemented interfaces (Thanks saejox) +
    • The script array is using the nested context functionality to avoid instanciating temporary contexts +
    • PrintException() is properly reporting nested calls when printing the callstack +
    +
+ +

Version 2.23.1 - 2012/04/28

+ +
    +
  • Bug fixes +
      +
    • Fixed assert failure when loading bytecode containing calls to functions returning value types by value in an if-case (Thanks Markus Larsson) +
    • Fixed crash when compiling constructor and base class doesn't have default constructor (Thanks Ekimr) +
    • Fixed bug in asCScriptFunction (Thanks Richard Viney) +
    • Compiler no longer accepts non-handles with the identity operator 'is' (Thanks SadSingleton) +
    • Shared global functions didn't fail to compile unless the return type was 'void' (Thanks TheAtom) +
    • Fixed problem with global get property accessor that returns a POD value type (Thanks Andrew Ackermann) +
    • Fixed problem with global get property accessor with index that returns an object type (Thanks Andrew Ackermann) +
    • Fixed crash when loading bytecode that contained shared classes in specific scenarios (Thanks TheAtom) +
    • Fixed crash with native calling convention on 32bit Mac OS 10.7 with XCode 4.3 (Thanks Matt Bush) +
    • Fixed crash with compiling private virtual property accessors (Thanks SadSingleton) +
    • Fixed assert failure when compiling identity operator on non-handle operands (Thanks FDsagizi) +
    +
  • Script language +
      +
    • Added proper support for const overloads in property accessors (Thanks Andrew Ackermann) +
    +
  • Library +
      +
    • Changed config to enable multithread support on Mac OS X 64bit (Thanks Radu Braniste) +
    • Bytecode optimizer replaces PshNull, RefCpyV, PopPtr with FREE +
    • Bytecode optimizer removes CHKREF instructions before and after the ADDSi instruction +
    • Bytecode optimizer removes CHKREF instructions before RDSPtr instruction +
    • Bytecode optimizer replaces ChkRefS, RDSPtr with RDSPtr, CHKREF +
    • Removed unnecessary ADDREF to object pointer in some class methods +
    • For loop has been rearranged to avoid one JMP instruction +
    • Context writes messages to callback if application does something wrong with Prepare or Execute. +
    • Improved thread safety of the thread manager when multiple threads create separate engines (Thanks Carsten Orthbandt) +
    +
  • Virtual machine +
      +
    • Changed ADDSi to check if the pointer is a null pointer +
    • Changed RDSPtr to check if the pointer is a null pointer +
    • Renamed the bytecode POP to PopPtr, and removed it's argument as it was always popping a single pointer. +
    • Created the new instruction RefCpyV that is used to replace the oft occurring pair PSF and REFCPY +
    • Added JLowZ and JLowNZ to replace ClrHi + JZ and ClrHi + JNZ +
    • Added PshGPtr that replaces PGA + RDSPtr +
    • Removed the PUSH instruction +
    • The VM is guaranteed to call line callback at least once per function to allow interruption of inifinitely recursive calls (Thanks Philip Bennefall) +
    • LoadThisR and LoadRObjR raises exception if the loaded object pointer is null +
    +
  • Add-ons & Samples +
      +
    • Added GetSize() and IsEmpty() to the dictionary add-on (Thanks _Vicious_) +
    • Added IsEmpty() to the array and string add-on (Thanks _Vicious_) +
    • Added Reserve() to the array add-on (Thanks Philip Bennefall) +
    • The string pool is now turned off by default, since it is not threadsafe. Turn it on with AS_USE_STRINGPOOL=1 +
    • Array, string, and dictionary now register their methods using the names from STL if AS_USE_STLNAMES=1 is defined (Thanks Thomas Grip) +
    • Corrected the syntax in autowrapper add-on to allow it to compile for Android (Thanks brumi) +
    +
+ +

Version 2.23.0 - 2012/03/11

+ +
    +
  • Bug fixes +
      +
    • Returning floats and doubles with native calling conventions wasn't working on Mac OSX Lion x64 with LLVM and -O0 (Thanks Jason Filsinger) +
    • The string factory can now be registered to return a reference to the string object (Thanks Philip Bennefall) +
    • The condition operator didn't accept when the two results differed in type with the only difference being const (Thanks Philip Bennefall) +
    • The information on local variables is now saved with the bytecode +
    • Fixed crash on Mac OS X 32bit with GCC 4.2 when compiling the library with optimizations (Thanks Matt Bush) +
    +
  • Library +
      +
    • By defining AS_NO_COMPILER the library can now be compiled without the script compiler for reducing the executable size (Thanks Philip Bennefall) +
    • The compiler will no longer share interface type ids unless the interfaces are explicitly marked as shared. Previous behaviour is still temporarily available with AS_DEPRECATED +
    • Improved some compiler messages +
    • Added configuration to allow the compilation for the Marmalade SDK (Thanks Kite and robt) +
    • Removed several compiler warnings for different compilers and target platforms (Thanks Richard Viney) +
    • Added asOBJ_NOCOUNT to support ref types that are not reference counted (Thanks virious) +
    • The saved bytecode is now independent of the platform's pointer size +
    +
  • Library interface +
      +
    • Added asIScriptContext::GetSystemFunction() that returns the registered function that is currently being called (Thanks rviney) +
    • Added asIScriptEngine::SetDefaultNamespace() permitting the application to register the interface in different namespaces +
    • Removed previously deprecated functions +
    • Added asIScriptEngine::GetGlobalPropertyIndexByName() and ByDecl() +
    • asIScriptContext::GetExceptionFunction() now returns a asIScriptFunction* instead of the function id +
    • Changed NotifyGarbageCollectorOfNewObject() to take asIObjectType* instead of type id +
    • Added asIScriptEngine::GetObjectTypeByName() +
    • Added accessMask argument in GetGlobalPropertyByIndex(), GetEnumByIndex(), GetTypedefByIndex(), and GetProperty() +
    • Removed configGroup argument in GetFuncDefByIndex() as this is already available in the asIScriptFunction interface +
    • Added GetAccessMask() to asIObjectType and asIScriptFunction +
    • Added asIScriptModule::RemoveFunction() that takes a pointer to asIScriptFunction +
    • Added asIScriptModule::GetObjectTypeByName() +
    • Added IsFinal(), IsOverride(), IsShared(), and GetNamespace() to asIScriptFunction +
    • Added includeNamespace argument to asIScriptFunction::GetDeclaration(), asIScriptModule::GetGlobalVarDeclaration(), and asIScriptEngine::GetTypeDeclaration() +
    • Added GetNamespace() to asIObjectType +
    • Added namespace argument to GetGlobalPropertyByIndex(), GetEnumByIndex(), GetTypedefByIndex(), and GetGlobalVar() +
    +
  • Script language +
      +
    • Enums can now be declared as shared across modules too +
    +
  • Add-ons & Samples +
      +
    • Placed the CDebugger in the AngelScript namespace (Thanks Thomas Fischer) +
    • Fixed compilation problem in CScriptBuilder on XBox360 with regards to missing getcwd (Thanks virious) +
    • Updated CSerializer to support namespaces +
    • Updated WriteConfigToFile() to write the access mask and namespace +
    • Updated asbuild sample to support access mask and namespace +
    • Removed the C lib as standard add-on +
    • Implemented memory pool for string literals in the string add-on which will improve performance for scripts that uses a lot of string literals +
    • New implementation for the auto wrapper that eliminates the need to declare the wrappers before they can be registered (Thanks SiCrane) +
    • Added opEquals to the script array +
    • Added getKeys to the script dictionary (Thanks Philip Bennefall) +
    • Fixed script arrays with enums (Thanks Philip Bennefall) +
    • Fixed the script arrays so it can accepts opEquals and opCmp that take the other value by handle (Thanks Philip Bennefall) +
    • Sort, Find, and opEquals now works for arrays of handles too (Thanks Philip Bennefall) +
    +
  • Project +
      +
    • Renamed as_callfunc_arm_xcode.s to as_callfunc_arm_xcode.S to fix problem with scons on Mac (Thanks Richard Viney) +
    +
+ +

Version 2.22.2 - 2012/01/29

+ +
    +
  • Bug fixes +
      +
    • Arrays of interfaces weren't properly handled when resolving equal interfaces in different modules (Thanks cvet) +
    • Shared code couldn't call template factories (Thanks TheAtom) +
    • Classes that contained shared classes as members would fail in the second module that declared the shared class (Thanks TheAtom) +
    • RegisterGlobalProperty was accepting null pointers (Thanks Quillraven) +
    • In some situations the value assign of a class member to an object would recieve the wrong reference (Thanks Philip Bennefall) +
    • Fixed segfault when compiling with -O2 on x86 32bit gnuc 4.6.1 (Thanks gdmarkou) +
    • Fixed problem with shared classes when the were orphaned (Thanks Thomas Grip) +
    • GetGlobalFunctionByDecl would return the wrong function (Thanks _Vicious_) +
    • Context failed when calling a system function through a function pointer (Thanks _Vicious_) +
    • Fixed problem when releasing engine while still holding a reference to a script function (Thanks _Vicious_) +
    +
  • Virtual machine +
      +
    • Created the instruction SwapPtr and removed the SWAP4, SWAP8, SWAP48, and SWAP84 instructions that were no longer used +
    • Created the instruction RDSPtr and removed the RDS4 and RDS8 instructions that won't be used anymore +
    • Created the instructions PshVPtr, PshNull that will be used for pointers instead of PshV4/8 and PshC4/8 +
    • Created the instruction ClrVPtr that will be used for pointers instead of SetV4/8 +
    • Created the instruction CmpPtr that will be used for pointers instead of CMPi or CMPi64 +
    +
  • Library +
      +
    • Separated the bytecode loader and saver in two different classes +
    • Some code can be left out to create a smaller library if only pre-compiled bytecode is going to be used +
    • Replaced internal use of strtod() with my own implementation to improve portability +
    +
  • Script language +
      +
    • Global functions can now be marked as 'shared' too +
    • Added keyword 'namespace' +
    • It is now possible to declare entities in namespaces to avoid name conflicts +
    • The scope operator :: is used to explicitly specify in which namespace to look for symbols +
    +
  • Add-ons & Samples +
      +
    • Made the script array more robust against out-of-memory conditions (Thanks Philip Bennefall) +
    • CScriptBuilder now properly extracts metadata for class methods and virtual properties (Thanks Ciaran Davies) +
    +
+ +

Version 2.22.1 - 2011/12/28

+ +
    +
  • Bug fixes +
      +
    • Fixed bug where passing inout ref to handle to a function didn't work properly with unsafe references turned on (Thanks TheAtom) +
    • Fixed bug with returning reference from temporary value type on stack (Thanks AgentC) +
    • Fixed assert failure on compilation error involving get_opIndex (Thanks Philip Bennefall) +
    • Fixed bug where a temporary variable was improperly reused under certain situations (Thanks Philip Bennefall) +
    • Fixed bug in native calling conventions for 64bit gnuc that was causing crashes on Mac OS X (Thanks dutt) +
    • Fixed bug with GetTypeIdByDecl when the declaration was a handle (Thanks scypior) +
    • Fixed problem where the compiler wasn't detecting that a class property didn't have a default constructor (Thanks pifor106) +
    +
  • Library +
      +
    • Added asOBJ_NOINHERIT that can be used to identify the script classes declared as final (Thanks InvalidPointer) +
    • Improved compiler performance when scripts have a lot of literal string constants (Thanks vroad) +
    • Optimized the algorithm for tokenizing the script, which will provide a significant performance improvement when compiling large scripts (Thanks m4ttbush) +
    • Added asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT to allow application to force the automatic implementation of default constructor and opAssign +
    • The compiler now avoids creating unnecessary temporary copies of objects when calling opAssign or copy constructor for the same type +
    • Engine writes more verbose errors for application interface configuration errors +
    • Added support for passing objects by value on 64bit GNUC when used with asOBJ_APP_CLASS_ALLINTS or asOBJ_APP_CLASS_ALLFLOATS +
    +
  • Script language +
      +
    • Added 'final' and 'override' keywords for improved control on how inheritance is implemented (Thanks InvalidPointer) +
    • Implemented an alternative shorter version for declaring get and set property accessors (Thanks InvalidPointer) +
    • Default constructor and opAssign is no longer implemented automatically if the script class has a non-default constructor +
    • The compiler no longer warns if 0 is passed to an output parameter, as it then assumes the result is meant to be ignored +
    • The compiler performs implicit conversions to objects registered as ASHANDLE by calling the available constructor +
    +
  • Add-ons & Samples +
      +
    • Added GetMetadataStringForTypeMethod to CScriptBuilder (Thanks InvalidPointer) +
    • Added property accessors for length on the CScriptArray (Thanks InvalidPointer) +
    • Added scriptmathcomplex.cpp that implements a value type for mathematics with complex numbers +
    • Improved performance of script compilations with CScriptBuilder (Thanks m4ttbush) +
    • Fixed compilation error in CScriptBuilder when turning off metadata (Thanks Philip Bennefall) +
    • Removed scriptmath3d.cpp as a standard add-on +
    • Fixed some compiler warnings in CScriptFile add-on +
    • Implemented formatInt(), formatFloat(), parseInt(), and parseFloat() as string utilities +
    • Added property accessors for length on the string registration +
    • Removed the use of CGameObjLink in the game sample and registered the CGameObj directly with the script engine +
    • The game sample is now using the CScriptHandle to pass the message data between game objects +
    • Fixed a problem where the CScriptBuilder didn't find the metadata for class properties of non-primitive types (Thanks Carrot) +
    +
+ +

Version 2.22.0 - 2011/11/06

+ +
    +
  • Bug fixes +
      +
    • Fixed bug where compiler would incorrectly reuse a temporary variable when preparing arguments for a function call (Thanks Philip Bennefall) +
    • Fixed bug in CSerializer add-on that wasn't properly handling the fact that typeIds change for each compilation +
    • Fixed bug with indexed property accessor where only set accessor was available (Thanks virious) +
    • Fixed bug where default args for registered functions were not recognized (Thanks Takashi Yamamoto) +
    • Fixed problems when compiling the library with optimizations on 64bit GNUC (Thanks Jameson) +
    • Fixed assert failure in VM when using JIT compiled functions (Thanks Andrew Ackermann) +
    • Fixed a null pointer exception in the compiler when compiling an assignment and the left hand expression was invalid (Thanks TheAtom) +
    • Fixed bug with value cast operator that returned an object by value (Thanks pifor106) +
    • Fixed crash when compiling scripts that import global property accessors from other modules (Thanks Andrew Ackermann) +
    +
  • Library interface +
      +
    • Added user data to the asIObjectType and asIScriptModule interfaces, and corresponding cleanup callbacks to the asIScriptEngine interface +
    • Changed some return types from int to asUINT where the methods couldn't return a negative value +
    • Added a Prepare method to the context that takes the asIScriptFunction pointer instead of the function id +
    • Added GetGlobalFunctionByIndex and Decl to asIScriptEngine +
    • Deprecated GetFunctionDescriptorById in asIScriptEngine and asIScriptModule and replaced it with asIScriptEngine::GetFunctionById +
    • Added GetFunctionByName and Decl to asIScriptModule +
    • Deprecated asIScriptModule::GetFunctionDescriptorByIndex and replaced it with GetFunctionByIndex +
    • Deprecated asIScriptGeneric::GetFunctionDescriptor and replaced it with GetFunction +
    • Added GetFactoryByIndex and Decl to asIObjectType +
    • Added GetMethodByName and Decl to asIObjectType +
    • Deprecated asIObjectType::GetMethodDescriptorByIndex and replaced it with GetMethodByIndex +
    • Added asIScriptEngine::SetDefaultAccessMask and asIScriptModule::SetAccessMask, which deprecates SetConfigGroupModuleAccess +
    • The asJITFunction now takes a asPWORD as the second argument incase the compiler wants to store a pointer as the argument (Thanks Andrew Ackermann) +
    • Added Implements, DerivesFrom, and GetSubType to the asIObjectType interface +
    • Added overloads for AddRefScriptObject and ReleaseScriptObject that take a pointer to asIObjectType which makes them more efficient than the previous version +
    • Created the macro asOFFSET that does the same thing as offsetof, except that GNUC doesn't complain about using it +
    +
  • Library +
      +
    • The module's access to types, functions, properties, and even class members can now be set individually for each object through an access mask and is no longer tied to the configuration group +
    • Improved library against registered types that can form circular references but don't register the GC behaviours (Thanks Quittouff) +
    • Added engine property asEP_DISALLOW_GLOBAL_VARS +
    • Classes can now be shared between modules if they are compiled with the 'shared' keyword +
    • Added object type flag asOBJ_SHARED that identifies script classes that are shared between modules +
    +
  • Virtual Machine +
      +
    • Added the context pointer to the asSVMRegisters so the JIT function can immediately access this without calling asGetActiveContext (Thanks Andrew Ackermann) +
    • The JitEntry instruction will now invoke the JIT function without decreasing 1 from the argument set by the JIT compiler +
    • The JitEntry instruction can also immediately return from the execution in case the context has been suspended, aborted, or an exception has been set +
    +
  • Script language +
      +
    • Added the keyword 'shared' that can be used with classes and interfaces that should be shared between modules +
    +
  • Add-ons & Samples +
      +
    • Improved the game sample to take advantage of the object type user data +
    • Improved the game sample to take advantage of the shared classes in the messaging between script objects +
    • Improved the game sample to report the compilation errors, instead of just continuing the execution without +
    • The #include directives in the CScriptBuilder add-on now accept strings within single-quotes too +
    • Added GetModule to the CScriptBuilder add-on +
    +
+ +

Version 2.21.2 - 2011/09/25

+ +
    +
  • Bug fixes +
      +
    • Fixed a bug when passing value from property accessor to function inout reference parameter (Thanks scypior) +
    • Fixed a bug with function overloading and default args (Thanks cvet) +
    • Minor change to fix compiler error with CLang (Thanks Jeremy Harmon) +
    • The library was not detecting return of simple value type on Linux 64bit. It should give error as this is not supported due to the use of different registers based on type of class members. (Thanks toukkapoukka) +
    +
  • Library +
      +
    • Value types returned by value are now returned on the stack to reduce dynamic memory allocations +
    • Added the flag asOBJ_APP_CLASS_ALLINTS to inform that a registered type should be treated like all members are integers +
    • Added the flag asOBJ_APP_CLASS_ALLFLOATS to inform that a registered type should be treated like all members are float or doubles +
    +
  • Add-ons & samples +
      +
    • The CScriptBuilder now supports metadata for class properties too (Thanks Thomas "Hardguy" Grip) +
    • Created a sample game that shows one way of integrating the script engine for game management +
    +
+ +

Version 2.21.1 - 2011/08/21

+ +
    +
  • Bug fixes +
      +
    • Fixed crash when doing a value assignment to a handle obtained from a property accessor (Thanks _orm_) +
    • Compiler will now give error when assigning to property of an object that is returned by value from a function +
    • Fixed bug in the std::string add-on in the boolean operators that concatenates a bool type to the string (Thanks Altren) +
    • Fixed bug when pass null to output parameter and the compiler didn't properly clean up the stack +
    • Fixed bug with ternary condition operator when the first option was null (Thanks TheAtom) +
    • Fixed bug with instanciating templates with subtypes of the same name as the internal template subtype (Thanks TheAtom) +
    • Fixed bug in debugger add-on when printing the value of an uint8 (Thanks Friggle) +
    • Fixed bug with handle assignment with set_opIndex (Thanks Lasse Öörni) +
    +
  • Library +
      +
    • Added the asOBJ_ASHANDLE type flag. This will be used together with asOBJ_VALUE to allow application to register a container type that can store any handle type +
    • Implemented support for asBEHAVE_REF_CAST with the signature 'void f(?&out)' which allow a cast to any handle type, evaluated at runtime +
    • asIScriptContext::Unprepare no longer free's the stack memory, so there is no performance penalty for that +
    • Added support for native calling conventions on Win64 with MinGW64 (Thanks _Vicious_) +
    +
  • Script language +
      +
    • The compiler will no longer warn if passing null to a function argument that is declared as an output handle +
    +
  • Add-ons +
      +
    • Added the CScriptHandle add-on which provides a default implementation of the new asOBJ_ASHANDLE type +
    • Updated the clib add-on to the latest interface (Thanks lexa-skripa) +
    • Added the CSerializer add-on which allow the application to backup values of variables in a module and then restore them (Thanks FDsagizi) +
    +
+ +

Version 2.21.0 - 2011/07/03

+ +
    +
  • Bug fixes +
      +
    • Fixed more compiler warnings for maximum warning level on MSVC (Thanks Thomas Fischer) +
    • Fixed crash if script tries to call function that has been declared incorrectly with default args (Thanks Károly Pintér) +
    • Fixed crash on MSVC when basic behaviour methods was implemented with multiple inheritance (Thanks Thomas Grip) +
    • Fixed bug when application compiles modules with imported functions over and over again, eventually crashing (Thanks loboWu) +
    • Fixed implicit conversion of negative float constant to uint making the value become 0 (Thanks Jeremy Harmon) +
    • Fixed bug with passing value types on stack to a function taking a var arg (Thanks immortius) +
    • Fixed native calling convention for objects with copy constructor on 64bit Windows with MSVC +
    • Fixed assembler code in as_Callfunc_x64_msvc_asm to allow stack unwinding in debugger (Thanks Zoner) +
    • It's now possible to use property accessor of another object of the same type from within a member property accessor (Thanks _orm_) +
    • Fixed crash if context is unprepared or released after SetObject but without calling Execute (Thanks immortius) +
    +
  • Virtual machine +
      +
    • The garbage collection is now automatically done by the VM during the execution, unless turned off by the application +
    • Improved the GC so now keeps 2 generations of objects. This will allow faster clean up of objects that live short times, thus improving performance +
    +
  • Library interface +
      +
    • Removed all previous deprecated code +
    • It is now possible to debug the initialization of global variables by passing a context to the ResetGlobalVars method +
    • Added asIScriptContext::IsVarInScope that the application can use to determine that the variable is actually visible at current program position +
    • Added engine property asEP_AUTO_GARBAGE_COLLECT that can be used to turn off the automatic garbage collection +
    • Added more parameters to the GetGCStatistics methods to get info on the new generation of objects +
    • Added asIScriptFunction::FindNextLineWithCode that a debugger can use to find a valid line with code to set breakpoints at +
    +
  • Library +
      +
    • Added configurations for native calling conventions on the Illumos operating system (Thanks Alexey A. Fakeyev) +
    • Improved error message in compiler when typing the wrong name for the data type in a variable declaration (Thanks Jeremy Harmon) +
    +
  • Script language +
      +
    • It is no longer prohibited to call functions in the expressions that initialize global variables. +
    • Implementation of interface methods can now be inherited from base class (Thanks Hardguy) +
    +
  • Project +
      +
    • Renamed as_callfunc_x64_msvc.asm to as_callfunc_x64_msvc_asm.asm to avoid conflict with as_callfunc_x64_msvc.cpp (Thanks Zoner) +
    +
  • Add-ons and samples +
      +
    • Added substr, findFirst, findLast, split, and join to the std::string registration +
    • Created the asrun sample +
    • Created the CDebugger add-on +
    • Removed CScriptString as standard add-on as it caused too many confusions +
    +
+ + +

Version 2.20.3 - 2011/05/14

+ +
    +
  • Bug fixes +
      +
    • Fixed compile warning on 64bit Mac (Thanks kainjow) +
    • Fixed native calling conventions on 64bit Mac for older GNUC compiler (Thanks Asgeir) +
    • Fixed bug in array add-on when declaring an array of void (Thanks Damian T0MALIK) +
    • Made the use of emms or fninit dynamic by defining macro CLEAR_FPU_STACK, as some projects needed it to be fninit (Thanks cvet) +
    • Fixed bug in compiler when a property that takes a reference in set accessor was used in a dual operator expression (Thanks Philip Bennefall) +
    • Properly handling loading bytecode that attempts to instanciate invalid template type +
    • Fixed a long standing bug with native class methods on iPhone (Thanks Pogacha) +
    • Fixed bug with asEP_ALLOW_UNSAFE_REFERENCES where it would allow casting a primitive type to another for reference parameters (Thanks cvet) +
    • Fixed crash with invalid script (Thanks arpeggiodragon) +
    • Fixed bug with private methods where the compiler was incorrectly invoking the base class constructor (Thanks Quittouff) +
    • Fixed bug with identifying shared interfaces in modules (Thanks TheAtom) +
    • Fixed some bugs related to enums (Thanks behc) +
    • Fixed compile error when attempting to assign to a member of a handle returned from another function (Thanks AgentC) +
    • Fixed null pointer access when compiling scripts that used write-only property accessors (Thanks Lasse Öörni) +
    • Fixed problem with native calling conventions on PS3 and XBox 360 (Thanks kdroben) +
    +
  • Library +
      +
    • Added the flag asOBJ_APP_CLASS_COPY_CONSTRUCTOR so classes with non-trivial copy constructor can be recognized and treated properly in the native calling conventions (Thanks namtabmai) +
    • Improved the bytecode optimization +
    +
  • Script language +
      +
    • Added support for default arguments in functions +
    +
  • Virtual machine +
      +
    • Added bytecode instructions LoadRObjR, LoadVObjR +
    +
  • Add-ons +
      +
    • Added the methods sortAsc, sortDesc, reverse, and find to the script array add-on (Thanks Damian T0MALIK) +
    • Removed duplicated functions in string utils as they can now use default arguments instead +
    +
+ + +

Version 2.20.2 - 2011/02/17

+ +
    +
  • Bug fixes +
      +
    • Fixed bug with division and modulo operations where the most significant bit of the value was set (Thanks loboWu) +
    • Fixed bug when calling copy constructor for value types allocated on the stack (Thanks speps) +
    • Using emms instead of fninit to preserve FPU configuration on x86 (Thanks Lasse Öörni) +
    • Set property accessor that takes the value by ref was incorrectly accepted for increment/decrement operators (Thanks Philip Bennefall) +
    • When copying an object to remove constness the compiler wasn't handling objects allocated on the stack correctly (Thanks Philip Bennefall) +
    • Value cast of an object retrieved from a get accessor wasn't working properly (Thanks speps) +
    • Value types allocated on the stack didn't work correctly with the condition operator (Thanks speps) +
    • Fixed a bug in the std::string add-on add operator implementations where the input string was incorrectly modified (Thanks speps) +
    • Fixed bug with compiling explicit ref cast of temporary handle that produced invalid bytecode (Thanks mandrav) +
    • Fixed bug with bool, int8, and int16 types in native functions on xbox 360 (Thanks speps) +
    • Added validation to prevent registering function pointers without @ (Thanks behc) +
    • Fixed bugs when invoking a function pointer directly as class member (Thanks behc) +
    • Fixed bug in parser that didn't report error for not closing brackets when using index operator in expressions (Thanks speps) +
    • Fixed bug in compiler with unsafe references and value types (Thanks hemicube) +
    • Fixed inline assembly in as_callfunc_x64_gcc to support gcc optimizations (Thanks Samuel E. Henley) +
    +
  • Virtual machine +
      +
    • Added bytecode instructions DIVu, MODu, DIVu64, MODu64 +
    • Unified a good part of the platform specific code into one common function +
    +
  • Library +
      +
    • Added configurations for Cygwin and Linux/ARM (Thanks Adrian Batzill) +
    +
  • Script language +
      +
    • It is now possible to declare function definitions that take other types as argument before the declaration of the other types +
    +
  • Add-ons +
      +
    • Added the copy constructor to the std::string registration +
    • Added swizzle operators xyz, yzx, zxy, zyx, yxz, and xzy to the vector3 add-on +
    +
+ +

Version 2.20.1 - 2010/12/10

+ +
    +
  • Bug fixes +
      +
    • All the methods on asIScriptContext to inspect the call stack had an inverted index (Thanks Philip Bennefall) +
    • Fixed a problem during clean up of configuration groups in the engine destructor (Thanks Friggle) +
    • Fixed bug in calling convention for 32bit PPC when a value type is passed by value +
    +
  • Virtual machine +
      +
    • Local variables using registered value types are now allocated on the stack +
    +
  • Library interface +
      +
    • RegisterObjectType now returns the type id of the newly registered type to indicate success. +
    +
  • Add-ons & samples +
      +
    • Added methods to CScriptFile add-on for reading and writing integers and floats, with configurable byte ordering +
    • The CContextMgr now invokes the garbage collector automatically +
    +
+ +

Version 2.20.0 - 2010/11/02

+ +
    +
  • Bug fixes +
      +
    • Fixed bug in parser when a function or method returned a handle to a template type (Thanks yzslhawk) +
    • Fixed the initialization order of some global variables that might get used by the engine if it is created in a global (Thanks heqing) +
    • If global variables in scripts were accessed during destruction of the script objects the application could crash when releasing the engine (Thanks TheAtom) +
    • Fixed bug on Android/GNUC involving the function type enum (Thanks Fredrik Ehnbom) +
    +
  • Library +
      +
    • Removed the built-in array type, the array type must be registered by the application instead +
    • Added support for native calling conventions on PS3 with SNC compiler (Thanks Kidneythief) +
    • Improved compiler error message when trying to declare variable in switch case +
    +
  • Library interface +
      +
    • Deprecated asBEHAVE_INDEX. Use opIndex method instead +
    • Improved const correctness of interface methods +
    • Added asIScriptFunction::IsPrivate and asIScriptObject::IsPropertyPrivate +
    • Removed asIScriptArray interface +
    • Added RegisterDefaultArrayType and GetDefaultArrayTypeId to asIScriptEngine +
    • Added asEP_EXPAND_DEF_ARRAY_TO_TMPL that tells the engine to format the declaration of the default array in the template form +
    • Removed the previously deprecated ExecuteString from script engine interface +
    • Added user data to the script function interface, and methods to retrieve it from the generic interface (Thanks Pierre Fortin) +
    • Added methods to asIScriptFunction to enumerate local variables (Thanks Ciaran "Carrot" Davies) +
    • Deprecated IsClassMethod and IsInterfaceMethod, use the new GetFuncType instead +
    • Added a parameter to the GetMethod methods to allow retrieving the real method instead of the virtual method +
    • Added the script section name to the functions that previously returned only line and column number +
    • Added GetGlobalVar to asIScriptModule +
    • Deprecated GetGlobalVarName and GetGlobalVarTypeId in asIScriptModule +
    • Added GetProperty and GetPropertyDeclaration to asIObjectType +
    • Deprecated GetPropertyName, GetPropertyTypeId, IsPropertyPrivate, and GetPropertyOffset in asIObjectType +
    • Added ability to set callback functions for cleaning up the user data when the objects are destroyed +
    • Deprecated GetCurrentFunction and GetCurrentLineNumber from asIScriptContext +
    • Removed GetCallStackFunction and GetCallStackLineNumber from asIScriptContext +
    • Added GetFunction and GetLineNumber to asIScriptContext +
    • Changed index parameter for the methods GetVarXXX, GetAddressOfVar, GetThisXXX in asIScriptContext so the current function is on 0 +
    +
  • Script language +
      +
    • Added support for the opPostInc, opPostDec, opPreInc, and opPreDec operator overloads (Thanks droz) +
    • Added support for get_opIndex and set_opIndex to allow property accessors for the index operator +
    • Property accessors can now accept an index argument to emulate an array +
    +
  • Project +
      +
    • Removed as_arrayobject.h and as_arrayobject.cpp +
    +
  • Add-ons & samples +
      +
    • The script array add-on can now be registered as the default array type +
    • Improved asbuild to support registration of template types and default array +
    • Improved WriteConfigToFile the same way +
    • Implemented InsertAt, RemoveAt, InsertLast, and RemoveLast for the array add-on +
    • Fixed compiler warnings in autowrappedcall.h when working with functions that take parameters by reference (Thanks Pierre Fortin) +
    • Further improvements to autowrappedcall to support asCALL_CDECL_OBJLAST and OBJFIRST (Thanks Pierre Fortin) +
    • Added PrintException as helper function +
    +
+ +

Version 2.19.2 - 2010/09/05

+ +
    +
  • Bug fixes +
      +
    • Compiler no longer crashes on empty heredoc strings (Thanks Thy Reaper) +
    • Fixed problem in compiler when switch condition had deferred parameters (Thanks Philip Bennefall) +
    • It is no longer possible to register a global function with const modifier (Thanks cvet) +
    • Fixed bug in built-in array object that prevented the GC from breaking circular references (Thanks cvet) +
    • Fixed bug in restoring bytecode that didn't properly detect when arrays needed to be garbage collected (Thanks cvet) +
    • Restoring bytecode to multiple modules with shared interfaces no longer crashes the application (Thanks TheAtom) +
    • Fixed bug with comparison of primitive returned by reference from property accessor (Thanks mk1x86) +
    • Fixed implicit conversion from enum to double (Thanks Philip Bennefall) +
    +
  • Library +
      +
    • Added explaining messages to callback when failing to initialize a global variable after a compilation +
    • Improved validation during loading bytecode to avoid crashes on invalid files +
    • Improved the way class methods with virtual inheritance on MSVC 32bit is registered, so that this is now properly detected and gives an error (Thanks vroad) +
    • Added configurations for native calling conventions on FreeBSD x64 and Haiku (Thanks droz) +
    +
  • Script language +
      +
    • It is now also permitted to return a reference to the 'this' pointer +
    • A get accessor can now return a handle, while the set accessor takes a value or reference. This allow the property to behave as a value property, even though a new object is created each time it's value is taken. +
    • Class methods can now be declared as private +
    • Float numbers can now be written as .42, without the leading 0 +
    • Enum types prioritizes implicit conversions to int before other primitive types when matching multiple function overloads +
    +
  • Virtual machine +
      +
    • Added PshV8 for improved bytecode optimizations on 64bit platforms +
    +
  • Add-ons & Samples +
      +
    • Made the addref/release methods on the add-ons const, so they can be used on const pointers as well +
    • Added operators to the string add-ons to allow conversion of bool to string +
    • Changed the index behaviour for the string add-ons to opIndex methods +
    • Implemented a generic offline script compiler, that shows how a dummy application interface is registered to allow compiling scripts to file +
    • Added WriteConfigToFile helper function that automatically creates the config file for the generic offline compiler +
    +
+ +

Version 2.19.1 - 2010/08/09

+ +
    +
  • Bug fixes +
      +
    • Fixed null pointer exception on specific compiler error (Thanks _orm_) +
    • Fixed precompiled byte code with enum types and arrays (Thanks hoboaki) +
    • The CAST instruction wasn't properly saved and loaded (Thanks hoboaki) +
    • Fixed bug with implicit conversion from 'const obj' to 'obj' (Thanks hoboaki) +
    • Fixed crash on compiler error where a variable is declared twice (Thanks Philip Bennefall) +
    • It is no longer possible to declare a class method with the name of the class (Thanks xadhoom) +
    • Fixed bug with implicit conversion from reference to primitive (Thanks Thy Reaper) +
    • asIScriptModule::GetFunctionIdByIndex is now returning the correct id (Thanks mandrav) +
    • Compiling the library with AS_DOUBLEBYTE_CHARSET is now working again (Thanks UeSyu) +
    • Removed unnecessary creation temporary copy when doing an assignment using the default copy behaviour (Thanks mandrav) +
    • Fixed assert failure on clean-up with registered function definitions (Thanks Engin Lee) +
    • Fixed problem with temporary variable being overwritten when evaluating the output parameters (Thanks IndependentHat) +
    • Fixed error in compiler where the expression in the switch case wasn't converted correctly if it wasn't a local variable (Thanks mandrav) +
    +
  • Library +
      +
    • The saved bytecode is now independent of object property offsets +
    • The script section names are now stored with the saved bytecode +
    • Added compatibility with Mac OS X on x64 CPUs (Thanks Zerotri) +
    +
  • Script language +
      +
    • Added support for returning references from script functions +
    • Added support for the opIndex operator overload method +
    • It is now allowed to declare functions with 'void' parameter lists +
    • Added reserved keyword 'private' +
    • Class properties can now be declared as private (Thanks InvalidPointer) +
    +
  • Virtual machine +
      +
    • Added the instruction LoadThisR that is used to load the address of a property into the register. +
    +
  • Add-ons +
      +
    • Implemented the opAssign method for the dictionary add-on so it can be copied. +
    +
+ +

Version 2.19.0 - 2010/06/27

+ +
    +
  • Bug fixes +
      +
    • The compiler was incorrectly treating enums as having 8 bytes on 64bit platforms (Thanks Nalin) +
    • Fixed crash when compiling scripts that contains inheritance of invalid classes (Thanks Tyler Spivey) +
    • Fixed bug when compiling a return statement that calls a get accessor (Thanks Tyler Spivey) +
    • Fixed calling property accessor surrounded by parenthesis (Thanks cvet) +
    • Compiler no longer hangs on compiling enum declarations with name conflicts (Thanks hoboaki) +
    • Property accessors will no longer call themselves if attempting to access true property of the same name (Thanks Philip Bennefall) +
    • Fixed bug with property accessors in switch expression (Thanks Philip Bennefall) +
    • Fixed bug with incremental garbage collector (Thanks hoboaki) +
    • Saving byte code that used template classes didn't work properly (Thanks hoboaki) +
    • Fixed bug with property accessors in type conversions (Thanks Philip Bennefall) +
    • Fixed assert failure on compílation error with undeclared variable (Thanks Philip Bennefall) +
    • Fixed bug with implicit ref casts for global variables (Thanks Gilad Novik) +
    • Fixes to the Xbox 360 calling convention codes (Thanks Cyril Tissier) +
    • Fixed bug in the bytecode optimization on big endian CPUs (Thanks Remi Gillig) +
    • Fixed buffer overflow in as_callfunc_x64_gcc.cpp (Thanks Mikhail Efremov) +
    • Fixed a bug with use of templates in script classes (Thanks xadhoom) +
    • Fixed problem with loading script that contained template types that refer to classes defined later in script (Thanks hoboaki) +
    • Fixed memory leak when cyclic reference between script class types and templates existed (Thanks hoboaki) +
    • Fixed assert failure when compiling script with void expression in while condition (Thanks Philip Bennefall) +
    • Fixed bug in compiler where in a very specific case it would lose the value of a reference (Thanks Lars Peter) +
    +
  • Library +
      +
    • Improved the size of the saved bytecode +
    • The saved bytecode is now byteorder independent +
    • Added the ability to disable property accessors through the engine property asEP_PROPERTY_ACCESSOR_MODE (Thanks Philip Bennefall) +
    • Improved support for Borland C++Builder (Thanks Moritz Beutel) +
    +
  • Library interface +
      +
    • Added RegisterFuncdef that allows the application to register function definitions for function pointers it wishes to receive +
    • Added GetFuncdefCount and GetFuncdefByIndex to enumerate the registered function definitions +
    +
  • Script language +
      +
    • Added a factory for the built-in array to allow setting the default value of elements upon initialization. This in turn allows the initialization of multidimensional arrays in one call. +
    +
  • Add-ons +
      +
    • Added a factory for the template array to allow setting the default value of elements upon initialization +
    +
+ + +

Version 2.18.2 - 2010/03/14

+ +
    +
  • Bug fixes +
      +
    • Fixed a bug in the compiler where in certain condition it would incorrectly reuse a temporary variable (Thanks Thy Reaper) +
    • Fixed a bug for property accessors in while and do-while conditions (Thanks Philip Bennefall) +
    • Fixed a bug for property accessors for objects in arrays (Thanks Philip Bennefall) +
    • Fixed a bug in the compiler where an invalid script could crash it (Thanks klusark) +
    • Variable declaration of script class with opAssign and assignment initialization wasn't releasing a temporary variable (Thanks hoboaki) +
    • When growing the stack the virtual machine wasn't copying the object pointer for class methods, leading to crashes (Thanks klusark) +
    • Implicit conversion from handle to reference is no longer giving compiler error (Thanks Thy Reaper) +
    • Fixed property accessors when used from within a class method (Thanks hoboaki) +
    • Fixed a bug with native calling conventions on 64bit Linux (Thanks namtabmai) +
    • Fixed bug with posix threads on 64bit platforms (Thanks Hideaki Imaizumi) +
    +
  • Script language +
      +
    • The language now supports function pointers to global functions. +
    • Added the keyword 'funcdef' that is used to declare function signatures for function pointers. +
    +
  • Virtual machine +
      +
    • Added the instruction CallPtr that is used to call a function stored in a function pointer. +
    • Added the instruction FuncPtr that is used to push the pointer of a function on the stack. +
    +
+ +

Version 2.18.1 - 2010/01/17

+ +
    +
  • Bug fixes +
      +
    • Fixed compiler error on GNUC (Thanks Samuel E. Henley) +
    • Missing text literal on 64bit Linux (Thanks Gibbon_99) +
    • Aborting a context only suspended the execution (Thanks Friggle) +
    • Characters above 127 were incorrectly converted to UTF8 when the scanner was set to ASCII (Thanks Friggle) +
    • When saving the bytecode the string constants got shuffled around (Thanks kk) +
    • Reference casts for null values incorrectly raised null pointer exceptions (Thanks Thy Reaper) +
    +
  • Virtual machine +
      +
    • Changed the bytecode instructions PGA, LDG, LdGRdR4, CpyVToG4, CpyGToV4, SetG4, and PshG4 to hold the address of the global variable in the argument directly +
    • Removed the globalVarPointers from the asSVMRegisters structure +
    • Changed the bytecode FREE to take the variable index directly in the argument instead of reading the reference from the stack +
    +
  • Library interface +
      +
    • Added the behaviour asBEHAVE_LIST_FACTORY, that is exclusively used to initialize a reference type with an initialization list. +
    +
  • Library +
      +
    • The compiler now attempts to use the copy constructor when creating temporary copies of objects (Thanks Wracky) +
    • Added support for native calling conventions on Win64 with MSVC +
    • Added several bytecode optimizations that should reduce the number of instructions and increase runtime performance +
    +
  • Script language +
      +
    • Property accessors may now be used for global variables as well +
    +
  • Add-ons +
      +
    • Improved the script array add-on to support initialization of the arrays through initialization lists +
    +
  • Project +
      +
    • Added as_callfunc_x64_msvc.asm and as_callfunc_x64_msvc.cpp to add support for native calling conventions on 64bit Windows +
    +
+ +

Version 2.18.0 - 2009/12/16

+ +
    +
  • Bug fixes +
      +
    • Fixed assert in compiler when accessing property through temporary object (Thanks Scarabus2) +
    • Fixed crash with too large array sizes, both for built-in array and array add-on (Thanks loboWu) +
    • Fixed memory leak when an exception occurred in ExecuteString, and another ExecuteString was called afterwards +
    • Fixed improper re-use of temporary variable by property get accessor when compiling binary operators (Thanks Scarabus2) +
    • Fixed a bug in array template add-on with max portability mode (Thanks quarnster) +
    +
  • Library interface +
      +
    • Added asIScriptModule::CompileFunction() for dynamically compiling a single function that can be executed, and optionally added to the module +
    • Added asIScriptFunction::GetId() +
    • Added asIScriptModule::RemoveFunction() for dynamically removing a single function from the scope +
    • Deprecated the asIScriptEngine::ExecuteString method. An add-on has been provided to replace it +
    • Removed the error code asMODULE_IS_IN_USE as it is no longer used +
    • Removed old deprecated methods +
    • Added asIScriptModule::CompileGlobalVar() and RemoveGlobalVar() for dynamically adding and removing single global variables to and from the module +
    +
  • Library +
      +
    • Added support for UTF-16 encoded string literals through dynamic engine property asEP_STRING_ENCODING (Thanks Jubok Kim) +
    • Each global variable has it's own intialization function now, which will allow individual globals to be added or removed dynamically +
    • Each script function now holds its own list of accessed global variables, so they do not have to go back to the module for that info +
    • Added support for native calling conventions on iPhone (Thanks Fredrik Ehnbom) +
    • String constants are now stored in the engine and shared between modules +
    • The context no longer references the module, as script functions no longer depend on the module for anything +
    • Changed the script functions to use reference counting +
    • Improved compiler messages when function arguments doesn't match available functions (Thanks droz) +
    +
  • Add-ons +
      +
    • Added the global helper function ExecuteString, which replaces the asIScriptEngine::ExecuteString method +
    +
  • Project +
      +
    • Renamed the as_callfunc_armasm.asm to as_callfunc_arm_msvc.asm +
    • Renamed the as_callfunc_armasm.S to as_callfunc_arm_gcc.S +
    • Added as_callfunc_arm_xcode.s which is the Apple XCode assembler code for arm CPUs (Thanks Gilad Novik) +
    • Added as_globalproperty.cpp +
    +
+ +

Version 2.17.2 - 2009/10/18

+ +
    +
  • Bug fixes +
      +
    • Fixed assert failure after compiler error in construct call (Thanks loboWu) +
    • Fixed bug in compiler that freed objects returned by value too early (Thanks xivVerge) +
    • Class methods are now allowed to be registered to types registered in previous config groups (Thanks Wavesonics) +
    • Template factory stubs weren't removing arguments from the stack (Thanks loboWu) +
    +
  • Script language +
      +
    • Ref classes without default factory can now be instanciated by explicitly calling one of the non-default factories (Thanks Wracky) +
    +
  • Library +
      +
    • Added the object behaviour asBEHAVE_TEMPLATE_CALLBACK, which is used to perform compile time validation of template instances +
    +
  • Add-ons +
      +
    • Fixed bug in CScriptBuilder to avoid endless loops in default include handler (Thanks leave) +
    +
+ +

Version 2.17.1 - 2009/09/16

+ +
    +
  • Bug fixes +
      +
    • Loading pre-compiled bytecode for scripts that used registered functions that included the built-in array type in the signature crashed (Thanks loboWu) +
    • Fixed the parsing of templates to accept handles as subtypes (Thanks dxj19831029) +
    • Fixed bug with &inout and constants for invalid scripts (Thanks scypior) +
    • Fixed crash when loading pre-compiled bytecode that had classes with enums as members (Thanks huangyous) +
    • Fixed memory access violation in CContextMgr add-on (Thanks Kim PoongHo) +
    +
  • Library +
      +
    • Improved the registerable template types to also support a template type as subtype. +
    • Loading pre-compiled bytecode is now agnostic of the order that global properties were registered. +
    +
  • Script language +
      +
    • Added support for class property get and set accessors. +
    +
  • Project +
      +
    • Added compile time option to GNUC makefile to build a shared library (Thanks Dan Horák) +
    • Added as_callfunc_armasm.S, which is an adaption of the MSVC assembler code in as_callfunc_armasm.asm to GNUC assembler (Thanks darktemplar216) +
    • Added configurations in as_config.h to detect the Android OS and enable support for native calling conventions on ARM for it (Thanks sliao) +
    +
  • Add-ons +
      +
    • Improved the script builder to allow custom processing of include directives via a callback +
    • Improved memory management in CContextMgr to reduce run-time allocations by pooling objects +
    +
+ +

Version 2.17.0 - 2009/08/09

+ +
    +
  • Bug fixes +
      +
    • Fixed compiler error in the XBox 360 specific code. (Thanks Marc Hanson) +
    • Scoped reference types can now be members of script classes. (Thanks Jeff Slutter) +
    • Fixed crash in compiler on invalid script (Thanks cvet) +
    • Reference types that had been registered with zero size wasn't allowed as members of script classes. (Thanks Friggle) +
    • Added validation for duplicate switch cases in script compiler (Thanks loboWu) +
    +
  • Library +
      +
    • Removed all old deprecated functionality +
    • The built-in array type is now completely unaware of the library internals and uses only the public interface +
    • Unified parts of the code for native calling conventions to improve maintainability +
    • Informing the application type when registering a value type is now only required if the type is returned by value or passed by value to a function with native calling convention +
    • Added engine property asEP_INCLUDE_JIT_INSTRUCTIONS to indicate if the JIT bytecode instructions should be included or not. Defaults to off. +
    • The variant parameter, ?, now receive a reference to the actual object if the argument is not a handle (Thanks IndependentHat) +
    +
  • Library interface +
      +
    • Added GetTypeId, GetSubTypeId, AddRef, and Release to asIObjectType +
    • Created the interface for an external JIT compiler plug-in (Thanks Fredrik Ehnbom) +
    • Deprecated RegisterGlobalBehaviour, GetGlobalBehaviourCount, and GetGlobalBehaviourByIndex. These behaviours should use the new class methods instead. +
    • Deprecated CompareScriptObjects. Use the helper functions CompareRelation or CompareEquality from the add-ons instead. +
    • Deprecated all assignment behaviours and the negate behaviour. These behaviours should use the new class methods instead. +
    • Changed asBEHAVE_REF_CAST and asBEHAVE_IMPLICIT_REF_CAST to be registered as object behaviours. Verify the documentation for implementation changes. +
    • Added AddRef, Release, IsReadOnly, and GetByteCode methods to asIScriptFunction. +
    • Deprecated asIScriptObject's GetPropertyPointer, which has been replaced with GetAddressOfProperty. +
    • Deprecated asIScriptContext's GetArgPointer, which has been replaced with GetAddressOfArg. +
    +
  • Virtual machine +
      +
    • Added bytecode instruction JitEntry that transfers control to the JIT compiled function +
    • Renamed SET8 to PshC8 +
    +
  • Add-ons +
      +
    • Added the atan2 function to the math add-on +
    • Added the helper functions CompareRelation and CompareEquality as add-ons +
    • Added a template script array object +
    • Implemented the CContextMgr add-on that supports co-routines and concurrent script threads +
    +
  • Project +
      +
    • Removed as_bytecodedef.h as its content has been moved to angelscript.h +
    • Renamed as_scriptstruct files to as_scriptobject +
    +
+ +

Version 2.16.3 - 2009/07/05

+ +
    +
  • Bug fixes +
      +
    • Fixed bug in compiler when passing a constant to argument expecting out ref. +
    +
  • Library +
      +
    • Added support for native calling conventions for ARM processors with MSVC compiler (Thanks Fredrik Ehnbom) +
    +
  • Script language +
      +
    • Script classes can now implement operator overloads for all dual operators with specific class methods +
    • Script classes can also implement overloads for the unary negate and bit complement operators +
    • An if condition followed by an empty statement will now give a compiler error (Thanks asterix12) +
    +
+ + +

Version 2.16.2 - 2009/06/07

+ +
    +
  • Bug fixes +
      +
    • Fixed crash after call to DiscardModule where GC held objects declared by the module (Thanks Jeff Slutter) +
    • Fixed crash on compiling invalid script (Thanks cvet) +
    • Fixed bug with virtual function table and multiple levels of inheritance (Thanks huangyous) +
    • Fixed some compatibility issues with MSVC and 64bit targets +
    • Fixed bug with implicit cast of const ref type to non-const ref type (Thanks cvet) +
    • The asFUNCTIONPR and asMETHODPR no longer accepts pointers to functions that are not exactly like the specified one (Thanks Wavesonics) +
    • Fixed crash on compiling global variable of registered type with missing copy behaviour (Thanks 39ster) +
    • Fixed value of asTYPEID_SCRIPTOBJECT to be just 1 bit (Thanks SiCrane) +
    • Fixed bug in string add-ons where the full string wouldn't be created by the factory if it contained null characters. +
    • Fixed rare bug when script called application function with float args and the application uses full optimization (this time on GNUC/x86) (Thanks kunitoki) +
    • Fixed alignment bug for script class properties (Thanks Fredrik Ehnbom) +
    +
  • Library +
      +
    • Build and ResetGlobalVars now return an error if the initialization of the global variables fails. +
    • Changed initialization of global variables so that variables of primitive types are initialized first. (Thanks Friggle) +
    • Added informational message to better explain the error 'missing behaviours' on invalid registration. +
    • It is now possible for the application to register template types, though the feature is still not considered complete. +
    • Added asEP_SCRIPT_SCANNER property for choosing between ASCII and UTF8 script encoding. Default is UTF8. +
    +
  • Script language +
      +
    • Added support for string escape sequences \uFFFF and \UFFFFFFFF for inserting unicode characters in string constants. +
    +
+ +

Version 2.16.1 - 2009/05/09

+ +
    +
  • Bug fixes +
      +
    • Fixed bug with implicit conversion from temporary 'const obj @' to 'obj &' (Thanks Jeff Slutter) +
    • Fixed problem with float values and locale (Thanks scypior) +
    • Fixed incorrect conversion of null handle to primitive (Thanks cvet) +
    • Fixed crash when assigning array to itself (Thanks cvet) +
    • Fixed assert failure after invalid conditional expression (Thanks Jeff Slutter) +
    • Fixed bug in compiler when attempting to return null handle for a function declared to return object by value (Thanks marvi) +
    • Compiler is now giving a proper error when script function returns reference (Thanks marvi) +
    • Fixed crash when a script constructor that receives object handle throws an exception (Thanks cvet) +
    • Fixed implicit value cast to another object type (Thanks SiCrane) +
    • Fixed multithread support on FreeBSD (Thanks droz) +
    • Character literals for characters above ASCII 127 are now compiled correctly (Thanks cvet) +
    • Fixed rare bug when script called application function with float args and the application uses full optimization (Thanks Jeff Slutter and DaBono) +
    +
  • Library +
      +
    • The built-in array type is now implemented using a template type. +
    • The tokenizer now recognizes the UTF8 byte-order-mark as whitespace permitting the compilation of UTF8 encoded scripts. +
    • Added support for multibyte character sets through the preprocessor flag AS_DOUBLEBYTE_CHARSET, it's recommended to use UTF8 instead though. (Thanks loverlin) +
    • Added asEP_REQUIRE_ENUM_SCOPE to force the use of enum scope when accessing enum values. (Thanks Jeff Slutter) +
    • The value cast behaviour can now be used to instanciate an object type if the type doesn't have the appropriate constructor. (Thanks SiCrane) +
    • The callstack is no longer cleaned up immediately on an exception, thus allowing the examination of it even after Execute returns. +
    +
  • Script language +
      +
    • Enum values can now be prefixed with the enum type to give the exact enum value when multiple enums declare the same name. (Thanks Jeff Slutter) +
    +
  • Add-ons +
      +
    • CScriptBuilder is now better at handling relative include paths (Stuart Golodetz) +
    +
+ +

Version 2.16.0 - 2009/03/30

+ +
    +
  • Bug fixes +
      +
    • Fixed bug in compiler where temporary variable was freed twice during compound assignments with some complex lvalue expressions (Thanks _Vicious_) +
    • Fixed crash when parsing invalid typedefs. +
    • Typedefs declared in scripts now accept float and double as well. +
    • Fixed crash when compiling handle comparison with invalid types (Thanks _Vicious_) +
    • It's now possible to determine type id for handle to scoped reference types (Thanks Jeff Slutter) +
    • Unary operators weren't supported for enum types (Thanks jal_) +
    • Fixed crash when declaring a script class that inherits from a class declared below it (Thanks Zeu5) +
    • Fixed bug when registering an interface after previously removing dynamic config group (Thanks Zeu5) +
    • Fixed bug in CScriptBuilder add-on that broke global declarations with array types (Thanks except134) +
    • Fixed problem with class inheritance and order of declaration (Thanks Zeu5) +
    • Fixed assert failure after compile error (Thanks Cliff Cawley) +
    +
  • Library +
      +
    • All primitive types now have fixed type ids, so it is no longer necessary to call the GetTypeIdByDecl method to obtain their ids. +
    • Removed the AS_NO_USER_ALLOC config option. +
    • Enumeration of functions in the modules now only return global functions. +
    • Enumeration of object types in modules now only return classes and interfaces. +
    • Added engine property asEP_BUILD_WITHOUT_LINE_CUES (replaces the config option). +
    • Added engine property asEP_INIT_GLOBAL_VARS_AFTER_BUILD, which will allow compiling scripts without having the implementation of the application functions. +
    • Enumeration of object types in the engine now only return registered object types. +
    +
  • Library interface +
      +
    • Removed some functions that had been deprecated in version 2.14.0. +
    • Renamed asIScriptStruct to asIScriptObject. +
    • Renamed GetStructTypeId to GetTypeId in asIScriptObject. +
    • Added enumeration of factory functions and behaviours to asIObjectType. +
    • Added GetBaseType, GetFlags, GetSize, and GetPropertyOffset to asIObjectType. +
    • Deprecated GetSubType and IsInterface in asIObjectType. +
    • Added enumeration of enums and typedefs to asIScriptModule. +
    • Added enumeration of registered functions, properties, enums, and typedefs to asIScriptEngine. +
    • Added parameter to asIScriptFunction::GetDeclaration to include or not the object name in the returned string. +
    • Removed all output length parameters for functions that returned strings, all strings are null terminated anyway. +
    • Deprecated GetReturnPointer in asIScriptGeneric, replaced by GetAddressOfReturnLocation. +
    +
  • Add-ons +
      +
    • Added registration of std::string as a standard add-on, complementing the CScriptString +
    • Added resize method to the string add-ons +
    • Changed CScriptFile to be compatible with both std::string and CScriptString +
    • Modified CScriptBuilder to permit enabling/disabling metadata processing through preprocessor define +
    • Added autowrapper add-on that automatically generates wrappers for the generic calling convention for functions and class methods (Thanks George Yohng) +
    • Added registration of the double counter parts to the math functions +
    +
+ +

Version 2.15.2 - 2009/02/22

+ +
    +
  • Bug fixes +
      +
    • The pre-compiled bytecode didn't store the script class destructors, nor the implemented interfaces +
    • Script class factories didn't work for constructors with more than 1 argument (Thanks BornToCode and scypior) +
    • Changed as_atomic.cpp to use critical sections for older versions of GCC on Linux (Thanks _Vicious_) +
    • Fixed some 64bit compatibility issues (Thanks Ionut "gargltk" Leonte and _Vicious_) +
    • Fixed dangling pointer problem after removing dynamic configuration group (Thanks Ionut "gargltk" Leonte) +
    +
  • Script language +
      +
    • Added support for single inheritance for script classes +
    • Added support for scope resolution operator +
    +
  • Library +
      +
    • Added support for native calling conventions on 64bit Linux (Thanks Ionut "gargltk" Leonte) +
    +
  • Add-ons +
      +
    • Implemented readLine, isEndOfFile, writeString, getPos, setPos, and movePos for the CScriptFile +
    • Removed use of bool in the C library header (Thanks Gibbon_99) +
    • Added support for #if/#endif preprocessor directives to the CScriptBuilder +
    +
+ +

Version 2.15.1 - 2009/01/25

+ +
    +
  • Bug fixes +
      +
    • Fixed a bug with bitwise operators and 8/16 bit integer types (Thanks jkhax0r) +
    • Fixed the error message when no matching constructor is found for a construct call +
    • Fixed bug when compiling expressions that called index operator that returned an object by value on a temporary variable (Thanks dxj19831029) +
    • Saved pre-compiled bytecode didn't store the read-only flag for class methods +
    • Fixed bug where class method calls that returned a reference to a member of the class would release the class before the reference was used +
    • Fixed bug that allowed object handles for value types (Thanks Wavesonics) +
    • Modified as_atomic.h to avoid use of kernel specific atomic.h on Linux (Thanks namtabmai) +
    • Fixed compile error in as_callfunc_x86.cpp on GNUC when using -O3 option (Thanks bigjo) +
    • Fixed the calling conventions for MinGW on Windows +
    +
  • Library +
      +
    • Internally reference types (including script classes) are now allocated by calling the factory function directly +
    • Updated as_config to properly identify operating system, thus improving multithreading performance +
    • Created script factory stub functions for instanciating template types, thus simplifying script compiler +
    • The memory for global variables declared in scripts is now allocated individually, which will allow more flexibility +
    +
  • Add-ons +
      +
    • Added the generic interface to the CScriptFile object +
    +
+ +

Version 2.15.0 - 2008/12/13

+ +
    +
  • Bug fixes +
      +
    • Fixed assignments where the rvalue is a temporary object instanciated with a construct call (Thanks SiCrane) +
    • The parser no longer accepts other digits than 0 to initiate a hex literal value (Thanks SiCrane) +
    • Fixed compiler error in as_callfunc_ppc_64.cpp (Thanks James Chan) +
    • Fixed saving bytecode with enums (Thanks loboWu) +
    • Fixed the index operator call on temporary object that caused an invalid reference (Thanks dxj19831029) +
    • Fixed bug in the tokenizer and the !in token versus identifier (Thanks xivVerge) +
    • Script functions can now be declared to return const types (Thanks SiCrane) +
    • Fixed multithread problem in memory manager for the script node pool (Thanks xivVerge) +
    • Fixed assert failure after compilation error with ref cast operator (Thanks Jeff Slutter) +
    • Fixed compiler warnings for g++ 4.3.2 (Thanks Matt Williams) +
    +
  • Library interface +
      +
    • Changed the parameters for the engine's GarbageCollect method to give more control to the application +
    • Replaced GetObjectsInGarbageCollectorCount in the engine interface with GetGCStatistics +
    • Added GetEngine to asIScriptStruct and asIScriptArray +
    • Replaced GetVarPointer and GetReturnPointer in the context interface with GetAddressOfVar and GetAddressOfReturnValue respectively +
    • Replaced GetArgPointer in the generic interface with GetAddressOfArg +
    • Added SetUserData/GetUserData to the engine interface +
    • Added the ParseToken method to the engine interface, useful for IDEs that provide syntax highlighting or intellisense +
    • Removed deprecated GetMethodDescriptorByIndex, GetMethodCount, GetMethodIDByIndex, GetMethodIDByName, GetMethodIDByDecl from engine interface +
    • Removed deprecated GetFunctionDeclaration, GetFunctionModule, GetFunctionSection, GetFunctionName from engine interface +
    • Removed deprecated SetDefaultContextStackSize from engine interface +
    • Added asIScriptModule, which will be used to interact with the modules directly, instead of through the engine interface +
    • Added GetModule to the engine +
    • Deprecated the methods in the engine for interacting with the modules, as these methods are now available in the module interface +
    • Added GetGlobalVarTypeId to the module interface. There were no corresponding method for this in the engine interface +
    • Renamed Discard in the engine interface to DiscardModule +
    • Modified the GetTypeIdByDecl in the engine interface to take only the declaration and not the module name +
    +
  • Library +
      +
    • Configured the library to work with Nintendo Wii (Thanks James Chan) +
    +
  • Project +
      +
    • Added as_criticalsection.h +
    • Moved as_c.cpp out of the main project, and into the C lib add-on project +
    +
  • Add-ons +
      +
    • Added CScriptBuilder with support for include directive and metadata through a pre-processing pass +
    • Improved const correctness to CScriptAny and CScriptDictionary +
    • Removed the 'as' prefix from CScriptString and CScriptFile +
    +
+ +

Version 2.14.1 - 2008/11/02

+ +
    +
  • Bug fixes +
      +
    • Removed the need to inform @ when performing explicit ref cast with an implicit ref cast behaviour +
    • Added the namespace macros to the scriptnode module (Thanks SiCrane) +
    • Fixed an application crash in the asCThreadManager when the script engine was released by a global var upon application exit (Thanks BornToCode and SiCrane) +
    • Fixed application freeze on compiling scripts that declare a const return value for class methods (Thanks SiCrane) +
    • Fixed some assert failures after compilation errors (Thanks SiCrane) +
    +
  • Library +
      +
    • Added engine property asEP_ALLOW_IMPLICIT_HANDLE_TYPES to turn on the experimental feature. +
    • Added compiler warning when compiling handle comparison where either of the operands have not been explicitly set as handle. +
    • Updated as_config.h to support MSVC 2008 + x64 processor (native calling conventions is still not supported). (Thanks wildmild and SiCrane) +
    • Improved thread safety in the library. +
    • Added multithread support for MacOS X, x86 and ppc +
    +
  • Script language +
      +
    • Added experimental support for implicit handle types. These are declared with 'class@ name {}' (Thanks George Yohng) +
    • Class methods can now be declared as 'const' in the script class declaration. +
    • Implemented the 'is' operator for identity comparisons, i.e. comparing two object handles. +
    +
  • Project +
      +
    • Added as_gc.h and as_gc.cpp, which holds the garbage collector previously in the script engine module. +
    • Added as_atomic.h and as_atomic.cpp, which provides a threadsafe reference counter. +
    +
+ +

Version 2.14.0 - 2008/10/05

+ +
    +
  • Bug fixes +
      +
    • Fixed some issues with the scoped reference type (Thanks Jeff Slutter) +
    • Improved validation of type flags on RegisterObjectType with asOBJ_VALUE (Thanks dxj19831029) +
    • Fixed bug with for loop that was not using primitives in the loop increment statement (Thanks jal) +
    +
  • Library interface +
      +
    • The C interface now has a dedicated header file with it's own project in the add_on directory. +
    • Added WriteMessage to the engine interface, for writing to the message callback. +
    • Deprecated GetGlobalVarIDByIndex, GetGlobalVarIDByName, GetGlobalVarIDByDecl, and GetGlobalVarPointer. +
    • Added GetGlobalVarIndexByName, GetGlobalVarIndexByDecl, and GetAddressOfGlobalVar. +
    • The method GetAddressOfGlobalVar that replaces GetGlobalVarPointer now returns the address of objects directly, rather than a pointer to the address of the objects, for object variables. +
    • Added asBEHAVE_IMPLICIT_VALUE_CAST to differenciate between implicit and explicit value cast behaviours. +
    +
  • Library +
      +
    • Identical interfaces declared in different modules will now share type id. +
    • Added constraint against multiple threads trying to compile scripts at the same time. +
    • The script compiler no longer uses constructor/factory behaviours in implicit value casts. +
    • The engine's GetObjectTypeCount and GetObjectTypeByIndex now return application registered types as well. +
    • The context can be used to call registered functions/class methods directly. +
    +
  • Script language +
      +
    • The cast<type>(expr) operator can now only be used for reference casts. Value casts must use the construct cast, i.e. type(expr). +
    +
+ +

Version 2.13.1 - 2008/08/17

+ +
    +
  • Bug fixes +
      +
    • Fixed reference casts when the source handle is a script class member (Thanks Marcin "Pris" Musial) +
    • Fixed the declaration of the CRITICAL_SECTION on 64 bit Windows (Thanks Viktor Levitin) +
    • Fixed bug with temporary variables being reused too early (Thanks loboWu and Dentoid) +
    • Fixed bug with temporary variable not being released (Thanks dxj19831029) +
    • Fixed bug with enum lists not ended with comma (Thanks Shurwint) +
    • Fixed bug with compiler optimization of constant expressions (Thanks loboWu) +
    +
  • Script language +
      +
    • Single quoted strings can now be used instead of double quoted strings. +
    +
  • Library interface +
      +
    • Added asEP_USE_CHARACTER_LITERALS to allow applications to interpret single quoted strings as character literals. +
    • Added asEP_ALLOW_MULTILINE_STRINGS that will allow the compiler to accept string constants with line breaks. +
    • Added extra validation to register functions to minimize user errors. +
    • Added support for asBEHAVE_IMPLICIT_REF_CAST. +
    +
  • Library +
      +
    • Added support for posix threads on the platforms that support it (Thanks kunitoki) +
    • Support for multithreading is now turned on by default, it can be turned off by defining AS_NO_THREADS. +
    +
+ +

Version 2.13.0 - 2008/06/08

+ +
    +
  • Bug fixes +
      +
    • Fixed compile error on non-standards compliant compilers, e.g. MSVC6 (Thanks Shurwint) +
    • Updated as_config.h to remove compiler warning for stdcall on 64bit linux (Thanks Alraz) +
    • Moved enum declarations to top of header to fix compile error on GNUC (Thanks Samuel E. Henley) +
    • Global variables declared with enum types crashed the engine (Thanks mono2k) +
    • Fixed bug with shift operators and byte operands that should have been converted to dword (Thanks loboWu) +
    • Fixed compile error on GNUC/Linux. (Thanks droz) +
    • bool[] objects didn't use the correct element size on Mac OS X with PPC (Thanks Edward Rudd) +
    • Enum values are now correct on big endian CPUs as well. +
    • Illegal casts without arguments would crash the compiler (Thanks loboWu) +
    • Fixed a bug in compiler that could make the script engine release invalid objects (Thanks Milleniumas) +
    • Fixed a bug where global arrays of handles where initialized with handles of other global variables (Thanks sunwoolee) +
    +
  • Library interface +
      +
    • Added engine property asEP_MAX_STACK_SIZE +
    • Added methods for enumerating object type methods and properties to the asIObjectType interface +
    • Added methods for enumerating parameter types to the asIScriptFunction interface +
    • Added GetFunctionDescriptorById to the asIScriptEngine interface +
    • Added methods for getting function declaration and script section to asIScriptFunction +
    • Deprecated SetDefaultContextStackSize in asIScriptEngine +
    • Deprecated GetFunctionName, GetFunctionDeclaration, GetFunctionModule, GetFunctionSection in asIScriptEngine +
    • Deprecated GetMethodCount, GetMethodIDByIndex, GetMethodIDByName, GetMethodIDByDecl, GetMethodDescriptorByIndex in asIScriptEngine +
    • Deprecated global behaviours LOGICAL_OR and LOGICAL_AND as these operators are exclusive to boolean types +
    • Added global behaviour asBEHAVE_REF_CAST, that allow explicit casts between handles to application registered types +
    +
  • Library +
      +
    • Added initial support for native calling conventions on 64bit platforms (Thanks niteice) +
    • Updated as_config.h to add support for native calling conventions on FreeBSD (Thanks Jeremy "droz" Harmon) +
    +
  • Project +
      +
    • Added as_callfunc_x64_gcc.cpp +
    +
+ +

Version 2.12.0 - 2008/03/22

+ +
    +
  • Bug fixes +
      +
    • Fixed assert failure when compiling if statement with incorrect expression (Thanks Chet Simpson) +
    • Fixed assert failure when returning an input reference by reference from script function (Thanks Chet Simpson) +
    • Fixed potential heap corruption when internally copying system function information (Thanks Chet Simpson) +
    • Fixed asOBJ_VALUE | asOBJ_APP_FLOAT with RegisterObjectType (Thanks RsblsbShawn) +
    • Fixed access to global variables when the object method is from another module (Thanks Chet Simpson) +
    • A const object can now be passed to a function expecting a non-const object by making a copy (Thanks Jeff Slutter) +
    • Fixed a bug in tokenizer on 64 bit platforms (Thanks DaBono) +
    +
  • Script language +
      +
    • Added typedef. Currently it allows to define aliases of built-in primitive types (Thanks Chet Simpson) +
    • Added enum. (Thanks Chet Simpson) +
    +
  • Library interface +
      +
    • Added RegisterEnum and RegisterEnumValue to asIScriptEngine (Thanks Chet Simpson) +
    • Added RegisterTypedef to asIScriptEngine (Thanks Chet Simpson) +
    • Added GetObjectTypeId, GetArgCount, and GetReturnTypeId to asIScriptGeneric. +
    • Added the asIObjectType interface (Thanks Chet Simpson) +
    • AngelScript is now capable of differentiating between global functions, class methods, and functions using the generic calling convention. +
    • Added asWRONG_CALLING_CONV return code when the wrong calling convention is used. +
    • Changed constants to enums for better grouping. +
    • Added asIScriptFunction interface (Thanks Chet Simpson) +
    +
+ +

Version 2.11.2 - 2008/01/21

+ +
    +
  • Bug fixes +
      +
    • Compiler didn't warn when using post incremental/decremental operator on uninitialized variable (Thanks Noelia Rodriguez Matilla) +
    • Switch cases didn't work properly for uint8 and uint16 types (Thanks Noelia Rodriguez Matilla) +
    • Compound assignments in conjunction with arrays could give incorrect results (Thanks loboWu) +
    +
  • Library interface +
      +
    • Added behaviour asBEHAVE_VALUE_CAST that allow objects to be cast to other types, including primitives +
    +
  • Library +
      +
    • ExecuteString no longer locks dynamic configuration groups. (Thanks mono2k) +
    • Compiler gives better error message when it cannot match class methods for a call (Thanks Jeremy Harmon) +
    +
+ +

Version 2.11.1 - 2007/12/16

+ +
    +
  • Bug fixes +
      +
    • Expressions that tried to use indexing operator on primitive types caused assert failure (Thanks Anders Hansson) +
    • GetFunctionIDByDecl returned asINVALID_DECLARATION for functions that returned or passed reference types by value (Thanks loboWu) +
    • Corrected as_config.h in regards to vsnprintf for MSVC9 (Thanks Schrompf) +
    +
  • Library interface +
      +
    • Added the new object type flag asOBJ_SCOPED, that allows applications to + register reference types that behaves like value types but with special memory management needs +
    +
  • Library +
      +
    • Compiler emits less error messages that are concequences of previously detected errors +
    +
+ +

Version 2.11.0 - 2007/11/30

+ +
    +
  • Bug fixes +
      +
    • Copying script classes that held object handles crashed (Thanks Jeff Slutter) +
    • Script class methods with the same name as an object type was incorrectly causing compilation error +
    • Compiler didn't find objects methods when compiling a method call if the method had the same name as an object type (Thanks Jeff Slutter) +
    • The bytecode optimizer failed in a specific situation (Thanks Jeff Slutter) +
    • The multithread support in as_thread.cpp was broken (Thanks Martin Kaeser) +
    • Garbage collector could in certain cases removed type definitions that were still needed causing application crashes (Thanks Jeff Slutter) +
    • Script classes inheriting from other classes didn't give a compiler error (Thanks Pris) +
    • The script allow called to non const methods for handles to const objects (Thanks virtualcodewarrior) +
    • Fixed a few null pointer accesses when passing null handles to and from application (Thanks behc) +
    • asIScriptContext::GetState can now return asEXECUTION_ABORTED as well (Thanks Anders Hansson) +
    • Fixed uint64 to double conversion +
    +
  • Library interface +
      +
    • Added new flags asOBJ_REF, asOBJ_VALUE, asOBJ_GC, asOBJ_POD, and asOBJ_NOHANDLE that represents how the type is intended to work in AngelScript +
    • Changed prefix for previous asOBJ flags to asOBJ_APP. They should only be used with asOBJ_VALUE. +
    • AngelScript now validates the behaviours, to check for missing behaviours or behaviours that shouldn't be registered for the type +
    • Types registered as reference counted won't be allowed to be passed by value to system functions, nor returned by value +
    • Reference types must now use the new FACTORY behaviour instead of the CONSTRUCT behaviour. +
    • Removed the asBEHAVE_ALLOC and asBEHAVE_FREE behaviours. +
    • Added Unprepare to context interface. +
    +
  • Library +
      +
    • Added native calling conventions for XBox 360 (Thanks Laszlo Perneky) +
    +
+ +

Version 2.10.0 - 2007/09/23

+ +
    +
  • Bug fixes +
      +
    • Fixed a bug with matching functions with boolean arguments (Thanks Jeff Slutter) +
    • CopyScriptObject is now able to copy registered types that have no registered copy behaviour (Thanks Jeff Slutter) +
    • Script classes crashed on construction with AS_MAX_PORTABILITY (Thanks Carlos Campaña) +
    • Fixed a null pointer access on stack clean up (Thanks Thomas Cowell) +
    • Fixed an assert failure in the compiler (Thanks Jeff Slutter) +
    • When compiling assignment the compiler made incorrect implicit conversions to object type (Thanks Anders Hansson) +
    • Fixed access violation in RegisterGlobalProperty when the property had already been registered in another group (Thanks mono2k) +
    • The condition operator didn't handle void expressions in the results (Thanks Anders Hansson) +
    • Comparison with local boolean variable toggled the variable's value (Thanks Anders Hansson) +
    +
  • Script language +
      +
    • The any type is no longer a built-in type +
    • Bitwise operators will maintain the signed/unsigned type of the left operand (Thanks Trikko) +
    +
  • Library interface +
      +
    • Added GCEnumCallback and NotifyGarbageCollectorOfNewObject to engine +
    • Added behaviours GETREFCOUNT, SETGCFLAG, GETGCFLAG, ENUMREFS, RELEASEREFS +
    • The any type is no longer a built-in type, thus the asIScriptAny interface + and the asTYPEID_SCRIPTANY constant have been removed (CScriptAny add-on was created to replace them) +
    • Added CompareScriptObjects method to engine (Thanks Jeff Slutter) +
    +
  • Project +
      +
    • Removed as_gcobject.cpp and as_gcobject.h +
    • Removed as_anyobject.cpp and as_anyobject.h +
    +
+ +

Version 2.9.1 - 2007/08/19

+ +
    +
  • Bug fixes +
      +
    • The default constructor wasn't called for script class members of script class types (Thanks Jeff Slutter) +
    • ReleaseScriptObject failed for types that didn't have the release behaviour, nor the destructor (Thanks Jeff Slutter) +
    +
  • Script language +
      +
    • Implemented support for destructors in the script classes. (Thanks Jeff Slutter) +
    +
+ +

Version 2.9.0 - 2007/08/12

+ +
    +
  • Bug fixes +
      +
    • Parser could hang on scripts with non-terminated strings. (Thanks derefed) +
    • Compiler died when compiling a return statement with a void expression. (Thanks SiCrane) +
    • A bug when calling class methods with 1 or 2 byte arguments was fixed for PPC, both 32bit and 64bit. (Thanks Jeff Slutter) +
    • Fixed a bug with &inout references and script class member variables (Thanks Jeff Slutter) +
    +
  • Library interface +
      +
    • GetGlobalVarPointer returns the pointer to the pointer to the object for object variables. Likewise for object handles a pointer to the object handle is returned (Thanks Jeff Slutter) +
    • Added GetArgByte(), GetArgWord(), SetReturnByte(), SetReturnWord() to asIScriptGeneric for better support on big endian processors +
    • Added SetArgByte(), SetArgWord(), GetReturnByte(), GetReturnWord() to asIScriptContext for better support on big endian processors +
    • GetArgDWord(), SetReturnDWord(), SetArgDWord(), and GetReturnDWord() now validates that type is 4 bytes +
    • Added GetThisTypeId and GetThisPointer to asIScriptContext (Thanks Jeff Slutter) +
    • GetTypeIdByDecl is now able to understand const type declarations. (Thanks Jeff Slutter) +
    • Added GetArgTypeId and GetFunctionId to the generic interface +
    • Removed the makeCopy parameter from AddScriptSection, and instead added a new engine property asEP_COPY_SCRIPT_SECTIONS +
    • Added CreateScriptObjectCopy, CopyScriptObject, AddRefScriptObject, ReleaseScriptObject, and GetSizeOfPrimitiveType to engine for easier development of generic container classes +
    • All methods for registering functions, methods, or behaviours are now returning the function id as a success indicator. Negative values still indicate an error. +
    • Implemented support for variable parameter type, ?&, in object constructor, object methods, and global functions +
    +
+ +

Version 2.8.1 - 2007/07/09

+ +
    +
  • Bug fixes +
      +
    • Fixed the behaviour of the AS_USE_NAMESPACE macro (Thanks SkunkGuru) +
    • Fixed misleading message when compiling statement like 'Object &ref' (Thanks Steve Williams) +
    • Fixed bug in compiler where it didn't reuse temporary variables properly +
    • Fixed problem with C++ compiler optimizations that changed the result of AngelScript code and thus breaking (Thanks Jeff Slutter) +
    • Fixed the as_config.h file for GNUC/Apple +
    • Fixed conversion of negative floating point values to unsigned int on GNUC based compilers +
    • Fixed bug with booleans returned from functions that didn't evaluate to false when expected. (Thanks Rakkar2) +
    • Fixed bug where the compiler failed when passing constant references as function parameters. (Thanks Rakkar2) +
    • Engine no longer permits the registration of functions with void parameters (Thanks Juan Pablo Bettini) +
    • Fixed compiler assert when assigning a void value to a variable (Thanks Anders Hansson) +
    • Fixed bug in compiler where the property name wasn't validated correctly for name conflicts (Thanks Andy R) +
    • Fixed intermittent bug in the byte code optimization that affected only big endian processors. +
    • Fixed incorrect name conflict between script class methods and global functions (Thanks Anders Hansson) +
    • Fixed assertion failure when declaring variables as void (Thanks Anders Hansson) +
    • Fixed bug with GetGlobalVarID that didn't return the id with the moduleId (Thanks Julian Storer) +
    • Fixed bug with initialization lists for arrays of object handles. +
    • Fixed bug with loading bytecode that used registered array types. (Thanks Juan Pablo Bettini) +
    • Fixed bug with loading bytecode with script classes that were declared out of order. (Thanks Juan Pablo Bettini) +
    • Fixed bug where CHKREF was placed incorrectly to verify only the first parameter on the stack. (Thanks CyberGorgolith) +
    • Fixed bug with boolean operations that treated false values as true due to trash data in upper bytes of the boolean variable. +
    • The default constructor for script classes wasn't called for classes in arrays. (Thanks Jeff Slutter) +
    • Fixed bug with explicit handle for class members and array elements (Thanks Juan Pablo Bettini) +
    +
  • Library +
      +
    • Improved memory foot print of the compiler. +
    • When parsing statements the parser now has full knowledge of available + types so it is able to better distinguish the true semantic of identifiers. +
    • Added support for PS3 native calling conventions. (Thanks Jeff Slutter) +
    • GNUC assembler for native calling conventions now guarantee stack pointer alignment on 16 bytes. +
    • Added support for Mac OS X with Intel native calling conventions. +
    • Added support for Mac OS X with PPC native calling conventions. +
    +
  • Library interface +
      +
    • Added OPTIMIZE_BYTECODE as engine property. +
    • Removed restriction on registered object type's sizes, they can now be of any size, even non-multiple of 4. (Thanks Tonin) +
    +
  • Virtual machine +
      +
    • New byte codes: ChkNullS, ClrHi +
    +
  • Project +
      +
    • Added as_callfunc_ppc_64.cpp +
    +
+ + +

Version 2.8.0a - 2007/02/18

+ +
    +
  • Bug fixes +
      +
    • Fixed memory leak with exception handler inside script class method +
    • Fixed the DELETEARRAY macro that didn't work on gnuc (Thanks Jeremy "droz" Harmon) +
    +
  • Library +
      +
    • Improved the memory management facility +
    • Added the config option AS_NO_USER_ALLOC. Define this to turn off the user defined memory + managements. The default memory management in the library may not be compatible with all compilers yet. By + defining this macro when you compile the library, you should be able to use the library anyway, though + without the functionality of asSetGlobalMemoryFunctions(). +
    +
  • Project +
      +
    • Removed as_objectarray.h +
    +
+ +

Version 2.8.0 - 2007/02/04

+ +
    +
  • Bug fixes +
      +
    • Fixed incorrect use of temporary variables during evaluation of function argument expressions (Thanks Gilad Novik) +
    • Fixed error with exception handler inside script class method (Thanks Anders "Dentoid" Stenberg) +
    +
  • Library interface +
      +
    • Added Set/GetEngineProperty() that will allow you to dynamically changes some settings that previously required a recompilation of the library. +
    • ALLOW_UNSAFE_REFERENCES is now an engine property instead of a compile time flag. +
    • Removed some deprecated functions. +
    • Added GetArgPointer() and GetReturnPointer() to asIScriptContext and asIScriptGeneric. +
    • Removed the SetCommonObjectMemoryFunctions() from the script engine. +
    • Added the global SetGlobalMemoryFunctions() and ResetGlobalMemoryFunctions(). +
    • Added SetUserData() and GetUserData() to the context interface (Thanks Steve Williams) +
    +
  • Library +
      +
    • Fixed a lot of compiler warnings (Thanks Manu Evans) +
    • All dynamically allocated memory now uses the memory functions registered with SetGlobalMemoryFunctions. +
    • By changing the asCString implementation I was able to decrease the number of memory allocations by 15%. +
    +
  • Script language +
      +
    • Deprecated the bits type. All bitwise operators are now performed on the uint type. There is no longer any bitwise conversion of float to uint. +
    • Added the int64 and uint64 types. +
    • The this keyword is now optional when accessing class members from within a class method. +
    • Object constructors can now be used to perform implicit conversions in expressions. +
    +
  • Virtual machine +
      +
    • New byte codes: + i64TOi, uTOi64, iTOi64, fTOi64, dTOi64, fTOu64, dTOu64, i64TOf, u64TOf, i64TOd, u64TOd, + NEGi64, INCi64, DECi64, BNOT64, + ADDi64, SUBi64, MULi64, DIVi64, MODi64, + BAND64, BOR64, BXOR64, BSLL64, BSRL64, BSRA64 + CMPi64, CMPu64 +
    +
  • Project +
      +
    • Added as_memory.h, as_memory.cpp, and as_objectarray.h +
    +
+ +

Version 2.7.1b - 2006/12/03

+ +
    +
  • Bug fixes +
      +
    • Save/load of bytecode followed by ExecuteString() that called one of the script functions failed during compilation. (Thanks coollofty) +
    +
+ +

Version 2.7.1a - 2006/11/04

+ +
    +
  • Bug fixes +
      +
    • Constant bits8 and bits16 variables didn't work properly (Thanks Cheetah3d) +
    +
+ +

Version 2.7.1 - 2006/11/02

+ +
    +
  • Bug fixes +
      +
    • Minor bug fix with an incorrect error message (Thanks Alraz) +
    • Empty switch statements would crash the compiler (Thanks the_bateman) +
    • Registering global properties didn't update a cache in compiled script modules, sometimes invalidating pointers (Thanks Anthony Rufrano, a.k.a "paradoxnj") +
    • Fixed compiler differences for 64bit integer constants +
    • Fixed some compiler asserts (Thanks Anders Hansson) +
    • The index operator on handles to array objects didn't work (Thanks Anders Hansson) +
    • The compiler would crash if a script class inherited from an undeclared type (Thanks Anders Hansson) +
    • The compiler incorrectly reused temporary variables (Thanks MrC_XBMC) +
    +
  • Library +
      +
    • The non-reserved tokens, any, from, and this, are now also defined in the as_tokendef.h file (Thanks Deyja) +
    • Adjustments have been made to make the library independent of CPU memory layout of words. This if for PPC. (Thanks Edward Rudd) +
    • Cleaned up as_config.h to make it easier to maintain +
    • Changed compiler to do proper conversion between types of different sizes, for the sake of big-endian CPUs. +
    +
  • Script language +
      +
    • Added the reserved keyword 'cast' +
    • Support for dynamic casts between object handles with cast<type>(expr) +
    +
  • Virtual machine +
      +
    • Added byte codes iTOb, iTOw, SetV1, and SetV2 to support big endian CPUs +
    • Added byte code Cast for dynamic casts of object handles +
    +
+ +

Version 2.7.0 - 2006/07/23

+ +
    +
  • Bug fixes +
      +
    • Fixed a problem with script classes and multiple modules where the engine failed to find the class methods (Thanks Dentoid) +
    • Fixed bug where an assert fails when the operands for an assignment has compiler errors (Thanks Dentoid) +
    • Parser entered endless loop if the script ended before closing the class declaration (Thanks Dentoid) +
    • Parser entered endless loop if a method declaration had syntax error (Thanks kunitoki) +
    • Fixed assert hit for some compiler errors (Thanks kunitoki) +
    • Discard() would remove array types from the configuration, leading to failure in following builds (Thanks loboWu) +
    • Fixed bug with the any type and AS_MAX_PORTABILITY +
    • Fixed bug with AS_MAX_PORTABILITY and script classes that were not constructed properly +
    • Fixed a bug with the bytecode optimization for 64bit processors +
    • Fixed some bugs with the internal array object and AS_MAX_PORTABILITY and AS_64BIT_PTR +
    • Fixed bug with null value and AS_64BIT_PTR +
    • Fixed some bugs in the virtual machine on 64bit processors +
    • Added check to see if script property has a size 0 (Thanks Maddi) +
    +
  • Library interface +
      +
    • The engine methods GetMethodCount(), GetMethodIDByIndex(), GetMethodIDByName(), and GetMethodIDByDecl() were changed to take the typeId instead of the module name and object type name. This makes it unnecessary to know the module if you only have the type id, and it is also much more efficient. +
    • Added methods RegisterInterface() and RegisterInterfaceMethod() that allow the application to register a script interface which can be passed to the application +
    • Added method GetFunctionModule() +
    • Deprecated the methods GetModuleIndex() and GetModuleNameFromIndex() +
    • Added GetVarTypeId() to the context interface +
    • Replaced SetCommonMessageStream() with SetMessageCallback() which is more flexible in that it receives a structure with info instead of a string +
    • asIOutputStream is removed +
    • Added asGetLibraryOptions() which returns a string with the compile time options. Mostly used for testing. +
    +
  • Library +
      +
    • Applied changes to make the library work better with 64bit platforms (Thanks Yiannis Mandravellos) +
    • Fixed a couple of compiler warnings (Thanks Alraz) +
    • Added support for native calling conventions on MIPS processors. (Contribution by Manu Evans) +
    • Added first support for native calling conventions on PPC processors. (Contribution by Pecan Heber) +
    • Unified the way registered functions and script functions are stored in the engine +
    • Improved performance of Prepare() when using the same function as last Prepare() +
    +
  • Script language +
      +
    • Added new token 'interface' +
    • Semi-colon after class declaration is now optional +
    • It's now possible to declare interfaces in the scripts +
    • Added support for the '\t' escape sequence in strings. (Thanks Lbas) +
    • Deprecated the keyword 'struct' in the script language +
    +
  • Virtual machine +
      +
    • Added bytecode CALLINTF which resolves interface methods to the real class method +
    +
  • Project +
      +
    • Added as_callfunc_mips.cpp +
    • Added as_callfunc_ppc.cpp +
    +
+ +

Version 2.6.0 - 2006/04/08

+ +
    +
  • Bug fixes +
      +
    • Fixed a bug with RegisterGlobalProperty() (Thanks loboWu) +
    • Type conversions may now be used in initialization of global variables. (Thanks iram) +
    +
  • Script language +
      +
    • It's now possible to define class methods and constructors for the script declared structures. The definition of the method must be written inside the struct declaration. +
    • The this keyword can be used to access the object and its members from within the class method. It's not yet possible to access the struct members without using the this keyword. +
    • Added the keyword 'class' as synonym for 'struct' +
    • For &inout parameter references the 'inout' keyword is now optional +
    • Only object types that support object handles can now use the &inout parameter references. Other types must use &in or &out, unless AS_ALLOW_UNSAFE_REFERENCES is defined. +
    • Added the reserved keyword: int64. Currently this is only used internally, but in time it will be a fully implemented primitive. +
    +
  • Library interface +
      +
    • Removed the deprecated version of the Build() method. +
    • Added SetArgAddress() and GetReturnAddress() methods to the context interface. These should be used to handle references +
    • Added GetArgAddress() and SetReturnAddress() methods to the generic interface. +
    • Changed AddScriptSection() to accept a size_t for the script length instead of int +
    • Improved the way the [Set|Get][Arg|Return][Address|Object]() methods work. +
    • Added the method SetObject() to the context for calling object methods +
    • ExecuteString() now adds a line break after the given string. This allows for one-line comments to be used without producing an invalid script. (Thanks B_old) +
    • Added the methods GetMethodCount(), GetMethodIDByIndex(), GetMethodIDByName(), and GetMethodIDByDecl() that should be used to obtain the function id for a script declared class method. +
    +
  • Library +
      +
    • Fixed a lot but not all of the compiler warnings that MSVC8 reports for 64bit incompatibilities. +
    • If native calling conventions are not supported for the target platform, then AS_MAX_PORTABILITY will automatically be defined to allow compilation of the library. (Thanks mandrav) +
    • Added a new compiler flag AS_64BIT_PTR, which should be defined for 64bit platforms. Ideally the as_config.h file should automatically set the flag according to the target platform. When this flag is defined, all pointers will be stored in the bytecode as 64bit words. +
    • Made improvements to better handle 64bit platforms +
    +
+ +

Version 2.5.0c - 2006/02/16

+ +
    +
  • Bug fixes +
      +
    • Using named constants, i.e. variables declared and initialized with constants, would in certain situations give the wrong value. (Thanks Villemon) +
    • Added null checks to fix memory access failure related to dynamic configurations. (Thanks mandrav) +
    +
  • Project +
      +
    • Removed as_structs.h +
    +
+ +

Version 2.5.0b - 2006/01/31

+ +
    +
  • Bug fixes +
      +
    • Comparison with object handle in a local variable produced incorrect byte code. (Thanks Villemon) +
    • A bug in the VM for the BC_ChkNullV byte code caused script exceptions when using asCScriptString compiled with VC++ 2005. (Thanks topcatse) +
    • When releasing the engine, the internal resources were released in the wrong order, causing assert failures in the memory manager with VC++ 2005. +
    • The assignment operator for the internal type 'any' wasn't properly registered, causing memory management problems. +
    • Global variables were not initialized properly when loading pre-compiled bytecode. (Thanks Villemon) +
    +
+ +

Version 2.5.0a - 2006/01/20

+ +
    +
  • Bug fixes +
      +
    • Using assignment behaviours that took a reference as &inout with asALLOW_UNSAFE_REFERENCES would crash the application. (Thanks Deyja) +
    • Using the default constructor for script structures to create temporary objects didn't work. +
    +
+ +

Version 2.5.0 - 2006/01/12

+ +
    +
  • Bug fixes +
      +
    • asCALL_CDECL_OBJLAST that returned objects by value didn't work correctly (Thanks Deyja) +
    +
  • Script language +
      +
    • Primitive types can be implicitly converted to a reference of another primitive type for function calls. This is something C++ doesn't accept. +
    • Parameter reference specified as &inout no longer copies the value. The argument is only computed once. The function receives a reference to the true value. Expressions where the reference cannot be guaranteed during the execution of the function generates a compiler error. The value must then be copied to a local variable instead. +
    • Added support for character literals. +
    +
  • Library interface +
      +
    • Overloaded operators may now use &inout references. Since this type of references now guarantees a pointer to the true object this is useful if the operand has to be modified, e.g. a stream class. +
    • Overloaded operators may now use &out references. The order of evaluation will change, but precedence order is kept. +
    • Added functions to the asIScriptContext interface that allow the application to enumerate variables on the stack and examine their values. (Thanks Ivan Marinov) +
    +
  • Library +
      +
    • A couple of minor code changes to make it easier to compile the library on Metrowerks CodeWarrior for NintendoDS (Thanks Fumihiro KanaYA) +
    • The script compiler was changed to generate less copies of objects when doing function parameters by reference. +
    • Added a new compile time flag: AS_ALLOW_UNSAFE_REFERENCES. When this is defined the library will allow parameter references without the in, out, or inout keywords. These parameters references will also work just like normal C++ parameter references, without any restrictions. +
    +
  • Virtual Machine +
      +
    • The VM has been changed to use three op instructions instead of stack based instructions. In some situations the new VM is faster, in others it is about the same. +
    +
  • Project +
      +
    • as_types.h was removed. +
    +
+ +

Version 2.4.1e - 2006/02/04

+ +
    +
  • Bug fixes +
      +
    • When releasing the engine, the internal resources were released in the wrong order, causing assert failures in the memory manager with VC++ 2005. +
    • The assignment operator for the internal type 'any' wasn't properly registered, causing memory management problems. +
    • asCALL_CDECL_OBJLAST that returned objects by value didn't work correctly (Thanks Deyja) +
    • Global variables were not initialized properly when loading pre-compiled bytecode. (Thanks Villemon) +
    • Using the default constructor for script structures to create temporary objects didn't work. +
    • Comparison with boolean values resulted in the value -1 instead of 1. +
    +
+ +

Version 2.4.1d - 2005/12/09

+ +
    +
  • Bug fixes +
      +
    • The compiler didn't raise an error when doing an handle assignment where the lvalue was a normal object (Thanks Lbas) +
    +
+ +

Version 2.4.1c - 2005/11/22

+ +
    +
  • Bug fixes +
      +
    • Overloaded indexing operators that take an object as parameter and returns a reference, crashed the application when compiling the script. (Thanks Desdemona) +
    +
+ +

Version 2.4.1b - 2005/11/08

+ +
    +
  • Bug fixes +
      +
    • Chained expressions with overloaded operators and registered types could cause null pointer violations (continued) (Thanks __Avatar__) +
    +
+ +

Version 2.4.1a - 2005/10/18

+ +
    +
  • Bug fixes +
      +
    • Registering global properties, after removing a config group with global properties, caused a null pointer violation. (Thanks DaesDemon) +
    • An assert failed when initializing variables with a function that took reference parameters. (Thanks mandrav) +
    • Chained expressions with overloaded operators and registered types could cause null pointer violations. (Thanks Anders Stenberg, a.k.a Dentoid) +
    • Expressions with multiple levels of indirections (.) and object handles as arguments in each level, caused incorrect bytecode. (Thanks Vexorian) +
    +
+ +

Version 2.4.1 - 2005/09/23

+ +
    +
  • Script language +
      +
    • Added support for heredoc string constants. (Thanks Ashish Ranjan) +
    • Added support for array initialization lists. +
    +
+ +

Version 2.4.0 - 2005/09/15

+ +
    +
  • Bug fixes +
      +
    • The bitwise negate operator, ~, now works with integer types as well, e.g. int and uint. (Thanks Suudy) +
    • Save and load of compiled bytecode with script arrays now work. (Thanks Evgeny Efremov, a.k.a wolfenstein) +
    +
  • Library interface +
      +
    • Added methods BeginConfigGroup(), EndConfigGroup(), and RemoveConfigGroup() for asIScriptEngine. +
    • The engine no longer allow overriding the array types if they are already being used elsewhere. +
    • All methods taking asUPtr as parameter was changed to take const asUPtr& instead, which ought to help avoid ESP problems that some people have encountered. +
    • Added an optional namespace. Define the flag AS_USE_NAMESPACE when compiling to put the script engine in the namespace AngelScript. +
    • Added a method SetCommonObjectMemoryFunctions() that allow the application to register an alloc()/free() function pair that will be used for all script objects. +
    • asIBinaryStream was changed to use asUINT instead of int for the block size, and const void * instead of void * for Write(). +
    • Added a method SetCommonMessageStream(). The engine uses this output stream to output error messages when registering configurations, and also if the Build() method is called with a null pointer for the output stream. A second version of this method is available that takes a simple function pointer and an optional parameter, like a normal callback function. +
    • Build() and ExecuteString() no longer takes a pointer to an asIOutputStream. The old version is still available by defining the flag AS_DEPRECATED. +
    • Added method SetConfigGroupModuleAccess() which is used to set both default module access mode and individual module accesses. +
    +
  • Script language +
      +
    • Constant variables that are initialized with a constant expression, can now be used as named constants in for example switch cases. (Thanks juhnu) +
    +
  • Library +
      +
    • Changed the way the modules free global variables. Instead of a script function, it is now just a simple loop freeing each of the variables. +
    • asBSTR is no longer used internally to store constant strings, asCString is used instead. +
    • Converted the asCMap to template code. +
    • The assembler VM was removed as it will no longer be possible to keep it compatible with the C++ VM. +
    +
  • Project +
      +
    • Added as_configgroup.cpp and as_configgroup.h. +
    • Removed as_map.cpp +
    • Removed as_context_x86.cpp +
    • Removed as_bstr_util.cpp and as_bstr_util.h. +
    +
+ +

Version 2.3.0b - 2005/08/09

+ +
    +
  • Bug fixes +
      +
    • Parameters where freed before the returned reference was used, which caused errors if the reference pointed to one of the parameters. (Thanks Suudy) +
    +
+ +

Version 2.3.0a - 2005/07/29

+ +
    +
  • Bug fixes +
      +
    • Structure definitions and function declarations where not order independent. (Thanks Carl Ådahl) +
    • Added the old CreateContext() and GetGlobalVarPointer() as deprecated methods. +
    • Fixed some more compiler warnings. +
    +
+ +

Version 2.3.0 - 2005/07/14

+ +
    +
  • Bug fixes +
      +
    • RegisterGlobalProperty() for object handles wasn't working correctly, the wrong address was used by the VM. +
    • The C interface for asIScriptGeneric wasn't declared correctly. +
    • Fixed a few compiler warnings. (Thanks Rain Dog) +
    • When calling methods on null handles, the application crashed with a memory access violation (Thanks Robert Manuszewski) +
    • If accessing the elements of a script array handle, the compiler wrongly made the elements handles as well (Thanks Scott Dillman, a.k.a AlphaDog) +
    +
  • Library interface +
      +
    • Added an interface to manipulate the any type, asIScriptAny. +
    • Added an interface to manipulate script structures, asIScriptStruct. +
    • Added an interface to manipulate script arrays, asIScriptArray. +
    • Added methods GetTypeIdByDecl() and GetTypeDeclaration(). +
    • Added the method asIScriptEngine::CreateScriptObject() that allow the application to create objects from a type id. +
    • Added the method asIScriptEngine::GetObjectsInGarbageCollectorCount() + which can be used to finetune how often the GarbageCollect() is called. +
    • Changed the asIScriptEngine::CreateContext() to return the context pointer instead of placing it in the parameter. +
    • asIScriptEngine::GetGlobalVarPointer() now returns the pointer directly, instead of putting it in the argument. +
    • Removed the deprecated asIScriptContext::ExecuteStep(). +
    +
  • Script language +
      +
    • New built-in type: any. This type will be able to hold any other type, as a generic container, though currently it can only hold object handles. It is possible to pass this type to the application. +
    +
  • Library +
      +
    • Changed the implementation for asCGCObject, since it is not possible to use multiple inheritance with anonymous pointers. +
    • Slimmed down the internal datatype representation, for the typeid feature. +
    +
  • Virtual machine +
      +
    • A new bytecode TYPEID has been implemented. +
    • The object types are now passed as pointers directly in the bytecode, instead of by index. +
    +
  • Project +
      +
    • Added as_anyobject.h and as_anyobject.cpp +
    +
+ +

Version 2.2.0 - 2005/06/08

+ +
    +
  • Script language +
      +
    • New reserved keyword: struct +
    • The scripts can now declare and use structures. +
    • The compiler now automatically converts objects to object handles, when it is obvious a handle is wanted, i.e. there will be less need to use the @ operator. +
    +
  • Library interface +
      +
    • It is now possible to tell the library to automatically handle reference for handles passed to and from application functions. Simply add a + after the @. This makes it possible to pass handles to functions that do not call the release method before returning. +
    • A new method GarbageCollect() has been implemented that will free unused script objects. For long running programs it is necessary to call this every now and then. It can do either a full cycle or just a small incremental step, depending on the needs of the application. +
    +
  • Virtual machine +
      +
    • The bytecode now identifies object types locally to each module. +
    • There is a new bytecode OBJTYPE that translates a local object type id to the engine's object type id. +
    +
  • Library +
      +
    • Added a new preprocessor flag, AS_MAX_PORTABILITY, which removes all calls to assembler routines, which should make the library work on all platforms. In this mode, only asCALL_GENERIC can be used for application functions. +
    • Changed the internal data type description class to be easier to work with. The intention is to allow the application to access this to get information about types for global variables, function declarations, etc. +
    • Changed the implementation of the internal script array object to work more similar to the way script structures work. +
    +
  • Project +
      +
    • New files: as_scriptstruct.cpp and as_scriptstruct.h +
    • Added as_callfunc.cpp which implements the portable functions when AS_MAX_PORTABILITY is defined. +
    • Added the files as_gcobject.h and as_gcobject.cpp +
    +
+ +

Version 2.1.0c - 2005/05/26

+ +
    +
  • Bug fixes +
      +
    • When getting the function declaration the library didn't set the 'in', 'out', 'inout' flags for parameter references (Thanks Andrey Kraynov, a.k.a _Dreamer) +
    • After loading precompiled bytecode script functions that took objects by handle couldn't be identified (Thanks Andrey Kraynov, a.k.a _Dreamer) +
    +
+ +

Version 2.1.0b - 2005/04/25

+ +
    +
  • Bug fixes +
      +
    • The C interface wasn't exporting the functions. (Thanks Lars Peter Christiansen) +
    • Variables of types int and uint of any size weren't implicitly converted to bits. +
    • Uninitialized variables passed to &out parameters were incorrectly reported as uninitialized. +
    • The compiler was accepting assignments of any type to objects with no registered assignment operator. +
    +
+ +

Version 2.1.0a - 2005/04/11

+ +
    +
  • Bug fixes +
      +
    • The null pointer access in the compiler when matching function arguments was removed (Thanks Lennart Denninger) +
    • The ?: operator was reusing temporary variables incorrectly. +
    • The compiler failed to compile the boolean not operator for variables. (Thanks SharkBait) +
    +
+ +

Version 2.1.0 - 2005/04/03

+ +
    +
  • Bug fixes +
      +
    • The line numbers reported by the VM were incorrect. +
    • GetGlobalVarPointer() was returning a pointer to a pointer for registered object types. (Thanks Rain Dog) +
    • Fixed a possible crash when calling AddScriptSection() with 0 for section name. +
    • The operands for overloaded operators are now evaluated left-to-right. +
    • Output parameters weren't working correctly for object methods (Thanks Mårten Svanfeldt, a.k.a thebolt00) +
    • The engine failed when calling registered functions that received objects both by value and by reference (Thanks Lennart Denninger) +
    • Registered object types without registered constructor couldn't be used to create temporary objects in expressions. +
    • Global variables couldn't use overloaded assignment operators to initialize the variables. +
    • Object properties declared as object handles were not handled correctly by the compiler. +
    • Fixed a bug that crashed the application when compiling a function declared with a void parameter. (Thanks SharkBait) +
    • Sending complex objects by value to class methods caused a crash on GNUC based compilers. (Thanks Torsten, a.k.a torsten_pf) +
    • Passing objects by reference to constructors in declarations caused an assert failure. (Thanks Rain Dog) +
    +
  • Script language +
      +
    • The script language now allows statements like: func(expr), where the function doesn't take any arguments and + the expression evaluates to a void type. This is especially useful when using dynamically generating scripts where + the expression type isn't known before hand. +
    • Object variables and properties can be declared as const again +
    • Properties of a const object are automatically const as well +
    • When the object is const, the compiler doesn't allow non-const methods to be called +
    • It is possible to take a handle for a const object, but it can only be assigned to a handle to a const object +
    • The object held by a handle that is member of a const object, is not automatically const +
    • An object handle that is member of a const object is also const +
    • Const can be used for parameters again +
    +
  • Virtual machine +
      +
    • The calling convention used by the script engine now passes the object pointer as the first parameter instead of the last. +
    • GETOBJ was changed to read the offset from the stack instead of the address to the variable. +
    • Added GETOBJREF and GETREF to handle parameter references. +
    • Parameter references to overloaded operators are also protected by copying them to temporary variables. +
    • Added SWAP48 and SWAP84 to swap two values of different bytesizes. +
    • The compiler has been changed to output bytecode that don't keep unprotected pointers on the stack where they cannot be controlled. This will prove especially useful when I will later implement context serialization and co-routines. +
    • Calling the constructors with arguments are now also protected by not pushing the object pointer on the stack before the arguments. +
    +
  • Library interface +
      +
    • Implemented a C wrapper for the library. Compile the library with AS_C_INTERFACE to use it. +
    • Added a dummy array in asUPtr to make the size equal on all compilers (even when the C++ interface is disabled) +
    • Added SetLineCallback()/ClearLineCallback() to the context interface. These should be used instead of ExecuteStep() to control how much is executed each frame. +
    • Added SetExceptionCallback()/ClearExceptionCallback() to the context interface. These methods can be used for debugging purposes and allow the application to examine the callstack when an exception is raised. +
    • Added GetCallstackSize() and GetCallstackFunction() to the context interface. +
    • Added the possibility to turn off support for registering class methods. Compile the library with AS_NO_CLASS_METHODS. This can be used on compilers where class methods don't currently work. +
    • Added GetFunctionSection() to the engine interface. +
    • ExecuteStep() is now a deprecated method. Use the line callback method instead, which is much more flexible. +
    • Added GetCallstackLineNumber() to the context interface. +
    • All methods that return line numbers can now optionally return column number as well. +
    • Added the asCALL_GENERIC flag for functions using the generic calling convention. +
    • Added a new asIScriptGeneric interface for handling generic functions. +
    • Added GetObject() to the generic interface, that will return the object pointer when a method function using the generic calling convention is called. +
    • Added GetArgDWord(), GetArgQWord(), GetArgFloat(), GetArgDouble(), and GetArgObject() to the generic interface. +
    • Added SetReturnDWord(), SetReturnQWord(), SetReturnFloat(), SetReturnDouble(), and SetReturnObject() to the generic interface. +
    • Added two new behaviours asBEHAVE_ALLOC and asBEHAVE_FREE, that can be used to register custom memory allocation functions for an object type. +
    • Overloaded operators have been limited to only allow parameter references marked as 'in' (non-references are still allowed). This means that you cannot rely on that you receive a reference to the actual operand, as it might be a copy. +
    • The extra call to addref/release for the object pointer when calling class methods has been removed. The responsibility of making sure the pointer is valid during the call has been moved to the application. +
    • RegisterObjectType() now returns asALREADY_REGISTERED if name has already been registered as a type. (Suggestion by Adrian Licu) +
    • It is now possible to declare object methods as const, so that they can be called for constant objects. Ex: "void GetVal() const" +
    • Const overloading is now available for object behaviours and methods, i.e. if the object is const then the const version will be used, otherwise the non-const version will be used. +
    • AddScriptSection() now has an extra parameter that can be used to tell the library not to make a copy of the script code, and instead use the original pointer directly. (Thanks Adrian Licu) +
    • A new method ResetModule() was added to the engine. This can be used to reset the value of global variables for a module. +
    +
  • Project +
      +
    • Added as_generic.cpp and as_generic.h with the interface for generic functions. +
    • Removed the #include <memory.h> from the angelscript.h file. +
    • Added as_c.cpp with the C wrapper functions. +
    +
+ +

Version 2.0.0a - 2005/01/31

+ +
    +
  • Bug fixes +
      +
    • GetCurrentFunction() and GetExceptionFunction() didn't return the function ID with the module index, affecting applications that were using module bindings (Thanks Tomas Stepanek) +
    • The library crashed when trying to register a function that used a handle to a type that had no addref/release behaviours registered (Thanks Adrian Licu) +
    • It wasn't possible to return null in a function which return type is a handle (Thanks Adrian Licu) +
    • Passing object handles by value to application functions could cause a crash (Thanks Adrian Licu) +
    • Fixed a minor memory leak when RegisterGlobalFunction() failed. +
    +
+ +

Version 2.0.0 - 2005/01/23

+ +
    +
  • Bug fixes +
      +
    • GNUC: Classes with destructors can now be sent by value to system functions +
    • The compiler failed to successfully parse/compile temporary array constructors, e.g. int[](3). +
    • On GCC/Linux all classes/structs are returned in memory regardless of size, complexity, or calling convention. (Thanks Fredrik Ehnbom) +
    • Some compilers complained about the negative array size in the template code that is never instanciated. The code was commented. +
    • Overloaded assignment operators that take types other than the target can now be used in initializations. (Thanks Alan Kemp) +
    • asGetActiveContext() would cause an assert failure if called when no context was active. (Thanks Chee Chong Tay, a.k.a Iram) +
    • It was not possible to register arrays of registered types. (Thanks Tomas Stepanek) +
    + +
  • Library interface +
      +
    • Removed deprecated functionality +
    • Removed the flag asOBJ_GUESS for RegisterObjectType(). +
    • Removed the macros asFUNCTIONP() and asMETHODP(). +
    • Removed GetReturnValue() +
    • Added GetReturnDWord(), GetReturnQWord(), GetReturnFloat(), GetReturnDouble(), and GetReturnObject() +
    • Removed SetArguments() +
    • Added SetArgDWord(), SetArgQWord(), SetArgFloat(), SetArgDouble(), SetArgObject() +
    • Protected destructors have been added to the interfaces so that the application doesn't call them by mistake (thanks Dan "Aggrav8d" Royer) +
    • Function declarations with arguments by ref must use the in, out, or inout flags +
    • Added the behaviours ADDREF and RELEASE that will be used by object handles to do memory management +
    • New context state: asEXECUTION_ERROR, that is set if one of the SetArg...() functions failed. +
    + +
  • Script language +
      +
    • Removed the pointer type modifier +
    • Removed the -> operator +
    • In declarations the array brackets are now part of the type, i.e. for "int[] a, b;" both a and b are arrays +
    • Arrays can now be resized by using the method resize(). +
    • Parameter references are now protected by copying the value into a + temporary variable when calling the function, and then copying the + temporary variable back to the original location when the function + returns. The expression is computed twice for in/out references. +
    • Function parameters by reference should use the flags in, out, or inout to allow the compiler to optimize the use of the parameters. +
    • Added the object handle type modifier so that object handles can be declared. The token @ is used so as not to confuse it with C++ pointers or references. +
    • Added the null keyword for object handles. +
    • const is now only available for variable and property declarations, and only for primitive types. This change was made for consistency and because the script language was not able to guarantee that an object isn't changed by object methods. +
    • Arrays have been limited to only allow four dimensions +
    + +
  • Virtual machine +
      +
    • Removed the bytecode ADDOFF +
    • Objects are stored in dynamically allocated memory. A pointer to the memory is stored on the stack +
    • Created ALLOC/FREE instructions for allocating and freeing the objects +
    • Objects are returned in a register +
    • Created LOADOBJ/STOREOBJ that moves an object pointer from a variable into the object register, and vice versa +
    • Created GETOBJ which moves an object pointer from a reference to the stack, overwriting the reference +
    • Removed END and PEID. +
    • Simplified the exception handler to free objects based only on their position on the stack +
    • A script function receives an object by value and by ref the same way. The difference is if the function is the owner of the object or not. +
    • Added REFCPY to support reference assignments for object handles +
    • Added CHKREF to validate object handles when used as normal objects +
    • Added the bytecodes RD1 and RD2 to fix alignment problems on CPUs that requires data to be aligned. +
    • The VM keeps a reference to the object when calling a method, to protect the object from being released before the method returns. +
    + +
  • Library +
      +
    • The library was made to work with Dreamcast once more. (Thanks Fredrik Ehnbom) +
    • The compile time flag BUILD_WITH_LINE_CUES was replaced with BUILD_WITHOUT_LINE_CUES. This flag is not +defined by default making ExecuteStep() work as specified, but for those that do not use this function the +performance may be increased a little by specifying this flag when compiling the library. +
    +
+ + + + + diff --git a/docs/index.html b/docs/index.html new file mode 100644 index 0000000..afdcc1d --- /dev/null +++ b/docs/index.html @@ -0,0 +1,120 @@ + + +Documentation + + + + + + + + +

AngelCode Scripting Library

+ +

+Application Writer's Manual
+This is the reference manual for the library interface.

+ +

+AngelScript Change Log versions 2.x
+AngelScript Change Log versions 1.x
+AngelScript Change Log versions 0.x
+The complete change log for the library. +

+ + \ No newline at end of file diff --git a/docs/manual/angelscript_8h.html b/docs/manual/angelscript_8h.html new file mode 100644 index 0000000..230e12a --- /dev/null +++ b/docs/manual/angelscript_8h.html @@ -0,0 +1,2390 @@ + + + + + + + +AngelScript: angelscript.h File Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
angelscript.h File Reference
+
+
+ +

The API definition for AngelScript. +More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Classes

struct  asSFuncPtr
 Represents a function or method pointer. More...
 
struct  asSMessageInfo
 Represents a compiler message. More...
 
class  asIScriptEngine
 The engine interface. More...
 
class  asIStringFactory
 The interface for the string factory. More...
 
class  asIThreadManager
 The interface for the thread manager. More...
 
class  asIScriptModule
 The interface to the script modules. More...
 
class  asIScriptContext
 The interface to the virtual machine. More...
 
class  asIScriptGeneric
 The interface for the generic calling convention. More...
 
class  asIScriptObject
 The interface for an instance of a script object. More...
 
class  asITypeInfo
 The interface for describing types This interface is used to describe the types in the script engine. More...
 
class  asIScriptFunction
 The interface for a script function description. More...
 
class  asIBinaryStream
 A binary stream interface. More...
 
class  asILockableSharedBool
 A lockable shared boolean. More...
 
struct  asSVMRegisters
 A struct with registers from the VM sent to a JIT compiled function. More...
 
class  asIJITCompiler
 The interface that AS use to interact with the JIT compiler. More...
 
struct  asSBCInfo
 Information on a bytecode instruction. More...
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Macros

+#define ANGELSCRIPT_VERSION   23500
 Version 2.35.0.
 
+#define AS_CAN_USE_CPP11   1
 This macro is defined if the compiler supports the C++11 feature set.
 
+#define asOFFSET(s, m)   ((int)(size_t)(&reinterpret_cast<s*>(100000)->m)-100000)
 Returns the offset of an attribute in a struct.
 
+#define asFUNCTION(f)   asFunctionPtr(f)
 Returns an asSFuncPtr representing the function specified by the name.
 
+#define asFUNCTIONPR(f, p, r)   asFunctionPtr(reinterpret_cast<void (*)()>(static_cast<r (*)p>(f)))
 Returns an asSFuncPtr representing the function specified by the name, parameter list, and return type.
 
+#define asMETHOD(c, m)   asSMethodPtr<sizeof(void (c::*)())>::Convert((void (c::*)())(&c::m))
 Returns an asSFuncPtr representing the class method specified by class and method name.
 
+#define asMETHODPR(c, m, p, r)   asSMethodPtr<sizeof(void (c::*)())>::Convert(AS_METHOD_AMBIGUITY_CAST(r (c::*)p)(&c::m))
 Returns an asSFuncPtr representing the class method specified by class, method name, parameter list, return type.
 
+#define AS_API
 A define that specifies how the function should be imported.
 
+#define asBC_DWORDARG(x)   (*(((asDWORD*)x)+1))
 Macro to access the first DWORD argument in the bytecode instruction.
 
+#define asBC_INTARG(x)   (*(int*)(((asDWORD*)x)+1))
 Macro to access the first 32bit integer argument in the bytecode instruction.
 
+#define asBC_QWORDARG(x)   (*(asQWORD*)(((asDWORD*)x)+1))
 Macro to access the first QWORD argument in the bytecode instruction.
 
+#define asBC_FLOATARG(x)   (*(float*)(((asDWORD*)x)+1))
 Macro to access the first float argument in the bytecode instruction.
 
+#define asBC_PTRARG(x)   (*(asPWORD*)(((asDWORD*)x)+1))
 Macro to access the first pointer argument in the bytecode instruction.
 
+#define asBC_WORDARG0(x)   (*(((asWORD*)x)+1))
 Macro to access the first WORD argument in the bytecode instruction.
 
+#define asBC_WORDARG1(x)   (*(((asWORD*)x)+2))
 Macro to access the second WORD argument in the bytecode instruction.
 
+#define asBC_SWORDARG0(x)   (*(((short*)x)+1))
 Macro to access the first signed WORD argument in the bytecode instruction.
 
+#define asBC_SWORDARG1(x)   (*(((short*)x)+2))
 Macro to access the second signed WORD argument in the bytecode instruction.
 
+#define asBC_SWORDARG2(x)   (*(((short*)x)+3))
 Macro to access the third signed WORD argument in the bytecode instruction.
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Typedefs

+typedef signed char asINT8
 8 bit signed integer
 
+typedef signed short asINT16
 16 bit signed integer
 
+typedef unsigned char asBYTE
 8 bit unsigned integer
 
+typedef unsigned short asWORD
 16 bit unsigned integer
 
+typedef unsigned int asUINT
 32 bit unsigned integer
 
+typedef uintptr_t asPWORD
 Unsigned integer with the size of a pointer.
 
+typedef unsigned long asDWORD
 32 bit unsigned integer
 
+typedef unsigned __int64 asQWORD
 64 bit unsigned integer
 
+typedef __int64 asINT64
 64 bit integer
 
+typedef void *(* asALLOCFUNC_t) (size_t)
 The function signature for the custom memory allocation function.
 
+typedef void(* asFREEFUNC_t) (void *)
 The function signature for the custom memory deallocation function.
 
+typedef void(* asCLEANENGINEFUNC_t) (asIScriptEngine *)
 The function signature for the engine cleanup callback function.
 
+typedef void(* asCLEANMODULEFUNC_t) (asIScriptModule *)
 The function signature for the module cleanup callback function.
 
+typedef void(* asCLEANCONTEXTFUNC_t) (asIScriptContext *)
 The function signature for the context cleanup callback function.
 
+typedef void(* asCLEANFUNCTIONFUNC_t) (asIScriptFunction *)
 The function signature for the function cleanup callback function.
 
+typedef void(* asCLEANTYPEINFOFUNC_t) (asITypeInfo *)
 The function signature for the type info cleanup callback function.
 
+typedef void(* asCLEANSCRIPTOBJECTFUNC_t) (asIScriptObject *)
 The function signature for the script object cleanup callback function.
 
+typedef asIScriptContext *(* asREQUESTCONTEXTFUNC_t) (asIScriptEngine *, void *)
 The function signature for the request context callback.
 
+typedef void(* asRETURNCONTEXTFUNC_t) (asIScriptEngine *, asIScriptContext *, void *)
 The function signature for the return context callback.
 
+typedef void(* asCIRCULARREFFUNC_t) (asITypeInfo *, const void *, void *)
 The function signature for the callback used when detecting a circular reference in garbage.
 
typedef void(* asJITFunction) (asSVMRegisters *registers, asPWORD jitArg)
 The function signature of a JIT compiled function. More...
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Enumerations

enum  asERetCodes {
+  asSUCCESS = 0, +
+  asERROR = -1, +
+  asCONTEXT_ACTIVE = -2, +
+  asCONTEXT_NOT_FINISHED = -3, +
+  asCONTEXT_NOT_PREPARED = -4, +
+  asINVALID_ARG = -5, +
+  asNO_FUNCTION = -6, +
+  asNOT_SUPPORTED = -7, +
+  asINVALID_NAME = -8, +
+  asNAME_TAKEN = -9, +
+  asINVALID_DECLARATION = -10, +
+  asINVALID_OBJECT = -11, +
+  asINVALID_TYPE = -12, +
+  asALREADY_REGISTERED = -13, +
+  asMULTIPLE_FUNCTIONS = -14, +
+  asNO_MODULE = -15, +
+  asNO_GLOBAL_VAR = -16, +
+  asINVALID_CONFIGURATION = -17, +
+  asINVALID_INTERFACE = -18, +
+  asCANT_BIND_ALL_FUNCTIONS = -19, +
+  asLOWER_ARRAY_DIMENSION_NOT_REGISTERED = -20, +
+  asWRONG_CONFIG_GROUP = -21, +
+  asCONFIG_GROUP_IS_IN_USE = -22, +
+  asILLEGAL_BEHAVIOUR_FOR_TYPE = -23, +
+  asWRONG_CALLING_CONV = -24, +
+  asBUILD_IN_PROGRESS = -25, +
+  asINIT_GLOBAL_VARS_FAILED = -26, +
+  asOUT_OF_MEMORY = -27, +
+  asMODULE_IS_IN_USE = -28 +
+ }
 Return codes. More...
 
enum  asEEngineProp {
+  asEP_ALLOW_UNSAFE_REFERENCES = 1, +
+  asEP_OPTIMIZE_BYTECODE = 2, +
+  asEP_COPY_SCRIPT_SECTIONS = 3, +
+  asEP_MAX_STACK_SIZE = 4, +
+  asEP_USE_CHARACTER_LITERALS = 5, +
+  asEP_ALLOW_MULTILINE_STRINGS = 6, +
+  asEP_ALLOW_IMPLICIT_HANDLE_TYPES = 7, +
+  asEP_BUILD_WITHOUT_LINE_CUES = 8, +
+  asEP_INIT_GLOBAL_VARS_AFTER_BUILD = 9, +
+  asEP_REQUIRE_ENUM_SCOPE = 10, +
+  asEP_SCRIPT_SCANNER = 11, +
+  asEP_INCLUDE_JIT_INSTRUCTIONS = 12, +
+  asEP_STRING_ENCODING = 13, +
+  asEP_PROPERTY_ACCESSOR_MODE = 14, +
+  asEP_EXPAND_DEF_ARRAY_TO_TMPL = 15, +
+  asEP_AUTO_GARBAGE_COLLECT = 16, +
+  asEP_DISALLOW_GLOBAL_VARS = 17, +
+  asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT = 18, +
+  asEP_COMPILER_WARNINGS = 19, +
+  asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE = 20, +
+  asEP_ALTER_SYNTAX_NAMED_ARGS = 21, +
+  asEP_DISABLE_INTEGER_DIVISION = 22, +
+  asEP_DISALLOW_EMPTY_LIST_ELEMENTS = 23, +
+  asEP_PRIVATE_PROP_AS_PROTECTED = 24, +
+  asEP_ALLOW_UNICODE_IDENTIFIERS = 25, +
+  asEP_HEREDOC_TRIM_MODE = 26, +
+  asEP_MAX_NESTED_CALLS = 27, +
+  asEP_GENERIC_CALL_MODE = 28, +
+  asEP_INIT_STACK_SIZE = 29, +
+  asEP_INIT_CALL_STACK_SIZE = 30, +
+  asEP_MAX_CALL_STACK_SIZE = 31 +
+ }
 Engine properties. More...
 
enum  asECallConvTypes {
+  asCALL_CDECL = 0, +
+  asCALL_STDCALL = 1, +
+  asCALL_THISCALL_ASGLOBAL = 2, +
+  asCALL_THISCALL = 3, +
+  asCALL_CDECL_OBJLAST = 4, +
+  asCALL_CDECL_OBJFIRST = 5, +
+  asCALL_GENERIC = 6, +
+  asCALL_THISCALL_OBJLAST = 7, +
+  asCALL_THISCALL_OBJFIRST = 8 +
+ }
 Calling conventions. More...
 
enum  asEObjTypeFlags {
+  asOBJ_REF = (1<<0), +
+  asOBJ_VALUE = (1<<1), +
+  asOBJ_GC = (1<<2), +
+  asOBJ_POD = (1<<3), +
+  asOBJ_NOHANDLE = (1<<4), +
+  asOBJ_SCOPED = (1<<5), +
+  asOBJ_TEMPLATE = (1<<6), +
+  asOBJ_ASHANDLE = (1<<7), +
+  asOBJ_APP_CLASS = (1<<8), +
+  asOBJ_APP_CLASS_CONSTRUCTOR = (1<<9), +
+  asOBJ_APP_CLASS_DESTRUCTOR = (1<<10), +
+  asOBJ_APP_CLASS_ASSIGNMENT = (1<<11), +
+  asOBJ_APP_CLASS_COPY_CONSTRUCTOR = (1<<12), +
+  asOBJ_APP_CLASS_C = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_CD = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR), +
+  asOBJ_APP_CLASS_CA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), +
+  asOBJ_APP_CLASS_CK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_CDA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), +
+  asOBJ_APP_CLASS_CDK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_CAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_CDAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_CONSTRUCTOR + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_D = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR), +
+  asOBJ_APP_CLASS_DA = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT), +
+  asOBJ_APP_CLASS_DK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_DAK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_DESTRUCTOR + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_A = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_ASSIGNMENT), +
+  asOBJ_APP_CLASS_AK = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_ASSIGNMENT + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_K = (asOBJ_APP_CLASS + asOBJ_APP_CLASS_COPY_CONSTRUCTOR), +
+  asOBJ_APP_CLASS_MORE_CONSTRUCTORS = (1<<31), +
+  asOBJ_APP_PRIMITIVE = (1<<13), +
+  asOBJ_APP_FLOAT = (1<<14), +
+  asOBJ_APP_ARRAY = (1<<15), +
+  asOBJ_APP_CLASS_ALLINTS = (1<<16), +
+  asOBJ_APP_CLASS_ALLFLOATS = (1<<17), +
+  asOBJ_NOCOUNT = (1<<18), +
+  asOBJ_APP_CLASS_ALIGN8 = (1<<19), +
+  asOBJ_IMPLICIT_HANDLE = (1<<20), +
+  asOBJ_MASK_VALID_FLAGS = 0x801FFFFF, +
+  asOBJ_SCRIPT_OBJECT = (1<<21), +
+  asOBJ_SHARED = (1<<22), +
+  asOBJ_NOINHERIT = (1<<23), +
+  asOBJ_FUNCDEF = (1<<24), +
+  asOBJ_LIST_PATTERN = (1<<25), +
+  asOBJ_ENUM = (1<<26), +
+  asOBJ_TEMPLATE_SUBTYPE = (1<<27), +
+  asOBJ_TYPEDEF = (1<<28), +
+  asOBJ_ABSTRACT = (1<<29), +
+  asOBJ_APP_ALIGN16 = (1<<30) +
+ }
 Object type flags. More...
 
enum  asEBehaviours {
+  asBEHAVE_CONSTRUCT, +
+  asBEHAVE_LIST_CONSTRUCT, +
+  asBEHAVE_DESTRUCT, +
+  asBEHAVE_FACTORY, +
+  asBEHAVE_LIST_FACTORY, +
+  asBEHAVE_ADDREF, +
+  asBEHAVE_RELEASE, +
+  asBEHAVE_GET_WEAKREF_FLAG, +
+  asBEHAVE_TEMPLATE_CALLBACK +,
+  asBEHAVE_GETREFCOUNT = asBEHAVE_FIRST_GC, +
+  asBEHAVE_SETGCFLAG, +
+  asBEHAVE_GETGCFLAG, +
+  asBEHAVE_ENUMREFS, +
+  asBEHAVE_RELEASEREFS +
+ }
 Behaviours. More...
 
enum  asEContextState {
+  asEXECUTION_FINISHED = 0, +
+  asEXECUTION_SUSPENDED = 1, +
+  asEXECUTION_ABORTED = 2, +
+  asEXECUTION_EXCEPTION = 3, +
+  asEXECUTION_PREPARED = 4, +
+  asEXECUTION_UNINITIALIZED = 5, +
+  asEXECUTION_ACTIVE = 6, +
+  asEXECUTION_ERROR = 7 +
+ }
 Context states. More...
 
enum  asEMsgType {
+  asMSGTYPE_ERROR = 0, +
+  asMSGTYPE_WARNING = 1, +
+  asMSGTYPE_INFORMATION = 2 +
+ }
 Compiler message types. More...
 
enum  asEGCFlags {
+  asGC_FULL_CYCLE = 1, +
+  asGC_ONE_STEP = 2, +
+  asGC_DESTROY_GARBAGE = 4, +
+  asGC_DETECT_GARBAGE = 8 +
+ }
 Garbage collector flags. More...
 
enum  asETokenClass {
+  asTC_UNKNOWN = 0, +
+  asTC_KEYWORD = 1, +
+  asTC_VALUE = 2, +
+  asTC_IDENTIFIER = 3, +
+  asTC_COMMENT = 4, +
+  asTC_WHITESPACE = 5 +
+ }
 Token classes. More...
 
enum  asETypeIdFlags {
+  asTYPEID_VOID = 0, +
+  asTYPEID_BOOL = 1, +
+  asTYPEID_INT8 = 2, +
+  asTYPEID_INT16 = 3, +
+  asTYPEID_INT32 = 4, +
+  asTYPEID_INT64 = 5, +
+  asTYPEID_UINT8 = 6, +
+  asTYPEID_UINT16 = 7, +
+  asTYPEID_UINT32 = 8, +
+  asTYPEID_UINT64 = 9, +
+  asTYPEID_FLOAT = 10, +
+  asTYPEID_DOUBLE = 11, +
+  asTYPEID_OBJHANDLE = 0x40000000, +
+  asTYPEID_HANDLETOCONST = 0x20000000, +
+  asTYPEID_MASK_OBJECT = 0x1C000000, +
+  asTYPEID_APPOBJECT = 0x04000000, +
+  asTYPEID_SCRIPTOBJECT = 0x08000000, +
+  asTYPEID_TEMPLATE = 0x10000000, +
+  asTYPEID_MASK_SEQNBR = 0x03FFFFFF +
+ }
 Type id flags. More...
 
enum  asETypeModifiers {
+  asTM_NONE = 0, +
+  asTM_INREF = 1, +
+  asTM_OUTREF = 2, +
+  asTM_INOUTREF = 3, +
+  asTM_CONST = 4 +
+ }
 Type modifiers. More...
 
enum  asEGMFlags {
+  asGM_ONLY_IF_EXISTS = 0, +
+  asGM_CREATE_IF_NOT_EXISTS = 1, +
+  asGM_ALWAYS_CREATE = 2 +
+ }
 Flags for GetModule. More...
 
enum  asECompileFlags { asCOMP_ADD_TO_MODULE = 1 + }
 Flags for compilation. More...
 
enum  asEFuncType { ,
+  asFUNC_SYSTEM = 0, +
+  asFUNC_SCRIPT = 1, +
+  asFUNC_INTERFACE = 2, +
+  asFUNC_VIRTUAL = 3, +
+  asFUNC_FUNCDEF = 4, +
+  asFUNC_IMPORTED = 5, +
+  asFUNC_DELEGATE = 6 +
+ }
 Function types. More...
 
enum  asEBCInstr {
+  asBC_PopPtr = 0, +
+  asBC_PshGPtr = 1, +
+  asBC_PshC4 = 2, +
+  asBC_PshV4 = 3, +
+  asBC_PSF = 4, +
+  asBC_SwapPtr = 5, +
+  asBC_NOT = 6, +
+  asBC_PshG4 = 7, +
+  asBC_LdGRdR4 = 8, +
+  asBC_CALL = 9, +
+  asBC_RET = 10, +
+  asBC_JMP = 11, +
+  asBC_JZ = 12, +
+  asBC_JNZ = 13, +
+  asBC_JS = 14, +
+  asBC_JNS = 15, +
+  asBC_JP = 16, +
+  asBC_JNP = 17, +
+  asBC_TZ = 18, +
+  asBC_TNZ = 19, +
+  asBC_TS = 20, +
+  asBC_TNS = 21, +
+  asBC_TP = 22, +
+  asBC_TNP = 23, +
+  asBC_NEGi = 24, +
+  asBC_NEGf = 25, +
+  asBC_NEGd = 26, +
+  asBC_INCi16 = 27, +
+  asBC_INCi8 = 28, +
+  asBC_DECi16 = 29, +
+  asBC_DECi8 = 30, +
+  asBC_INCi = 31, +
+  asBC_DECi = 32, +
+  asBC_INCf = 33, +
+  asBC_DECf = 34, +
+  asBC_INCd = 35, +
+  asBC_DECd = 36, +
+  asBC_IncVi = 37, +
+  asBC_DecVi = 38, +
+  asBC_BNOT = 39, +
+  asBC_BAND = 40, +
+  asBC_BOR = 41, +
+  asBC_BXOR = 42, +
+  asBC_BSLL = 43, +
+  asBC_BSRL = 44, +
+  asBC_BSRA = 45, +
+  asBC_COPY = 46, +
+  asBC_PshC8 = 47, +
+  asBC_PshVPtr = 48, +
+  asBC_RDSPtr = 49, +
+  asBC_CMPd = 50, +
+  asBC_CMPu = 51, +
+  asBC_CMPf = 52, +
+  asBC_CMPi = 53, +
+  asBC_CMPIi = 54, +
+  asBC_CMPIf = 55, +
+  asBC_CMPIu = 56, +
+  asBC_JMPP = 57, +
+  asBC_PopRPtr = 58, +
+  asBC_PshRPtr = 59, +
+  asBC_STR = 60, +
+  asBC_CALLSYS = 61, +
+  asBC_CALLBND = 62, +
+  asBC_SUSPEND = 63, +
+  asBC_ALLOC = 64, +
+  asBC_FREE = 65, +
+  asBC_LOADOBJ = 66, +
+  asBC_STOREOBJ = 67, +
+  asBC_GETOBJ = 68, +
+  asBC_REFCPY = 69, +
+  asBC_CHKREF = 70, +
+  asBC_GETOBJREF = 71, +
+  asBC_GETREF = 72, +
+  asBC_PshNull = 73, +
+  asBC_ClrVPtr = 74, +
+  asBC_OBJTYPE = 75, +
+  asBC_TYPEID = 76, +
+  asBC_SetV4 = 77, +
+  asBC_SetV8 = 78, +
+  asBC_ADDSi = 79, +
+  asBC_CpyVtoV4 = 80, +
+  asBC_CpyVtoV8 = 81, +
+  asBC_CpyVtoR4 = 82, +
+  asBC_CpyVtoR8 = 83, +
+  asBC_CpyVtoG4 = 84, +
+  asBC_CpyRtoV4 = 85, +
+  asBC_CpyRtoV8 = 86, +
+  asBC_CpyGtoV4 = 87, +
+  asBC_WRTV1 = 88, +
+  asBC_WRTV2 = 89, +
+  asBC_WRTV4 = 90, +
+  asBC_WRTV8 = 91, +
+  asBC_RDR1 = 92, +
+  asBC_RDR2 = 93, +
+  asBC_RDR4 = 94, +
+  asBC_RDR8 = 95, +
+  asBC_LDG = 96, +
+  asBC_LDV = 97, +
+  asBC_PGA = 98, +
+  asBC_CmpPtr = 99, +
+  asBC_VAR = 100, +
+  asBC_iTOf = 101, +
+  asBC_fTOi = 102, +
+  asBC_uTOf = 103, +
+  asBC_fTOu = 104, +
+  asBC_sbTOi = 105, +
+  asBC_swTOi = 106, +
+  asBC_ubTOi = 107, +
+  asBC_uwTOi = 108, +
+  asBC_dTOi = 109, +
+  asBC_dTOu = 110, +
+  asBC_dTOf = 111, +
+  asBC_iTOd = 112, +
+  asBC_uTOd = 113, +
+  asBC_fTOd = 114, +
+  asBC_ADDi = 115, +
+  asBC_SUBi = 116, +
+  asBC_MULi = 117, +
+  asBC_DIVi = 118, +
+  asBC_MODi = 119, +
+  asBC_ADDf = 120, +
+  asBC_SUBf = 121, +
+  asBC_MULf = 122, +
+  asBC_DIVf = 123, +
+  asBC_MODf = 124, +
+  asBC_ADDd = 125, +
+  asBC_SUBd = 126, +
+  asBC_MULd = 127, +
+  asBC_DIVd = 128, +
+  asBC_MODd = 129, +
+  asBC_ADDIi = 130, +
+  asBC_SUBIi = 131, +
+  asBC_MULIi = 132, +
+  asBC_ADDIf = 133, +
+  asBC_SUBIf = 134, +
+  asBC_MULIf = 135, +
+  asBC_SetG4 = 136, +
+  asBC_ChkRefS = 137, +
+  asBC_ChkNullV = 138, +
+  asBC_CALLINTF = 139, +
+  asBC_iTOb = 140, +
+  asBC_iTOw = 141, +
+  asBC_SetV1 = 142, +
+  asBC_SetV2 = 143, +
+  asBC_Cast = 144, +
+  asBC_i64TOi = 145, +
+  asBC_uTOi64 = 146, +
+  asBC_iTOi64 = 147, +
+  asBC_fTOi64 = 148, +
+  asBC_dTOi64 = 149, +
+  asBC_fTOu64 = 150, +
+  asBC_dTOu64 = 151, +
+  asBC_i64TOf = 152, +
+  asBC_u64TOf = 153, +
+  asBC_i64TOd = 154, +
+  asBC_u64TOd = 155, +
+  asBC_NEGi64 = 156, +
+  asBC_INCi64 = 157, +
+  asBC_DECi64 = 158, +
+  asBC_BNOT64 = 159, +
+  asBC_ADDi64 = 160, +
+  asBC_SUBi64 = 161, +
+  asBC_MULi64 = 162, +
+  asBC_DIVi64 = 163, +
+  asBC_MODi64 = 164, +
+  asBC_BAND64 = 165, +
+  asBC_BOR64 = 166, +
+  asBC_BXOR64 = 167, +
+  asBC_BSLL64 = 168, +
+  asBC_BSRL64 = 169, +
+  asBC_BSRA64 = 170, +
+  asBC_CMPi64 = 171, +
+  asBC_CMPu64 = 172, +
+  asBC_ChkNullS = 173, +
+  asBC_ClrHi = 174, +
+  asBC_JitEntry = 175, +
+  asBC_CallPtr = 176, +
+  asBC_FuncPtr = 177, +
+  asBC_LoadThisR = 178, +
+  asBC_PshV8 = 179, +
+  asBC_DIVu = 180, +
+  asBC_MODu = 181, +
+  asBC_DIVu64 = 182, +
+  asBC_MODu64 = 183, +
+  asBC_LoadRObjR = 184, +
+  asBC_LoadVObjR = 185, +
+  asBC_RefCpyV = 186, +
+  asBC_JLowZ = 187, +
+  asBC_JLowNZ = 188, +
+  asBC_AllocMem = 189, +
+  asBC_SetListSize = 190, +
+  asBC_PshListElmnt = 191, +
+  asBC_SetListType = 192, +
+  asBC_POWi = 193, +
+  asBC_POWu = 194, +
+  asBC_POWf = 195, +
+  asBC_POWd = 196, +
+  asBC_POWdi = 197, +
+  asBC_POWi64 = 198, +
+  asBC_POWu64 = 199, +
+  asBC_Thiscall1 = 200 +
+ }
 The bytecode instructions used by the VM. More...
 
enum  asEBCType { ,
+  asBCTYPE_NO_ARG = 1, +
+  asBCTYPE_W_ARG = 2, +
+  asBCTYPE_wW_ARG = 3, +
+  asBCTYPE_DW_ARG = 4, +
+  asBCTYPE_rW_DW_ARG = 5, +
+  asBCTYPE_QW_ARG = 6, +
+  asBCTYPE_DW_DW_ARG = 7, +
+  asBCTYPE_wW_rW_rW_ARG = 8, +
+  asBCTYPE_wW_QW_ARG = 9, +
+  asBCTYPE_wW_rW_ARG = 10, +
+  asBCTYPE_rW_ARG = 11, +
+  asBCTYPE_wW_DW_ARG = 12, +
+  asBCTYPE_wW_rW_DW_ARG = 13, +
+  asBCTYPE_rW_rW_ARG = 14, +
+  asBCTYPE_wW_W_ARG = 15, +
+  asBCTYPE_QW_DW_ARG = 16, +
+  asBCTYPE_rW_QW_ARG = 17, +
+  asBCTYPE_W_DW_ARG = 18, +
+  asBCTYPE_rW_W_DW_ARG = 19, +
+  asBCTYPE_rW_DW_DW_ARG = 20 +
+ }
 Describes the structure of a bytecode instruction. More...
 
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

AS_API asIScriptEngineasCreateScriptEngine (asDWORD version=ANGELSCRIPT_VERSION)
 Creates the script engine. More...
 
AS_API const char * asGetLibraryVersion ()
 Returns the version of the compiled library. More...
 
AS_API const char * asGetLibraryOptions ()
 Returns the options used to compile the library. More...
 
AS_API asIScriptContextasGetActiveContext ()
 Returns the currently active context. More...
 
AS_API int asPrepareMultithread (asIThreadManager *externalMgr=0)
 Sets up the internally shared resources for multithreading. More...
 
AS_API void asUnprepareMultithread ()
 Frees resources prepared for multithreading. More...
 
AS_API asIThreadManagerasGetThreadManager ()
 Get the thread manager used by the application. More...
 
AS_API void asAcquireExclusiveLock ()
 Acquire an exclusive lock. More...
 
AS_API void asReleaseExclusiveLock ()
 Release an exclusive lock. More...
 
AS_API void asAcquireSharedLock ()
 Acquire a shared lock. More...
 
AS_API void asReleaseSharedLock ()
 Release a shared lock. More...
 
AS_API int asAtomicInc (int &value)
 Increments the value by one and returns the result as a single atomic instruction. More...
 
AS_API int asAtomicDec (int &value)
 Decrements the value by one and returns the result as a single atomic instruction. More...
 
AS_API int asThreadCleanup ()
 Cleans up memory allocated for the current thread. More...
 
AS_API int asSetGlobalMemoryFunctions (asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc)
 Set the memory management functions that AngelScript should use. More...
 
AS_API int asResetGlobalMemoryFunctions ()
 Remove previously registered memory management functions. More...
 
AS_API void * asAllocMem (size_t size)
 Allocate memory using the memory function registered with AngelScript. More...
 
AS_API void asFreeMem (void *mem)
 Deallocates memory using the memory function registered with AngelScript. More...
 
AS_API asILockableSharedBoolasCreateLockableSharedBool ()
 Create a lockable shared boolean. More...
 
template<typename T >
asUINT asGetTypeTraits ()
 Returns the appropriate flags for use with RegisterObjectType. More...
 
+ + + + + + + +

+Variables

+const int asBCTypeSize [21]
 Lookup table for determining the size of each type of bytecode instruction.
 
+const asSBCInfo asBCInfo [256]
 Information on each bytecode instruction.
 
+

Detailed Description

+

This header file describes the complete application programming interface for AngelScript.

+

Typedef Documentation

+ +

◆ asJITFunction

+ +
+
+ + + + +
typedef void(* asJITFunction) (asSVMRegisters *registers, asPWORD jitArg)
+
+
Parameters
+ + + +
[in]registersA pointer to the virtual machine's registers.
[in]jitArgThe value defined by the JIT compiler for the current entry point in the JIT function.
+
+
+

A JIT function receives a pointer to the virtual machine's registers when called and an argument telling it where in the script function to continue the execution. The JIT function must make sure to update the VM's registers according to the actions performed before returning control to the VM.

+
See also
How to build a JIT compiler
+ +
+
+

Enumeration Type Documentation

+ +

◆ asEBCInstr

+ +
+
+ + + + +
enum asEBCInstr
+
+
See also
Byte code instructions
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
asBC_PopPtr 

Removes a pointer from the stack.

+
asBC_PshGPtr 

Pushes a pointer from a global variable onto the stack.

+
asBC_PshC4 

Push the 32bit value in the argument onto the stack.

+
asBC_PshV4 

Push the 32bit value from a variable onto the stack.

+
asBC_PSF 

Push the address of the stack frame onto the stack.

+
asBC_SwapPtr 

Swap the top two pointers on the stack.

+
asBC_NOT 

Perform a boolean not on the value in a variable.

+
asBC_PshG4 

Push the 32bit value from a global variable onto the stack.

+
asBC_LdGRdR4 

Perform the actions of asBC_LDG followed by asBC_RDR4.

+
asBC_CALL 

Jump to a script function, indexed by the argument.

+
asBC_RET 

Return to the instruction after the last executed call.

+
asBC_JMP 

Unconditional jump to a relative position in this function.

+
asBC_JZ 

If the value register is 0 jump to a relative position in this function.

+
asBC_JNZ 

If the value register is not 0 jump to a relative position in this function.

+
asBC_JS 

If the value register is less than 0 jump to a relative position in this function.

+
asBC_JNS 

If the value register is greater than or equal to 0 jump to a relative position in this function.

+
asBC_JP 

If the value register is greater than 0 jump to a relative position in this function.

+
asBC_JNP 

If the value register is less than or equal to 0 jump to a relative position in this function.

+
asBC_TZ 

If the value register is 0 set it to 1.

+
asBC_TNZ 

If the value register is not 0 set it to 1.

+
asBC_TS 

If the value register is less than 0 set it to 1.

+
asBC_TNS 

If the value register is greater than or equal to 0 set it to 1.

+
asBC_TP 

If the value register is greater than 0 set it to 1.

+
asBC_TNP 

If the value register is less than or equal to 0 set it to 1.

+
asBC_NEGi 

Negate the 32bit integer value in the variable.

+
asBC_NEGf 

Negate the float value in the variable.

+
asBC_NEGd 

Negate the double value in the variable.

+
asBC_INCi16 

Increment the 16bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_INCi8 

Increment the 8bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_DECi16 

Decrement the 16bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_DECi8 

Increment the 8bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_INCi 

Increment the 32bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_DECi 

Decrement the 32bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_INCf 

Increment the float value that is stored at the address pointed to by the reference in the value register.

+
asBC_DECf 

Decrement the float value that is stored at the address pointed to by the reference in the value register.

+
asBC_INCd 

Increment the double value that is stored at the address pointed to by the reference in the value register.

+
asBC_DECd 

Decrement the double value that is stored at the address pointed to by the reference in the value register.

+
asBC_IncVi 

Increment the 32bit integer value in the variable.

+
asBC_DecVi 

Decrement the 32bit integer value in the variable.

+
asBC_BNOT 

Perform a bitwise complement on the 32bit value in the variable.

+
asBC_BAND 

Perform a bitwise and of two 32bit values and store the result in a third variable.

+
asBC_BOR 

Perform a bitwise or of two 32bit values and store the result in a third variable.

+
asBC_BXOR 

Perform a bitwise exclusive or of two 32bit values and store the result in a third variable.

+
asBC_BSLL 

Perform a logical left shift of a 32bit value and store the result in a third variable.

+
asBC_BSRL 

Perform a logical right shift of a 32bit value and store the result in a third variable.

+
asBC_BSRA 

Perform a arithmetical right shift of a 32bit value and store the result in a third variable.

+
asBC_COPY 

Pop the destination and source addresses from the stack. Perform a bitwise copy of the referred object. Push the destination address on the stack.

+
asBC_PshC8 

Push a 64bit value on the stack.

+
asBC_PshVPtr 

Push a pointer from the variable on the stack.

+
asBC_RDSPtr 

Pop top address, read a pointer from it, and push the pointer onto the stack.

+
asBC_CMPd 

Compare two double variables and store the result in the value register.

+
asBC_CMPu 

Compare two unsigned 32bit integer variables and store the result in the value register.

+
asBC_CMPf 

Compare two float variables and store the result in the value register.

+
asBC_CMPi 

Compare two 32bit integer variables and store the result in the value register.

+
asBC_CMPIi 

Compare 32bit integer variable with constant and store the result in value register.

+
asBC_CMPIf 

Compare float variable with constant and store the result in value register.

+
asBC_CMPIu 

Compare unsigned 32bit integer variable with constant and store the result in value register.

+
asBC_JMPP 

Jump to relative position in the function where the offset is stored in a variable.

+
asBC_PopRPtr 

Pop a pointer from the stack and store it in the value register.

+
asBC_PshRPtr 

Push a pointer from the value register onto the stack.

+
asBC_STR 

Not used.

+
asBC_CALLSYS 

Call registered function. Suspend further execution if requested.

+
asBC_CALLBND 

Jump to an imported script function, indexed by the argument.

+
asBC_SUSPEND 

Call line callback function if set. Suspend execution if requested.

+
asBC_ALLOC 

Allocate the memory for the object. If the type is a script object then jump to the constructor, else call the registered constructor behaviour. Suspend further execution if requested.

+
asBC_FREE 

Pop the address of the object variable from the stack. If ref type, call the release method, else call the destructor then free the memory. Clear the pointer in the variable.

+
asBC_LOADOBJ 

Copy the object pointer from a variable to the object register. Clear the variable.

+
asBC_STOREOBJ 

Copy the object pointer from the object register to the variable. Clear the object register.

+
asBC_GETOBJ 

Move object pointer from variable onto stack location.

+
asBC_REFCPY 

Pop destination handle reference. Perform a handle assignment, while updating the reference count for both previous and new objects.

+
asBC_CHKREF 

Throw an exception if the pointer on the top of the stack is null.

+
asBC_GETOBJREF 

Replace a variable index on the stack with the object handle stored in that variable.

+
asBC_GETREF 

Replace a variable index on the stack with the address of the variable.

+
asBC_PshNull 

Push a null pointer on the stack.

+
asBC_ClrVPtr 

Clear pointer in a variable.

+
asBC_OBJTYPE 

Push the pointer argument onto the stack. The pointer is a pointer to an object type structure.

+
asBC_TYPEID 

Push the type id onto the stack. Equivalent to PshC4.

+
asBC_SetV4 

Initialize the variable with a DWORD.

+
asBC_SetV8 

Initialize the variable with a QWORD.

+
asBC_ADDSi 

Add a value to the top pointer on the stack, thus updating the address itself.

+
asBC_CpyVtoV4 

Copy a DWORD from one variable to another.

+
asBC_CpyVtoV8 

Copy a QWORD from one variable to another.

+
asBC_CpyVtoR4 

Copy a DWORD from a variable into the value register.

+
asBC_CpyVtoR8 

Copy a QWORD from a variable into the value register.

+
asBC_CpyVtoG4 

Copy a DWORD from a local variable to a global variable.

+
asBC_CpyRtoV4 

Copy a DWORD from the value register into a variable.

+
asBC_CpyRtoV8 

Copy a QWORD from the value register into a variable.

+
asBC_CpyGtoV4 

Copy a DWORD from a global variable to a local variable.

+
asBC_WRTV1 

Copy a BYTE from a variable to the address held in the value register.

+
asBC_WRTV2 

Copy a WORD from a variable to the address held in the value register.

+
asBC_WRTV4 

Copy a DWORD from a variable to the address held in the value register.

+
asBC_WRTV8 

Copy a QWORD from a variable to the address held in the value register.

+
asBC_RDR1 

Copy a BYTE from address held in the value register to a variable. Clear the top bytes in the variable.

+
asBC_RDR2 

Copy a WORD from address held in the value register to a variable. Clear the top word in the variable.

+
asBC_RDR4 

Copy a DWORD from address held in the value register to a variable.

+
asBC_RDR8 

Copy a QWORD from address held in the value register to a variable.

+
asBC_LDG 

Load the address of a global variable into the value register.

+
asBC_LDV 

Load the address of a local variable into the value register.

+
asBC_PGA 

Push the address of a global variable on the stack.

+
asBC_CmpPtr 

Compare two pointers.

+
asBC_VAR 

Push the index of the variable on the stack, with the size of a pointer.

+
asBC_iTOf 

Convert the 32bit integer value to a float in the variable.

+
asBC_fTOi 

Convert the float value to a 32bit integer in the variable.

+
asBC_uTOf 

Convert the unsigned 32bit integer value to a float in the variable.

+
asBC_fTOu 

Convert the float value to an unsigned 32bit integer in the variable.

+
asBC_sbTOi 

Expand the low byte as a signed value to a full 32bit integer in the variable.

+
asBC_swTOi 

Expand the low word as a signed value to a full 32bit integer in the variable.

+
asBC_ubTOi 

Expand the low byte as an unsigned value to a full 32bit integer in the variable.

+
asBC_uwTOi 

Expand the low word as an unsigned value to a full 32bit integer in the variable.

+
asBC_dTOi 

Convert the double value in one variable to a 32bit integer in another variable.

+
asBC_dTOu 

Convert the double value in one variable to a 32bit unsigned integer in another variable.

+
asBC_dTOf 

Convert the double value in one variable to a float in another variable.

+
asBC_iTOd 

Convert the 32bit integer value in one variable to a double in another variable.

+
asBC_uTOd 

Convert the 32bit unsigned integer value in one variable to a double in another variable.

+
asBC_fTOd 

Convert the float value in one variable to a double in another variable.

+
asBC_ADDi 

Add the values of two 32bit integer variables and store in a third variable.

+
asBC_SUBi 

Subtract the values of two 32bit integer variables and store in a third variable.

+
asBC_MULi 

Multiply the values of two 32bit integer variables and store in a third variable.

+
asBC_DIVi 

Divide the values of two 32bit integer variables and store in a third variable.

+
asBC_MODi 

Calculate the modulo of values of two 32bit integer variables and store in a third variable.

+
asBC_ADDf 

Add the values of two float variables and store in a third variable.

+
asBC_SUBf 

Subtract the values of two float variables and store in a third variable.

+
asBC_MULf 

Multiply the values of two float variables and store in a third variable.

+
asBC_DIVf 

Divide the values of two float variables and store in a third variable.

+
asBC_MODf 

Calculate the modulo of values of two float variables and store in a third variable.

+
asBC_ADDd 

Add the values of two double variables and store in a third variable.

+
asBC_SUBd 

Subtract the values of two double variables and store in a third variable.

+
asBC_MULd 

Multiply the values of two double variables and store in a third variable.

+
asBC_DIVd 

Divide the values of two double variables and store in a third variable.

+
asBC_MODd 

Calculate the modulo of values of two double variables and store in a third variable.

+
asBC_ADDIi 

Add a 32bit integer variable with a constant value and store the result in another variable.

+
asBC_SUBIi 

Subtract a 32bit integer variable with a constant value and store the result in another variable.

+
asBC_MULIi 

Multiply a 32bit integer variable with a constant value and store the result in another variable.

+
asBC_ADDIf 

Add a float variable with a constant value and store the result in another variable.

+
asBC_SUBIf 

Subtract a float variable with a constant value and store the result in another variable.

+
asBC_MULIf 

Multiply a float variable with a constant value and store the result in another variable.

+
asBC_SetG4 

Set the value of global variable to a 32bit word.

+
asBC_ChkRefS 

Throw an exception if the address stored on the stack points to a null pointer.

+
asBC_ChkNullV 

Throw an exception if the variable is null.

+
asBC_CALLINTF 

Jump to an interface method, indexed by the argument.

+
asBC_iTOb 

Convert a 32bit integer in a variable to a byte, clearing the top bytes.

+
asBC_iTOw 

Convert a 32bit integer in a variable to a word, clearing the top word.

+
asBC_SetV1 

Same as SetV4.

+
asBC_SetV2 

Same as SetV4.

+
asBC_Cast 

Pop an object handle to a script class from the stack. Perform a dynamic cast on it and store the result in the object register.

+
asBC_i64TOi 

Convert the 64bit integer value in one variable to a 32bit integer in another variable.

+
asBC_uTOi64 

Convert the 32bit unsigned integer value in one variable to a 64bit integer in another variable.

+
asBC_iTOi64 

Convert the 32bit integer value in one variable to a 64bit integer in another variable.

+
asBC_fTOi64 

Convert the float value in one variable to a 64bit integer in another variable.

+
asBC_dTOi64 

Convert the double value in the variable to a 64bit integer.

+
asBC_fTOu64 

Convert the float value in one variable to a 64bit unsigned integer in another variable.

+
asBC_dTOu64 

Convert the double value in the variable to a 64bit unsigned integer.

+
asBC_i64TOf 

Convert the 64bit integer value in one variable to a float in another variable.

+
asBC_u64TOf 

Convert the 64bit unsigned integer value in one variable to a float in another variable.

+
asBC_i64TOd 

Convert the 32bit integer value in the variable to a double.

+
asBC_u64TOd 

Convert the 32bit unsigned integer value in the variable to a double.

+
asBC_NEGi64 

Negate the 64bit integer value in the variable.

+
asBC_INCi64 

Increment the 64bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_DECi64 

Decrement the 64bit integer value that is stored at the address pointed to by the reference in the value register.

+
asBC_BNOT64 

Perform a bitwise complement on the 64bit value in the variable.

+
asBC_ADDi64 

Perform an addition with two 64bit integer variables and store the result in a third variable.

+
asBC_SUBi64 

Perform a subtraction with two 64bit integer variables and store the result in a third variable.

+
asBC_MULi64 

Perform a multiplication with two 64bit integer variables and store the result in a third variable.

+
asBC_DIVi64 

Perform a division with two 64bit integer variables and store the result in a third variable.

+
asBC_MODi64 

Perform the modulo operation with two 64bit integer variables and store the result in a third variable.

+
asBC_BAND64 

Perform a bitwise and of two 64bit values and store the result in a third variable.

+
asBC_BOR64 

Perform a bitwise or of two 64bit values and store the result in a third variable.

+
asBC_BXOR64 

Perform a bitwise exclusive or of two 64bit values and store the result in a third variable.

+
asBC_BSLL64 

Perform a logical left shift of a 64bit value and store the result in a third variable.

+
asBC_BSRL64 

Perform a logical right shift of a 64bit value and store the result in a third variable.

+
asBC_BSRA64 

Perform a arithmetical right shift of a 64bit value and store the result in a third variable.

+
asBC_CMPi64 

Compare two 64bit integer variables and store the result in the value register.

+
asBC_CMPu64 

Compare two unsigned 64bit integer variables and store the result in the value register.

+
asBC_ChkNullS 

Check if a pointer on the stack is null, and if it is throw an exception. The argument is relative to the top of the stack.

+
asBC_ClrHi 

Clear the upper bytes of the value register so that only the value in the lowest byte is kept.

+
asBC_JitEntry 

If a JIT function is available and the argument is not 0 then call the JIT function.

+
asBC_CallPtr 

Call a function stored in a local function pointer.

+
asBC_FuncPtr 

Push a function pointer on the stack.

+
asBC_LoadThisR 

Load the address to a property of the local object into the stack. PshV4 0, ADDSi x, PopRPtr.

+
asBC_PshV8 

Push the 64bit value from a variable onto the stack.

+
asBC_DIVu 

Divide the values of two 32bit unsigned integer variables and store in a third variable.

+
asBC_MODu 

Calculate the modulo of values of two 32bit unsigned integer variables and store in a third variable.

+
asBC_DIVu64 

Divide the values of two 64bit unsigned integer variables and store in a third variable.

+
asBC_MODu64 

Calculate the modulo of values of two 64bit unsigned integer variables and store in a third variable.

+
asBC_LoadRObjR 

Load address of member of reference object into register.

+
asBC_LoadVObjR 

Load address of member of value object into register.

+
asBC_RefCpyV 

Copies a handle to a variable.

+
asBC_JLowZ 

Jump if low byte of value register is 0.

+
asBC_JLowNZ 

Jump if low byte of value register is not 0.

+
asBC_AllocMem 

Allocates memory for an initialization list buffer.

+
asBC_SetListSize 

Sets a repeat count in the list buffer.

+
asBC_PshListElmnt 

Pushes the address of an element in the list buffer on the stack.

+
asBC_SetListType 

Sets the type of the next element in the list buffer.

+
asBC_POWi 

Computes the power of for two int values.

+
asBC_POWu 

Computes the power of for two uint values.

+
asBC_POWf 

Computes the power of for two float values.

+
asBC_POWd 

Computes the power of for two double values.

+
asBC_POWdi 

Computes the power of where base is a double and exponent is an int value.

+
asBC_POWi64 

Computes the power of for two int64 values.

+
asBC_POWu64 

Computes the power of for two uint64 values.

+
asBC_Thiscall1 

Call registered function with single 32bit integer argument. Suspend further execution if requested.

+
+ +
+
+ +

◆ asEBCType

+ +
+
+ + + + +
enum asEBCType
+
+ + + + + + + + + + + + + + + + + + + + + +
Enumerator
asBCTYPE_NO_ARG 

Instruction + no args.

+
asBCTYPE_W_ARG 

Instruction + WORD arg.

+
asBCTYPE_wW_ARG 

Instruction + WORD arg (dest var)

+
asBCTYPE_DW_ARG 

Instruction + DWORD arg.

+
asBCTYPE_rW_DW_ARG 

Instruction + WORD arg (source var) + DWORD arg.

+
asBCTYPE_QW_ARG 

Instruction + QWORD arg.

+
asBCTYPE_DW_DW_ARG 

Instruction + DWORD arg + DWORD arg.

+
asBCTYPE_wW_rW_rW_ARG 

Instruction + WORD arg (dest var) + WORD arg (source var) + WORD arg (source var)

+
asBCTYPE_wW_QW_ARG 

Instruction + WORD arg (dest var) + QWORD arg.

+
asBCTYPE_wW_rW_ARG 

Instruction + WORD arg (dest var) + WORD arg (source var)

+
asBCTYPE_rW_ARG 

Instruction + WORD arg (source var)

+
asBCTYPE_wW_DW_ARG 

Instruction + WORD arg (dest var) + DWORD arg.

+
asBCTYPE_wW_rW_DW_ARG 

Instruction + WORD arg (dest var) + WORD arg (source var) + DWORD arg.

+
asBCTYPE_rW_rW_ARG 

Instruction + WORD arg (source var) + WORD arg (source var)

+
asBCTYPE_wW_W_ARG 

Instruction + WORD arg (dest var) + WORD arg.

+
asBCTYPE_QW_DW_ARG 

Instruction + QWORD arg + DWORD arg.

+
asBCTYPE_rW_QW_ARG 

Instruction + WORD arg (source var) + QWORD arg.

+
asBCTYPE_W_DW_ARG 

Instruction + WORD arg + DWORD arg.

+
asBCTYPE_rW_W_DW_ARG 

Instruction + WORD arg(source var) + WORD arg + DWORD arg.

+
asBCTYPE_rW_DW_DW_ARG 

Instruction + WORD arg(source var) + DWORD arg + DWORD arg.

+
+ +
+
+ +

◆ asEBehaviours

+ +
+
+ + + + +
enum asEBehaviours
+
+ + + + + + + + + + + + + + + +
Enumerator
asBEHAVE_CONSTRUCT 

Constructor.

+
asBEHAVE_LIST_CONSTRUCT 

Constructor used exclusively for initialization lists.

+
asBEHAVE_DESTRUCT 

Destructor.

+
asBEHAVE_FACTORY 

Factory.

+
asBEHAVE_LIST_FACTORY 

Factory used exclusively for initialization lists.

+
asBEHAVE_ADDREF 

AddRef.

+
asBEHAVE_RELEASE 

Release.

+
asBEHAVE_GET_WEAKREF_FLAG 

Obtain weak ref flag.

+
asBEHAVE_TEMPLATE_CALLBACK 

Callback for validating template instances.

+
asBEHAVE_GETREFCOUNT 

(GC) Get reference count

+
asBEHAVE_SETGCFLAG 

(GC) Set GC flag

+
asBEHAVE_GETGCFLAG 

(GC) Get GC flag

+
asBEHAVE_ENUMREFS 

(GC) Enumerate held references

+
asBEHAVE_RELEASEREFS 

(GC) Release all references

+
+ +
+
+ +

◆ asECallConvTypes

+ +
+
+ + + + +
enum asECallConvTypes
+
+ + + + + + + + + + +
Enumerator
asCALL_CDECL 

A cdecl function.

+
asCALL_STDCALL 

A stdcall function.

+
asCALL_THISCALL_ASGLOBAL 

A thiscall class method registered as a global function.

+
asCALL_THISCALL 

A thiscall class method.

+
asCALL_CDECL_OBJLAST 

A cdecl function that takes the object pointer as the last parameter.

+
asCALL_CDECL_OBJFIRST 

A cdecl function that takes the object pointer as the first parameter.

+
asCALL_GENERIC 

A function using the generic calling convention.

+
asCALL_THISCALL_OBJLAST 

A thiscall class method registered as a functor object.

+
asCALL_THISCALL_OBJFIRST 

A thiscall class method registered as a functor object.

+
+ +
+
+ +

◆ asECompileFlags

+ +
+
+ + + + +
enum asECompileFlags
+
+ + +
Enumerator
asCOMP_ADD_TO_MODULE 

The compiled function should be added to the scope of the module.

+
+ +
+
+ +

◆ asEContextState

+ +
+
+ + + + +
enum asEContextState
+
+ + + + + + + + + +
Enumerator
asEXECUTION_FINISHED 

The context has successfully completed the execution.

+
asEXECUTION_SUSPENDED 

The execution is suspended and can be resumed.

+
asEXECUTION_ABORTED 

The execution was aborted by the application.

+
asEXECUTION_EXCEPTION 

The execution was terminated by an unhandled script exception.

+
asEXECUTION_PREPARED 

The context has been prepared for a new execution.

+
asEXECUTION_UNINITIALIZED 

The context is not initialized.

+
asEXECUTION_ACTIVE 

The context is currently executing a function call.

+
asEXECUTION_ERROR 

The context has encountered an error and must be reinitialized.

+
+ +
+
+ +

◆ asEEngineProp

+ +
+
+ + + + +
enum asEEngineProp
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
asEP_ALLOW_UNSAFE_REFERENCES 

Allow unsafe references. Default: false.

+
asEP_OPTIMIZE_BYTECODE 

Optimize byte code. Default: true.

+
asEP_COPY_SCRIPT_SECTIONS 

Copy script section memory. Default: true.

+
asEP_MAX_STACK_SIZE 

Maximum stack size in bytes for script contexts. Default: 0 (no limit).

+
asEP_USE_CHARACTER_LITERALS 

Interpret single quoted strings as character literals. Default: false.

+
asEP_ALLOW_MULTILINE_STRINGS 

Allow linebreaks in string constants. Default: false.

+
asEP_ALLOW_IMPLICIT_HANDLE_TYPES 

Allow script to declare implicit handle types. Default: false.

+
asEP_BUILD_WITHOUT_LINE_CUES 

Remove SUSPEND instructions between each statement. Default: false.

+
asEP_INIT_GLOBAL_VARS_AFTER_BUILD 

Initialize global variables after a build. Default: true.

+
asEP_REQUIRE_ENUM_SCOPE 

When set the enum values must be prefixed with the enum type. Default: false.

+
asEP_SCRIPT_SCANNER 

Select scanning method: 0 - ASCII, 1 - UTF8. Default: 1 (UTF8).

+
asEP_INCLUDE_JIT_INSTRUCTIONS 

When set extra bytecode instructions needed for JIT compiled funcions will be included. Default: false.

+
asEP_STRING_ENCODING 

Select string encoding for literals: 0 - UTF8/ASCII, 1 - UTF16. Default: 0 (UTF8)

+
asEP_PROPERTY_ACCESSOR_MODE 

Enable or disable property accessors: 0 - no accessors, 1 - app registered accessors only, property keyword optional, 2 - app and script created accessors, property keyword optional, 3 - app and script created accesors, property keyword required. Default: 3.

+
asEP_EXPAND_DEF_ARRAY_TO_TMPL 

Format default array in template form in messages and declarations. Default: false.

+
asEP_AUTO_GARBAGE_COLLECT 

Enable or disable automatic garbage collection. Default: true.

+
asEP_DISALLOW_GLOBAL_VARS 

Disallow the use of global variables in the script. Default: false.

+
asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT 

When true, the compiler will always provide a default constructor for script classes. Default: false.

+
asEP_COMPILER_WARNINGS 

Set how warnings should be treated: 0 - dismiss, 1 - emit, 2 - treat as error.

+
asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE 

Disallow value assignment for reference types to avoid ambiguity. Default: false.

+
asEP_ALTER_SYNTAX_NAMED_ARGS 

Change the script syntax for named arguments: 0 - no change, 1 - accept '=' but warn, 2 - accept '=' without warning. Default: 0.

+
asEP_DISABLE_INTEGER_DIVISION 

When true, the / and /= operators will perform floating-point division (i.e. 1/2 = 0.5 instead of 0). Default: false.

+
asEP_DISALLOW_EMPTY_LIST_ELEMENTS 

When true, the initialization lists may not contain empty elements. Default: false.

+
asEP_PRIVATE_PROP_AS_PROTECTED 

When true, private properties behave like protected properties. Default: false.

+
asEP_ALLOW_UNICODE_IDENTIFIERS 

When true, the compiler will not give an error if identifiers contain characters with byte value above 127, thus permit identifiers to contain international characters. Default: false.

+
asEP_HEREDOC_TRIM_MODE 

Define how heredoc strings will be trimmed by the compiler: 0 - never trim, 1 - trim if multiple lines, 2 - always trim. Default: 1.

+
asEP_MAX_NESTED_CALLS 

Define the maximum number of nested calls the script engine will allow. Default: 100.

+
asEP_GENERIC_CALL_MODE 

Define how generic calling convention treats handles: 0 - ignore auto handles, 1 - treat them the same way as native calling convention. Default: 1.

+
asEP_INIT_STACK_SIZE 

Initial stack size in bytes for script contexts. Default: 4096.

+
asEP_INIT_CALL_STACK_SIZE 

Initial call stack size for script contexts. Default: 10.

+
asEP_MAX_CALL_STACK_SIZE 

Maximum call stack size for script contexts. Default: 0 (no limit)

+
+ +
+
+ +

◆ asEFuncType

+ +
+
+ + + + +
enum asEFuncType
+
+ + + + + + + + +
Enumerator
asFUNC_SYSTEM 

An application registered function.

+
asFUNC_SCRIPT 

A script implemented function.

+
asFUNC_INTERFACE 

An interface method.

+
asFUNC_VIRTUAL 

A virtual method for script classes.

+
asFUNC_FUNCDEF 

A function definition.

+
asFUNC_IMPORTED 

An imported function.

+
asFUNC_DELEGATE 

A function delegate.

+
+ +
+
+ +

◆ asEGCFlags

+ +
+
+ + + + +
enum asEGCFlags
+
+ + + + + +
Enumerator
asGC_FULL_CYCLE 

Execute a full cycle.

+
asGC_ONE_STEP 

Execute only one step.

+
asGC_DESTROY_GARBAGE 

Destroy known garbage.

+
asGC_DETECT_GARBAGE 

Detect garbage with circular references.

+
+ +
+
+ +

◆ asEGMFlags

+ +
+
+ + + + +
enum asEGMFlags
+
+ + + + +
Enumerator
asGM_ONLY_IF_EXISTS 

Don't return any module if it is not found.

+
asGM_CREATE_IF_NOT_EXISTS 

Create the module if it doesn't exist.

+
asGM_ALWAYS_CREATE 

Always create a new module, discarding the existing one.

+
+ +
+
+ +

◆ asEMsgType

+ +
+
+ + + + +
enum asEMsgType
+
+ + + + +
Enumerator
asMSGTYPE_ERROR 

The message is an error.

+
asMSGTYPE_WARNING 

The message is a warning.

+
asMSGTYPE_INFORMATION 

The message is informational only.

+
+ +
+
+ +

◆ asEObjTypeFlags

+ +
+
+ + + + +
enum asEObjTypeFlags
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
asOBJ_REF 

A reference type.

+
asOBJ_VALUE 

A value type.

+
asOBJ_GC 

A garbage collected type. Only valid for reference types.

+
asOBJ_POD 

A plain-old-data type. Only valid for value types.

+
asOBJ_NOHANDLE 

This reference type doesn't allow handles to be held. Only valid for reference types.

+
asOBJ_SCOPED 

The life time of objects of this type are controlled by the scope of the variable. Only valid for reference types.

+
asOBJ_TEMPLATE 

A template type.

+
asOBJ_ASHANDLE 

The value type should be treated as a handle.

+
asOBJ_APP_CLASS 

The C++ type is a class type. Only valid for value types.

+
asOBJ_APP_CLASS_CONSTRUCTOR 

The C++ class has an explicit constructor. Only valid for value types.

+
asOBJ_APP_CLASS_DESTRUCTOR 

The C++ class has an explicit destructor. Only valid for value types.

+
asOBJ_APP_CLASS_ASSIGNMENT 

The C++ class has an explicit assignment operator. Only valid for value types.

+
asOBJ_APP_CLASS_COPY_CONSTRUCTOR 

The C++ class has an explicit copy constructor. Only valid for value types.

+
asOBJ_APP_CLASS_C 

The C++ type is a class with a constructor.

+
asOBJ_APP_CLASS_CD 

The C++ type is a class with a constructor and destructor.

+
asOBJ_APP_CLASS_CA 

The C++ type is a class with a constructor and assignment operator.

+
asOBJ_APP_CLASS_CK 

The C++ type is a class with a constructor and copy constructor.

+
asOBJ_APP_CLASS_CDA 

The C++ type is a class with a constructor, destructor, and assignment operator.

+
asOBJ_APP_CLASS_CDK 

The C++ type is a class with a constructor, destructor, and copy constructor.

+
asOBJ_APP_CLASS_CAK 

The C++ type is a class with a constructor, assignment operator, and copy constructor.

+
asOBJ_APP_CLASS_CDAK 

The C++ type is a class with a constructor, destructor, assignment operator, and copy constructor.

+
asOBJ_APP_CLASS_D 

The C++ type is a class with a destructor.

+
asOBJ_APP_CLASS_DA 

The C++ type is a class with a destructor and assignment operator.

+
asOBJ_APP_CLASS_DK 

The C++ type is a class with a destructor and copy constructor.

+
asOBJ_APP_CLASS_DAK 

The C++ type is a class with a destructor, assignment operator, and copy constructor.

+
asOBJ_APP_CLASS_A 

The C++ type is a class with an assignment operator.

+
asOBJ_APP_CLASS_AK 

The C++ type is a class with an assignment operator and copy constructor.

+
asOBJ_APP_CLASS_K 

The C++ type is a class with a copy constructor.

+
asOBJ_APP_CLASS_MORE_CONSTRUCTORS 

The C++ class has additional constructors beyond the default and copy constructors.

+
asOBJ_APP_PRIMITIVE 

The C++ type is a primitive type. Only valid for value types.

+
asOBJ_APP_FLOAT 

The C++ type is a float or double. Only valid for value types.

+
asOBJ_APP_ARRAY 

The C++ type is a static array. Only valid for value types.

+
asOBJ_APP_CLASS_ALLINTS 

The C++ class can be treated as if all its members are integers.

+
asOBJ_APP_CLASS_ALLFLOATS 

The C++ class can be treated as if all its members are floats or doubles.

+
asOBJ_NOCOUNT 

The type doesn't use reference counting. Only valid for reference types.

+
asOBJ_APP_CLASS_ALIGN8 

The C++ class contains types that may require 8byte alignment. Only valid for value types.

+
asOBJ_IMPLICIT_HANDLE 

The object is declared for implicit handle. Only valid for reference types.

+
asOBJ_MASK_VALID_FLAGS 

This mask shows which flags are value for RegisterObjectType.

+
asOBJ_SCRIPT_OBJECT 

The object is a script class or an interface.

+
asOBJ_SHARED 

Type object type is shared between modules.

+
asOBJ_NOINHERIT 

The object type is marked as final and cannot be inherited.

+
asOBJ_FUNCDEF 

The type is a script funcdef.

+
asOBJ_LIST_PATTERN 

Internal type. Do not use.

+
asOBJ_ENUM 

The type is an enum.

+
asOBJ_TEMPLATE_SUBTYPE 

Internal type. Do no use.

+
asOBJ_TYPEDEF 

The type is a typedef.

+
asOBJ_ABSTRACT 

The class is abstract, i.e. cannot be instantiated.

+
asOBJ_APP_ALIGN16 

Reserved for future use.

+
+ +
+
+ +

◆ asERetCodes

+ +
+
+ + + + +
enum asERetCodes
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Enumerator
asSUCCESS 

Success.

+
asERROR 

Failure.

+
asCONTEXT_ACTIVE 

The context is active.

+
asCONTEXT_NOT_FINISHED 

The context is not finished.

+
asCONTEXT_NOT_PREPARED 

The context is not prepared.

+
asINVALID_ARG 

Invalid argument.

+
asNO_FUNCTION 

The function was not found.

+
asNOT_SUPPORTED 

Not supported.

+
asINVALID_NAME 

Invalid name.

+
asNAME_TAKEN 

The name is already taken.

+
asINVALID_DECLARATION 

Invalid declaration.

+
asINVALID_OBJECT 

Invalid object.

+
asINVALID_TYPE 

Invalid type.

+
asALREADY_REGISTERED 

Already registered.

+
asMULTIPLE_FUNCTIONS 

Multiple matching functions.

+
asNO_MODULE 

The module was not found.

+
asNO_GLOBAL_VAR 

The global variable was not found.

+
asINVALID_CONFIGURATION 

Invalid configuration.

+
asINVALID_INTERFACE 

Invalid interface.

+
asCANT_BIND_ALL_FUNCTIONS 

All imported functions couldn't be bound.

+
asLOWER_ARRAY_DIMENSION_NOT_REGISTERED 

The array sub type has not been registered yet.

+
asWRONG_CONFIG_GROUP 

Wrong configuration group.

+
asCONFIG_GROUP_IS_IN_USE 

The configuration group is in use.

+
asILLEGAL_BEHAVIOUR_FOR_TYPE 

Illegal behaviour for the type.

+
asWRONG_CALLING_CONV 

The specified calling convention doesn't match the function/method pointer.

+
asBUILD_IN_PROGRESS 

A build is currently in progress.

+
asINIT_GLOBAL_VARS_FAILED 

The initialization of global variables failed.

+
asOUT_OF_MEMORY 

It wasn't possible to allocate the needed memory.

+
asMODULE_IS_IN_USE 

The module is referred to by live objects or from the application.

+
+ +
+
+ +

◆ asETokenClass

+ +
+
+ + + + +
enum asETokenClass
+
+ + + + + + + +
Enumerator
asTC_UNKNOWN 

Unknown token.

+
asTC_KEYWORD 

Keyword token.

+
asTC_VALUE 

Literal value token.

+
asTC_IDENTIFIER 

Identifier token.

+
asTC_COMMENT 

Comment token.

+
asTC_WHITESPACE 

White space token.

+
+ +
+
+ +

◆ asETypeIdFlags

+ +
+
+ + + + +
enum asETypeIdFlags
+
+ + + + + + + + + + + + + + + + + + + + +
Enumerator
asTYPEID_VOID 

The type id for void.

+
asTYPEID_BOOL 

The type id for bool.

+
asTYPEID_INT8 

The type id for int8.

+
asTYPEID_INT16 

The type id for int16.

+
asTYPEID_INT32 

The type id for int.

+
asTYPEID_INT64 

The type id for int64.

+
asTYPEID_UINT8 

The type id for uint8.

+
asTYPEID_UINT16 

The type id for uint16.

+
asTYPEID_UINT32 

The type id for uint.

+
asTYPEID_UINT64 

The type id for uint64.

+
asTYPEID_FLOAT 

The type id for float.

+
asTYPEID_DOUBLE 

The type id for double.

+
asTYPEID_OBJHANDLE 

The bit that shows if the type is a handle.

+
asTYPEID_HANDLETOCONST 

The bit that shows if the type is a handle to a const.

+
asTYPEID_MASK_OBJECT 

If any of these bits are set, then the type is an object.

+
asTYPEID_APPOBJECT 

The bit that shows if the type is an application registered type.

+
asTYPEID_SCRIPTOBJECT 

The bit that shows if the type is a script class.

+
asTYPEID_TEMPLATE 

The bit that shows if the type is a template type.

+
asTYPEID_MASK_SEQNBR 

The mask for the type id sequence number.

+
+ +
+
+ +

◆ asETypeModifiers

+ +
+
+ + + + +
enum asETypeModifiers
+
+ + + + + + +
Enumerator
asTM_NONE 

No modification.

+
asTM_INREF 

Input reference.

+
asTM_OUTREF 

Output reference.

+
asTM_INOUTREF 

In/out reference.

+
asTM_CONST 

Read only.

+
+ +
+
+
+
+ + + + diff --git a/docs/manual/annotated.html b/docs/manual/annotated.html new file mode 100644 index 0000000..0b533a0 --- /dev/null +++ b/docs/manual/annotated.html @@ -0,0 +1,130 @@ + + + + + + + +AngelScript: Class List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Class List
+
+
+
Here are the classes, structs, unions and interfaces with brief descriptions:
+ + + + + + + + + + + + + + + + + +
 CasIBinaryStreamA binary stream interface
 CasIJITCompilerThe interface that AS use to interact with the JIT compiler
 CasILockableSharedBoolA lockable shared boolean
 CasIScriptContextThe interface to the virtual machine
 CasIScriptEngineThe engine interface
 CasIScriptFunctionThe interface for a script function description
 CasIScriptGenericThe interface for the generic calling convention
 CasIScriptModuleThe interface to the script modules
 CasIScriptObjectThe interface for an instance of a script object
 CasIStringFactoryThe interface for the string factory
 CasIThreadManagerThe interface for the thread manager
 CasITypeInfoThe interface for describing types This interface is used to describe the types in the script engine
 CasSBCInfoInformation on a bytecode instruction
 CasSFuncPtrRepresents a function or method pointer
 CasSMessageInfoRepresents a compiler message
 CasSVMRegistersA struct with registers from the VM sent to a JIT compiled function
+
+
+
+ + + + diff --git a/docs/manual/aslogo.png b/docs/manual/aslogo.png new file mode 100644 index 0000000..c2157d1 Binary files /dev/null and b/docs/manual/aslogo.png differ diff --git a/docs/manual/aslogo_small.png b/docs/manual/aslogo_small.png new file mode 100644 index 0000000..ef3adaf Binary files /dev/null and b/docs/manual/aslogo_small.png differ diff --git a/docs/manual/bc_s.png b/docs/manual/bc_s.png new file mode 100644 index 0000000..224b29a Binary files /dev/null and b/docs/manual/bc_s.png differ diff --git a/docs/manual/bdwn.png b/docs/manual/bdwn.png new file mode 100644 index 0000000..940a0b9 Binary files /dev/null and b/docs/manual/bdwn.png differ diff --git a/docs/manual/classas_i_binary_stream-members.html b/docs/manual/classas_i_binary_stream-members.html new file mode 100644 index 0000000..53a9738 --- /dev/null +++ b/docs/manual/classas_i_binary_stream-members.html @@ -0,0 +1,115 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIBinaryStream Member List
+
+
+ +

This is the complete list of members for asIBinaryStream, including all inherited members.

+ + + +
Read(void *ptr, asUINT size)=0asIBinaryStreampure virtual
Write(const void *ptr, asUINT size)=0asIBinaryStreampure virtual
+
+ + + + diff --git a/docs/manual/classas_i_binary_stream.html b/docs/manual/classas_i_binary_stream.html new file mode 100644 index 0000000..50bbc83 --- /dev/null +++ b/docs/manual/classas_i_binary_stream.html @@ -0,0 +1,224 @@ + + + + + + + +AngelScript: asIBinaryStream Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIBinaryStream Class Referenceabstract
+
+
+ +

A binary stream interface. + More...

+ + + + + + + + +

+Public Member Functions

virtual int Read (void *ptr, asUINT size)=0
 Read size bytes from the stream into the memory pointed to by ptr. More...
 
virtual int Write (const void *ptr, asUINT size)=0
 Write size bytes to the stream from the memory pointed to by ptr. More...
 
+

Detailed Description

+

This interface is used when storing compiled bytecode to disk or memory, and then loading it into the engine again.

+
See also
asIScriptModule::SaveByteCode, asIScriptModule::LoadByteCode
+

Member Function Documentation

+ +

◆ Read()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIBinaryStream::Read (void * ptr,
asUINT size 
)
+
+pure virtual
+
+
Parameters
+ + + +
[out]ptrA pointer to the buffer that will receive the data.
[in]sizeThe number of bytes to read.
+
+
+
Returns
A negative value on error.
+

Read size bytes from the data stream into the memory pointed to by ptr.

+ +
+
+ +

◆ Write()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIBinaryStream::Write (const void * ptr,
asUINT size 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]ptrA pointer to the buffer that the data should written from.
[in]sizeThe number of bytes to write.
+
+
+
Returns
A negative value on error.
+

Write size bytes to the data stream from the memory pointed to by ptr.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_j_i_t_compiler-members.html b/docs/manual/classas_i_j_i_t_compiler-members.html new file mode 100644 index 0000000..9a3e523 --- /dev/null +++ b/docs/manual/classas_i_j_i_t_compiler-members.html @@ -0,0 +1,115 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIJITCompiler Member List
+
+
+ +

This is the complete list of members for asIJITCompiler, including all inherited members.

+ + + +
CompileFunction(asIScriptFunction *function, asJITFunction *output)=0asIJITCompilerpure virtual
ReleaseJITFunction(asJITFunction func)=0asIJITCompilerpure virtual
+
+ + + + diff --git a/docs/manual/classas_i_j_i_t_compiler.html b/docs/manual/classas_i_j_i_t_compiler.html new file mode 100644 index 0000000..75d7e1b --- /dev/null +++ b/docs/manual/classas_i_j_i_t_compiler.html @@ -0,0 +1,211 @@ + + + + + + + +AngelScript: asIJITCompiler Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIJITCompiler Class Referenceabstract
+
+
+ +

The interface that AS use to interact with the JIT compiler. + More...

+ + + + + + + + +

+Public Member Functions

virtual int CompileFunction (asIScriptFunction *function, asJITFunction *output)=0
 Called by AngelScript to begin the compilation. More...
 
virtual void ReleaseJITFunction (asJITFunction func)=0
 Called by AngelScript when the JIT function is released. More...
 
+

Detailed Description

+

This is the minimal interface that the JIT compiler must implement so that AngelScript can request the compilation of the script functions.

+
See also
How to build a JIT compiler
+

Member Function Documentation

+ +

◆ CompileFunction()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIJITCompiler::CompileFunction (asIScriptFunctionfunction,
asJITFunctionoutput 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]functionA pointer to the script function
[out]outputThe JIT compiled function
+
+
+
Returns
A negative value on error.
+

AngelScript will call this function to request the compilation of a script function. The JIT compiler should produce the native machine code representation of the function and update the JitEntry instructions in the byte code to allow the VM to transfer the control to the JIT compiled function.

+ +
+
+ +

◆ ReleaseJITFunction()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void asIJITCompiler::ReleaseJITFunction (asJITFunction func)
+
+pure virtual
+
+
Parameters
+ + +
[in]funcPointer to the JIT function
+
+
+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_lockable_shared_bool-members.html b/docs/manual/classas_i_lockable_shared_bool-members.html new file mode 100644 index 0000000..bcf6f42 --- /dev/null +++ b/docs/manual/classas_i_lockable_shared_bool-members.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asILockableSharedBool Member List
+
+
+ +

This is the complete list of members for asILockableSharedBool, including all inherited members.

+ + + + + + + +
AddRef() const =0asILockableSharedBoolpure virtual
Get() const =0asILockableSharedBoolpure virtual
Lock() const =0asILockableSharedBoolpure virtual
Release() const =0asILockableSharedBoolpure virtual
Set(bool val)=0asILockableSharedBoolpure virtual
Unlock() const =0asILockableSharedBoolpure virtual
+
+ + + + diff --git a/docs/manual/classas_i_lockable_shared_bool.html b/docs/manual/classas_i_lockable_shared_bool.html new file mode 100644 index 0000000..26091be --- /dev/null +++ b/docs/manual/classas_i_lockable_shared_bool.html @@ -0,0 +1,308 @@ + + + + + + + +AngelScript: asILockableSharedBool Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asILockableSharedBool Class Referenceabstract
+
+
+ +

A lockable shared boolean. + More...

+ + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

virtual int AddRef () const =0
 Adds a reference to the shared boolean. More...
 
virtual int Release () const =0
 Releases a reference to the shared boolean. More...
 
virtual bool Get () const =0
 Get the value of the shared boolean. More...
 
virtual void Set (bool val)=0
 Sets the value of the shared boolean. More...
 
virtual void Lock () const =0
 Locks the shared boolean. More...
 
virtual void Unlock () const =0
 Unlocks the shared boolean. More...
 
+

Detailed Description

+

This interface represents a lockable shared boolean.

+

Member Function Documentation

+ +

◆ AddRef()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asILockableSharedBool::AddRef () const
+
+pure virtual
+
+
Returns
The new reference count
+ +
+
+ +

◆ Get()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asILockableSharedBool::Get () const
+
+pure virtual
+
+
Returns
The value of the shared boolean
+ +
+
+ +

◆ Lock()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void asILockableSharedBool::Lock () const
+
+pure virtual
+
+

If the boolean is already locked, then this method will wait until it is unlocked before returning.

+

Unlock the shared boolean with a call to Unlock

+ +
+
+ +

◆ Release()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asILockableSharedBool::Release () const
+
+pure virtual
+
+
Returns
The new reference count
+ +
+
+ +

◆ Set()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void asILockableSharedBool::Set (bool val)
+
+pure virtual
+
+
Parameters
+ + +
[in]valThe new value
+
+
+ +
+
+ +

◆ Unlock()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void asILockableSharedBool::Unlock () const
+
+pure virtual
+
+

Unlock the shared boolean after a call to Lock

+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_script_context-members.html b/docs/manual/classas_i_script_context-members.html new file mode 100644 index 0000000..0b8892c --- /dev/null +++ b/docs/manual/classas_i_script_context-members.html @@ -0,0 +1,168 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIScriptContext Member List
+
+
+ +

This is the complete list of members for asIScriptContext, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Abort()=0asIScriptContextpure virtual
AddRef() const =0asIScriptContextpure virtual
ClearExceptionCallback()=0asIScriptContextpure virtual
ClearLineCallback()=0asIScriptContextpure virtual
Execute()=0asIScriptContextpure virtual
GetAddressOfArg(asUINT arg)=0asIScriptContextpure virtual
GetAddressOfReturnValue()=0asIScriptContextpure virtual
GetAddressOfVar(asUINT varIndex, asUINT stackLevel=0)=0asIScriptContextpure virtual
GetCallstackSize() const =0asIScriptContextpure virtual
GetEngine() const =0asIScriptContextpure virtual
GetExceptionFunction()=0asIScriptContextpure virtual
GetExceptionLineNumber(int *column=0, const char **sectionName=0)=0asIScriptContextpure virtual
GetExceptionString()=0asIScriptContextpure virtual
GetFunction(asUINT stackLevel=0)=0asIScriptContextpure virtual
GetLineNumber(asUINT stackLevel=0, int *column=0, const char **sectionName=0)=0asIScriptContextpure virtual
GetReturnAddress()=0asIScriptContextpure virtual
GetReturnByte()=0asIScriptContextpure virtual
GetReturnDouble()=0asIScriptContextpure virtual
GetReturnDWord()=0asIScriptContextpure virtual
GetReturnFloat()=0asIScriptContextpure virtual
GetReturnObject()=0asIScriptContextpure virtual
GetReturnQWord()=0asIScriptContextpure virtual
GetReturnWord()=0asIScriptContextpure virtual
GetState() const =0asIScriptContextpure virtual
GetSystemFunction()=0asIScriptContextpure virtual
GetThisPointer(asUINT stackLevel=0)=0asIScriptContextpure virtual
GetThisTypeId(asUINT stackLevel=0)=0asIScriptContextpure virtual
GetUserData(asPWORD type=0) const =0asIScriptContextpure virtual
GetVarCount(asUINT stackLevel=0)=0asIScriptContextpure virtual
GetVarDeclaration(asUINT varIndex, asUINT stackLevel=0, bool includeNamespace=false)=0asIScriptContextpure virtual
GetVarName(asUINT varIndex, asUINT stackLevel=0)=0asIScriptContextpure virtual
GetVarTypeId(asUINT varIndex, asUINT stackLevel=0)=0asIScriptContextpure virtual
IsNested(asUINT *nestCount=0) const =0asIScriptContextpure virtual
IsVarInScope(asUINT varIndex, asUINT stackLevel=0)=0asIScriptContextpure virtual
PopState()=0asIScriptContextpure virtual
Prepare(asIScriptFunction *func)=0asIScriptContextpure virtual
PushState()=0asIScriptContextpure virtual
Release() const =0asIScriptContextpure virtual
SetArgAddress(asUINT arg, void *addr)=0asIScriptContextpure virtual
SetArgByte(asUINT arg, asBYTE value)=0asIScriptContextpure virtual
SetArgDouble(asUINT arg, double value)=0asIScriptContextpure virtual
SetArgDWord(asUINT arg, asDWORD value)=0asIScriptContextpure virtual
SetArgFloat(asUINT arg, float value)=0asIScriptContextpure virtual
SetArgObject(asUINT arg, void *obj)=0asIScriptContextpure virtual
SetArgQWord(asUINT arg, asQWORD value)=0asIScriptContextpure virtual
SetArgVarType(asUINT arg, void *ptr, int typeId)=0asIScriptContextpure virtual
SetArgWord(asUINT arg, asWORD value)=0asIScriptContextpure virtual
SetException(const char *info, bool allowCatch=true)=0asIScriptContextpure virtual
SetExceptionCallback(asSFuncPtr callback, void *obj, int callConv)=0asIScriptContextpure virtual
SetLineCallback(asSFuncPtr callback, void *obj, int callConv)=0asIScriptContextpure virtual
SetObject(void *obj)=0asIScriptContextpure virtual
SetUserData(void *data, asPWORD type=0)=0asIScriptContextpure virtual
Suspend()=0asIScriptContextpure virtual
Unprepare()=0asIScriptContextpure virtual
WillExceptionBeCaught()=0asIScriptContextpure virtual
+
+ + + + diff --git a/docs/manual/classas_i_script_context.html b/docs/manual/classas_i_script_context.html new file mode 100644 index 0000000..057dd38 --- /dev/null +++ b/docs/manual/classas_i_script_context.html @@ -0,0 +1,2417 @@ + + + + + + + +AngelScript: asIScriptContext Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIScriptContext Class Referenceabstract
+
+
+ +

The interface to the virtual machine. + More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

Memory management
virtual int AddRef () const =0
 Increase reference counter. More...
 
virtual int Release () const =0
 Decrease reference counter. More...
 
Miscellaneous
virtual asIScriptEngineGetEngine () const =0
 Returns a pointer to the engine. More...
 
Execution
virtual int Prepare (asIScriptFunction *func)=0
 Prepares the context for execution of the function. More...
 
virtual int Unprepare ()=0
 Frees resources held by the context. More...
 
virtual int Execute ()=0
 Executes the prepared function. More...
 
virtual int Abort ()=0
 Aborts the execution. More...
 
virtual int Suspend ()=0
 Suspends the execution, which can then be resumed by calling Execute again. More...
 
virtual asEContextState GetState () const =0
 Returns the state of the context. More...
 
virtual int PushState ()=0
 Backups the current state to prepare the context for a nested call. More...
 
virtual int PopState ()=0
 Restores the state to resume previous script execution. More...
 
virtual bool IsNested (asUINT *nestCount=0) const =0
 Returns true if the context has any nested calls. More...
 
Object pointer for calling class methods
virtual int SetObject (void *obj)=0
 Sets the object for a class method call. More...
 
Arguments
virtual int SetArgByte (asUINT arg, asBYTE value)=0
 Sets an 8-bit argument value. More...
 
virtual int SetArgWord (asUINT arg, asWORD value)=0
 Sets a 16-bit argument value. More...
 
virtual int SetArgDWord (asUINT arg, asDWORD value)=0
 Sets a 32-bit integer argument value. More...
 
virtual int SetArgQWord (asUINT arg, asQWORD value)=0
 Sets a 64-bit integer argument value. More...
 
virtual int SetArgFloat (asUINT arg, float value)=0
 Sets a float argument value. More...
 
virtual int SetArgDouble (asUINT arg, double value)=0
 Sets a double argument value. More...
 
virtual int SetArgAddress (asUINT arg, void *addr)=0
 Sets the address of a reference or handle argument. More...
 
virtual int SetArgObject (asUINT arg, void *obj)=0
 Sets the object argument value. More...
 
virtual int SetArgVarType (asUINT arg, void *ptr, int typeId)=0
 Sets the variable argument value and type. More...
 
virtual void * GetAddressOfArg (asUINT arg)=0
 Returns a pointer to the argument for assignment. More...
 
Return value
virtual asBYTE GetReturnByte ()=0
 Returns the 8-bit return value. More...
 
virtual asWORD GetReturnWord ()=0
 Returns the 16-bit return value. More...
 
virtual asDWORD GetReturnDWord ()=0
 Returns the 32-bit return value. More...
 
virtual asQWORD GetReturnQWord ()=0
 Returns the 64-bit return value. More...
 
virtual float GetReturnFloat ()=0
 Returns the float return value. More...
 
virtual double GetReturnDouble ()=0
 Returns the double return value. More...
 
virtual void * GetReturnAddress ()=0
 Returns the address for a reference or handle return type. More...
 
virtual void * GetReturnObject ()=0
 Return a pointer to the returned object. More...
 
virtual void * GetAddressOfReturnValue ()=0
 Returns the address of the returned value. More...
 
Exception handling
virtual int SetException (const char *info, bool allowCatch=true)=0
 Sets an exception, which aborts the execution. More...
 
virtual int GetExceptionLineNumber (int *column=0, const char **sectionName=0)=0
 Returns the line number where the exception occurred. More...
 
virtual asIScriptFunctionGetExceptionFunction ()=0
 Returns the function where the exception occurred. More...
 
virtual const char * GetExceptionString ()=0
 Returns the exception string text. More...
 
virtual bool WillExceptionBeCaught ()=0
 Determine if the current exception will be caught by the script. More...
 
virtual int SetExceptionCallback (asSFuncPtr callback, void *obj, int callConv)=0
 Sets an exception callback function. The function will be called if a script exception occurs. More...
 
virtual void ClearExceptionCallback ()=0
 Removes the registered callback. More...
 
Debugging
virtual int SetLineCallback (asSFuncPtr callback, void *obj, int callConv)=0
 Sets a line callback function. The function will be called for each executed script statement. More...
 
virtual void ClearLineCallback ()=0
 Removes the registered callback. More...
 
virtual asUINT GetCallstackSize () const =0
 Returns the size of the callstack, i.e. the number of functions that have yet to complete. More...
 
virtual asIScriptFunctionGetFunction (asUINT stackLevel=0)=0
 Returns the function at the specified callstack level. More...
 
virtual int GetLineNumber (asUINT stackLevel=0, int *column=0, const char **sectionName=0)=0
 Returns the line number at the specified callstack level. More...
 
virtual int GetVarCount (asUINT stackLevel=0)=0
 Returns the number of local variables at the specified callstack level. More...
 
virtual const char * GetVarName (asUINT varIndex, asUINT stackLevel=0)=0
 Returns the name of local variable at the specified callstack level. More...
 
virtual const char * GetVarDeclaration (asUINT varIndex, asUINT stackLevel=0, bool includeNamespace=false)=0
 Returns the declaration of a local variable at the specified callstack level. More...
 
virtual int GetVarTypeId (asUINT varIndex, asUINT stackLevel=0)=0
 Returns the type id of a local variable at the specified callstack level. More...
 
virtual void * GetAddressOfVar (asUINT varIndex, asUINT stackLevel=0)=0
 Returns a pointer to a local variable at the specified callstack level. More...
 
virtual bool IsVarInScope (asUINT varIndex, asUINT stackLevel=0)=0
 Informs whether the variable is in scope at the current program position. More...
 
virtual int GetThisTypeId (asUINT stackLevel=0)=0
 Returns the type id of the object, if a class method is being executed. More...
 
virtual void * GetThisPointer (asUINT stackLevel=0)=0
 Returns a pointer to the object, if a class method is being executed. More...
 
virtual asIScriptFunctionGetSystemFunction ()=0
 Returns the registered function that is currently being called by the context. More...
 
User data
virtual void * SetUserData (void *data, asPWORD type=0)=0
 Register the memory address of some user data. More...
 
virtual void * GetUserData (asPWORD type=0) const =0
 Returns the address of the previously registered user data. More...
 
+

Detailed Description

+

The script context provides the interface for a single script execution. The object stores the call stack where the local variables used by the execution are kept, however it doesn't keep copies of global variables as these are stored in the asIScriptModule, and only referenced by the context.

+

The value stored in a global variable is shared between all contexts, as they all refer to the same memory. This means that the global variables outlive the execution of a script, and will keep their values between executions.

+

It is seldom necessary to maintain more than one script context at a time, with the only exceptions being when a script calls an application function that in turn calls another script before returning, and if multiple scripts are running in parallel.

+

Try to avoid associating a unique context with each object that may need to call scripts. Instead keep a shared pool of contexts that can be requested by the objects on a need-to basis.

+

Member Function Documentation

+ +

◆ Abort()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::Abort ()
+
+pure virtual
+
+
Returns
A negative value on error.
+
Return values
+ + +
asERRORInvalid context object.
+
+
+

Aborts the current execution of a script.

+

If the call to Abort is done from within a function called by the script, it will only take effect after that function returns.

+ +
+
+ +

◆ AddRef()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::AddRef () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when storing an additional reference to the object. Remember that the first reference that is received from asIScriptEngine::CreateContext is already accounted for.

+ +
+
+ +

◆ ClearExceptionCallback()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void asIScriptContext::ClearExceptionCallback ()
+
+pure virtual
+
+

Removes a previously registered callback.

+ +
+
+ +

◆ ClearLineCallback()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void asIScriptContext::ClearLineCallback ()
+
+pure virtual
+
+

Removes a previously registered callback.

+ +
+
+ +

◆ Execute()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::Execute ()
+
+pure virtual
+
+
Returns
A negative value on error, or one of asEContextState.
+
Return values
+ + + + + + +
asCONTEXT_NOT_PREPAREDThe context is not prepared or it is not in suspended state.
asEXECUTION_ABORTEDThe execution was aborted with a call to Abort.
asEXECUTION_SUSPENDEDThe execution was suspended with a call to Suspend.
asEXECUTION_FINISHEDThe execution finished successfully.
asEXECUTION_EXCEPTIONThe execution ended with an exception.
+
+
+

Executes the prepared function until the script returns. If the execution was previously suspended the function resumes where it left of.

+

Note that if the script freezes, e.g. if trapped in a never ending loop, you may call Abort from another thread to stop execution.

+

If the function returns asEXECUTION_EXCEPTION, use the GetExceptionString, GetExceptionFunction, and GetExceptionLineNumber to obtain more information on the exception and where it occurred.

+
See also
Calling a script function
+ +
+
+ +

◆ GetAddressOfArg()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptContext::GetAddressOfArg (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
A pointer to the argument on the stack.
+

This method returns a pointer to the argument on the stack for assignment. For object handles, you should increment the reference counter. For object values, you should pass a pointer to a copy of the object.

+ +
+
+ +

◆ GetAddressOfReturnValue()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptContext::GetAddressOfReturnValue ()
+
+pure virtual
+
+
Returns
A pointer to the return value returned from the script function, or 0 on error.
+ +
+
+ +

◆ GetAddressOfVar()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asIScriptContext::GetAddressOfVar (asUINT varIndex,
asUINT stackLevel = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]varIndexThe index of the variable.
[in]stackLevelThe index on the call stack.
+
+
+
Returns
A pointer to the variable.
+

Returns a pointer to the variable, so that its value can be read and written. The address is valid until the script function returns.

+

Note that object variables may not be initalized at all moments, thus you must verify if the address returned points to a null pointer, before you try to dereference it.

+ +
+
+ +

◆ GetCallstackSize()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptContext::GetCallstackSize () const
+
+pure virtual
+
+
Returns
The number of functions on the call stack, including the current function.
+

This methods returns the size of the callstack. It can be used to enumerate the callstack in order to generate a detailed report when an exception occurs, or for debugging running scripts.

+ +
+
+ +

◆ GetEngine()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptEngine* asIScriptContext::GetEngine () const
+
+pure virtual
+
+
Returns
A pointer to the engine.
+ +
+
+ +

◆ GetExceptionFunction()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptFunction* asIScriptContext::GetExceptionFunction ()
+
+pure virtual
+
+
Returns
The function where the exception occurred.
+ +
+
+ +

◆ GetExceptionLineNumber()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::GetExceptionLineNumber (int * column = 0,
const char ** sectionName = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[out]columnThe variable will receive the column number.
[out]sectionNameThe variable will receive the name of the script section.
+
+
+
Returns
The line number where the exception occurred.
+

This method returns the line number where the exception ocurred. The line number is relative to the script section where the function was implemented.

+

Observe that the returned sectionName can be null, e.g. if the function in which the exception occurred was a generated stub function.

+ +
+
+ +

◆ GetExceptionString()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptContext::GetExceptionString ()
+
+pure virtual
+
+
Returns
A null terminated string describing the exception that occurred.
+ +
+
+ +

◆ GetFunction()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asIScriptContext::GetFunction (asUINT stackLevel = 0)
+
+pure virtual
+
+
Parameters
+ + +
[in]stackLevelThe index on the call stack.
+
+
+
Returns
The function descriptor on the call stack referred to by the index.
+

Index 0 refers to the current function, index 1 to the calling function, and so on. The highest index is the originating function that the application called.

+

The returned value will be null if the stackLevel is invalid, or if the requested stack level doesn't have a defined function. The latter scenario happens when the engine performs a nested call internally, e.g. to call a constructor for a script object indirectly created.

+

If the application performs a nested call, then the returned value will give the application registered function that was called by the previous script.

+
See also
PushState
+ +
+
+ +

◆ GetLineNumber()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::GetLineNumber (asUINT stackLevel = 0,
int * column = 0,
const char ** sectionName = 0 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]stackLevelThe index on the call stack.
[out]columnThe variable will receive the column number.
[out]sectionNameThe variable will receive the name of the script section.
+
+
+
Returns
The line number for the call stack level referred to by the index.
+

This function returns the line number, and optionally the column number and the name of the script section where the program is current at.

+

The sectionName pointer will point to an internal buffer, so do not deallocate it. If the function doesn't have any debug info sectionName will be set to null.

+ +
+
+ +

◆ GetReturnAddress()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptContext::GetReturnAddress ()
+
+pure virtual
+
+
Returns
The address value returned from the script function, or 0 on error.
+

The method doesn't increase the reference counter with this call, so if you store the pointer of a reference counted object you need to increase the reference manually otherwise the object will be released when the context is released or reused.

+ +
+
+ +

◆ GetReturnByte()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asBYTE asIScriptContext::GetReturnByte ()
+
+pure virtual
+
+
Returns
The 1 byte value returned from the script function, or 0 on error.
+ +
+
+ +

◆ GetReturnDouble()

+ +
+
+ + + + + +
+ + + + + + + +
virtual double asIScriptContext::GetReturnDouble ()
+
+pure virtual
+
+
Returns
The double value returned from the script function, or 0 on error.
+ +
+
+ +

◆ GetReturnDWord()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asDWORD asIScriptContext::GetReturnDWord ()
+
+pure virtual
+
+
Returns
The 4 byte value returned from the script function, or 0 on error.
+ +
+
+ +

◆ GetReturnFloat()

+ +
+
+ + + + + +
+ + + + + + + +
virtual float asIScriptContext::GetReturnFloat ()
+
+pure virtual
+
+
Returns
The float value returned from the script function, or 0 on error.
+ +
+
+ +

◆ GetReturnObject()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptContext::GetReturnObject ()
+
+pure virtual
+
+
Returns
A pointer to the object returned from the script function, or 0 on error.
+

The method doesn't increase the reference counter with this call, so if you store the pointer of a reference counted object you need to increase the reference manually otherwise the object will be released when the context is released or reused.

+ +
+
+ +

◆ GetReturnQWord()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asQWORD asIScriptContext::GetReturnQWord ()
+
+pure virtual
+
+
Returns
The 8 byte value returned from the script function, or 0 on error.
+ +
+
+ +

◆ GetReturnWord()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asWORD asIScriptContext::GetReturnWord ()
+
+pure virtual
+
+
Returns
The 2 byte value returned from the script function, or 0 on error.
+ +
+
+ +

◆ GetState()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asEContextState asIScriptContext::GetState () const
+
+pure virtual
+
+
Returns
The current state of the context.
+ +
+
+ +

◆ GetSystemFunction()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptFunction* asIScriptContext::GetSystemFunction ()
+
+pure virtual
+
+
Returns
Returns the registered function that is currently being called, or null if no registered function is being called at the moment.
+ +
+
+ +

◆ GetThisPointer()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptContext::GetThisPointer (asUINT stackLevel = 0)
+
+pure virtual
+
+
Parameters
+ + +
[in]stackLevelThe index on the call stack.
+
+
+
Returns
Returns a pointer to the object if it is a class method.
+ +
+
+ +

◆ GetThisTypeId()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptContext::GetThisTypeId (asUINT stackLevel = 0)
+
+pure virtual
+
+
Parameters
+ + +
[in]stackLevelThe index on the call stack.
+
+
+
Returns
Returns the type id of the object if it is a class method.
+ +
+
+ +

◆ GetUserData()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptContext::GetUserData (asPWORD type = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeAn identifier specifying the user data to set.
+
+
+
Returns
The pointer to the user data.
+ +
+
+ +

◆ GetVarCount()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptContext::GetVarCount (asUINT stackLevel = 0)
+
+pure virtual
+
+
Parameters
+ + +
[in]stackLevelThe index on the call stack.
+
+
+
Returns
The number of variables in the function on the call stack level. Or negative value on error.
+
Return values
+ + +
asINVALID_ARGThe stackLevel is invalid.
+
+
+

Returns the number of declared variables, including the parameters, in the function on the stack.

+ +
+
+ +

◆ GetVarDeclaration()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual const char* asIScriptContext::GetVarDeclaration (asUINT varIndex,
asUINT stackLevel = 0,
bool includeNamespace = false 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]varIndexThe index of the variable.
[in]stackLevelThe index on the call stack.
[in]includeNamespaceSet to true if the namespace should be included in the declaration.
+
+
+
Returns
A null terminated string with the declaration of the variable.
+ +
+
+ +

◆ GetVarName()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual const char* asIScriptContext::GetVarName (asUINT varIndex,
asUINT stackLevel = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]varIndexThe index of the variable.
[in]stackLevelThe index on the call stack.
+
+
+
Returns
A null terminated string with the name of the variable.
+ +
+
+ +

◆ GetVarTypeId()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::GetVarTypeId (asUINT varIndex,
asUINT stackLevel = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]varIndexThe index of the variable.
[in]stackLevelThe index on the call stack.
+
+
+
Returns
The type id of the variable, or a negative value on error.
+
Return values
+ + +
asINVALID_ARGThe index or stack level is invalid.
+
+
+ +
+
+ +

◆ IsNested()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool asIScriptContext::IsNested (asUINTnestCount = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[out]nestCountThis argument receives the nesting level.
+
+
+
Returns
true if there are any nested calls.
+ +
+
+ +

◆ IsVarInScope()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual bool asIScriptContext::IsVarInScope (asUINT varIndex,
asUINT stackLevel = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]varIndexThe index of the variable.
[in]stackLevelThe index on the call stack.
+
+
+
Returns
True if variable is in scope.
+

This method can be used to determine if a variable is currently visible from the current program position. This is especially useful if multiple variables with the same name is declared in different scopes.

+ +
+
+ +

◆ PopState()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::PopState ()
+
+pure virtual
+
+
Returns
A negative value on error.
+
Return values
+ + +
asERRORThe state couldn't be restored.
+
+
+ +
+
+ +

◆ Prepare()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptContext::Prepare (asIScriptFunctionfunc)
+
+pure virtual
+
+
Parameters
+ + +
[in]funcThe id of the function/method that will be executed.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + + +
asCONTEXT_ACTIVEThe context is still active or suspended.
asNO_FUNCTIONThe function pointer is null.
asINVALID_ARGThe function is from a different engine than the context.
asOUT_OF_MEMORYThe context ran out of memory while allocating call stack.
+
+
+

This method prepares the context for executeion of a script function. It allocates the stack space required and reserves space for return value and parameters. The default value for parameters and return value is 0.

+
See also
Calling a script function
+ +
+
+ +

◆ PushState()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::PushState ()
+
+pure virtual
+
+
Returns
A negative value on error.
+
Return values
+ + + +
asERRORThe current context is not active.
asOUT_OF_MEMORYCouldn't allocate memory to store state.
+
+
+

This method can be invoked on an active context in order to reuse the context for a nested call, e.g. when a function called by a script needs to call another script before returning. After the method returns with success the method Prepare() shall be invoked to prepare the new execution.

+

By reusing an active context the application can avoid creating a temporary context, and thus improve the run-time performance.

+

For each successful call to PushState() the method PopState() must be called to return the state in order to resume the previous script execution.

+

If PushState() fails, the context was not modified, so the application can just create a different context instead, and when it is done with it the original context can be resumed normally.

+ +
+
+ +

◆ Release()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::Release () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when you will no longer use the references that you own.

+ +
+
+ +

◆ SetArgAddress()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgAddress (asUINT arg,
void * addr 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]addrThe address that should be passed in the argument.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not a reference or an object handle.
+
+
+

Sets an address argument, e.g. an object handle or a reference.

+ +
+
+ +

◆ SetArgByte()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgByte (asUINT arg,
asBYTE value 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]valueThe value of the argument.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not an 8-bit value.
+
+
+

Sets a 1 byte argument.

+ +
+
+ +

◆ SetArgDouble()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgDouble (asUINT arg,
double value 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]valueThe value of the argument.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not a 64-bit value.
+
+
+

Sets a double argument.

+ +
+
+ +

◆ SetArgDWord()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgDWord (asUINT arg,
asDWORD value 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]valueThe value of the argument.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not a 32-bit value.
+
+
+

Sets a 4 byte argument.

+ +
+
+ +

◆ SetArgFloat()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgFloat (asUINT arg,
float value 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]valueThe value of the argument.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not a 32-bit value.
+
+
+

Sets a float argument.

+ +
+
+ +

◆ SetArgObject()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgObject (asUINT arg,
void * obj 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]objA pointer to the object.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not an object or handle.
+
+
+

Sets an object argument. If the argument is an object handle AngelScript will increment the reference for the object. If the argument is an object value AngelScript will make a copy of the object.

+ +
+
+ +

◆ SetArgQWord()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgQWord (asUINT arg,
asQWORD value 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]valueThe value of the argument.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not a 64-bit value.
+
+
+

Sets an 8 byte argument.

+ +
+
+ +

◆ SetArgVarType()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgVarType (asUINT arg,
void * ptr,
int typeId 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]argThe argument index.
[in]ptrA pointer to the value.
[in]typeIdThe type id of the value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not a variable type.
+
+
+

This method should be used when setting the argument for functions with variable parameter types.

+ +
+
+ +

◆ SetArgWord()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetArgWord (asUINT arg,
asWORD value 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[in]valueThe value of the argument.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asINVALID_ARGThe arg is larger than the number of arguments in the prepared function.
asINVALID_TYPEThe argument is not a 16-bit value.
+
+
+

Sets a 2 byte argument.

+ +
+
+ +

◆ SetException()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetException (const char * info,
bool allowCatch = true 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]infoA string that describes the exception that occurred.
[in]allowCatchSet to false if the script shouldn't be allowed to catch the exception.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asERRORThe context isn't currently calling an application registered function.
+
+
+

This method sets a script exception in the context. This will only work if the context is currently calling a system function, thus this method can only be used for system functions.

+

Note that if your system function sets an exception, it should not return any object references because the engine will not release the returned reference.

+ +
+
+ +

◆ SetExceptionCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetExceptionCallback (asSFuncPtr callback,
void * obj,
int callConv 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]callbackThe callback function/method that should be called upon an exception.
[in]objThe object pointer on which the callback is called.
[in]callConvThe calling convention of the callback function/method.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asNOT_SUPPORTEDCalling convention must not be asCALL_GENERIC, or the routine's calling convention is not supported.
asINVALID_ARGobj must not be null for class methods.
asWRONG_CALLING_CONVcallConv isn't compatible with the routines' calling convention.
+
+
+

This callback function will be called by the VM when a script exception is raised, which allow the application to examine the callstack and generate a detailed report before the callstack is cleaned up.

+

The callback function can be either a global function or a class method. For a global function the VM will pass two parameters, first the context pointer and then the object pointer specified by the application. For a class method, the VM will call the method using the object pointer as the owner.

+
void Callback(asIScriptContext *ctx, void *obj);
+
void Object::Callback(asIScriptContext *ctx);
+

The global function can use either asCALL_CDECL or asCALL_STDCALL, and the class method can use either asCALL_THISCALL, asCALL_CDECL_OBJLAST, or asCALL_CDECL_OBJFIRST.

+
See also
Exception handling
+ +
+
+ +

◆ SetLineCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptContext::SetLineCallback (asSFuncPtr callback,
void * obj,
int callConv 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]callbackThe callback function/method that should be called for each script line executed.
[in]objThe object pointer on which the callback is called.
[in]callConvThe calling convention of the callback function/method.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asNOT_SUPPORTEDCalling convention must not be asCALL_GENERIC, or the routine's calling convention is not supported.
asINVALID_ARGobj must not be null for class methods.
asWRONG_CALLING_CONVcallConv isn't compatible with the routines' calling convention.
+
+
+

This function sets a callback function that will be called by the VM each time the SUSPEND instruction is encounted. Generally this instruction is placed before each statement. Thus by setting this callback function it is possible to monitor the execution, and suspend the execution at application defined locations.

+

The callback function can be either a global function or a class method. For a global function the VM will pass two parameters, first the context pointer and then the object pointer specified by the application. For a class method, the VM will call the method using the object pointer as the owner.

+
void Callback(asIScriptContext *ctx, void *obj);
+
void Object::Callback(asIScriptContext *ctx);
+

The global function can use either asCALL_CDECL or asCALL_STDCALL, and the class method can use either asCALL_THISCALL, asCALL_CDECL_OBJLAST, or asCALL_CDECL_OBJFIRST.

+
See also
Debugging scripts
+ +
+
+ +

◆ SetObject()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptContext::SetObject (void * obj)
+
+pure virtual
+
+
Parameters
+ + +
[in]objA pointer to the object.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + +
asCONTEXT_NOT_PREPAREDThe context is not in prepared state.
asERRORThe prepared function is not a class method.
+
+
+

This method sets object pointer when calling class methods.

+ +
+
+ +

◆ SetUserData()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asIScriptContext::SetUserData (void * data,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]dataA pointer to the user data.
[in]typeAn identifier specifying the user data to set.
+
+
+
Returns
The previous pointer stored in the context.
+

This method allows the application to associate a value, e.g. a pointer, with the context instance.

+

The type values 1000 through 1999 are reserved for use by the official add-ons.

+

Optionally, a callback function can be registered to clean up the user data when the context is destroyed. As the callback is registered with the engine, it is only necessary to do it once, even if more than one context is used.

+ +
+
+ +

◆ Suspend()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::Suspend ()
+
+pure virtual
+
+
Returns
A negative value on error.
+
Return values
+ + +
asERRORInvalid context object.
+
+
+

Suspends the current execution of a script. The execution can then be resumed by calling Execute again.

+

If the call to Suspend is done from within a function called by the script, it will only take effect after that function returns.

+
See also
Calling a script function
+ +
+
+ +

◆ Unprepare()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptContext::Unprepare ()
+
+pure virtual
+
+
Returns
A negative value on error.
+
Return values
+ + +
asCONTEXT_ACTIVEThe context is still active or suspended.
+
+
+

This function frees resources held by the context. It's usually not necessary to call this function as the resources are automatically freed when the context is released, or reused when Prepare is called again.

+ +
+
+ +

◆ WillExceptionBeCaught()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptContext::WillExceptionBeCaught ()
+
+pure virtual
+
+
Returns
True if the exception will be caught by the script.
+

This method is intended to be used from the exception callback, where the application can potentially make a different decision depending on whether the script will catch the exception or not.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+ + + + diff --git a/docs/manual/classas_i_script_engine-members.html b/docs/manual/classas_i_script_engine-members.html new file mode 100644 index 0000000..01275b3 --- /dev/null +++ b/docs/manual/classas_i_script_engine-members.html @@ -0,0 +1,202 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIScriptEngine Member List
+
+
+ +

This is the complete list of members for asIScriptEngine, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddRef() const =0asIScriptEnginepure virtual
AddRefScriptObject(void *obj, const asITypeInfo *type)=0asIScriptEnginepure virtual
AssignScriptObject(void *dstObj, void *srcObj, const asITypeInfo *type)=0asIScriptEnginepure virtual
BeginConfigGroup(const char *groupName)=0asIScriptEnginepure virtual
ClearMessageCallback()=0asIScriptEnginepure virtual
CreateContext()=0asIScriptEnginepure virtual
CreateDelegate(asIScriptFunction *func, void *obj)=0asIScriptEnginepure virtual
CreateScriptObject(const asITypeInfo *type)=0asIScriptEnginepure virtual
CreateScriptObjectCopy(void *obj, const asITypeInfo *type)=0asIScriptEnginepure virtual
CreateUninitializedScriptObject(const asITypeInfo *type)=0asIScriptEnginepure virtual
DiscardModule(const char *module)=0asIScriptEnginepure virtual
EndConfigGroup()=0asIScriptEnginepure virtual
ForwardGCEnumReferences(void *ref, asITypeInfo *type)=0asIScriptEnginepure virtual
ForwardGCReleaseReferences(void *ref, asITypeInfo *type)=0asIScriptEnginepure virtual
GarbageCollect(asDWORD flags=asGC_FULL_CYCLE, asUINT numIterations=1)=0asIScriptEnginepure virtual
GCEnumCallback(void *reference)=0asIScriptEnginepure virtual
GetDefaultArrayTypeId() const =0asIScriptEnginepure virtual
GetDefaultNamespace() const =0asIScriptEnginepure virtual
GetEngineProperty(asEEngineProp property) const =0asIScriptEnginepure virtual
GetEnumByIndex(asUINT index) const =0asIScriptEnginepure virtual
GetEnumCount() const =0asIScriptEnginepure virtual
GetFuncdefByIndex(asUINT index) const =0asIScriptEnginepure virtual
GetFuncdefCount() const =0asIScriptEnginepure virtual
GetFunctionById(int funcId) const =0asIScriptEnginepure virtual
GetGCStatistics(asUINT *currentSize, asUINT *totalDestroyed=0, asUINT *totalDetected=0, asUINT *newObjects=0, asUINT *totalNewDestroyed=0) const =0asIScriptEnginepure virtual
GetGlobalFunctionByDecl(const char *declaration) const =0asIScriptEnginepure virtual
GetGlobalFunctionByIndex(asUINT index) const =0asIScriptEnginepure virtual
GetGlobalFunctionCount() const =0asIScriptEnginepure virtual
GetGlobalPropertyByIndex(asUINT index, const char **name, const char **nameSpace=0, int *typeId=0, bool *isConst=0, const char **configGroup=0, void **pointer=0, asDWORD *accessMask=0) const =0asIScriptEnginepure virtual
GetGlobalPropertyCount() const =0asIScriptEnginepure virtual
GetGlobalPropertyIndexByDecl(const char *decl) const =0asIScriptEnginepure virtual
GetGlobalPropertyIndexByName(const char *name) const =0asIScriptEnginepure virtual
GetJITCompiler() const =0asIScriptEnginepure virtual
GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0asIScriptEnginepure virtual
GetModuleByIndex(asUINT index) const =0asIScriptEnginepure virtual
GetModuleCount() const =0asIScriptEnginepure virtual
GetObjectInGC(asUINT idx, asUINT *seqNbr=0, void **obj=0, asITypeInfo **type=0)=0asIScriptEnginepure virtual
GetObjectTypeByIndex(asUINT index) const =0asIScriptEnginepure virtual
GetObjectTypeCount() const =0asIScriptEnginepure virtual
GetSizeOfPrimitiveType(int typeId) const =0asIScriptEnginepure virtual
GetStringFactoryReturnTypeId(asDWORD *flags=0) const =0asIScriptEnginepure virtual
GetTypeDeclaration(int typeId, bool includeNamespace=false) const =0asIScriptEnginepure virtual
GetTypedefByIndex(asUINT index) const =0asIScriptEnginepure virtual
GetTypedefCount() const =0asIScriptEnginepure virtual
GetTypeIdByDecl(const char *decl) const =0asIScriptEnginepure virtual
GetTypeInfoByDecl(const char *decl) const =0asIScriptEnginepure virtual
GetTypeInfoById(int typeId) const =0asIScriptEnginepure virtual
GetTypeInfoByName(const char *name) const =0asIScriptEnginepure virtual
GetUserData(asPWORD type=0) const =0asIScriptEnginepure virtual
GetWeakRefFlagOfScriptObject(void *obj, const asITypeInfo *type) const =0asIScriptEnginepure virtual
NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type)=0asIScriptEnginepure virtual
ParseToken(const char *string, size_t stringLength=0, asUINT *tokenLength=0) const =0asIScriptEnginepure virtual
RefCastObject(void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast=false)=0asIScriptEnginepure virtual
RegisterDefaultArrayType(const char *type)=0asIScriptEnginepure virtual
RegisterEnum(const char *type)=0asIScriptEnginepure virtual
RegisterEnumValue(const char *type, const char *name, int value)=0asIScriptEnginepure virtual
RegisterFuncdef(const char *decl)=0asIScriptEnginepure virtual
RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0asIScriptEnginepure virtual
RegisterGlobalProperty(const char *declaration, void *pointer)=0asIScriptEnginepure virtual
RegisterInterface(const char *name)=0asIScriptEnginepure virtual
RegisterInterfaceMethod(const char *intf, const char *declaration)=0asIScriptEnginepure virtual
RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0asIScriptEnginepure virtual
RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0asIScriptEnginepure virtual
RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset=0, bool isCompositeIndirect=false)=0asIScriptEnginepure virtual
RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0asIScriptEnginepure virtual
RegisterStringFactory(const char *datatype, asIStringFactory *factory)=0asIScriptEnginepure virtual
RegisterTypedef(const char *type, const char *decl)=0asIScriptEnginepure virtual
Release() const =0asIScriptEnginepure virtual
ReleaseScriptObject(void *obj, const asITypeInfo *type)=0asIScriptEnginepure virtual
RemoveConfigGroup(const char *groupName)=0asIScriptEnginepure virtual
RequestContext()=0asIScriptEnginepure virtual
ReturnContext(asIScriptContext *ctx)=0asIScriptEnginepure virtual
SetCircularRefDetectedCallback(asCIRCULARREFFUNC_t callback, void *param=0)=0asIScriptEnginepure virtual
SetContextCallbacks(asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param=0)=0asIScriptEnginepure virtual
SetContextUserDataCleanupCallback(asCLEANCONTEXTFUNC_t callback, asPWORD type=0)=0asIScriptEnginepure virtual
SetDefaultAccessMask(asDWORD defaultMask)=0asIScriptEnginepure virtual
SetDefaultNamespace(const char *nameSpace)=0asIScriptEnginepure virtual
SetEngineProperty(asEEngineProp property, asPWORD value)=0asIScriptEnginepure virtual
SetEngineUserDataCleanupCallback(asCLEANENGINEFUNC_t callback, asPWORD type=0)=0asIScriptEnginepure virtual
SetFunctionUserDataCleanupCallback(asCLEANFUNCTIONFUNC_t callback, asPWORD type=0)=0asIScriptEnginepure virtual
SetJITCompiler(asIJITCompiler *compiler)=0asIScriptEnginepure virtual
SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv)=0asIScriptEnginepure virtual
SetModuleUserDataCleanupCallback(asCLEANMODULEFUNC_t callback, asPWORD type=0)=0asIScriptEnginepure virtual
SetScriptObjectUserDataCleanupCallback(asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type=0)=0asIScriptEnginepure virtual
SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv)=0asIScriptEnginepure virtual
SetTypeInfoUserDataCleanupCallback(asCLEANTYPEINFOFUNC_t callback, asPWORD type=0)=0asIScriptEnginepure virtual
SetUserData(void *data, asPWORD type=0)=0asIScriptEnginepure virtual
ShutDownAndRelease()=0asIScriptEnginepure virtual
WriteMessage(const char *section, int row, int col, asEMsgType type, const char *message)=0asIScriptEnginepure virtual
+
+ + + + diff --git a/docs/manual/classas_i_script_engine.html b/docs/manual/classas_i_script_engine.html new file mode 100644 index 0000000..c54d89b --- /dev/null +++ b/docs/manual/classas_i_script_engine.html @@ -0,0 +1,4344 @@ + + + + + + + +AngelScript: asIScriptEngine Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIScriptEngine Class Referenceabstract
+
+
+ +

The engine interface. + More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

Memory management
virtual int AddRef () const =0
 Increase reference counter. More...
 
virtual int Release () const =0
 Decrease reference counter. More...
 
virtual int ShutDownAndRelease ()=0
 Shuts down the engine then decrease the reference counter. More...
 
Engine properties
virtual int SetEngineProperty (asEEngineProp property, asPWORD value)=0
 Dynamically change some engine properties. More...
 
virtual asPWORD GetEngineProperty (asEEngineProp property) const =0
 Retrieve current engine property settings. More...
 
Compiler messages
virtual int SetMessageCallback (const asSFuncPtr &callback, void *obj, asDWORD callConv)=0
 Sets a message callback that will receive compiler messages. More...
 
virtual int ClearMessageCallback ()=0
 Clears the registered message callback routine. More...
 
virtual int WriteMessage (const char *section, int row, int col, asEMsgType type, const char *message)=0
 Writes a message to the message callback. More...
 
JIT compiler
virtual int SetJITCompiler (asIJITCompiler *compiler)=0
 Sets the JIT compiler. More...
 
virtual asIJITCompilerGetJITCompiler () const =0
 Returns the JIT compiler. More...
 
Global functions
virtual int RegisterGlobalFunction (const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
 Registers a global function. More...
 
virtual asUINT GetGlobalFunctionCount () const =0
 Returns the number of registered functions. More...
 
virtual asIScriptFunctionGetGlobalFunctionByIndex (asUINT index) const =0
 Returns the registered function. More...
 
virtual asIScriptFunctionGetGlobalFunctionByDecl (const char *declaration) const =0
 Returns the registered function. More...
 
Global properties
virtual int RegisterGlobalProperty (const char *declaration, void *pointer)=0
 Registers a global property. More...
 
virtual asUINT GetGlobalPropertyCount () const =0
 Returns the number of registered global properties. More...
 
virtual int GetGlobalPropertyByIndex (asUINT index, const char **name, const char **nameSpace=0, int *typeId=0, bool *isConst=0, const char **configGroup=0, void **pointer=0, asDWORD *accessMask=0) const =0
 Returns the detail on the registered global property. More...
 
virtual int GetGlobalPropertyIndexByName (const char *name) const =0
 Returns the index of the property. More...
 
virtual int GetGlobalPropertyIndexByDecl (const char *decl) const =0
 Returns the index of the property. More...
 
Object types
virtual int RegisterObjectType (const char *obj, int byteSize, asDWORD flags)=0
 Registers a new object type. More...
 
virtual int RegisterObjectProperty (const char *obj, const char *declaration, int byteOffset, int compositeOffset=0, bool isCompositeIndirect=false)=0
 Registers a property for the object type. More...
 
virtual int RegisterObjectMethod (const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
 Registers a method for the object type. More...
 
virtual int RegisterObjectBehaviour (const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
 Registers a behaviour for the object type. More...
 
virtual int RegisterInterface (const char *name)=0
 Registers a script interface. More...
 
virtual int RegisterInterfaceMethod (const char *intf, const char *declaration)=0
 Registers a script interface method. More...
 
virtual asUINT GetObjectTypeCount () const =0
 Returns the number of registered object types. More...
 
virtual asITypeInfoGetObjectTypeByIndex (asUINT index) const =0
 Returns the object type interface by index. More...
 
String factory
virtual int RegisterStringFactory (const char *datatype, asIStringFactory *factory)=0
 Registers the string factory. More...
 
virtual int GetStringFactoryReturnTypeId (asDWORD *flags=0) const =0
 Returns the type id of the type that the string factory returns. More...
 
Default array type
virtual int RegisterDefaultArrayType (const char *type)=0
 Registers the type that should be used as the default array. More...
 
virtual int GetDefaultArrayTypeId () const =0
 Returns the type id of the registered type. More...
 
Enums
virtual int RegisterEnum (const char *type)=0
 Registers an enum type. More...
 
virtual int RegisterEnumValue (const char *type, const char *name, int value)=0
 Registers an enum value. More...
 
virtual asUINT GetEnumCount () const =0
 Returns the number of registered enum types. More...
 
virtual asITypeInfoGetEnumByIndex (asUINT index) const =0
 Returns the registered enum type. More...
 
Funcdefs
virtual int RegisterFuncdef (const char *decl)=0
 Registers a function definition. More...
 
virtual asUINT GetFuncdefCount () const =0
 Returns the number of registered function definitions. More...
 
virtual asITypeInfoGetFuncdefByIndex (asUINT index) const =0
 Returns a registered function definition. More...
 
Typedefs
virtual int RegisterTypedef (const char *type, const char *decl)=0
 Registers a typedef. More...
 
virtual asUINT GetTypedefCount () const =0
 Returns the number of registered typedefs. More...
 
virtual asITypeInfoGetTypedefByIndex (asUINT index) const =0
 Returns a registered typedef. More...
 
Configuration groups
virtual int BeginConfigGroup (const char *groupName)=0
 Starts a new dynamic configuration group. More...
 
virtual int EndConfigGroup ()=0
 Ends the configuration group. More...
 
virtual int RemoveConfigGroup (const char *groupName)=0
 Removes a previously registered configuration group. More...
 
virtual asDWORD SetDefaultAccessMask (asDWORD defaultMask)=0
 Sets the access mask that should be used for subsequent registered entities. More...
 
virtual int SetDefaultNamespace (const char *nameSpace)=0
 Sets the current default namespace for registrations and searches. More...
 
virtual const char * GetDefaultNamespace () const =0
 Returns the current default namespace. More...
 
Script modules
virtual asIScriptModuleGetModule (const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
 Return an interface pointer to the module. More...
 
virtual int DiscardModule (const char *module)=0
 Discard a module. More...
 
virtual asUINT GetModuleCount () const =0
 Get the number of modules. More...
 
virtual asIScriptModuleGetModuleByIndex (asUINT index) const =0
 Get a module by index. More...
 
Script functions
virtual asIScriptFunctionGetFunctionById (int funcId) const =0
 Returns the function by its id. More...
 
Type identification
virtual int GetTypeIdByDecl (const char *decl) const =0
 Returns a type id by declaration. More...
 
virtual const char * GetTypeDeclaration (int typeId, bool includeNamespace=false) const =0
 Returns a type declaration. More...
 
virtual int GetSizeOfPrimitiveType (int typeId) const =0
 Returns the size of a primitive type. More...
 
virtual asITypeInfoGetTypeInfoById (int typeId) const =0
 Returns the type interface for type. More...
 
virtual asITypeInfoGetTypeInfoByName (const char *name) const =0
 Returns the type interface by name. More...
 
virtual asITypeInfoGetTypeInfoByDecl (const char *decl) const =0
 Returns a type by declaration. More...
 
Script execution
virtual asIScriptContextCreateContext ()=0
 Creates a new script context. More...
 
virtual void * CreateScriptObject (const asITypeInfo *type)=0
 Creates an object defined by its type. More...
 
virtual void * CreateScriptObjectCopy (void *obj, const asITypeInfo *type)=0
 Creates a copy of a script object. More...
 
virtual void * CreateUninitializedScriptObject (const asITypeInfo *type)=0
 Creates an uninitialized script object defined by its type. More...
 
virtual asIScriptFunctionCreateDelegate (asIScriptFunction *func, void *obj)=0
 Create a delegate for an object and method. More...
 
virtual int AssignScriptObject (void *dstObj, void *srcObj, const asITypeInfo *type)=0
 Copy one script object to another. More...
 
virtual void ReleaseScriptObject (void *obj, const asITypeInfo *type)=0
 Release the object pointer. More...
 
virtual void AddRefScriptObject (void *obj, const asITypeInfo *type)=0
 Increase the reference counter for the script object. More...
 
virtual int RefCastObject (void *obj, asITypeInfo *fromType, asITypeInfo *toType, void **newPtr, bool useOnlyImplicitCast=false)=0
 Returns the handle on a successful reference cast to desired type. More...
 
virtual asILockableSharedBoolGetWeakRefFlagOfScriptObject (void *obj, const asITypeInfo *type) const =0
 Returns the weak ref flag from the object. More...
 
Context pooling
virtual asIScriptContextRequestContext ()=0
 Request a context. More...
 
virtual void ReturnContext (asIScriptContext *ctx)=0
 Return a context when it won't be used anymore. More...
 
virtual int SetContextCallbacks (asREQUESTCONTEXTFUNC_t requestCtx, asRETURNCONTEXTFUNC_t returnCtx, void *param=0)=0
 Register context callbacks for pooling. More...
 
String interpretation
virtual asETokenClass ParseToken (const char *string, size_t stringLength=0, asUINT *tokenLength=0) const =0
 Returns the class and length of the first token in the string. More...
 
Garbage collection
virtual int GarbageCollect (asDWORD flags=asGC_FULL_CYCLE, asUINT numIterations=1)=0
 Perform garbage collection. More...
 
virtual void GetGCStatistics (asUINT *currentSize, asUINT *totalDestroyed=0, asUINT *totalDetected=0, asUINT *newObjects=0, asUINT *totalNewDestroyed=0) const =0
 Obtain statistics from the garbage collector. More...
 
virtual int NotifyGarbageCollectorOfNewObject (void *obj, asITypeInfo *type)=0
 Notify the garbage collector of a new object that needs to be managed. More...
 
virtual int GetObjectInGC (asUINT idx, asUINT *seqNbr=0, void **obj=0, asITypeInfo **type=0)=0
 Gets an object in the garbage collector. More...
 
virtual void GCEnumCallback (void *reference)=0
 Used by the garbage collector to enumerate all references held by an object. More...
 
virtual void ForwardGCEnumReferences (void *ref, asITypeInfo *type)=0
 Used to forward GC callback to held value types that may contain references. More...
 
virtual void ForwardGCReleaseReferences (void *ref, asITypeInfo *type)=0
 Used to forward GC callback to held value types that may contain references. More...
 
virtual void SetCircularRefDetectedCallback (asCIRCULARREFFUNC_t callback, void *param=0)=0
 Set a callback for capturing more info on circular reference for debugging. More...
 
User data
virtual void * SetUserData (void *data, asPWORD type=0)=0
 Register the memory address of some user data. More...
 
virtual void * GetUserData (asPWORD type=0) const =0
 Returns the address of the previously registered user data. More...
 
virtual void SetEngineUserDataCleanupCallback (asCLEANENGINEFUNC_t callback, asPWORD type=0)=0
 Set the function that should be called when the engine is destroyed. More...
 
virtual void SetModuleUserDataCleanupCallback (asCLEANMODULEFUNC_t callback, asPWORD type=0)=0
 Set the function that should be called when the module is destroyed. More...
 
virtual void SetContextUserDataCleanupCallback (asCLEANCONTEXTFUNC_t callback, asPWORD type=0)=0
 Set the function that should be called when a context is destroyed. More...
 
virtual void SetFunctionUserDataCleanupCallback (asCLEANFUNCTIONFUNC_t callback, asPWORD type=0)=0
 Set the function that should be called when a function is destroyed. More...
 
virtual void SetTypeInfoUserDataCleanupCallback (asCLEANTYPEINFOFUNC_t callback, asPWORD type=0)=0
 Set the function that should be called when a type info is destroyed. More...
 
virtual void SetScriptObjectUserDataCleanupCallback (asCLEANSCRIPTOBJECTFUNC_t callback, asPWORD type=0)=0
 Set the function that should be called when a script object is destroyed. More...
 
Exception handling
virtual int SetTranslateAppExceptionCallback (asSFuncPtr callback, void *param, int callConv)=0
 Register the exception translation callback. More...
 
+

Detailed Description

+

The engine is the central object. It is where the application registers the application interface that the scripts should be able to use, and it is where the application can request modules to build scripts and contexts to execute them.

+

The engine instance is created with a call to asCreateScriptEngine.

+

It is allowed to have multiple instances of script engines, but there is rarely a need for it. Even if the application needs to expose different interfaces to different types of scripts this can usually be accomplished through the use of configuration groups and access profiles.

+

Member Function Documentation

+ +

◆ AddRef()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptEngine::AddRef () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when storing an additional reference to the object. Remember that the first reference that is received from asCreateScriptEngine is already accounted for.

+ +
+
+ +

◆ AddRefScriptObject()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::AddRefScriptObject (void * obj,
const asITypeInfotype 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]objA pointer to the object.
[in]typeThe type of the object.
+
+
+

This calls the add ref method of the object to increase the reference count.

+ +
+
+ +

◆ AssignScriptObject()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::AssignScriptObject (void * dstObj,
void * srcObj,
const asITypeInfotype 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]dstObjA pointer to the destination object.
[in]srcObjA pointer to the source object.
[in]typeThe type of the objects.
+
+
+
Returns
A negative value on error
+
Return values
+ + + +
asINVALID_ARGOne of the arguments is null
asNOT_SUPPORTEDThe object type is a ref type and value assignment has been turned off
+
+
+

This calls the assignment operator to copy the object from one to the other.

+

This only works for objects.

+ +
+
+ +

◆ BeginConfigGroup()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::BeginConfigGroup (const char * groupName)
+
+pure virtual
+
+
Parameters
+ + +
[in]groupNameThe name of the configuration group
+
+
+
Returns
A negative value on error
+
Return values
+ + + +
asNAME_TAKENAnother group with the same name already exists.
asNOT_SUPPORTEDNesting configuration groups is not supported.
+
+
+

Starts a new dynamic configuration group. This group can be setup so that it is only visible to specific modules, and it can also be removed when it is no longer used.

+
See also
Dynamic configurations
+ +
+
+ +

◆ ClearMessageCallback()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptEngine::ClearMessageCallback ()
+
+pure virtual
+
+
Returns
A negative value on error.
+

Call this method to remove the message callback.

+ +
+
+ +

◆ CreateContext()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptContext* asIScriptEngine::CreateContext ()
+
+pure virtual
+
+
Returns
A pointer to the new script context.
+

This method creates a context that will be used to execute the script functions. The context interface created will have its reference counter already increased.

+
See also
RequestContext
+ +
+
+ +

◆ CreateDelegate()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual asIScriptFunction* asIScriptEngine::CreateDelegate (asIScriptFunctionfunc,
void * obj 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]funcThe object method
[in]objThe object pointer
+
+
+
Returns
The new delegate instance
+ +
+
+ +

◆ CreateScriptObject()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptEngine::CreateScriptObject (const asITypeInfotype)
+
+pure virtual
+
+
Parameters
+ + +
[in]typeThe type of the object to create.
+
+
+
Returns
A pointer to the new object if successful, or null if not.
+

This method is used to create an object based on it's type. The method will call the object type's default factory. If the object type doesn't have a default factory the call will fail and no object will be created.

+

Created objects will have their reference counter set to 1 so the application needs to release the pointer when it will no longer use it.

+

If the type is a registered value type, then the memory for the object will be allocated using the default memory routine. To destroy and and deallocate the object it is best to use ReleaseScriptObject.

+

The method only works for objects, for primitive types and object handles the method doesn't do anything and returns a null pointer.

+ +
+
+ +

◆ CreateScriptObjectCopy()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asIScriptEngine::CreateScriptObjectCopy (void * obj,
const asITypeInfotype 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]objA pointer to the source object.
[in]typeThe type of the object.
+
+
+
Returns
A pointer to the new object if successful, or null if not.
+

This method is used to create a copy of an existing object.

+

This only works for objects, for primitive types and object handles the method doesn't do anything and returns a null pointer.

+ +
+
+ +

◆ CreateUninitializedScriptObject()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptEngine::CreateUninitializedScriptObject (const asITypeInfotype)
+
+pure virtual
+
+
Parameters
+ + +
[in]typeThe type of the object to create.
+
+
+
Returns
A pointer to the new object if successful, or null if not.
+

This method can only be used to create instances of script classes.

+

The returned object will only be initialized so far that there are no invalid pointers or references. The constructor of the script class will not be invoked.

+

If the script class has any registered types as members, the default constructor for those members will be executed.

+

This method is meant for objects that will be initialized manually by the application, e.g. when restoring a serialized object.

+ +
+
+ +

◆ DiscardModule()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::DiscardModule (const char * module)
+
+pure virtual
+
+
Parameters
+ + +
[in]moduleThe name of the module
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asNO_MODULEThe module was not found.
+
+
+

Discards a module and frees its memory. Any pointers that the application holds to this module will be invalid after this call.

+ +
+
+ +

◆ EndConfigGroup()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptEngine::EndConfigGroup ()
+
+pure virtual
+
+
Returns
A negative value on error
+
Return values
+ + +
asERRORCan't end a group that hasn't been begun.
+
+
+

Ends the current configuration group. Once finished a config group cannot be changed, but it can be removed when it is no longer used.

+
See also
Dynamic configurations
+ +
+
+ +

◆ ForwardGCEnumReferences()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::ForwardGCEnumReferences (void * ref,
asITypeInfotype 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]refThe object pointer
[in]typeThe type of the object
+
+
+

This should be used by reference types that implement the asBEHAVE_ENUMREFS behaviour when the object holds a value type that can in turn contain references.

+
See also
Garbage collected objects
+ +
+
+ +

◆ ForwardGCReleaseReferences()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::ForwardGCReleaseReferences (void * ref,
asITypeInfotype 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]refThe object pointer
[in]typeThe type of the object
+
+
+

This should be used by reference types that implement the asBEHAVE_RELEASEREFS behaviour when the object holds a value type that can in turn contain references.

+
See also
Garbage collected objects
+ +
+
+ +

◆ GarbageCollect()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::GarbageCollect (asDWORD flags = asGC_FULL_CYCLE,
asUINT numIterations = 1 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]flagsSet to a combination of the asEGCFlags.
[in]numIterationsThe number of iterations to perform when not doing a full cycle
+
+
+
Returns
1 if the cycle wasn't completed, 0 if it was.
+

This method will free script objects that can no longer be reached. When the engine is released the garbage collector will automatically do a full cycle to release all objects still alive. If the engine is long living it is important to call this method every once in a while to free up memory allocated by the scripts. If a script does a lot of allocations before returning it may be necessary to implement a line callback function that calls the garbage collector during execution of the script.

+

It is not necessary to do a full cycle with every call. This makes it possible to spread out the garbage collection time over a large period, thus not impacting the responsiveness of the application.

+
See also
Garbage collection
+ +
+
+ +

◆ GCEnumCallback()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void asIScriptEngine::GCEnumCallback (void * reference)
+
+pure virtual
+
+
Parameters
+ + +
[in]referenceA pointer to the referenced object.
+
+
+

When processing the asBEHAVE_ENUMREFS call the called object should call GCEnumCallback for each of the references it holds to other objects. If the object holds a value type that may contain references, then use the ForwardGCEnumReferences.

+
See also
Garbage collected objects
+ +
+
+ +

◆ GetDefaultArrayTypeId()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptEngine::GetDefaultArrayTypeId () const
+
+pure virtual
+
+
Returns
The type id, or a negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe default array type hasn't been registered.
+
+
+ +
+
+ +

◆ GetDefaultNamespace()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptEngine::GetDefaultNamespace () const
+
+pure virtual
+
+
Returns
The current default namespace
+ +
+
+ +

◆ GetEngineProperty()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asPWORD asIScriptEngine::GetEngineProperty (asEEngineProp property) const
+
+pure virtual
+
+
Parameters
+ + +
[in]propertyOne of the asEEngineProp values.
+
+
+
Returns
The value of the property, or 0 if it is an invalid property.
+

Calling this method lets you determine the current value of the engine properties.

+ +
+
+ +

◆ GetEnumByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptEngine::GetEnumByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the enum type.
+
+
+
Returns
The type info of the registered enum type, or null on error.
+ +
+
+ +

◆ GetEnumCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptEngine::GetEnumCount () const
+
+pure virtual
+
+
Returns
The number of registered enum types.
+ +
+
+ +

◆ GetFuncdefByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptEngine::GetFuncdefByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the funcdef.
+
+
+
Returns
The type info of the funcdef.
+

This function does not increase the reference count of the returned function definition.

+ +
+
+ +

◆ GetFuncdefCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptEngine::GetFuncdefCount () const
+
+pure virtual
+
+
Returns
The number of registered funcdefs.
+ +
+
+ +

◆ GetFunctionById()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asIScriptEngine::GetFunctionById (int funcId) const
+
+pure virtual
+
+
Parameters
+ + +
[in]funcIdThe id of the function or method.
+
+
+
Returns
A pointer to the function description interface, or null if not found.
+

This does not increment the reference count of the returned function interface.

+ +
+
+ +

◆ GetGCStatistics()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::GetGCStatistics (asUINTcurrentSize,
asUINTtotalDestroyed = 0,
asUINTtotalDetected = 0,
asUINTnewObjects = 0,
asUINTtotalNewDestroyed = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + + + + +
[out]currentSizeThe current number of objects known to the garbage collector.
[out]totalDestroyedThe total number of objects destroyed by the garbage collector.
[out]totalDetectedThe total number of objects detected as garbage with circular references.
[out]newObjectsThe current number of objects in the new generation.
[out]totalNewDestroyedThe total number of objects destroyed while still in the new generation.
+
+
+

This method can be used to query the number of objects that the garbage collector is keeping track of. If the number is very large then it is probably time to call the GarbageCollect method so that some of the objects ca be freed.

+
See also
Garbage collection
+ +
+
+ +

◆ GetGlobalFunctionByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asIScriptEngine::GetGlobalFunctionByDecl (const char * declaration) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declarationThe signature of the function.
+
+
+
Returns
The function object, or null on error.
+ +
+
+ +

◆ GetGlobalFunctionByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asIScriptEngine::GetGlobalFunctionByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the registered global function.
+
+
+
Returns
The function object, or null on error.
+ +
+
+ +

◆ GetGlobalFunctionCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptEngine::GetGlobalFunctionCount () const
+
+pure virtual
+
+
Returns
The number of registered functions.
+ +
+
+ +

◆ GetGlobalPropertyByIndex()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::GetGlobalPropertyByIndex (asUINT index,
const char ** name,
const char ** nameSpace = 0,
int * typeId = 0,
bool * isConst = 0,
const char ** configGroup = 0,
void ** pointer = 0,
asDWORDaccessMask = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + + + + + + + +
[in]indexThe index of the global variable.
[out]nameReceives the name of the property.
[out]nameSpaceReceives the namespace of the property.
[out]typeIdReceives the typeId of the property.
[out]isConstReceives the constness indicator of the property.
[out]configGroupReceives the config group in which the property was registered.
[out]pointerReceives the pointer of the property.
[out]accessMaskReceives the access mask of the property.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_ARGindex is too large.
+
+
+ +
+
+ +

◆ GetGlobalPropertyCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptEngine::GetGlobalPropertyCount () const
+
+pure virtual
+
+
Returns
The number of registered global properties.
+ +
+
+ +

◆ GetGlobalPropertyIndexByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::GetGlobalPropertyIndexByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe declaration of the property to search for.
+
+
+
Returns
The index of the matching property or negative on error.
+
Return values
+ + + +
asNO_GLOBAL_VARNo matching property was found.
asINVALID_DECLARATIONThe given declaration is invalid.
+
+
+ +
+
+ +

◆ GetGlobalPropertyIndexByName()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::GetGlobalPropertyIndexByName (const char * name) const
+
+pure virtual
+
+
Parameters
+ + +
[in]nameThe name of the property.
+
+
+
Returns
The index of the matching property or negative on error.
+
Return values
+ + + +
asNO_GLOBAL_VARNo matching property was found.
asINVALID_ARGThe name and scope for search cannot be determined.
+
+
+

The search for global properties will be performed in the default namespace as given by SetDefaultNamespace unless the name is prefixed with a scope, using the scoping operator ::. If the scope starts with :: it will be used as the absolute scope, otherwise it will be relative to the default namespace.

+ +
+
+ +

◆ GetJITCompiler()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIJITCompiler* asIScriptEngine::GetJITCompiler () const
+
+pure virtual
+
+
Returns
Returns a pointer to the JIT compiler
+ +
+
+ +

◆ GetModule()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual asIScriptModule* asIScriptEngine::GetModule (const char * module,
asEGMFlags flag = asGM_ONLY_IF_EXISTS 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]moduleThe name of the module
[in]flagOne of the asEGMFlags flags
+
+
+
Returns
A pointer to the module interface
+

Use this method to get access to the module interface, which will let you build new scripts, and enumerate functions and types in existing modules.

+

If asGM_ALWAYS_CREATE is informed as the flag the previous module with the same name will be discarded, thus any pointers that the engine holds to it will be invalid after the call.

+ +
+
+ +

◆ GetModuleByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptModule* asIScriptEngine::GetModuleByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the module.
+
+
+
Returns
A pointer to the module or null on error.
+ +
+
+ +

◆ GetModuleCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptEngine::GetModuleCount () const
+
+pure virtual
+
+
Returns
The number of modules.
+ +
+
+ +

◆ GetObjectInGC()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::GetObjectInGC (asUINT idx,
asUINTseqNbr = 0,
void ** obj = 0,
asITypeInfo ** type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + + + +
[in]idxThe index of the desired object
[out]seqNbrThe sequence number of the obtained object
[out]objThe object pointer
[out]typeThe type of the obtained object
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asINVALID_ARGThe index is not valid
+
+
+ +
+
+ +

◆ GetObjectTypeByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptEngine::GetObjectTypeByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the type.
+
+
+
Returns
The registered object type interface for the type, or null if not found.
+ +
+
+ +

◆ GetObjectTypeCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptEngine::GetObjectTypeCount () const
+
+pure virtual
+
+
Returns
The number of object types registered by the application.
+ +
+
+ +

◆ GetSizeOfPrimitiveType()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::GetSizeOfPrimitiveType (int typeId) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeIdThe type id of the type.
+
+
+
Returns
The size of the type in bytes, or zero if it is not a primitive type.
+

This method can be used to return the size of any built-in primitive type, and also for script declared or application registered enums.

+ +
+
+ +

◆ GetStringFactoryReturnTypeId()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::GetStringFactoryReturnTypeId (asDWORDflags = 0) const
+
+pure virtual
+
+
Returns
The type id of the type that the string type returns, or a negative value on error.
+
Parameters
+ + +
[out]flagsThe type modifiers for the return type
+
+
+
Return values
+ + +
asNO_FUNCTIONThe string factory has not been registered.
+
+
+ +
+
+ +

◆ GetTypeDeclaration()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual const char* asIScriptEngine::GetTypeDeclaration (int typeId,
bool includeNamespace = false 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]typeIdThe type id of the type.
[in]includeNamespaceSet to true if the namespace should be included in the formatted declaration.
+
+
+
Returns
A null terminated string with the type declaration, or null if not found.
+ +
+
+ +

◆ GetTypedefByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptEngine::GetTypedefByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the typedef.
+
+
+
Returns
The type info of the typedef.
+ +
+
+ +

◆ GetTypedefCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptEngine::GetTypedefCount () const
+
+pure virtual
+
+
Returns
The number of registered typedefs.
+ +
+
+ +

◆ GetTypeIdByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::GetTypeIdByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe declaration of the type.
+
+
+
Returns
A negative value on error, or the type id of the type.
+
Return values
+ + +
asINVALID_TYPEdecl is not a valid type.
+
+
+

Translates a type declaration into a type id. The returned type id is valid for as long as the type is valid, so you can safely store it for later use to avoid potential overhead by calling this function each time. Just remember to update the type id, any time the type is changed within the engine, e.g. when recompiling script declared classes, or changing the engine configuration.

+

The type id is based on a sequence number and depends on the order in which the type ids are queried, thus is not guaranteed to always be the same for each execution of the application. The asETypeIdFlags can be used to obtain some information about the type directly from the id.

+

A base type yields the same type id whether the declaration is const or not, however if the const is for the subtype then the type id is different, e.g. string@ isn't the same as const string@ but string is the same as const string.

+

This method is only able to return the type id that are not specific for a script module, i.e. built-in types and application registered types. Type ids for script declared types should be obtained through the script module's GetTypeIdByDecl.

+ +
+
+ +

◆ GetTypeInfoByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptEngine::GetTypeInfoByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe declaration of the type.
+
+
+
Returns
The type or null on error.
+

Translates a type declaration into the type info. The returned type is valid for as long as the type is valid, so you can safely store it for later use to avoid potential overhead from calling this function each time. Just remember to update the type info pointer any time the type is changed within the engine, e.g. when recompiling script declared classes, or changing the engine configuration.

+ +
+
+ +

◆ GetTypeInfoById()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptEngine::GetTypeInfoById (int typeId) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeIdThe type id of the type.
+
+
+
Returns
The type interface for the type, or null if not found.
+

This does not increment the reference count of the returned type.

+ +
+
+ +

◆ GetTypeInfoByName()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptEngine::GetTypeInfoByName (const char * name) const
+
+pure virtual
+
+
Parameters
+ + +
[in]nameThe name of the type.
+
+
+
Returns
The type interface for the type, or null if not found.
+

The search for types will be performed in the default namespace as given by SetDefaultNamespace unless the name is prefixed with a scope, using the scoping operator ::. If the scope starts with :: it will be used as the absolute scope, otherwise it will be relative to the default namespace.

+ +
+
+ +

◆ GetUserData()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptEngine::GetUserData (asPWORD type = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeAn identifier specifying the user data to get.
+
+
+
Returns
The pointer to the user data.
+ +
+
+ +

◆ GetWeakRefFlagOfScriptObject()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual asILockableSharedBool* asIScriptEngine::GetWeakRefFlagOfScriptObject (void * obj,
const asITypeInfotype 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]objThe object
[in]typeThe object type
+
+
+
Returns
The weak ref flag, if the object supports weak references.
+

As long as the weak ref flag is not set, the owning object is still alive. Once the weak ref flag is set, the object is dead and should no longer be accessed. Check if the flag is set with the asILockableSharedBool::Get method.

+

This method doesn't increase the reference to the returned shared boolean.

+ +
+
+ +

◆ NotifyGarbageCollectorOfNewObject()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::NotifyGarbageCollectorOfNewObject (void * obj,
asITypeInfotype 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]objA pointer to the newly created object.
[in]typeThe type of the object.
+
+
+
Returns
The sequence number of the added object, or a negative value on error.
+
Return values
+ + +
asINVALID_ARGEither the object or the type is null
+
+
+

This method should be called when a new garbage collected object is created. The GC will then store a reference to the object so that it can automatically detect whether the object is involved in any circular references that should be released.

+
See also
Garbage collected objects
+ +
+
+ +

◆ ParseToken()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual asETokenClass asIScriptEngine::ParseToken (const char * string,
size_t stringLength = 0,
asUINTtokenLength = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + + +
[in]stringThe string to parse.
[in]stringLengthThe length of the string. Can be 0 if the string is null terminated.
[out]tokenLengthGives the length of the identified token.
+
+
+
Returns
One of the asETokenClass values.
+

This function is useful for those applications that want to tokenize strings into tokens that the script language uses, e.g. IDEs providing syntax highlighting, or intellisense. It can also be used to parse the meta data strings that may be declared for script entities.

+ +
+
+ +

◆ RefCastObject()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RefCastObject (void * obj,
asITypeInfofromType,
asITypeInfotoType,
void ** newPtr,
bool useOnlyImplicitCast = false 
)
+
+pure virtual
+
+
Parameters
+ + + + + + +
[in]objA pointer to the object.
[in]fromTypeThe type of the object.
[in]toTypeThe desired type for the cast.
[out]newPtrThe new pointer to the object if successful.
[in]useOnlyImplicitCastIf only the implicit reference cast operators should be used.
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asINVALID_ARGA null pointer was supplied
+
+
+

This method is used to cast an pointer to a different type. While both the new and old pointers are expected to refer to the same instance, the address of the pointers are not necessarily the same.

+

If the cast is successful the newPtr will be set to the new pointer, and the reference counter will be incremented. If the cast is not successful, the newPtr will be set to null, and the reference count left unchanged.

+ +
+
+ +

◆ RegisterDefaultArrayType()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::RegisterDefaultArrayType (const char * type)
+
+pure virtual
+
+
Parameters
+ + +
[in]typeThe name of the template type, e.g. array<T>
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe type is not a template type
+
+
+ +
+
+ +

◆ RegisterEnum()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::RegisterEnum (const char * type)
+
+pure virtual
+
+
Parameters
+ + +
[in]typeThe name of the enum type.
+
+
+
Returns
The type id on success, or a negative value on error.
+
Return values
+ + + + + +
asINVALID_NAMEtype is null, not an identifier, or it is a reserved keyword.
asALREADY_REGISTEREDAnother type with this name already exists.
asERRORThe type couldn't be parsed.
asNAME_TAKENThe type name is already taken.
+
+
+

This method registers an enum type in the engine. The enum values should then be registered with RegisterEnumValue.

+ +
+
+ +

◆ RegisterEnumValue()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterEnumValue (const char * type,
const char * name,
int value 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]typeThe name of the enum type.
[in]nameThe name of the enum value.
[in]valueThe integer value of the enum value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asWRONG_CONFIG_GROUPThe enum type was registered in a different configuration group.
asINVALID_TYPEThe type is invalid.
asALREADY_REGISTEREDThe name is already registered for this enum.
+
+
+

This method registers an enum value for a previously registered enum type.

+ +
+
+ +

◆ RegisterFuncdef()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::RegisterFuncdef (const char * decl)
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe declaration of the function definition.
+
+
+
Returns
The type id on success, else a negative value on error.
+
Return values
+ + + + +
asINVALID_ARGThe decl parameter is not given.
asINVALID_DECLARATIONdecl is not a valid function definition.
asNAME_TAKENThe name of the funcdef conflicts with another name.
+
+
+

Funcdefs are used to define the signature of function pointers. If the application is going to receive function pointers from scripts, it is necessary to first register the funcdef before registering the function or property that will be used to receive it.

+

Funcdefs are usually registered as global entities, but can also be registered as a child of a class. To do this simply prefix the name of the funcdef with the name of the class and the scope operator to specify which class should be the owner.

+ +
+
+ +

◆ RegisterGlobalFunction()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterGlobalFunction (const char * declaration,
const asSFuncPtrfuncPointer,
asDWORD callConv,
void * auxiliary = 0 
)
+
+pure virtual
+
+
Parameters
+ + + + + +
[in]declarationThe declaration of the global function in script syntax.
[in]funcPointerThe function pointer.
[in]callConvThe calling convention for the function.
[in]auxiliaryA helper object for use with some calling conventions.
+
+
+
Returns
A negative value on error, or the function id if successful.
+
Return values
+ + + + + + + +
asNOT_SUPPORTEDThe calling convention is not supported.
asWRONG_CALLING_CONVThe function's calling convention doesn't match callConv.
asINVALID_DECLARATIONThe function declaration is invalid.
asNAME_TAKENThe function name is already used elsewhere.
asALREADY_REGISTEREDThe function has already been registered with the same parameter list.
asINVALID_ARGThe auxiliary pointer wasn't set according to calling convention.
+
+
+

This method registers system functions that the scripts may use to communicate with the host application.

+

The auxiliary pointer can optionally be used with asCALL_GENERIC. For the calling convention asCALL_THISCALL_ASGLOBAL the auxiliary is required.

+
See also
Registering a function
+ +
+
+ +

◆ RegisterGlobalProperty()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterGlobalProperty (const char * declaration,
void * pointer 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]declarationThe declaration of the global property in script syntax.
[in]pointerThe address of the property that will be used to access the property value.
+
+
+
Returns
The index of the property on success, or a negative value on error.
+
Return values
+ + + + + +
asINVALID_DECLARATIONThe declaration has invalid syntax.
asINVALID_TYPEThe declaration is a reference.
asINVALID_ARGThe pointer is null.
asNAME_TAKENThe name is already taken.
+
+
+

Use this method to register a global property that the scripts will be able to access as global variables. The property may optionally be registered as const, if the scripts shouldn't be allowed to modify it.

+

When registering the property, the application must pass the address to the actual value. The application must also make sure that this address remains valid throughout the life time of this registration, i.e. until the engine is released or the dynamic configuration group is removed.

+

Upon success the function returns the index of the registered property
+ that can be used to lookup the info with GetGlobalPropertyByIndex. Note that this index may not stay valid after a dynamic config group has been removed, which would reorganize the internal structure.

+ +
+
+ +

◆ RegisterInterface()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::RegisterInterface (const char * name)
+
+pure virtual
+
+
Parameters
+ + +
[in]nameThe name of the interface.
+
+
+
Returns
The type id of the interface on success, else a negative value on error.
+
Return values
+ + + + + +
asINVALID_NAMEThe name is null, or a reserved keyword.
asALREADY_REGISTEREDAn object type with this name already exists.
asERRORThe name is not a proper identifier.
asNAME_TAKENThe name is already used elsewhere.
+
+
+

This registers an interface that script classes can implement. By doing this the application can register functions and methods that receives an asIScriptObject and still be sure that the class implements certain methods needed by the application.

+
See also
Receiving script classes
+ +
+
+ +

◆ RegisterInterfaceMethod()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterInterfaceMethod (const char * intf,
const char * declaration 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]intfThe name of the interface.
[in]declarationThe method declaration.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + + +
asWRONG_CONFIG_GROUPThe interface was registered in another configuration group.
asINVALID_TYPEintf is not an interface type.
asINVALID_DECLARATIONThe declaration is invalid.
asNAME_TAKENThe method name is already taken.
+
+
+

This registers a method that the class that implements the script interface must have.

+ +
+
+ +

◆ RegisterObjectBehaviour()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterObjectBehaviour (const char * obj,
asEBehaviours behaviour,
const char * declaration,
const asSFuncPtrfuncPointer,
asDWORD callConv,
void * auxiliary = 0,
int compositeOffset = 0,
bool isCompositeIndirect = false 
)
+
+pure virtual
+
+
Parameters
+ + + + + + + + + +
[in]objThe name of the type.
[in]behaviourOne of the object behaviours from asEBehaviours.
[in]declarationThe declaration of the method in script syntax.
[in]funcPointerThe method or function pointer.
[in]callConvThe calling convention for the method or function.
[in]auxiliaryA helper object for use with some calling conventions.
[in]compositeOffsetThe offset to the composite object.
[in]isCompositeIndirectSet to false if the composite object is inline, and true if it is refered to by pointer.
+
+
+
Returns
A negative value on error, or the function id is successful.
+
Return values
+ + + + + + + + + +
asWRONG_CONFIG_GROUPThe object type was registered in a different configuration group.
asINVALID_ARGobj is not set, or a global behaviour is given in behaviour, or the objForThiscall pointer wasn't set according to calling convention.
asWRONG_CALLING_CONVThe function's calling convention isn't compatible with callConv.
asNOT_SUPPORTEDThe calling convention or the behaviour signature is not supported.
asINVALID_TYPEThe obj parameter is not a valid object name.
asINVALID_DECLARATIONThe declaration is invalid.
asILLEGAL_BEHAVIOUR_FOR_TYPEThe behaviour is not allowed for this type.
asALREADY_REGISTEREDThe behaviour is already registered with the same signature.
+
+
+

Use this method to register behaviour functions that will be called by the virtual machine to perform certain operations, such as memory management, math operations, comparisons, etc.

+

The declaration must form a valid function signature, but the give function name will not be used or stored in the application so there is no need to provide a meaningful function name.

+

The auxiliary pointer can optionally be used with asCALL_GENERIC. For the calling conventions asCALL_THISCALL_ASGLOBAL, asCALL_THISCALL_OBJFIRST and asCALL_THISCALL_OBJLAST the auxiliary is required.

+

In case the method to be registered is part of a composite member, then the compositeOffset should be used to give the offset to the composite member, and the method pointer should be method of the composite member. If the composite member is inline then set isCompositeIndirect as false, else set it to true for proper indirection.

+
See also
Registering a function, Registering operator behaviours
+ +
+
+ +

◆ RegisterObjectMethod()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterObjectMethod (const char * obj,
const char * declaration,
const asSFuncPtrfuncPointer,
asDWORD callConv,
void * auxiliary = 0,
int compositeOffset = 0,
bool isCompositeIndirect = false 
)
+
+pure virtual
+
+
Parameters
+ + + + + + + + +
[in]objThe name of the type.
[in]declarationThe declaration of the method in script syntax.
[in]funcPointerThe method or function pointer.
[in]callConvThe calling convention for the method or function.
[in]auxiliaryA helper object for use with some calling conventions.
[in]compositeOffsetThe offset to the composite object.
[in]isCompositeIndirectSet to false if the composite object is inline, and true if it is refered to by pointer.
+
+
+
Returns
A negative value on error, or the function id if successful.
+
Return values
+ + + + + + + + + +
asWRONG_CONFIG_GROUPThe object type was registered in a different configuration group.
asNOT_SUPPORTEDThe calling convention is not supported.
asINVALID_TYPEThe obj parameter is not a valid object name.
asINVALID_DECLARATIONThe declaration is invalid.
asNAME_TAKENThe name conflicts with other members.
asWRONG_CALLING_CONVThe function's calling convention isn't compatible with callConv.
asALREADY_REGISTEREDThe method has already been registered with the same parameter list.
asINVALID_ARGThe auxiliary pointer wasn't set according to calling convention.
+
+
+

Use this method to register a member method for the type. The method that is registered may be an actual class method, or a global function that takes the object pointer as either the first or last parameter. Or it may be a global function implemented with the generic calling convention.

+

The auxiliary pointer can optionally be used with asCALL_GENERIC. For the calling conventions asCALL_THISCALL_OBJFIRST and asCALL_THISCALL_OBJLAST the auxiliary is required.

+

In case the method to be registered is part of a composite member, then the compositeOffset should be used to give the offset to the composite member, and the method pointer should be method of the composite member. If the composite member is inline then set isCompositeIndirect as false, else set it to true for proper indirection.

+
See also
Registering a function
+ +
+
+ +

◆ RegisterObjectProperty()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterObjectProperty (const char * obj,
const char * declaration,
int byteOffset,
int compositeOffset = 0,
bool isCompositeIndirect = false 
)
+
+pure virtual
+
+
Parameters
+ + + + + + +
[in]objThe name of the type.
[in]declarationThe property declaration in script syntax.
[in]byteOffsetThe offset into the memory block where this property is found.
[in]compositeOffsetThe offset to the composite object.
[in]isCompositeIndirectSet to false if the composite object is inline, and true if it is refered to by pointer.
+
+
+
Returns
The index of the property on success, or a negative value on error.
+
Return values
+ + + + + + +
asWRONG_CONFIG_GROUPThe object type was registered in a different configuration group.
asINVALID_OBJECTThe obj does not specify an object type.
asINVALID_TYPEThe obj parameter has invalid syntax.
asINVALID_DECLARATIONThe declaration is invalid.
asNAME_TAKENThe name conflicts with other members.
+
+
+

Use this method to register a member property of a class. The property must be local to the object, i.e. not a global variable or a static member. The easiest way to get the offset of the property is to use the asOFFSET macro.

+
struct MyType {float prop;};
+
r = engine->RegisterObjectProperty("MyType", "float prop", asOFFSET(MyType, prop)));
+

In case the property to be registered is part of a composite member, then the compositeOffset should be used to give the offset to the composite member, and byteOffset should be the offset to the property in that composite member. If the composite member is inline then set isCompositeIndirect as false, else set it to true for proper indirection.

+

The method returns the index of the property upon success. This can be used to look up the property in the object type with asITypeInfo::GetProperty.

+ +
+
+ +

◆ RegisterObjectType()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterObjectType (const char * obj,
int byteSize,
asDWORD flags 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]objThe name of the type.
[in]byteSizeThe size of the type in bytes. Only necessary for value types.
[in]flagsOne or more of the asEObjTypeFlags.
+
+
+
Returns
The type id on success or a negative value on error.
+
Return values
+ + + + + + + + +
asINVALID_ARGThe flags are invalid.
asINVALID_NAMEThe name is invalid.
asALREADY_REGISTEREDAnother type of the same name already exists.
asNAME_TAKENThe name conflicts with other symbol names.
asLOWER_ARRAY_DIMENSION_NOT_REGISTEREDWhen registering an array type the array element must be a primitive or a registered type.
asINVALID_TYPEThe array type was not properly formed.
asNOT_SUPPORTEDThe array type is not supported, or already in use preventing it from being overloaded.
+
+
+

Use this method to register new types that should be available to the scripts. Reference types, which have their memory managed by the application, should be registered with asOBJ_REF. Value types, which have their memory managed by the engine, should be registered with asOBJ_VALUE.

+
See also
Registering an object type
+ +
+
+ +

◆ RegisterStringFactory()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterStringFactory (const char * datatype,
asIStringFactoryfactory 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]datatypeThe datatype that the string factory returns
[in]factoryThe pointer to the factory object
+
+
+
Returns
A negative value on error, or the function id if successful.
+
Return values
+ + + +
asINVALID_ARGThe factory is null.
asINVALID_TYPEThe datatype is not a valid type, or it is a reference or handle.
+
+
+

Use this function to register a string factory that will be called during compilation to create instances of a string constant. The string factory will also be used while saving bytecode in order to get the raw string data for serialization.

+

The data type that represents the string type should be informed without reference or handle token, as the script engine will assume a const reference anyway.

+
See also
Custom string type
+ +
+
+ +

◆ RegisterTypedef()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::RegisterTypedef (const char * type,
const char * decl 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]typeThe name of the new typedef
[in]declThe datatype that the typedef represents
+
+
+
Returns
The type id on success, else a negative value on error.
+
Return values
+ + + + + +
asINVALID_NAMEThe type is null, is not an identifier, or it is a reserved keyword.
asALREADY_REGISTEREDA type with the same name already exists.
asINVALID_TYPEThe decl is not a primitive type.
asNAME_TAKENThe name is already used elsewhere.
+
+
+

This method registers an alias for a data type.

+

Currently typedefs can only be registered for built-in primitive types.

+ +
+
+ +

◆ Release()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptEngine::Release () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when you will no longer use the references that you own.

+

If you know that the engine is supposed to be shut down, then it is recommended to call the ShutDownAndRelease method instead.

+ +
+
+ +

◆ ReleaseScriptObject()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::ReleaseScriptObject (void * obj,
const asITypeInfotype 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]objA pointer to the object.
[in]typeThe type of the object.
+
+
+

This calls the release method of the object to release the reference.

+

If the type is a value type, the method will destroy the object and deallocate the memory using the default memory routine.

+ +
+
+ +

◆ RemoveConfigGroup()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::RemoveConfigGroup (const char * groupName)
+
+pure virtual
+
+
Parameters
+ + +
[in]groupNameThe name of the configuration group
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asCONFIG_GROUP_IS_IN_USEThe group is in use and cannot be removed.
+
+
+

Remove the configuration group. If something in the configuration group is currently in use, the function will return with an error code. Examples of uses are compiled modules that have function calls to functions in the group and global variables of types registered in the group.

+
See also
Dynamic configurations
+ +
+
+ +

◆ RequestContext()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptContext* asIScriptEngine::RequestContext ()
+
+pure virtual
+
+
Returns
An unprepared context
+

This method will invoke the registered request context callback and return an available context in an unprepared state.

+

Contexts obtained through this method shouldn't be released, instead they should be returned to the origin with a call to ReturnContext.

+
See also
CreateContext
+ +
+
+ +

◆ ReturnContext()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void asIScriptEngine::ReturnContext (asIScriptContextctx)
+
+pure virtual
+
+
Parameters
+ + +
[in]ctxThe context that should be returned to the origin
+
+
+ +
+
+ +

◆ SetCircularRefDetectedCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::SetCircularRefDetectedCallback (asCIRCULARREFFUNC_t callback,
void * param = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]callbackThe callback function
[in]paramOptional parameter that will be passed back to the callback function
+
+
+

This callback is meant to be used during development to help identify scripts that are creating circular references. As the callback will be invoked when the objects in the circular reference are detected, but before they are destroyed, the application can investigate their content to get hints where the objects are created from.

+
See also
Garbage collection
+ +
+
+ +

◆ SetContextCallbacks()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::SetContextCallbacks (asREQUESTCONTEXTFUNC_t requestCtx,
asRETURNCONTEXTFUNC_t returnCtx,
void * param = 0 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]requestCtxThe request context callback function
[in]returnCtxThe return context callback function
[in]paramAn optional parameter that will be passed to the callback
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asINVALID_ARGOnly one of the context functions is informed
+
+
+

This method can be used by the application to implement a context pool, or to perform custom configuration on the contexts that the engine uses internally.

+

This can for example be used to debug calls to initialize global variables when building modules, or to detect script exceptions that may occur in script class destructors when called from the garbage collector.

+ +
+
+ +

◆ SetContextUserDataCleanupCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::SetContextUserDataCleanupCallback (asCLEANCONTEXTFUNC_t callback,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]callbackA pointer to the function
[in]typeAn identifier specifying which user data the callback is to be used with.
+
+
+

The function given with this call will be invoked when a context is destroyed if any user data has been registered with the context.

+

The function is called from within the context destructor, so the callback should not be used for anything but cleaning up the user data itself.

+ +
+
+ +

◆ SetDefaultAccessMask()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asDWORD asIScriptEngine::SetDefaultAccessMask (asDWORD defaultMask)
+
+pure virtual
+
+
Parameters
+ + +
[in]defaultMaskThe default access bit mask.
+
+
+
Returns
The previous default mask.
+
See also
Access masks and exposing different interfaces
+ +
+
+ +

◆ SetDefaultNamespace()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::SetDefaultNamespace (const char * nameSpace)
+
+pure virtual
+
+
Parameters
+ + +
[in]nameSpaceThe namespace that should be used.
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asINVALID_ARGThe namespace is invalid
+
+
+

Call this method to set the default namespace for which the following calls should assume. This applies to registration of the application interface and also to the functions that searches for registered entities.

+

Nested namespaces can be informed by separating them with the scope token, i.e. ::

+ +
+
+ +

◆ SetEngineProperty()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::SetEngineProperty (asEEngineProp property,
asPWORD value 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]propertyOne of the asEEngineProp values.
[in]valueThe new value of the property.
+
+
+
Returns
Negative value on error.
+
Return values
+ + +
asINVALID_ARGInvalid property.
+
+
+

With this method you can change the way the script engine works in some regards.

+ +
+
+ +

◆ SetEngineUserDataCleanupCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::SetEngineUserDataCleanupCallback (asCLEANENGINEFUNC_t callback,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]callbackA pointer to the function
[in]typeAn identifier specifying which user data the callback is to be used with.
+
+
+

The function given with this call will be invoked when the engine is destroyed if any user data has been registered with the engine.

+

The function is called from within the engine destructor, so the callback should not be used for anything but cleaning up the user data itself.

+ +
+
+ +

◆ SetFunctionUserDataCleanupCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::SetFunctionUserDataCleanupCallback (asCLEANFUNCTIONFUNC_t callback,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]callbackA pointer to the function
[in]typeAn identifier specifying which user data the callback is to be used with.
+
+
+

The function given with this call will be invoked when a function is destroyed if any user data has been registered with the function.

+

The function is called from within the function destructor, so the callback should not be used for anything but cleaning up the user data itself.

+ +
+
+ +

◆ SetJITCompiler()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptEngine::SetJITCompiler (asIJITCompilercompiler)
+
+pure virtual
+
+
Parameters
+ + +
[in]compilerA pointer to the JIT compiler
+
+
+
Returns
A negative value on error.
+

This method is used to set the JIT compiler. The engine will automatically invoke the JIT compiler when it is set after compiling scripts or loading pre-compiled byte code.

+
See also
How to build a JIT compiler
+ +
+
+ +

◆ SetMessageCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::SetMessageCallback (const asSFuncPtrcallback,
void * obj,
asDWORD callConv 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]callbackA function or class method pointer.
[in]objThe object for methods, or an optional parameter for functions.
[in]callConvThe calling convention.
+
+
+
Returns
A negative value for an error.
+
Return values
+ + + +
asINVALID_ARGOne of the arguments is incorrect, e.g. obj is null for a class method.
asNOT_SUPPORTEDThe arguments are not supported, e.g. asCALL_GENERIC.
+
+
+

This method sets the callback routine that will receive compiler messages. The callback routine can be either a class method, e.g:

void MyClass::MessageCallback(const asSMessageInfo *msg);
+
r = engine->SetMessageCallback(asMETHOD(MyClass,MessageCallback), &obj, asCALL_THISCALL);
+

or a global function, e.g:

void MessageCallback(const asSMessageInfo *msg, void *param);
+
r = engine->SetMessageCallback(asFUNCTION(MessageCallback), param, asCALL_CDECL);
+

It is recommended to register the message callback routine right after creating the engine, as some of the registration functions can provide useful information to better explain errors.

+ +
+
+ +

◆ SetModuleUserDataCleanupCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::SetModuleUserDataCleanupCallback (asCLEANMODULEFUNC_t callback,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]callbackA pointer to the function
[in]typeAn identifier specifying which user data the callback is to be used with.
+
+
+

The function given with this call will be invoked when the module is destroyed if any user data has been registered with the module.

+

The function is called from within the module destructor, so the callback should not be used for anything but cleaning up the user data itself.

+ +
+
+ +

◆ SetScriptObjectUserDataCleanupCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::SetScriptObjectUserDataCleanupCallback (asCLEANSCRIPTOBJECTFUNC_t callback,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]callbackA pointer to the function
[in]typeAn identifier specifying which user data the callback is to be used with.
+
+
+

The function given with this call will be invoked when a script object instance is destroyed if any user data has been registered with the type.

+

The function is called from within the script object destructor, so the callback should not be used for anything but cleaning up the user data itself.

+ +
+
+ +

◆ SetTranslateAppExceptionCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::SetTranslateAppExceptionCallback (asSFuncPtr callback,
void * param,
int callConv 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]callbackThe callback function/method that should be called upon an exception.
[in]paramA user defined parameter, or the object pointer on which the callback is called.
[in]callConvThe calling convention of the callback function/method.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asNOT_SUPPORTEDCalling convention must not be asCALL_GENERIC, or the routine's calling convention is not supported.
asINVALID_ARGparam must not be null for class methods.
asWRONG_CALLING_CONVcallConv isn't compatible with the routines' calling convention.
+
+
+

This callback function will be called by the VM when an application exception is raised, which allow the application to translate the exception into a useful string to inform in SetException.

+

The callback function signature must be either:

+
  void (*)(asIScriptContext *, void *);

or

+
  void (param::*)(asIScriptContext *);

See Exceptions for an example on how to use this.

+ +
+
+ +

◆ SetTypeInfoUserDataCleanupCallback()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void asIScriptEngine::SetTypeInfoUserDataCleanupCallback (asCLEANTYPEINFOFUNC_t callback,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]callbackA pointer to the function
[in]typeAn identifier specifying which user data the callback is to be used with.
+
+
+

The function given with this call will be invoked when a type info is destroyed if any user data has been registered with the type.

+

The function is called from within the type info destructor, so the callback should not be used for anything but cleaning up the user data itself.

+ +
+
+ +

◆ SetUserData()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asIScriptEngine::SetUserData (void * data,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]dataA pointer to the user data.
[in]typeAn identifier specifying the user data to set.
+
+
+
Returns
The previous pointer stored in the engine.
+

This method allows the application to associate a value, e.g. a pointer, with the engine instance.

+

The type values 1000 through 1999 are reserved for use by the official add-ons.

+

Optionally, a callback function can be registered to clean up the user data when the engine is destroyed.

+ +
+
+ +

◆ ShutDownAndRelease()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptEngine::ShutDownAndRelease ()
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when you know it is time to shut down the engine. This will automatically discard all the script modules and run a complete garbage collection cycle.

+

Calling this method rather than the ordinary Release method will avoid potential memory leaks if for example there are objects in the modules or garbage collector that indirectly holds a reference to the engine.

+ +
+
+ +

◆ WriteMessage()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptEngine::WriteMessage (const char * section,
int row,
int col,
asEMsgType type,
const char * message 
)
+
+pure virtual
+
+
Parameters
+ + + + + + +
[in]sectionThe name of the script section.
[in]rowThe row number.
[in]colThe column number.
[in]typeThe message type.
[in]messageThe message text.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_ARGThe section or message is null.
+
+
+

This method can be used by the application to write messages to the same message callback that the script compiler uses. This is useful for example if a preprocessor is used.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+
virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv)=0
Sets a message callback that will receive compiler messages.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a property for the object type.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
Represents a compiler message.
Definition: angelscript.h:767
+
#define asOFFSET(s, m)
Returns the offset of an attribute in a struct.
Definition: angelscript.h:672
+ + + + diff --git a/docs/manual/classas_i_script_function-members.html b/docs/manual/classas_i_script_function-members.html new file mode 100644 index 0000000..82a035c --- /dev/null +++ b/docs/manual/classas_i_script_function-members.html @@ -0,0 +1,152 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIScriptFunction Member List
+
+
+ +

This is the complete list of members for asIScriptFunction, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddRef() const =0asIScriptFunctionpure virtual
FindNextLineWithCode(int line) const =0asIScriptFunctionpure virtual
GetAccessMask() const =0asIScriptFunctionpure virtual
GetAuxiliary() const =0asIScriptFunctionpure virtual
GetByteCode(asUINT *length=0)=0asIScriptFunctionpure virtual
GetConfigGroup() const =0asIScriptFunctionpure virtual
GetDeclaration(bool includeObjectName=true, bool includeNamespace=false, bool includeParamNames=false) const =0asIScriptFunctionpure virtual
GetDelegateFunction() const =0asIScriptFunctionpure virtual
GetDelegateObject() const =0asIScriptFunctionpure virtual
GetDelegateObjectType() const =0asIScriptFunctionpure virtual
GetEngine() const =0asIScriptFunctionpure virtual
GetFuncType() const =0asIScriptFunctionpure virtual
GetId() const =0asIScriptFunctionpure virtual
GetModule() const =0asIScriptFunctionpure virtual
GetModuleName() const =0asIScriptFunctionpure virtual
GetName() const =0asIScriptFunctionpure virtual
GetNamespace() const =0asIScriptFunctionpure virtual
GetObjectName() const =0asIScriptFunctionpure virtual
GetObjectType() const =0asIScriptFunctionpure virtual
GetParam(asUINT index, int *typeId, asDWORD *flags=0, const char **name=0, const char **defaultArg=0) const =0asIScriptFunctionpure virtual
GetParamCount() const =0asIScriptFunctionpure virtual
GetReturnTypeId(asDWORD *flags=0) const =0asIScriptFunctionpure virtual
GetScriptSectionName() const =0asIScriptFunctionpure virtual
GetTypeId() const =0asIScriptFunctionpure virtual
GetUserData(asPWORD type=0) const =0asIScriptFunctionpure virtual
GetVar(asUINT index, const char **name, int *typeId=0) const =0asIScriptFunctionpure virtual
GetVarCount() const =0asIScriptFunctionpure virtual
GetVarDecl(asUINT index, bool includeNamespace=false) const =0asIScriptFunctionpure virtual
IsCompatibleWithTypeId(int typeId) const =0asIScriptFunctionpure virtual
IsExplicit() const =0asIScriptFunctionpure virtual
IsFinal() const =0asIScriptFunctionpure virtual
IsOverride() const =0asIScriptFunctionpure virtual
IsPrivate() const =0asIScriptFunctionpure virtual
IsProperty() const =0asIScriptFunctionpure virtual
IsProtected() const =0asIScriptFunctionpure virtual
IsReadOnly() const =0asIScriptFunctionpure virtual
IsShared() const =0asIScriptFunctionpure virtual
Release() const =0asIScriptFunctionpure virtual
SetUserData(void *userData, asPWORD type=0)=0asIScriptFunctionpure virtual
+
+ + + + diff --git a/docs/manual/classas_i_script_function.html b/docs/manual/classas_i_script_function.html new file mode 100644 index 0000000..72fef8d --- /dev/null +++ b/docs/manual/classas_i_script_function.html @@ -0,0 +1,1441 @@ + + + + + + + +AngelScript: asIScriptFunction Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIScriptFunction Class Referenceabstract
+
+
+ +

The interface for a script function description. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

Miscellaneous
virtual asIScriptEngineGetEngine () const =0
 Returns a pointer to the script engine. More...
 
virtual int AddRef () const =0
 Increases the reference counter. More...
 
virtual int Release () const =0
 Decrease reference counter. More...
 
virtual int GetId () const =0
 Returns the id of the function. More...
 
virtual asEFuncType GetFuncType () const =0
 Returns the type of the function. More...
 
virtual const char * GetModuleName () const =0
 Returns the name of the module where the function was implemented. More...
 
virtual asIScriptModuleGetModule () const =0
 Returns the module where the function is declared. More...
 
virtual const char * GetScriptSectionName () const =0
 Returns the name of the script section where the function was implemented. More...
 
virtual const char * GetConfigGroup () const =0
 Returns the name of the config group in which the function was registered. More...
 
virtual asDWORD GetAccessMask () const =0
 Returns the access mast of the function. More...
 
virtual void * GetAuxiliary () const =0
 Returns the auxiliary object registered with the function. More...
 
Function signature
virtual asITypeInfoGetObjectType () const =0
 Returns the object type for class or interface method. More...
 
virtual const char * GetObjectName () const =0
 Returns the name of the object for class or interface methods. More...
 
virtual const char * GetName () const =0
 Returns the name of the function or method. More...
 
virtual const char * GetNamespace () const =0
 Returns the namespace of the function. More...
 
virtual const char * GetDeclaration (bool includeObjectName=true, bool includeNamespace=false, bool includeParamNames=false) const =0
 Returns the function declaration. More...
 
virtual bool IsReadOnly () const =0
 Returns true if the class method is read-only. More...
 
virtual bool IsPrivate () const =0
 Returns true if the class method is private. More...
 
virtual bool IsProtected () const =0
 Returns true if the class method is protected. More...
 
virtual bool IsFinal () const =0
 Returns true if the method is final. More...
 
virtual bool IsOverride () const =0
 Returns true if the method is meant to override a method in the base class. More...
 
virtual bool IsShared () const =0
 Returns true if the function is shared. More...
 
virtual bool IsExplicit () const =0
 Returns true if the function is declared as 'explicit'. More...
 
virtual bool IsProperty () const =0
 Returns true if the function is declared as 'property'. More...
 
virtual asUINT GetParamCount () const =0
 Returns the number of parameters for this function. More...
 
virtual int GetParam (asUINT index, int *typeId, asDWORD *flags=0, const char **name=0, const char **defaultArg=0) const =0
 Returns the type id of the specified parameter. More...
 
virtual int GetReturnTypeId (asDWORD *flags=0) const =0
 Returns the type id of the return type. More...
 
Type id for function pointers
virtual int GetTypeId () const =0
 Returns the type id representing a function pointer for this function. More...
 
virtual bool IsCompatibleWithTypeId (int typeId) const =0
 Checks if the given type id can represent this function. More...
 
Delegates
virtual void * GetDelegateObject () const =0
 Returns the object for the delegate. More...
 
virtual asITypeInfoGetDelegateObjectType () const =0
 Returns the type of the delegated object. More...
 
virtual asIScriptFunctionGetDelegateFunction () const =0
 Returns the function for the delegate. More...
 
Debug information
virtual asUINT GetVarCount () const =0
 Returns the number of local variables in the function. More...
 
virtual int GetVar (asUINT index, const char **name, int *typeId=0) const =0
 Returns information about a local variable. More...
 
virtual const char * GetVarDecl (asUINT index, bool includeNamespace=false) const =0
 Returns the declaration of a local variable. More...
 
virtual int FindNextLineWithCode (int line) const =0
 Returns the next line number with code. More...
 
JIT compilation
virtual asDWORDGetByteCode (asUINT *length=0)=0
 Returns the byte code buffer and length. More...
 
User data
virtual void * SetUserData (void *userData, asPWORD type=0)=0
 Register the memory address of some user data. More...
 
virtual void * GetUserData (asPWORD type=0) const =0
 Returns the address of the previously registered user data. More...
 
+

Member Function Documentation

+ +

◆ AddRef()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptFunction::AddRef () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when storing an additional reference to the object.

+ +
+
+ +

◆ FindNextLineWithCode()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptFunction::FindNextLineWithCode (int line) const
+
+pure virtual
+
+
Parameters
+ + +
[in]lineA line number
+
+
+
Returns
The number of the next line with code, or a negative value if the line is outside the function.
+ +
+
+ +

◆ GetAccessMask()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asDWORD asIScriptFunction::GetAccessMask () const
+
+pure virtual
+
+
Returns
The access mask of the function.
+ +
+
+ +

◆ GetAuxiliary()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptFunction::GetAuxiliary () const
+
+pure virtual
+
+
Returns
The auxiliary object registered with the function.
+ +
+
+ +

◆ GetByteCode()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asDWORD* asIScriptFunction::GetByteCode (asUINTlength = 0)
+
+pure virtual
+
+
Parameters
+ + +
[out]lengthThe length of the byte code buffer in DWORDs
+
+
+
Returns
A pointer to the byte code buffer, or 0 if this is not a script function.
+

This function is used by the asIJITCompiler to obtain the byte code buffer for building the native machine code representation.

+ +
+
+ +

◆ GetConfigGroup()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptFunction::GetConfigGroup () const
+
+pure virtual
+
+
Returns
The name of the config group, or null if not in any group.
+ +
+
+ +

◆ GetDeclaration()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual const char* asIScriptFunction::GetDeclaration (bool includeObjectName = true,
bool includeNamespace = false,
bool includeParamNames = false 
) const
+
+pure virtual
+
+
Parameters
+ + + + +
[in]includeObjectNameIndicate whether the object name should be prepended to the function name
[in]includeNamespaceIndicates whether the namespace should be prepended to the function name and types
[in]includeParamNamesIndicates whether parameter names should be added to the declaration
+
+
+
Returns
A null terminated string with the function declaration.
+

The parameter names are not stored for virtual methods. If you want to know the name of parameters to class methods, be sure to get the actual implementation rather than the virtual method.

+

The namespace will always be included for types that are declared in a different namespace than the function itself.

+ +
+
+ +

◆ GetDelegateFunction()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptFunction* asIScriptFunction::GetDelegateFunction () const
+
+pure virtual
+
+
Returns
A pointer to the delegated function
+ +
+
+ +

◆ GetDelegateObject()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptFunction::GetDelegateObject () const
+
+pure virtual
+
+
Returns
A pointer to the delegated object
+ +
+
+ +

◆ GetDelegateObjectType()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asITypeInfo* asIScriptFunction::GetDelegateObjectType () const
+
+pure virtual
+
+
Returns
A pointer to the object type of the delegated object.
+ +
+
+ +

◆ GetEngine()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptEngine* asIScriptFunction::GetEngine () const
+
+pure virtual
+
+
Returns
A pointer to the engine.
+ +
+
+ +

◆ GetFuncType()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asEFuncType asIScriptFunction::GetFuncType () const
+
+pure virtual
+
+
Returns
The type of the function
+ +
+
+ +

◆ GetId()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptFunction::GetId () const
+
+pure virtual
+
+
Returns
The id of the function
+ +
+
+ +

◆ GetModule()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptModule* asIScriptFunction::GetModule () const
+
+pure virtual
+
+
Returns
The module where the function is declared.
+

The returned value can be null if the module doesn't exist anymore.

+ +
+
+ +

◆ GetModuleName()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptFunction::GetModuleName () const
+
+pure virtual
+
+
Returns
A null terminated string with the module name.
+ +
+
+ +

◆ GetName()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptFunction::GetName () const
+
+pure virtual
+
+
Returns
A null terminated string with the name of the function.
+ +
+
+ +

◆ GetNamespace()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptFunction::GetNamespace () const
+
+pure virtual
+
+
Returns
The namespace of the function, or null if not defined.
+ +
+
+ +

◆ GetObjectName()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptFunction::GetObjectName () const
+
+pure virtual
+
+
Returns
A null terminated string with the name of the object type if this a method.
+ +
+
+ +

◆ GetObjectType()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asITypeInfo* asIScriptFunction::GetObjectType () const
+
+pure virtual
+
+
Returns
A pointer to the object type interface if this is a method.
+

This does not increase the reference count of the returned object type.

+ +
+
+ +

◆ GetParam()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptFunction::GetParam (asUINT index,
int * typeId,
asDWORDflags = 0,
const char ** name = 0,
const char ** defaultArg = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + + + + +
[in]indexThe zero based parameter index.
[out]typeIdThe typeId of the parameter.
[out]flagsA combination of asETypeModifiers.
[out]nameThe name of the parameter (or null if not defined).
[out]defaultArgThe default argument expression (or null if not defined).
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_ARGThe index is out of bounds.
+
+
+

The parameter names are not stored for virtual methods. If you want to know the name of parameters to class methods, be sure to get the actual implementation rather than the virtual method.

+ +
+
+ +

◆ GetParamCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptFunction::GetParamCount () const
+
+pure virtual
+
+
Returns
The number of parameters.
+ +
+
+ +

◆ GetReturnTypeId()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptFunction::GetReturnTypeId (asDWORDflags = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[out]flagsA combination of asETypeModifiers.
+
+
+
Returns
The type id of the return type.
+ +
+
+ +

◆ GetScriptSectionName()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptFunction::GetScriptSectionName () const
+
+pure virtual
+
+
Returns
A null terminated string with the script section name where the function was implemented.
+

The returned pointer is null when the function doesn't originate from a script file, i.e. a registered function or an auto-generated script function. It can also be null if the information has been removed, e.g. when saving bytecode without debug info.

+ +
+
+ +

◆ GetTypeId()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptFunction::GetTypeId () const
+
+pure virtual
+
+
Returns
The type id that represents a function pointer for this function
+ +
+
+ +

◆ GetUserData()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptFunction::GetUserData (asPWORD type = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeAn identifier specifying the user data to set.
+
+
+
Returns
The pointer to the user data.
+ +
+
+ +

◆ GetVar()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptFunction::GetVar (asUINT index,
const char ** name,
int * typeId = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + + +
[in]indexThe zero based index of the local variable
[out]nameReceives the name of the variable
[out]typeIdReceives the typeId of the variable
+
+
+
Returns
A negative value on error
+
Return values
+ + + +
asINVALID_ARGThe index is out of range
asNOT_SUPPORTEDThe function is not a script function
+
+
+ +
+
+ +

◆ GetVarCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptFunction::GetVarCount () const
+
+pure virtual
+
+
Returns
The number of local variables in the function
+ +
+
+ +

◆ GetVarDecl()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual const char* asIScriptFunction::GetVarDecl (asUINT index,
bool includeNamespace = false 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]indexThe zero based index of the local variable
[in]includeNamespaceSet to true if the namespace should be included in the declaration.
+
+
+
Returns
The declaration string, or null on error
+ +
+
+ +

◆ IsCompatibleWithTypeId()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool asIScriptFunction::IsCompatibleWithTypeId (int typeId) const
+
+pure virtual
+
+
Returns
Returns true if the type id can represent this function.
+ +
+
+ +

◆ IsExplicit()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsExplicit () const
+
+pure virtual
+
+
Returns
True if the function is explicit.
+ +
+
+ +

◆ IsFinal()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsFinal () const
+
+pure virtual
+
+
Returns
True if the method is final.
+ +
+
+ +

◆ IsOverride()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsOverride () const
+
+pure virtual
+
+
Returns
True if the method is meant to override a method in the base class.
+ +
+
+ +

◆ IsPrivate()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsPrivate () const
+
+pure virtual
+
+
Returns
True if the class method is private
+ +
+
+ +

◆ IsProperty()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsProperty () const
+
+pure virtual
+
+
Returns
True if the function is a property accessor.
+ +
+
+ +

◆ IsProtected()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsProtected () const
+
+pure virtual
+
+
Returns
True if the class method is protected
+ +
+
+ +

◆ IsReadOnly()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsReadOnly () const
+
+pure virtual
+
+
Returns
True if the class method is read-only
+ +
+
+ +

◆ IsShared()

+ +
+
+ + + + + +
+ + + + + + + +
virtual bool asIScriptFunction::IsShared () const
+
+pure virtual
+
+
Returns
True if the function is shared.
+ +
+
+ +

◆ Release()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptFunction::Release () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when you will no longer use the references that you own.

+ +
+
+ +

◆ SetUserData()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asIScriptFunction::SetUserData (void * userData,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]userDataA pointer to the user data.
[in]typeAn identifier specifying the user data to set.
+
+
+
Returns
The previous pointer stored in the context.
+

This method allows the application to associate a value, e.g. a pointer, with the context instance.

+

The type values 1000 through 1999 are reserved for use by the official add-ons.

+

Optionally, a callback function can be registered to clean up the user data when the function is destroyed. As the callback is registered with the engine, it is only necessary to do it once.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_script_generic-members.html b/docs/manual/classas_i_script_generic-members.html new file mode 100644 index 0000000..416dfd1 --- /dev/null +++ b/docs/manual/classas_i_script_generic-members.html @@ -0,0 +1,139 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIScriptGeneric Member List
+
+
+ +

This is the complete list of members for asIScriptGeneric, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
GetAddressOfArg(asUINT arg)=0asIScriptGenericpure virtual
GetAddressOfReturnLocation()=0asIScriptGenericpure virtual
GetArgAddress(asUINT arg)=0asIScriptGenericpure virtual
GetArgByte(asUINT arg)=0asIScriptGenericpure virtual
GetArgCount() const =0asIScriptGenericpure virtual
GetArgDouble(asUINT arg)=0asIScriptGenericpure virtual
GetArgDWord(asUINT arg)=0asIScriptGenericpure virtual
GetArgFloat(asUINT arg)=0asIScriptGenericpure virtual
GetArgObject(asUINT arg)=0asIScriptGenericpure virtual
GetArgQWord(asUINT arg)=0asIScriptGenericpure virtual
GetArgTypeId(asUINT arg, asDWORD *flags=0) const =0asIScriptGenericpure virtual
GetArgWord(asUINT arg)=0asIScriptGenericpure virtual
GetAuxiliary() const =0asIScriptGenericpure virtual
GetEngine() const =0asIScriptGenericpure virtual
GetFunction() const =0asIScriptGenericpure virtual
GetObject()=0asIScriptGenericpure virtual
GetObjectTypeId() const =0asIScriptGenericpure virtual
GetReturnTypeId(asDWORD *flags=0) const =0asIScriptGenericpure virtual
SetReturnAddress(void *addr)=0asIScriptGenericpure virtual
SetReturnByte(asBYTE val)=0asIScriptGenericpure virtual
SetReturnDouble(double val)=0asIScriptGenericpure virtual
SetReturnDWord(asDWORD val)=0asIScriptGenericpure virtual
SetReturnFloat(float val)=0asIScriptGenericpure virtual
SetReturnObject(void *obj)=0asIScriptGenericpure virtual
SetReturnQWord(asQWORD val)=0asIScriptGenericpure virtual
SetReturnWord(asWORD val)=0asIScriptGenericpure virtual
+
+ + + + diff --git a/docs/manual/classas_i_script_generic.html b/docs/manual/classas_i_script_generic.html new file mode 100644 index 0000000..b28fdc9 --- /dev/null +++ b/docs/manual/classas_i_script_generic.html @@ -0,0 +1,1082 @@ + + + + + + + +AngelScript: asIScriptGeneric Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIScriptGeneric Class Referenceabstract
+
+
+ +

The interface for the generic calling convention. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

Miscellaneous
virtual asIScriptEngineGetEngine () const =0
 Returns a pointer to the script engine. More...
 
virtual asIScriptFunctionGetFunction () const =0
 Returns the function that is being called. More...
 
virtual void * GetAuxiliary () const =0
 Return the auxiliary registered with the function. More...
 
Object
virtual void * GetObject ()=0
 Returns the object pointer if this is a class method, or null if it not. More...
 
virtual int GetObjectTypeId () const =0
 Returns the type id of the object if this is a class method. More...
 
Arguments
virtual int GetArgCount () const =0
 Returns the number of arguments. More...
 
virtual int GetArgTypeId (asUINT arg, asDWORD *flags=0) const =0
 Returns the type id of the argument. More...
 
virtual asBYTE GetArgByte (asUINT arg)=0
 Returns the value of an 8-bit argument. More...
 
virtual asWORD GetArgWord (asUINT arg)=0
 Returns the value of a 16-bit argument. More...
 
virtual asDWORD GetArgDWord (asUINT arg)=0
 Returns the value of a 32-bit integer argument. More...
 
virtual asQWORD GetArgQWord (asUINT arg)=0
 Returns the value of a 64-bit integer argument. More...
 
virtual float GetArgFloat (asUINT arg)=0
 Returns the value of a float argument. More...
 
virtual double GetArgDouble (asUINT arg)=0
 Returns the value of a double argument. More...
 
virtual void * GetArgAddress (asUINT arg)=0
 Returns the address held in a reference or handle argument. More...
 
virtual void * GetArgObject (asUINT arg)=0
 Returns a pointer to the object in a object argument. More...
 
virtual void * GetAddressOfArg (asUINT arg)=0
 Returns a pointer to the argument value. More...
 
Return value
virtual int GetReturnTypeId (asDWORD *flags=0) const =0
 Gets the type id of the return value. More...
 
virtual int SetReturnByte (asBYTE val)=0
 Sets the 8-bit return value. More...
 
virtual int SetReturnWord (asWORD val)=0
 Sets the 16-bit return value. More...
 
virtual int SetReturnDWord (asDWORD val)=0
 Sets the 32-bit integer return value. More...
 
virtual int SetReturnQWord (asQWORD val)=0
 Sets the 64-bit integer return value. More...
 
virtual int SetReturnFloat (float val)=0
 Sets the float return value. More...
 
virtual int SetReturnDouble (double val)=0
 Sets the double return value. More...
 
virtual int SetReturnAddress (void *addr)=0
 Sets the address return value when the return is a reference or handle. More...
 
virtual int SetReturnObject (void *obj)=0
 Sets the object return value. More...
 
virtual void * GetAddressOfReturnLocation ()=0
 Gets the address to the memory where the return value should be placed. More...
 
+

Member Function Documentation

+ +

◆ GetAddressOfArg()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptGeneric::GetAddressOfArg (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
A pointer to the argument value.
+ +
+
+ +

◆ GetAddressOfReturnLocation()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptGeneric::GetAddressOfReturnLocation ()
+
+pure virtual
+
+
Returns
A pointer to the memory where the return values is to be placed.
+

The memory is not initialized, so if you're going to return a complex type by value you shouldn't use the assignment operator to initialize it. Instead use the placement new operator to call the type's copy constructor to perform the initialization.

+
new(gen->GetAddressOfReturnLocation()) std::string(myRetValue);
+

The placement new operator works for primitive types too, so this method is ideal for writing automatically generated functions that works the same way for all types.

+ +
+
+ +

◆ GetArgAddress()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptGeneric::GetArgAddress (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
The address argument value, which can be a reference or and object handle.
+

Don't release the pointer if this is an object or object handle, the asIScriptGeneric object will do that for you.

+ +
+
+ +

◆ GetArgByte()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asBYTE asIScriptGeneric::GetArgByte (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
The 1 byte argument value.
+ +
+
+ +

◆ GetArgCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptGeneric::GetArgCount () const
+
+pure virtual
+
+
Returns
The number of arguments to the function.
+ +
+
+ +

◆ GetArgDouble()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual double asIScriptGeneric::GetArgDouble (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
The double argument value.
+ +
+
+ +

◆ GetArgDWord()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asDWORD asIScriptGeneric::GetArgDWord (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
The 4 byte argument value.
+ +
+
+ +

◆ GetArgFloat()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual float asIScriptGeneric::GetArgFloat (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
The float argument value.
+ +
+
+ +

◆ GetArgObject()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptGeneric::GetArgObject (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
A pointer to the object argument, which can be an object value or object handle.
+

Don't release the pointer if this is an object handle, the asIScriptGeneric object will do that for you.

+ +
+
+ +

◆ GetArgQWord()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asQWORD asIScriptGeneric::GetArgQWord (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
The 8 byte argument value.
+ +
+
+ +

◆ GetArgTypeId()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptGeneric::GetArgTypeId (asUINT arg,
asDWORDflags = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]argThe argument index.
[out]flagsA combination of asETypeModifiers.
+
+
+
Returns
The type id of the argument.
+ +
+
+ +

◆ GetArgWord()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asWORD asIScriptGeneric::GetArgWord (asUINT arg)
+
+pure virtual
+
+
Parameters
+ + +
[in]argThe argument index.
+
+
+
Returns
The 2 byte argument value.
+ +
+
+ +

◆ GetAuxiliary()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptGeneric::GetAuxiliary () const
+
+pure virtual
+
+
Returns
The auxiliary registered with the function.
+ +
+
+ +

◆ GetEngine()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptEngine* asIScriptGeneric::GetEngine () const
+
+pure virtual
+
+
Returns
A pointer to the engine.
+ +
+
+ +

◆ GetFunction()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptFunction* asIScriptGeneric::GetFunction () const
+
+pure virtual
+
+
Returns
The function that is being called.
+ +
+
+ +

◆ GetObject()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void* asIScriptGeneric::GetObject ()
+
+pure virtual
+
+
Returns
A pointer to the object, if this is a method.
+ +
+
+ +

◆ GetObjectTypeId()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptGeneric::GetObjectTypeId () const
+
+pure virtual
+
+
Returns
The type id of the object if this is a method.
+ +
+
+ +

◆ GetReturnTypeId()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::GetReturnTypeId (asDWORDflags = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[out]flagsA combination of asETypeModifiers.
+
+
+
Returns
The type id of the return value.
+ +
+
+ +

◆ SetReturnAddress()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnAddress (void * addr)
+
+pure virtual
+
+
Parameters
+ + +
[in]addrThe return value, which is an address.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not a reference or handle.
+
+
+

Sets the address return value. If an object handle the application must first increment the reference counter, unless it won't keep a reference itself.

+ +
+
+ +

◆ SetReturnByte()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnByte (asBYTE val)
+
+pure virtual
+
+
Parameters
+ + +
[in]valThe return value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not an 8-bit value. Sets the 1 byte return value.
+
+
+ +
+
+ +

◆ SetReturnDouble()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnDouble (double val)
+
+pure virtual
+
+
Parameters
+ + +
[in]valThe return value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not a 64-bit value. Sets the double return value.
+
+
+ +
+
+ +

◆ SetReturnDWord()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnDWord (asDWORD val)
+
+pure virtual
+
+
Parameters
+ + +
[in]valThe return value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not a 32-bit value. Sets the 4 byte return value.
+
+
+ +
+
+ +

◆ SetReturnFloat()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnFloat (float val)
+
+pure virtual
+
+
Parameters
+ + +
[in]valThe return value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not a 32-bit value. Sets the float return value.
+
+
+ +
+
+ +

◆ SetReturnObject()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnObject (void * obj)
+
+pure virtual
+
+
Parameters
+ + +
[in]objA pointer to the object return value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not an object value or handle.
+
+
+

If the function returns an object, the library will automatically do what is necessary based on how the object was declared, i.e. if the function was registered to return a handle then the library will call the addref behaviour. If it was registered to return an object by value, then the library will make a copy of the object.

+ +
+
+ +

◆ SetReturnQWord()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnQWord (asQWORD val)
+
+pure virtual
+
+
Parameters
+ + +
[in]valThe return value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not a 64-bit value. Sets the 8 byte return value.
+
+
+ +
+
+ +

◆ SetReturnWord()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptGeneric::SetReturnWord (asWORD val)
+
+pure virtual
+
+
Parameters
+ + +
[in]valThe return value.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_TYPEThe return type is not a 16-bit value. Sets the 2 byte return value.
+
+
+ +
+
+
The documentation for this class was generated from the following file: +
+
+
virtual void * GetAddressOfReturnLocation()=0
Gets the address to the memory where the return value should be placed.
+ + + + diff --git a/docs/manual/classas_i_script_module-members.html b/docs/manual/classas_i_script_module-members.html new file mode 100644 index 0000000..22c0d8a --- /dev/null +++ b/docs/manual/classas_i_script_module-members.html @@ -0,0 +1,158 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIScriptModule Member List
+
+
+ +

This is the complete list of members for asIScriptModule, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddScriptSection(const char *name, const char *code, size_t codeLength=0, int lineOffset=0)=0asIScriptModulepure virtual
BindAllImportedFunctions()=0asIScriptModulepure virtual
BindImportedFunction(asUINT importIndex, asIScriptFunction *func)=0asIScriptModulepure virtual
Build()=0asIScriptModulepure virtual
CompileFunction(const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc)=0asIScriptModulepure virtual
CompileGlobalVar(const char *sectionName, const char *code, int lineOffset)=0asIScriptModulepure virtual
Discard()=0asIScriptModulepure virtual
GetAddressOfGlobalVar(asUINT index)=0asIScriptModulepure virtual
GetDefaultNamespace() const =0asIScriptModulepure virtual
GetEngine() const =0asIScriptModulepure virtual
GetEnumByIndex(asUINT index) const =0asIScriptModulepure virtual
GetEnumCount() const =0asIScriptModulepure virtual
GetFunctionByDecl(const char *decl) const =0asIScriptModulepure virtual
GetFunctionByIndex(asUINT index) const =0asIScriptModulepure virtual
GetFunctionByName(const char *name) const =0asIScriptModulepure virtual
GetFunctionCount() const =0asIScriptModulepure virtual
GetGlobalVar(asUINT index, const char **name, const char **nameSpace=0, int *typeId=0, bool *isConst=0) const =0asIScriptModulepure virtual
GetGlobalVarCount() const =0asIScriptModulepure virtual
GetGlobalVarDeclaration(asUINT index, bool includeNamespace=false) const =0asIScriptModulepure virtual
GetGlobalVarIndexByDecl(const char *decl) const =0asIScriptModulepure virtual
GetGlobalVarIndexByName(const char *name) const =0asIScriptModulepure virtual
GetImportedFunctionCount() const =0asIScriptModulepure virtual
GetImportedFunctionDeclaration(asUINT importIndex) const =0asIScriptModulepure virtual
GetImportedFunctionIndexByDecl(const char *decl) const =0asIScriptModulepure virtual
GetImportedFunctionSourceModule(asUINT importIndex) const =0asIScriptModulepure virtual
GetName() const =0asIScriptModulepure virtual
GetObjectTypeByIndex(asUINT index) const =0asIScriptModulepure virtual
GetObjectTypeCount() const =0asIScriptModulepure virtual
GetTypedefByIndex(asUINT index) const =0asIScriptModulepure virtual
GetTypedefCount() const =0asIScriptModulepure virtual
GetTypeIdByDecl(const char *decl) const =0asIScriptModulepure virtual
GetTypeInfoByDecl(const char *decl) const =0asIScriptModulepure virtual
GetTypeInfoByName(const char *name) const =0asIScriptModulepure virtual
GetUserData(asPWORD type=0) const =0asIScriptModulepure virtual
LoadByteCode(asIBinaryStream *in, bool *wasDebugInfoStripped=0)=0asIScriptModulepure virtual
RemoveFunction(asIScriptFunction *func)=0asIScriptModulepure virtual
RemoveGlobalVar(asUINT index)=0asIScriptModulepure virtual
ResetGlobalVars(asIScriptContext *ctx=0)=0asIScriptModulepure virtual
SaveByteCode(asIBinaryStream *out, bool stripDebugInfo=false) const =0asIScriptModulepure virtual
SetAccessMask(asDWORD accessMask)=0asIScriptModulepure virtual
SetDefaultNamespace(const char *nameSpace)=0asIScriptModulepure virtual
SetName(const char *name)=0asIScriptModulepure virtual
SetUserData(void *data, asPWORD type=0)=0asIScriptModulepure virtual
UnbindAllImportedFunctions()=0asIScriptModulepure virtual
UnbindImportedFunction(asUINT importIndex)=0asIScriptModulepure virtual
+
+ + + + diff --git a/docs/manual/classas_i_script_module.html b/docs/manual/classas_i_script_module.html new file mode 100644 index 0000000..134585a --- /dev/null +++ b/docs/manual/classas_i_script_module.html @@ -0,0 +1,2022 @@ + + + + + + + +AngelScript: asIScriptModule Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIScriptModule Class Referenceabstract
+
+
+ +

The interface to the script modules. + More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

Miscellaneous
virtual asIScriptEngineGetEngine () const =0
 Returns a pointer to the engine. More...
 
virtual void SetName (const char *name)=0
 Sets the name of the module. More...
 
virtual const char * GetName () const =0
 Gets the name of the module. More...
 
virtual void Discard ()=0
 Discards the module. More...
 
Compilation
virtual int AddScriptSection (const char *name, const char *code, size_t codeLength=0, int lineOffset=0)=0
 Add a script section for the next build. More...
 
virtual int Build ()=0
 Build the previously added script sections. More...
 
virtual int CompileFunction (const char *sectionName, const char *code, int lineOffset, asDWORD compileFlags, asIScriptFunction **outFunc)=0
 Compile a single function. More...
 
virtual int CompileGlobalVar (const char *sectionName, const char *code, int lineOffset)=0
 Compile a single global variable and add it to the scope of the module. More...
 
virtual asDWORD SetAccessMask (asDWORD accessMask)=0
 Sets the access mask that should be used during the compilation. More...
 
virtual int SetDefaultNamespace (const char *nameSpace)=0
 Sets the default namespace that should be used in the following calls. More...
 
virtual const char * GetDefaultNamespace () const =0
 Returns the current default namespace. More...
 
Functions
virtual asUINT GetFunctionCount () const =0
 Returns the number of global functions in the module. More...
 
virtual asIScriptFunctionGetFunctionByIndex (asUINT index) const =0
 Returns the function by index. More...
 
virtual asIScriptFunctionGetFunctionByDecl (const char *decl) const =0
 Returns the function by its declaration. More...
 
virtual asIScriptFunctionGetFunctionByName (const char *name) const =0
 Returns the function by its name. More...
 
virtual int RemoveFunction (asIScriptFunction *func)=0
 Remove a single function from the scope of the module. More...
 
Global variables
virtual int ResetGlobalVars (asIScriptContext *ctx=0)=0
 Reset the global variables of the module. More...
 
virtual asUINT GetGlobalVarCount () const =0
 Returns the number of global variables in the module. More...
 
virtual int GetGlobalVarIndexByName (const char *name) const =0
 Returns the global variable index by name. More...
 
virtual int GetGlobalVarIndexByDecl (const char *decl) const =0
 Returns the global variable index by declaration. More...
 
virtual const char * GetGlobalVarDeclaration (asUINT index, bool includeNamespace=false) const =0
 Returns the global variable declaration. More...
 
virtual int GetGlobalVar (asUINT index, const char **name, const char **nameSpace=0, int *typeId=0, bool *isConst=0) const =0
 Returns the global variable properties. More...
 
virtual void * GetAddressOfGlobalVar (asUINT index)=0
 Returns the pointer to the global variable. More...
 
virtual int RemoveGlobalVar (asUINT index)=0
 Remove the global variable from the scope of the module. More...
 
Type identification
virtual asUINT GetObjectTypeCount () const =0
 Returns the number of object types. More...
 
virtual asITypeInfoGetObjectTypeByIndex (asUINT index) const =0
 Returns the object type interface by index. More...
 
virtual int GetTypeIdByDecl (const char *decl) const =0
 Returns a type id by declaration. More...
 
virtual asITypeInfoGetTypeInfoByName (const char *name) const =0
 Returns the type interface by name. More...
 
virtual asITypeInfoGetTypeInfoByDecl (const char *decl) const =0
 Returns a type by declaration. More...
 
Enums
virtual asUINT GetEnumCount () const =0
 Returns the number of enum types declared in the module. More...
 
virtual asITypeInfoGetEnumByIndex (asUINT index) const =0
 Returns the enum type. More...
 
Typedefs
virtual asUINT GetTypedefCount () const =0
 Returns the number of typedefs in the module. More...
 
virtual asITypeInfoGetTypedefByIndex (asUINT index) const =0
 Returns the typedef. More...
 
Dynamic binding between modules
virtual asUINT GetImportedFunctionCount () const =0
 Returns the number of functions declared for import. More...
 
virtual int GetImportedFunctionIndexByDecl (const char *decl) const =0
 Returns the imported function index by declaration. More...
 
virtual const char * GetImportedFunctionDeclaration (asUINT importIndex) const =0
 Returns the imported function declaration. More...
 
virtual const char * GetImportedFunctionSourceModule (asUINT importIndex) const =0
 Returns the declared imported function source module. More...
 
virtual int BindImportedFunction (asUINT importIndex, asIScriptFunction *func)=0
 Binds an imported function to the function from another module. More...
 
virtual int UnbindImportedFunction (asUINT importIndex)=0
 Unbinds an imported function. More...
 
virtual int BindAllImportedFunctions ()=0
 Binds all imported functions in a module, by searching their equivalents in the declared source modules. More...
 
virtual int UnbindAllImportedFunctions ()=0
 Unbinds all imported functions. More...
 
Byte code saving and loading
virtual int SaveByteCode (asIBinaryStream *out, bool stripDebugInfo=false) const =0
 Save compiled byte code to a binary stream. More...
 
virtual int LoadByteCode (asIBinaryStream *in, bool *wasDebugInfoStripped=0)=0
 Load pre-compiled byte code from a binary stream. More...
 
User data
virtual void * SetUserData (void *data, asPWORD type=0)=0
 Register the memory address of some user data. More...
 
virtual void * GetUserData (asPWORD type=0) const =0
 Returns the address of the previously registered user data. More...
 
+

Detailed Description

+

A script module can be thought of a library of script functions, classes, and global variables.

+

A pointer to the module interface is obtained by calling asIScriptEngine::GetModule. The module can then be built from a single or multiple script files, also known as script sections. Alternatively pre-built bytecode can be loaded, if it has been saved from a previous build.

+
See also
Script modules
+

Member Function Documentation

+ +

◆ AddScriptSection()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptModule::AddScriptSection (const char * name,
const char * code,
size_t codeLength = 0,
int lineOffset = 0 
)
+
+pure virtual
+
+
Parameters
+ + + + + +
[in]nameThe name of the script section
[in]codeThe script code buffer
[in]codeLengthThe length of the script code
[in]lineOffsetAn offset that will be added to compiler message line numbers
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asINVALID_ARGThe code argument is null.
asNOT_SUPPORTEDCompiler support is disabled in the engine.
asOUT_OF_MEMORYThe necessary memory to hold the script code couldn't be allocated.
+
+
+

This adds a script section to the module. The script section isn't processed with this call. Only when Build is called will the script be parsed and compiled into executable byte code.

+

Error messages from the compiler will refer to the name of the script section and the position within it. Normally each section is the content of a source file, so it is recommended to name the script sections as the name of the source file.

+

The code added is copied by the engine, so there is no need to keep the original buffer after the call. Note that this can be changed by setting the engine property asEP_COPY_SCRIPT_SECTIONS with asIScriptEngine::SetEngineProperty.

+ +
+
+ +

◆ BindAllImportedFunctions()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptModule::BindAllImportedFunctions ()
+
+pure virtual
+
+
Returns
A negative value on error.
+
Return values
+ + + +
asERRORAn error occurred.
asCANT_BIND_ALL_FUNCTIONSNot all functions where bound.
+
+
+

This functions tries to bind all imported functions in the module by searching for matching functions in the suggested modules. If a function cannot be bound the function will give an error asCANT_BIND_ALL_FUNCTIONS, but it will continue binding the rest of the functions.

+ +
+
+ +

◆ BindImportedFunction()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptModule::BindImportedFunction (asUINT importIndex,
asIScriptFunctionfunc 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]importIndexThe index of the imported function.
[in]funcThe true function that will be bound to the imported function.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + +
asNO_FUNCTIONimportIndex or func is incorrect.
asINVALID_INTERFACEThe signature of function doesn't match the import statement.
+
+
+

The imported function is only bound if the functions have the exact same signature, i.e the same return type, and parameters.

+ +
+
+ +

◆ Build()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptModule::Build ()
+
+pure virtual
+
+
Returns
A negative value on error
+
Return values
+ + + + + + + +
asINVALID_CONFIGURATIONThe engine configuration is invalid.
asERRORThe script failed to build.
asBUILD_IN_PROGRESSAnother thread is currently building.
asINIT_GLOBAL_VARS_FAILEDIt was not possible to initialize at least one of the global variables.
asNOT_SUPPORTEDCompiler support is disabled in the engine.
asMODULE_IS_IN_USEThe code in the module is still being used and and cannot be removed.
+
+
+

Builds the script based on the previously added sections, registered types and functions. After the build is complete the script sections are removed to free memory.

+

Before starting the build the Build method removes any previously compiled script content, including the dynamically added content from CompileFunction and CompileGlobalVar. If the script module needs to be rebuilt all of the script sections needs to be added again.

+

Compiler messages are sent to the message callback function set with asIScriptEngine::SetMessageCallback. If there are no errors or warnings, no messages will be sent to the callback function.

+

Any global variables found in the script will be initialized by the compiler if the engine property asEP_INIT_GLOBAL_VARS_AFTER_BUILD is set. If you get the error asINIT_GLOBAL_VARS_FAILED, then it is probable that one of the global variables during the initialization is trying to access another global variable before it has been initialized.

+
See also
Compiling scripts
+ +
+
+ +

◆ CompileFunction()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptModule::CompileFunction (const char * sectionName,
const char * code,
int lineOffset,
asDWORD compileFlags,
asIScriptFunction ** outFunc 
)
+
+pure virtual
+
+
Parameters
+ + + + + + +
[in]sectionNameThe name of the script section
[in]codeThe script code buffer
[in]lineOffsetAn offset that will be added to compiler message line numbers
[in]compileFlagsOne of asECompileFlags values
[out]outFuncOptional parameter to receive the compiled function descriptor
+
+
+
Returns
A negative value on error
+
Return values
+ + + + + + +
asINVALID_ARGOne or more arguments have invalid values.
asINVALID_CONFIGURATIONThe engine configuration is invalid.
asBUILD_IN_PROGRESSAnother build is in progress.
asERRORThe compilation failed.
asNOT_SUPPORTEDCompiler support is disabled in the engine.
+
+
+

Use this to compile a single function. Any existing compiled code in the module can be used by the function.

+

The newly compiled function can be optionally added to the scope of the module where it can later be referred to by the application or used in subsequent compilations. If not added to the module the function can still be returned in the output parameter, which will allow the application to execute it and then discard it when it is no longer needed.

+

If the output function parameter is set, remember to release the function object when you're done with it.

+ +
+
+ +

◆ CompileGlobalVar()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptModule::CompileGlobalVar (const char * sectionName,
const char * code,
int lineOffset 
)
+
+pure virtual
+
+
Parameters
+ + + + +
[in]sectionNameThe name of the script section
[in]codeThe script code buffer
[in]lineOffsetAn offset that will be added to compiler message line numbers
+
+
+
Returns
A negative value on error
+
Return values
+ + + + + + +
asINVALID_ARGOne or more arguments have invalid values.
asINVALID_CONFIGURATIONThe engine configuration is invalid.
asBUILD_IN_PROGRESSAnother build is in progress.
asERRORThe compilation failed.
asNOT_SUPPORTEDCompiler support is disabled in the engine.
+
+
+

Use this to add a single global variable to the scope of a module. The variable can then be referred to by the application and subsequent compilations.

+

The script code may contain an initialization expression, which will be executed by the compiler if the engine property asEP_INIT_GLOBAL_VARS_AFTER_BUILD is set.

+

Any existing compiled code in the module can be used in the initialization expression.

+ +
+
+ +

◆ Discard()

+ +
+
+ + + + + +
+ + + + + + + +
virtual void asIScriptModule::Discard ()
+
+pure virtual
+
+

This method is used to discard the module and any compiled bytecode it has. After calling this method the module pointer is no longer valid and shouldn't be used by the application.

+ +
+
+ +

◆ GetAddressOfGlobalVar()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptModule::GetAddressOfGlobalVar (asUINT index)
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the global variable.
+
+
+
Returns
A pointer to the global variable, or null if not found.
+

This method should be used to retrieve the pointer of a variable that you wish to access.

+ +
+
+ +

◆ GetDefaultNamespace()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptModule::GetDefaultNamespace () const
+
+pure virtual
+
+
Returns
The current default namespace
+ +
+
+ +

◆ GetEngine()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptEngine* asIScriptModule::GetEngine () const
+
+pure virtual
+
+
Returns
A pointer to the engine.
+ +
+
+ +

◆ GetEnumByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptModule::GetEnumByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the enum type.
+
+
+
Returns
The type info of the enum type, or null on error.
+ +
+
+ +

◆ GetEnumCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptModule::GetEnumCount () const
+
+pure virtual
+
+
Returns
The number of enum types in the module.
+ +
+
+ +

◆ GetFunctionByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asIScriptModule::GetFunctionByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe function declaration.
+
+
+
Returns
The function or null in case of error.
+ +
+
+ +

◆ GetFunctionByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asIScriptModule::GetFunctionByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the function
+
+
+
Returns
The function or null in case of error.
+ +
+
+ +

◆ GetFunctionByName()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asIScriptModule::GetFunctionByName (const char * name) const
+
+pure virtual
+
+
Parameters
+ + +
[in]nameThe function name
+
+
+
Returns
The function or null if not found or there are multiple matches.
+

The search for functions will be performed in the default namespace as given by SetDefaultNamespace unless the name is prefixed with a scope, using the scoping operator ::. If the scope starts with :: it will be used as the absolute scope, otherwise it will be relative to the default namespace.

+ +
+
+ +

◆ GetFunctionCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptModule::GetFunctionCount () const
+
+pure virtual
+
+
Returns
The number of global functions in this module.
+

This method retrieves the number of compiled script functions.

+ +
+
+ +

◆ GetGlobalVar()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIScriptModule::GetGlobalVar (asUINT index,
const char ** name,
const char ** nameSpace = 0,
int * typeId = 0,
bool * isConst = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + + + + +
[in]indexThe index of the global variable.
[out]nameThe name of the variable.
[out]nameSpaceThe namespace of the variable.
[out]typeIdThe type of the variable.
[out]isConstWhether or not the variable is const.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_ARGThe index is out of range.
+
+
+ +
+
+ +

◆ GetGlobalVarCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptModule::GetGlobalVarCount () const
+
+pure virtual
+
+
Returns
The number of global variables in the module.
+ +
+
+ +

◆ GetGlobalVarDeclaration()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual const char* asIScriptModule::GetGlobalVarDeclaration (asUINT index,
bool includeNamespace = false 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]indexThe index of the global variable.
[in]includeNamespaceSet to true if the namespace should be included in the declaration.
+
+
+
Returns
A null terminated string with the variable declaration, or null if not found.
+

This method can be used to retrieve the variable declaration of the script variables that the host application will access. Verifying the declaration is important because, even though the script may compile correctly the user may not have used the variable types as intended.

+ +
+
+ +

◆ GetGlobalVarIndexByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::GetGlobalVarIndexByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe global variable declaration.
+
+
+
Returns
A negative value on error, or the global variable index.
+
Return values
+ + + + +
asERRORThe module was not built successfully.
asNO_GLOBAL_VARNo matching global variable was found.
asINVALID_DECLARATIONThe given declaration is invalid.
+
+
+

This method should be used to retrieve the index of the script variable that you wish to access.

+

The method will find the script variable with the exact same declaration.

+

If the variable is declared in a namespace first call SetDefaultNamespace to set the namespace that should be searched first for the variable.

+ +
+
+ +

◆ GetGlobalVarIndexByName()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::GetGlobalVarIndexByName (const char * name) const
+
+pure virtual
+
+
Parameters
+ + +
[in]nameThe name of the global variable.
+
+
+
Returns
A negative value on error, or the global variable index.
+
Return values
+ + + +
asINVALID_ARGThe name and scope for search cannot be determined
asNO_GLOBAL_VARThe matching global variable was found.
+
+
+

This method should be used to retrieve the index of the script variable that you wish to access.

+

The search for global variables will be performed in the default namespace as given by SetDefaultNamespace unless the name is prefixed with a scope, using the scoping operator ::. If the scope starts with :: it will be used as the absolute scope, otherwise it will be relative to the default namespace.

+ +
+
+ +

◆ GetImportedFunctionCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptModule::GetImportedFunctionCount () const
+
+pure virtual
+
+
Returns
The number of imported functions.
+

This function returns the number of functions that are imported in a module. These functions need to be bound before they can be used, or a script exception will be thrown.

+ +
+
+ +

◆ GetImportedFunctionDeclaration()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual const char* asIScriptModule::GetImportedFunctionDeclaration (asUINT importIndex) const
+
+pure virtual
+
+
Parameters
+ + +
[in]importIndexThe index of the imported function.
+
+
+
Returns
A null terminated string with the function declaration, or null if not found.
+

Use this function to get the declaration of the imported function. The returned declaration can be used to find a matching function in another module that can be bound to the imported function.
+

+ +
+
+ +

◆ GetImportedFunctionIndexByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::GetImportedFunctionIndexByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe function declaration of the imported function.
+
+
+
Returns
A negative value on error, or the index of the imported function.
+
Return values
+ + + + +
asERRORThe module was not built successfully.
asMULTIPLE_FUNCTIONSFound multiple matching functions.
asNO_FUNCTIONDidn't find any matching function.
+
+
+

This function is used to find a specific imported function by its declaration.

+ +
+
+ +

◆ GetImportedFunctionSourceModule()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual const char* asIScriptModule::GetImportedFunctionSourceModule (asUINT importIndex) const
+
+pure virtual
+
+
Parameters
+ + +
[in]importIndexThe index of the imported function.
+
+
+
Returns
A null terminated string with the name of the source module, or null if not found.
+

Use this function to get the name of the suggested module to import the function from.

+ +
+
+ +

◆ GetName()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asIScriptModule::GetName () const
+
+pure virtual
+
+
Returns
The name of the module.
+ +
+
+ +

◆ GetObjectTypeByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptModule::GetObjectTypeByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the type.
+
+
+
Returns
The object type interface for the type, or null if not found.
+

This does not increase the reference count of the returned object.

+ +
+
+ +

◆ GetObjectTypeCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptModule::GetObjectTypeCount () const
+
+pure virtual
+
+
Returns
The number of object types declared in the module.
+ +
+
+ +

◆ GetTypedefByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptModule::GetTypedefByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the typedef.
+
+
+
Returns
The type info of the typedef, or null on error.
+ +
+
+ +

◆ GetTypedefCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptModule::GetTypedefCount () const
+
+pure virtual
+
+
Returns
The number of typedefs in the module.
+ +
+
+ +

◆ GetTypeIdByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::GetTypeIdByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe declaration of the type.
+
+
+
Returns
A negative value on error, or the type id of the type.
+
Return values
+ + +
asINVALID_TYPEdecl is not a valid type.
+
+
+

Translates a type declaration into a type id. The returned type id is valid for as long as the type is valid, so you can safely store it for later use to avoid potential overhead from calling this function each time. Just remember to update the type id, any time the type is changed within the engine, e.g. when recompiling script declared classes, or changing the engine configuration.

+

The type id is based on a sequence number and depends on the order in which the type ids are queried, thus is not guaranteed to always be the same for each execution of the application. The asETypeIdFlags can be used to obtain some information about the type directly from the id.

+

A base type yields the same type id whether the declaration is const or not, however if the const is for the subtype then the type id is different, e.g. string@ isn't the same as const string@ but string is the same as const string.
+

+ +
+
+ +

◆ GetTypeInfoByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptModule::GetTypeInfoByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe declaration of the type.
+
+
+
Returns
The type or null on error.
+

Translates a type declaration into the type info. The returned type is valid for as long as the type is valid, so you can safely store it for later use to avoid potential overhead from calling this function each time. Just remember to update the type info pointer any time the type is changed within the engine, e.g. when recompiling script declared classes, or changing the engine configuration.

+ +
+
+ +

◆ GetTypeInfoByName()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asIScriptModule::GetTypeInfoByName (const char * name) const
+
+pure virtual
+
+
Parameters
+ + +
[in]nameThe name of the type.
+
+
+
Returns
The type interface for the type, or null if not found.
+

The search for types will be performed in the default namespace as given by SetDefaultNamespace unless the name is prefixed with a scope, using the scoping operator ::. If the scope starts with :: it will be used as the absolute scope, otherwise it will be relative to the default namespace.

+ +
+
+ +

◆ GetUserData()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptModule::GetUserData (asPWORD type = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeAn identifier specifying the user data to set.
+
+
+
Returns
The pointer to the user data.
+ +
+
+ +

◆ LoadByteCode()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptModule::LoadByteCode (asIBinaryStreamin,
bool * wasDebugInfoStripped = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]inThe input stream.
[out]wasDebugInfoStrippedSet to true if the byte code was saved without debug information.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + + + +
asINVALID_ARGThe stream object wasn't specified.
asBUILD_IN_PROGRESSAnother thread is currently building.
asOUT_OF_MEMORYThe engine ran out of memory while loading the byte code.
asMODULE_IS_IN_USEThe code in the module is still being used and and cannot be removed.
asERRORIt was not possible to load the byte code.
+
+
+

This method is used to load pre-compiled byte code from disk or memory. The application must implement an object that inherits from asIBinaryStream to provide the necessary stream operations.

+

It is expected that the application performs the necessary validations to make sure the pre-compiled byte code is from a trusted source. The application should also make sure the pre-compiled byte code is compatible with the current engine configuration, i.e. that the engine has been configured in the same way as when the byte code was first compiled.

+

If the method returns asERROR it is either because the byte code is incorrect, e.g. corrupted due to disk failure, or it has been compiled with a different engine configuration. If possible the engine provides information about the type of error that caused the failure while loading the byte code to the message stream.

+
See also
Pre-compiled byte code
+ +
+
+ +

◆ RemoveFunction()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::RemoveFunction (asIScriptFunctionfunc)
+
+pure virtual
+
+
Parameters
+ + +
[in]funcThe pointer to the function that should be removed.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asNO_FUNCTIONThe function is not part of the scope.
+
+
+

This method allows the application to remove a single function from the scope of the module. The function is not destroyed immediately though, only when no more references point to it.

+ +
+
+ +

◆ RemoveGlobalVar()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::RemoveGlobalVar (asUINT index)
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the global variable.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_ARGThe index is out of range.
+
+
+

The global variable is removed from the scope of the module, but it is not destroyed until all functions that access it are freed.

+ +
+
+ +

◆ ResetGlobalVars()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::ResetGlobalVars (asIScriptContextctx = 0)
+
+pure virtual
+
+
Parameters
+ + +
[in]ctxOptional script context.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + +
asERRORThe module was not compiled successfully.
asINIT_GLOBAL_VARS_FAILEDThe initialization of the global variables failed.
+
+
+

Resets the global variables declared in this module to their initial value. The context should be informed if the application needs to have extra control over how the initialization is done, for example for debugging, or for catching exceptions.

+ +
+
+ +

◆ SaveByteCode()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual int asIScriptModule::SaveByteCode (asIBinaryStreamout,
bool stripDebugInfo = false 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]outThe output stream.
[in]stripDebugInfoSet to true to skip saving the debug information.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + + +
asINVALID_ARGThe stream object wasn't specified.
asNOT_SUPPORTEDCompiler support is disabled in the engine.
asERRORNothing has been compiled in the module.
+
+
+

This method is used to save pre-compiled byte code to disk or memory, for a later restoral. The application must implement an object that inherits from asIBinaryStream to provide the necessary stream operations.

+
See also
Pre-compiled byte code
+ +
+
+ +

◆ SetAccessMask()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asDWORD asIScriptModule::SetAccessMask (asDWORD accessMask)
+
+pure virtual
+
+
Parameters
+ + +
[in]accessMaskThe access bit mask
+
+
+
Returns
The previous access mask.
+

The module's access mask with be bitwise and-ed with the registered entity's access mask in order to determine if the module is allowed to access the entity. If the result is zero then the script in the module will not be able to use the entity.

+

This can be used to provide different interfaces to scripts that serve different purposes in the application.

+
See also
Access masks and exposing different interfaces
+ +
+
+ +

◆ SetDefaultNamespace()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::SetDefaultNamespace (const char * nameSpace)
+
+pure virtual
+
+
Parameters
+ + +
[in]nameSpaceThe namespace that should be used.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + +
asINVALID_ARGThe namespace is null.
asINVALID_DECLARATIONThe namespace is invalid.
+
+
+

Set the default namespace that should be used in the following calls for searching for declared entities, or when compiling new individual entities.

+ +
+
+ +

◆ SetName()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void asIScriptModule::SetName (const char * name)
+
+pure virtual
+
+
Parameters
+ + +
[in]nameThe new name.
+
+
+

Sets the name of the script module.

+ +
+
+ +

◆ SetUserData()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asIScriptModule::SetUserData (void * data,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]dataA pointer to the user data.
[in]typeAn identifier specifying the user data to set.
+
+
+
Returns
The previous pointer stored in the module
+

This method allows the application to associate a value, e.g. a pointer, with the module instance.

+

The type values 1000 through 1999 are reserved for use by the official add-ons.

+

Optionally, a callback function can be registered to clean up the user data when the module is destroyed.

+ +
+
+ +

◆ UnbindAllImportedFunctions()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptModule::UnbindAllImportedFunctions ()
+
+pure virtual
+
+
Returns
A negative value on error.
+

Unbinds all imported functions in the module.

+ +
+
+ +

◆ UnbindImportedFunction()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptModule::UnbindImportedFunction (asUINT importIndex)
+
+pure virtual
+
+
Parameters
+ + +
[in]importIndexThe index of the imported function.
+
+
+
Returns
A negative value on error.
+
Return values
+ + +
asINVALID_ARGThe index is not valid.
+
+
+

Unbinds the imported function.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_script_object-members.html b/docs/manual/classas_i_script_object-members.html new file mode 100644 index 0000000..2943105 --- /dev/null +++ b/docs/manual/classas_i_script_object-members.html @@ -0,0 +1,126 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIScriptObject Member List
+
+
+ +

This is the complete list of members for asIScriptObject, including all inherited members.

+ + + + + + + + + + + + + + +
AddRef() const =0asIScriptObjectpure virtual
CopyFrom(const asIScriptObject *other)=0asIScriptObjectpure virtual
GetAddressOfProperty(asUINT prop)=0asIScriptObjectpure virtual
GetEngine() const =0asIScriptObjectpure virtual
GetObjectType() const =0asIScriptObjectpure virtual
GetPropertyCount() const =0asIScriptObjectpure virtual
GetPropertyName(asUINT prop) const =0asIScriptObjectpure virtual
GetPropertyTypeId(asUINT prop) const =0asIScriptObjectpure virtual
GetTypeId() const =0asIScriptObjectpure virtual
GetUserData(asPWORD type=0) const =0asIScriptObjectpure virtual
GetWeakRefFlag() const =0asIScriptObjectpure virtual
Release() const =0asIScriptObjectpure virtual
SetUserData(void *data, asPWORD type=0)=0asIScriptObjectpure virtual
+
+ + + + diff --git a/docs/manual/classas_i_script_object.html b/docs/manual/classas_i_script_object.html new file mode 100644 index 0000000..b3e3106 --- /dev/null +++ b/docs/manual/classas_i_script_object.html @@ -0,0 +1,581 @@ + + + + + + + +AngelScript: asIScriptObject Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIScriptObject Class Referenceabstract
+
+
+ +

The interface for an instance of a script object. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

Memory management
virtual int AddRef () const =0
 Increase reference counter. More...
 
virtual int Release () const =0
 Decrease reference counter. More...
 
virtual asILockableSharedBoolGetWeakRefFlag () const =0
 Returns the weak ref flag for the object. More...
 
Type info
virtual int GetTypeId () const =0
 Returns the type id of the object. More...
 
virtual asITypeInfoGetObjectType () const =0
 Returns the object type interface for the object. More...
 
Properties
virtual asUINT GetPropertyCount () const =0
 Returns the number of properties that the object contains. More...
 
virtual int GetPropertyTypeId (asUINT prop) const =0
 Returns the type id of the property referenced by prop. More...
 
virtual const char * GetPropertyName (asUINT prop) const =0
 Returns the name of the property referenced by prop. More...
 
virtual void * GetAddressOfProperty (asUINT prop)=0
 Returns a pointer to the property referenced by prop. More...
 
Miscellaneous
virtual asIScriptEngineGetEngine () const =0
 Return the script engine. More...
 
virtual int CopyFrom (const asIScriptObject *other)=0
 Copies the content from another object of the same type. More...
 
User data
virtual void * SetUserData (void *data, asPWORD type=0)=0
 Sets user data on the script object instance. More...
 
virtual void * GetUserData (asPWORD type=0) const =0
 Gets user data from the script object instance. More...
 
+

Member Function Documentation

+ +

◆ AddRef()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptObject::AddRef () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when storing an additional reference to the object.

+ +
+
+ +

◆ CopyFrom()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptObject::CopyFrom (const asIScriptObjectother)
+
+pure virtual
+
+
Parameters
+ + +
[in]otherA pointer to the source object.
+
+
+
Returns
A negative value on error.
+
Return values
+ + + +
asINVALID_ARGThe argument is null.
asINVALID_TYPEThe other object is of different type.
+
+
+

This method copies the contents of the other object to this one.

+ +
+
+ +

◆ GetAddressOfProperty()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptObject::GetAddressOfProperty (asUINT prop)
+
+pure virtual
+
+
Parameters
+ + +
[in]propThe property index.
+
+
+
Returns
A pointer to the property value.
+

The method returns a pointer to the memory location for the property. Use the type id for the property to determine the content of the pointer, and how to handle it.

+ +
+
+ +

◆ GetEngine()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptEngine* asIScriptObject::GetEngine () const
+
+pure virtual
+
+
Returns
The script engine.
+ +
+
+ +

◆ GetObjectType()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asITypeInfo* asIScriptObject::GetObjectType () const
+
+pure virtual
+
+
Returns
The object type interface of the script object.
+

This does not increase the reference count of the returned object type.

+ +
+
+ +

◆ GetPropertyCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asIScriptObject::GetPropertyCount () const
+
+pure virtual
+
+
Returns
The number of member properties of the script object.
+ +
+
+ +

◆ GetPropertyName()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual const char* asIScriptObject::GetPropertyName (asUINT prop) const
+
+pure virtual
+
+
Parameters
+ + +
[in]propThe property index.
+
+
+
Returns
A null terminated string with the property name.
+ +
+
+ +

◆ GetPropertyTypeId()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIScriptObject::GetPropertyTypeId (asUINT prop) const
+
+pure virtual
+
+
Parameters
+ + +
[in]propThe property index.
+
+
+
Returns
The type id of the member property, or a negative value on error.
+
Return values
+ + +
asINVALID_ARGprop is too large
+
+
+ +
+
+ +

◆ GetTypeId()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptObject::GetTypeId () const
+
+pure virtual
+
+
Returns
The type id of the script object.
+ +
+
+ +

◆ GetUserData()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asIScriptObject::GetUserData (asPWORD type = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeAn identifier used to identify which user data to get.
+
+
+
Returns
The pointer to the user data.
+ +
+
+ +

◆ GetWeakRefFlag()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asILockableSharedBool* asIScriptObject::GetWeakRefFlag () const
+
+pure virtual
+
+
Returns
The weak ref flag for the object.
+

This is a short-cut for the asIScriptEngine::GetWeakRefFlagOfScriptObject method.

+ +
+
+ +

◆ Release()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asIScriptObject::Release () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when you will no longer use the references that you own.

+ +
+
+ +

◆ SetUserData()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asIScriptObject::SetUserData (void * data,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]dataA pointer to the user data.
[in]typeAn identifier used to identify which user data to set.
+
+
+
Returns
The previous pointer stored in the object type.
+

This method allows the application to associate a value, e.g. a pointer, with the script object instance. Multiple different values can be defined where the type argument identifies which is referred to.

+

The user data types identifiers between 1000 and 1999 are reserved for use by official add-ons.

+

Optionally, a callback function can be registered to clean up the user data when the script object is destroyed.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_string_factory-members.html b/docs/manual/classas_i_string_factory-members.html new file mode 100644 index 0000000..e080c3b --- /dev/null +++ b/docs/manual/classas_i_string_factory-members.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIStringFactory Member List
+
+
+ +

This is the complete list of members for asIStringFactory, including all inherited members.

+ + + + +
GetRawStringData(const void *str, char *data, asUINT *length) const =0asIStringFactorypure virtual
GetStringConstant(const char *data, asUINT length)=0asIStringFactorypure virtual
ReleaseStringConstant(const void *str)=0asIStringFactorypure virtual
+
+ + + + diff --git a/docs/manual/classas_i_string_factory.html b/docs/manual/classas_i_string_factory.html new file mode 100644 index 0000000..3f1ce6a --- /dev/null +++ b/docs/manual/classas_i_string_factory.html @@ -0,0 +1,268 @@ + + + + + + + +AngelScript: asIStringFactory Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIStringFactory Class Referenceabstract
+
+
+ +

The interface for the string factory. + More...

+ + + + + + + + + + + +

+Public Member Functions

virtual const void * GetStringConstant (const char *data, asUINT length)=0
 Called by engine to instantiate a string constant. More...
 
virtual int ReleaseStringConstant (const void *str)=0
 Called by engine when the string constant is no longer used. More...
 
virtual int GetRawStringData (const void *str, char *data, asUINT *length) const =0
 Called by engine to get the raw string data for serialization. More...
 
+

Detailed Description

+

This interface is used to manage the string constants that the scripts use. If string constants should be supported the application must implement this object and register it with asIScriptEngine::RegisterStringFactory.

+

Member Function Documentation

+ +

◆ GetRawStringData()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asIStringFactory::GetRawStringData (const void * str,
char * data,
asUINTlength 
) const
+
+pure virtual
+
+
Parameters
+ + + + +
[in]strThe same pointer returned by GetStringConstant
[out]dataA pointer to the data buffer that should be filled with the content
[out]lengthA pointer to the variable that should be set with the length of the data
+
+
+
Returns
A negative value on error.
+

The engine will first call this with data set to null to retrieve the size of the buffer that must be allocated. Then the engine will call the method once more with the allocated data buffer to be filled with the content. The length should always be informed in number of bytes.

+ +
+
+ +

◆ GetStringConstant()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual const void* asIStringFactory::GetStringConstant (const char * data,
asUINT length 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]dataThe content of the string
[in]lengthThe length in bytes of the data buffer
+
+
+
Returns
The pointer to the instantiated string constant
+

The contents of data must be copied by the string factory, as the engine will not keep a copy of the original data.

+

The string factory can cache and return a pointer to the same instance multiple times if the same string content is requested multiple times. If the same instance is returned multiple times the string factory must keep track of the number of instances as ReleaseStringConstant will be called for each of them.

+ +
+
+ +

◆ ReleaseStringConstant()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asIStringFactory::ReleaseStringConstant (const void * str)
+
+pure virtual
+
+
Parameters
+ + +
[in]strThe same pointer returned by GetStringConstant
+
+
+
Returns
A negative value on error.
+

The engine will call this method for each pointer returned by GetStringConstant. If the string factory returns a pointer to the same instance multiple times, then the string instance can only be destroyed when the last call to ReleaseStringConstant for that pointer is made.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_thread_manager-members.html b/docs/manual/classas_i_thread_manager-members.html new file mode 100644 index 0000000..d6055ab --- /dev/null +++ b/docs/manual/classas_i_thread_manager-members.html @@ -0,0 +1,112 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asIThreadManager Member List
+
+
+ +

This is the complete list of members for asIThreadManager, including all inherited members.

+
+
+ + + + diff --git a/docs/manual/classas_i_thread_manager.html b/docs/manual/classas_i_thread_manager.html new file mode 100644 index 0000000..47ff832 --- /dev/null +++ b/docs/manual/classas_i_thread_manager.html @@ -0,0 +1,121 @@ + + + + + + + +AngelScript: asIThreadManager Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asIThreadManager Class Reference
+
+
+ +

The interface for the thread manager. + More...

+

Detailed Description

+

This interface is used to represent the internal thread manager prepared with asPrepareMultithread() and returned by asGetThreadManager(). The application shouldn't do anything with this except pass it to another call to asPrepareMultithread() in case there is a need to share a common thread manager across multiple application modules (dlls).

+

The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classas_i_type_info-members.html b/docs/manual/classas_i_type_info-members.html new file mode 100644 index 0000000..e7a9fe3 --- /dev/null +++ b/docs/manual/classas_i_type_info-members.html @@ -0,0 +1,153 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asITypeInfo Member List
+
+
+ +

This is the complete list of members for asITypeInfo, including all inherited members.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
AddRef() const =0asITypeInfopure virtual
DerivesFrom(const asITypeInfo *objType) const =0asITypeInfopure virtual
GetAccessMask() const =0asITypeInfopure virtual
GetBaseType() const =0asITypeInfopure virtual
GetBehaviourByIndex(asUINT index, asEBehaviours *outBehaviour) const =0asITypeInfopure virtual
GetBehaviourCount() const =0asITypeInfopure virtual
GetChildFuncdef(asUINT index) const =0asITypeInfopure virtual
GetChildFuncdefCount() const =0asITypeInfopure virtual
GetConfigGroup() const =0asITypeInfopure virtual
GetEngine() const =0asITypeInfopure virtual
GetEnumValueByIndex(asUINT index, int *outValue) const =0asITypeInfopure virtual
GetEnumValueCount() const =0asITypeInfopure virtual
GetFactoryByDecl(const char *decl) const =0asITypeInfopure virtual
GetFactoryByIndex(asUINT index) const =0asITypeInfopure virtual
GetFactoryCount() const =0asITypeInfopure virtual
GetFlags() const =0asITypeInfopure virtual
GetFuncdefSignature() const =0asITypeInfopure virtual
GetInterface(asUINT index) const =0asITypeInfopure virtual
GetInterfaceCount() const =0asITypeInfopure virtual
GetMethodByDecl(const char *decl, bool getVirtual=true) const =0asITypeInfopure virtual
GetMethodByIndex(asUINT index, bool getVirtual=true) const =0asITypeInfopure virtual
GetMethodByName(const char *name, bool getVirtual=true) const =0asITypeInfopure virtual
GetMethodCount() const =0asITypeInfopure virtual
GetModule() const =0asITypeInfopure virtual
GetName() const =0asITypeInfopure virtual
GetNamespace() const =0asITypeInfopure virtual
GetParentType() const =0asITypeInfopure virtual
GetProperty(asUINT index, const char **name, int *typeId=0, bool *isPrivate=0, bool *isProtected=0, int *offset=0, bool *isReference=0, asDWORD *accessMask=0, int *compositeOffset=0, bool *isCompositeIndirect=0) const =0asITypeInfopure virtual
GetPropertyCount() const =0asITypeInfopure virtual
GetPropertyDeclaration(asUINT index, bool includeNamespace=false) const =0asITypeInfopure virtual
GetSize() const =0asITypeInfopure virtual
GetSubType(asUINT subTypeIndex=0) const =0asITypeInfopure virtual
GetSubTypeCount() const =0asITypeInfopure virtual
GetSubTypeId(asUINT subTypeIndex=0) const =0asITypeInfopure virtual
GetTypedefTypeId() const =0asITypeInfopure virtual
GetTypeId() const =0asITypeInfopure virtual
GetUserData(asPWORD type=0) const =0asITypeInfopure virtual
Implements(const asITypeInfo *objType) const =0asITypeInfopure virtual
Release() const =0asITypeInfopure virtual
SetUserData(void *data, asPWORD type=0)=0asITypeInfopure virtual
+
+ + + + diff --git a/docs/manual/classas_i_type_info.html b/docs/manual/classas_i_type_info.html new file mode 100644 index 0000000..0bd2ac8 --- /dev/null +++ b/docs/manual/classas_i_type_info.html @@ -0,0 +1,1590 @@ + + + + + + + +AngelScript: asITypeInfo Class Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asITypeInfo Class Referenceabstract
+
+
+ +

The interface for describing types This interface is used to describe the types in the script engine. + More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Member Functions

Miscellaneous
virtual asIScriptEngineGetEngine () const =0
 Returns a pointer to the script engine. More...
 
virtual const char * GetConfigGroup () const =0
 Returns the config group in which the type was registered. More...
 
virtual asDWORD GetAccessMask () const =0
 Returns the access mask for this type. More...
 
virtual asIScriptModuleGetModule () const =0
 Returns the module where the type is declared. More...
 
Memory management
virtual int AddRef () const =0
 Increases the reference counter. More...
 
virtual int Release () const =0
 Decrease reference counter. More...
 
Type info
virtual const char * GetName () const =0
 Returns a temporary pointer to the name of the datatype. More...
 
virtual const char * GetNamespace () const =0
 Return the namespace of the type. More...
 
virtual asITypeInfoGetBaseType () const =0
 Returns the object type that this type derives from. More...
 
virtual bool DerivesFrom (const asITypeInfo *objType) const =0
 Returns true if the type inherits directly or indirectly from the informed type. More...
 
virtual asDWORD GetFlags () const =0
 Returns the type flags. More...
 
virtual asUINT GetSize () const =0
 Returns the size of the object type. More...
 
virtual int GetTypeId () const =0
 Returns the type id for the object type. More...
 
virtual int GetSubTypeId (asUINT subTypeIndex=0) const =0
 Returns the type id of the template sub type. More...
 
virtual asITypeInfoGetSubType (asUINT subTypeIndex=0) const =0
 Returns the template subtype, in case it is an object type. More...
 
virtual asUINT GetSubTypeCount () const =0
 Returns the number of template sub types. More...
 
Interfaces
virtual asUINT GetInterfaceCount () const =0
 Returns the number of interfaces implemented. More...
 
virtual asITypeInfoGetInterface (asUINT index) const =0
 Returns a temporary pointer to the specified interface or null if none are found. More...
 
virtual bool Implements (const asITypeInfo *objType) const =0
 Returns true if the type implements the informed interface type. More...
 
Factories
virtual asUINT GetFactoryCount () const =0
 Returns the number of factory functions for the object type. More...
 
virtual asIScriptFunctionGetFactoryByIndex (asUINT index) const =0
 Returns the factory function by the index. More...
 
virtual asIScriptFunctionGetFactoryByDecl (const char *decl) const =0
 Returns the factory function by the declaration. More...
 
Methods
virtual asUINT GetMethodCount () const =0
 Returns the number of methods for the object type. More...
 
virtual asIScriptFunctionGetMethodByIndex (asUINT index, bool getVirtual=true) const =0
 Returns the method by index. More...
 
virtual asIScriptFunctionGetMethodByName (const char *name, bool getVirtual=true) const =0
 Returns the method by name. More...
 
virtual asIScriptFunctionGetMethodByDecl (const char *decl, bool getVirtual=true) const =0
 Returns the method by declaration. More...
 
Properties
virtual asUINT GetPropertyCount () const =0
 Returns the number of properties that the object contains. More...
 
virtual int GetProperty (asUINT index, const char **name, int *typeId=0, bool *isPrivate=0, bool *isProtected=0, int *offset=0, bool *isReference=0, asDWORD *accessMask=0, int *compositeOffset=0, bool *isCompositeIndirect=0) const =0
 Returns the attributes of the property. More...
 
virtual const char * GetPropertyDeclaration (asUINT index, bool includeNamespace=false) const =0
 Returns the declaration of the property. More...
 
Behaviours
virtual asUINT GetBehaviourCount () const =0
 Returns the number of behaviours. More...
 
virtual asIScriptFunctionGetBehaviourByIndex (asUINT index, asEBehaviours *outBehaviour) const =0
 Returns the function and type of the behaviour. More...
 
Child types
virtual asUINT GetChildFuncdefCount () const =0
 Returns the number of child funcdefs declared in the class. More...
 
virtual asITypeInfoGetChildFuncdef (asUINT index) const =0
 Returns a child funcdef by index. More...
 
virtual asITypeInfoGetParentType () const =0
 Returns the parent type if this is a child type. More...
 
Enums
virtual asUINT GetEnumValueCount () const =0
 Returns the number of values defined for the enum type. More...
 
virtual const char * GetEnumValueByIndex (asUINT index, int *outValue) const =0
 Returns the name and value of the enum value for the enum type. More...
 
Typedef
virtual int GetTypedefTypeId () const =0
 Returns the type id that the typedef represents. More...
 
Funcdef
virtual asIScriptFunctionGetFuncdefSignature () const =0
 Returns the function description for the funcdef type. More...
 
User data
virtual void * SetUserData (void *data, asPWORD type=0)=0
 Register the memory address of some user data. More...
 
virtual void * GetUserData (asPWORD type=0) const =0
 Returns the address of the previously registered user data. More...
 
+

Detailed Description

+

It can represent object types, funcdefs, typedefs, and enums. To determine which family the type belong to verify the flags.

+

Member Function Documentation

+ +

◆ AddRef()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asITypeInfo::AddRef () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when storing an additional reference to the object.

+ +
+
+ +

◆ DerivesFrom()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool asITypeInfo::DerivesFrom (const asITypeInfoobjType) const
+
+pure virtual
+
+
Parameters
+ + +
[in]objTypeThe potential parent type.
+
+
+
Returns
True if the type inherits directly or indirectly from the informed type.
+ +
+
+ +

◆ GetAccessMask()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asDWORD asITypeInfo::GetAccessMask () const
+
+pure virtual
+
+
Returns
The access mask for this type.
+ +
+
+ +

◆ GetBaseType()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asITypeInfo* asITypeInfo::GetBaseType () const
+
+pure virtual
+
+
Returns
A pointer to the object type that this type derives from.
+

This method will only return a pointer in case of script classes that derives from another script class.

+

This does not increase the reference count of the returned object type.

+ +
+
+ +

◆ GetBehaviourByIndex()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual asIScriptFunction* asITypeInfo::GetBehaviourByIndex (asUINT index,
asEBehavioursoutBehaviour 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]indexThe index of the behaviour.
[out]outBehaviourReceives the type of the behaviour.
+
+
+
Returns
The function of the behaviour, or null on error.
+ +
+
+ +

◆ GetBehaviourCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetBehaviourCount () const
+
+pure virtual
+
+
Returns
The number of behaviours for this type.
+ +
+
+ +

◆ GetChildFuncdef()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asITypeInfo::GetChildFuncdef (asUINT index) const
+
+pure virtual
+
+
Returns
The child funcdef matching the index.
+ +
+
+ +

◆ GetChildFuncdefCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetChildFuncdefCount () const
+
+pure virtual
+
+
Returns
The number of child funcdefs declared in the class.
+ +
+
+ +

◆ GetConfigGroup()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asITypeInfo::GetConfigGroup () const
+
+pure virtual
+
+
Returns
The name of the config group, or null if not set.
+ +
+
+ +

◆ GetEngine()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptEngine* asITypeInfo::GetEngine () const
+
+pure virtual
+
+
Returns
A pointer to the engine.
+ +
+
+ +

◆ GetEnumValueByIndex()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual const char* asITypeInfo::GetEnumValueByIndex (asUINT index,
int * outValue 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]indexThe index of the enum value.
[out]outValueReceives the value of the enum value.
+
+
+
Returns
The name of the enum value.
+ +
+
+ +

◆ GetEnumValueCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetEnumValueCount () const
+
+pure virtual
+
+
Returns
The number of enum values.
+ +
+
+ +

◆ GetFactoryByDecl()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asITypeInfo::GetFactoryByDecl (const char * decl) const
+
+pure virtual
+
+
Parameters
+ + +
[in]declThe declaration of the function
+
+
+
Returns
The matching factory function or null if there are no matches
+ +
+
+ +

◆ GetFactoryByIndex()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asIScriptFunction* asITypeInfo::GetFactoryByIndex (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe index of the factory function.
+
+
+
Returns
The factory function or null if the index is invalid.
+ +
+
+ +

◆ GetFactoryCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetFactoryCount () const
+
+pure virtual
+
+
Returns
The number of factory functions for this object.
+ +
+
+ +

◆ GetFlags()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asDWORD asITypeInfo::GetFlags () const
+
+pure virtual
+
+
Returns
A bit mask with the flags from asEObjTypeFlags.
+

Object types are identified by having the flags asOBJ_REF or asOBJ_VALUE set.

+

Enums are identified by having the flag asOBJ_ENUM set.

+

Funcdefs are identified by having the flag asOBJ_FUNCDEF set.

+

Typedefs are identified by having the flag asOBJ_TYPEDEF set.

+

Script classes are identified by having the asOBJ_SCRIPT_OBJECT flag set. Interfaces are identified as a script class with a size of zero.

+
See also
GetSize
+ +
+
+ +

◆ GetFuncdefSignature()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptFunction* asITypeInfo::GetFuncdefSignature () const
+
+pure virtual
+
+
Returns
A pointer to the function description interface, or null if not a funcdef type.
+

This does not increment the reference count of the returned function interface.

+ +
+
+ +

◆ GetInterface()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asITypeInfo::GetInterface (asUINT index) const
+
+pure virtual
+
+
Parameters
+ + +
[in]indexThe interface index.
+
+
+
Returns
A pointer to the interface type.
+ +
+
+ +

◆ GetInterfaceCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetInterfaceCount () const
+
+pure virtual
+
+
Returns
The number of interfaces implemented by this type.
+ +
+
+ +

◆ GetMethodByDecl()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual asIScriptFunction* asITypeInfo::GetMethodByDecl (const char * decl,
bool getVirtual = true 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]declThe method signature.
[in]getVirtualSet to true if the virtual method or the real method should be retrieved.
+
+
+
Returns
The method or null on error.
+

This method should be used to retrieve the script method for the object that you wish to execute. The method is then sent to the context's Prepare method.

+

The method will find the script method with the exact same declaration.

+ +
+
+ +

◆ GetMethodByIndex()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual asIScriptFunction* asITypeInfo::GetMethodByIndex (asUINT index,
bool getVirtual = true 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]indexThe index of the method.
[in]getVirtualSet to true if the virtual method or the real method should be retrieved.
+
+
+
Returns
The method or null on error.
+

This method should be used to retrieve the script method for the object that you wish to execute. The method is then sent to the context's Prepare method.

+

By default this returns the virtual method for script classes. This will allow you to call the virtual method on classes, and rely on the polymorphism to call the correct implementation. If you wish to inspect the real method, then you should set the second parameter to false to retrieve the real method.

+ +
+
+ +

◆ GetMethodByName()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual asIScriptFunction* asITypeInfo::GetMethodByName (const char * name,
bool getVirtual = true 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]nameThe name of the method.
[in]getVirtualSet to true if the virtual method or the real method should be retrieved.
+
+
+
Returns
Tthe method or null in case of error
+

This method should be used to retrieve the script method for the object that you wish to execute. The method is then sent to the context's Prepare method.

+ +
+
+ +

◆ GetMethodCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetMethodCount () const
+
+pure virtual
+
+
Returns
The number of methods for this object.
+ +
+
+ +

◆ GetModule()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asIScriptModule* asITypeInfo::GetModule () const
+
+pure virtual
+
+
Returns
The module where the type is declared.
+

The returned value can be null if the module doesn't exist anymore.

+ +
+
+ +

◆ GetName()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asITypeInfo::GetName () const
+
+pure virtual
+
+
Returns
A null terminated string with the name of the object type.
+ +
+
+ +

◆ GetNamespace()

+ +
+
+ + + + + +
+ + + + + + + +
virtual const char* asITypeInfo::GetNamespace () const
+
+pure virtual
+
+
Returns
The namespace of the type, or null if not defined.
+

If the namespace is not defined it means that this is a child type.

+ +
+
+ +

◆ GetParentType()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asITypeInfo* asITypeInfo::GetParentType () const
+
+pure virtual
+
+
Returns
The parent type if this is a child type.
+ +
+
+ +

◆ GetProperty()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
virtual int asITypeInfo::GetProperty (asUINT index,
const char ** name,
int * typeId = 0,
bool * isPrivate = 0,
bool * isProtected = 0,
int * offset = 0,
bool * isReference = 0,
asDWORDaccessMask = 0,
int * compositeOffset = 0,
bool * isCompositeIndirect = 0 
) const
+
+pure virtual
+
+
Parameters
+ + + + + + + + + + + +
[in]indexThe index of the property
[out]nameThe name of the property
[out]typeIdThe type of the property
[out]isPrivateWhether the property is private or not
[out]isProtectedWhether the property is protected or not
[out]offsetThe offset into the object where the property is stored
[out]isReferenceTrue if the property is not stored inline
[out]accessMaskThe access mask of the property
[out]compositeOffsetThe offset to composite type if used
[out]isCompositeIndirectSet to false if the composite type is inline
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asINVALID_ARGThe index is out of bounds
+
+
+ +
+
+ +

◆ GetPropertyCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetPropertyCount () const
+
+pure virtual
+
+
Returns
The number of member properties of the script object.
+ +
+
+ +

◆ GetPropertyDeclaration()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual const char* asITypeInfo::GetPropertyDeclaration (asUINT index,
bool includeNamespace = false 
) const
+
+pure virtual
+
+
Parameters
+ + + +
[in]indexThe index of the property
[in]includeNamespaceSet to true if the namespace should be included in the declaration.
+
+
+
Returns
The declaration of the property, or null on error.
+ +
+
+ +

◆ GetSize()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetSize () const
+
+pure virtual
+
+
Returns
The number of bytes necessary to store instances of this type.
+

Application registered reference types doesn't store this information, as the script engine doesn't allocate memory for these itself.

+ +
+
+ +

◆ GetSubType()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual asITypeInfo* asITypeInfo::GetSubType (asUINT subTypeIndex = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]subTypeIndexThe zero based index of the template sub type.
+
+
+
Returns
The type info of the template sub type, or null if the template subtype is a primitive.
+ +
+
+ +

◆ GetSubTypeCount()

+ +
+
+ + + + + +
+ + + + + + + +
virtual asUINT asITypeInfo::GetSubTypeCount () const
+
+pure virtual
+
+
Returns
The number of template sub types.
+ +
+
+ +

◆ GetSubTypeId()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual int asITypeInfo::GetSubTypeId (asUINT subTypeIndex = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]subTypeIndexThe zero based index of the template sub type.
+
+
+
Returns
The type id of the template sub type, or a negative value on error.
+
Return values
+ + +
asERRORThe type is not a template type.
+
+
+ +
+
+ +

◆ GetTypedefTypeId()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asITypeInfo::GetTypedefTypeId () const
+
+pure virtual
+
+
Returns
The type id that the typedef represents.
+ +
+
+ +

◆ GetTypeId()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asITypeInfo::GetTypeId () const
+
+pure virtual
+
+
Returns
The type id for the object type.
+ +
+
+ +

◆ GetUserData()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual void* asITypeInfo::GetUserData (asPWORD type = 0) const
+
+pure virtual
+
+
Parameters
+ + +
[in]typeAn identifier used to identify which user data to get.
+
+
+
Returns
The pointer to the user data.
+ +
+
+ +

◆ Implements()

+ +
+
+ + + + + +
+ + + + + + + + +
virtual bool asITypeInfo::Implements (const asITypeInfoobjType) const
+
+pure virtual
+
+
Parameters
+ + +
[in]objTypeThe interface type.
+
+
+
Returns
True if the type implements the informed interface type.
+ +
+
+ +

◆ Release()

+ +
+
+ + + + + +
+ + + + + + + +
virtual int asITypeInfo::Release () const
+
+pure virtual
+
+
Returns
The number of references to this object.
+

Call this method when you will no longer use the references that you own.

+ +
+
+ +

◆ SetUserData()

+ +
+
+ + + + + +
+ + + + + + + + + + + + + + + + + + +
virtual void* asITypeInfo::SetUserData (void * data,
asPWORD type = 0 
)
+
+pure virtual
+
+
Parameters
+ + + +
[in]dataA pointer to the user data.
[in]typeAn identifier used to identify which user data to set.
+
+
+
Returns
The previous pointer stored in the object type.
+

This method allows the application to associate a value, e.g. a pointer, with the object type instance. Multiple different values can be defined where the type argument identifies which is referred to.

+

The user data types identifiers between 1000 and 1999 are reserved for use by official add-ons.

+

Optionally, a callback function can be registered to clean up the user data when the object type is destroyed.

+ +
+
+
The documentation for this class was generated from the following file: +
+
+ + + + diff --git a/docs/manual/classes.html b/docs/manual/classes.html new file mode 100644 index 0000000..579389d --- /dev/null +++ b/docs/manual/classes.html @@ -0,0 +1,137 @@ + + + + + + + +AngelScript: Class Index + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Class Index
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + +
  a  
+
asILockableSharedBool   asIScriptGeneric   asIThreadManager   asSMessageInfo   
asIScriptContext   asIScriptModule   asITypeInfo   asSVMRegisters   
asIBinaryStream   asIScriptEngine   asIScriptObject   asSBCInfo   
asIJITCompiler   asIScriptFunction   asIStringFactory   asSFuncPtr   
+ +
+
+ + + + diff --git a/docs/manual/closed.png b/docs/manual/closed.png new file mode 100644 index 0000000..98cc2c9 Binary files /dev/null and b/docs/manual/closed.png differ diff --git a/docs/manual/dir_b2f33c71d4aa5e7af42a1ca61ff5af1b.html b/docs/manual/dir_b2f33c71d4aa5e7af42a1ca61ff5af1b.html new file mode 100644 index 0000000..139b208 --- /dev/null +++ b/docs/manual/dir_b2f33c71d4aa5e7af42a1ca61ff5af1b.html @@ -0,0 +1,118 @@ + + + + + + + +AngelScript: source Directory Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
source Directory Reference
+
+
+ + + + + +

+Files

file  angelscript.h
 The API definition for AngelScript.
 
+
+
+ + + + diff --git a/docs/manual/doc.png b/docs/manual/doc.png new file mode 100644 index 0000000..17edabf Binary files /dev/null and b/docs/manual/doc.png differ diff --git a/docs/manual/doc_addon.html b/docs/manual/doc_addon.html new file mode 100644 index 0000000..b1f11dd --- /dev/null +++ b/docs/manual/doc_addon.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Add-ons + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Add-ons
+
+
+

This page gives a brief description of the add-ons that you'll find in the /sdk/add_on/ folder.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_addon.js b/docs/manual/doc_addon.js new file mode 100644 index 0000000..75bb5ac --- /dev/null +++ b/docs/manual/doc_addon.js @@ -0,0 +1,5 @@ +var doc_addon = +[ + [ "Application modules", "doc_addon_application.html", "doc_addon_application" ], + [ "Script extensions", "doc_addon_script.html", "doc_addon_script" ] +]; \ No newline at end of file diff --git a/docs/manual/doc_addon_any.html b/docs/manual/doc_addon_any.html new file mode 100644 index 0000000..665e9bd --- /dev/null +++ b/docs/manual/doc_addon_any.html @@ -0,0 +1,201 @@ + + + + + + + +AngelScript: any object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
any object
+
+
+

Path: /sdk/add_on/scriptany/

+

The any type is a generic container that can hold any value. It is a reference type.

+

The type is registered with RegisterScriptAny(asIScriptEngine*).

+

+Public C++ interface

+
class CScriptAny
+
{
+
public:
+
// Constructors
+
CScriptAny(asIScriptEngine *engine);
+
CScriptAny(void *ref, int refTypeId, asIScriptEngine *engine);
+
+
// Memory management
+
int AddRef() const;
+
int Release() const;
+
+
// Copy the stored value from another any object
+
CScriptAny &operator=(const CScriptAny&);
+
int CopyFrom(const CScriptAny *other);
+
+
// Store the value, either as variable type, integer number, or real number
+
void Store(void *ref, int refTypeId);
+
void Store(asINT64 &value);
+
void Store(double &value);
+
+
// Retrieve the stored value, either as variable type, integer number, or real number
+
bool Retrieve(void *ref, int refTypeId) const;
+
bool Retrieve(asINT64 &value) const;
+
bool Retrieve(double &value) const;
+
+
// Get the type id of the stored value
+
int GetTypeId() const;
+
};
+

+Public script interface

+
+  class any
+  {
+    any();
+    any(? &in value);
+    any(int64 &in value);
+    any(double &in value);
    any &opAssign(const any &in other);
    void store(? &in value);
+    void store(int64 &in value);
+    void store(double &in value);
    bool retrieve(? &out value) const;
+    bool retrieve(int64 &out value) const;
+    bool retrieve(double &out value) const;
+  }
+

any()
+ any(? &in value)
+ any(int64 &in value)
+ any(double &in value)
+

+

The default constructor creates an empty object, and the second initializes the object with the provided value.

+

The int64 and double overloads make sure that all numbers are converted to 64bit before being stored in the object.

+

any &opAssign(const any &in other)
+

+

The assignment operator will copy the contained value from the other object.

+

void store(? &in value)
+ void store(int64 &in value)
+ void store(double &in value)
+

+

These methods sets the value in the object.

+

The int64 and double overloads make sure that all numbers are converted to 64bit before being stored in the object.

+

bool retrieve(? &out value) const
+ bool retrieve(int64 &out value) const
+ bool retrieve(double &out value) const
+

+

These methods retrieve the value stored in the object. The methods will return true if the stored value is compatible with the requested type.

+

+Example usage

+

In the scripts it can be used as follows:

+
+  int value;
+  obj object;
+  obj @handle;
+  any a,b,c;
+  a.store(value);      // store the value
+  b.store(@handle);    // store an object handle
+  c.store(object);     // store a copy of the object
  a.retrieve(value);   // retrieve the value
+  b.retrieve(@handle); // retrieve the object handle
+  c.retrieve(object);  // retrieve a copy of the object
+

In C++ the type can be used as follows:

+
CScriptAny *myAny;
+
int typeId = engine->GetTypeIdByDecl("string@");
+
CScriptString *str = new CScriptString("hello world");
+
myAny->Store((void*)&str, typeId);
+
myAny->Retrieve((void*)&str, typeId);
+
+
+
+
__int64 asINT64
64 bit integer
Definition: angelscript.h:620
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int GetTypeIdByDecl(const char *decl) const =0
Returns a type id by declaration.
+ + + + diff --git a/docs/manual/doc_addon_application.html b/docs/manual/doc_addon_application.html new file mode 100644 index 0000000..603a17b --- /dev/null +++ b/docs/manual/doc_addon_application.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Application modules + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ + +
+ + + + diff --git a/docs/manual/doc_addon_application.js b/docs/manual/doc_addon_application.js new file mode 100644 index 0000000..21c4e6d --- /dev/null +++ b/docs/manual/doc_addon_application.js @@ -0,0 +1,32 @@ +var doc_addon_application = +[ + [ "Script builder", "doc_addon_build.html", [ + [ "Public C++ interface", "doc_addon_build.html#doc_addon_build_1", [ + [ "The include callback signature", "doc_addon_build.html#doc_addon_build_1_1", null ], + [ "The pragma callback signature", "doc_addon_build.html#doc_addon_build_1_2", null ] + ] ], + [ "Include directives", "doc_addon_build.html#doc_addon_build_2", null ], + [ "Conditional programming", "doc_addon_build.html#doc_addon_build_condition", null ], + [ "Metadata in scripts", "doc_addon_build.html#doc_addon_build_metadata", null ] + ] ], + [ "Context manager", "doc_addon_ctxmgr.html", [ + [ "Public C++ interface", "doc_addon_ctxmgr.html#doc_addon_ctxmgr_1", null ], + [ "Public script interface", "doc_addon_ctxmgr.html#doc_addon_ctxmgr_2", null ] + ] ], + [ "Debugger", "doc_addon_debugger.html", [ + [ "Public C++ interface", "doc_addon_debugger.html#doc_addon_debugger_1", null ], + [ "Example usage", "doc_addon_debugger.html#doc_addon_debugger_2", null ] + ] ], + [ "Serializer", "doc_addon_serializer.html", [ + [ "Public C++ interface", "doc_addon_serializer.html#doc_addon_serializer_1", null ], + [ "Example usage", "doc_addon_serializer.html#doc_addon_serializer_2", null ] + ] ], + [ "Helper functions", "doc_addon_helpers.html", [ + [ "Public C++ interface", "doc_addon_helpers.html#doc_addon_helpers_1", null ], + [ "Example", "doc_addon_helpers.html#doc_addon_helpers_2", null ] + ] ], + [ "Automatic wrapper functions", "doc_addon_autowrap.html", [ + [ "Example usage", "doc_addon_autowrap.html#doc_addon_autowrap_1", null ], + [ "Adding support for more parameters", "doc_addon_autowrap.html#doc_addon_autowrap_2", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_addon_array.html b/docs/manual/doc_addon_array.html new file mode 100644 index 0000000..196de9f --- /dev/null +++ b/docs/manual/doc_addon_array.html @@ -0,0 +1,232 @@ + + + + + + + +AngelScript: array template object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
array template object
+
+
+

Path: /sdk/add_on/scriptarray/

+

The array type is a template object that allow the scripts to declare arrays of any type. Since it is a generic class it is not the most performatic due to the need to determine characteristics at runtime. For that reason it is recommended that the application registers a template specialization for the array types that are most commonly used.

+

The type is registered with RegisterScriptArray(asIScriptEngine *engine, bool defaultArrayType). The second parameter should be set to true if you wish to allow the syntax form type[] to declare arrays.

+

Compile the add-on with the pre-processor define AS_USE_STLNAMES=1 to register the methods with the same names as used by C++ STL where the methods have the same significance. Not all methods from STL is implemented in the add-on, but many of the most frequent once are so a port from script to C++ and vice versa might be easier if STL names are used.

+

Compile the add-on with the pre-processor define AS_USE_ACCESSORS=1 to register length as a virtual property instead of the method length().

+

+Public C++ interface

+
class CScriptArray
+
{
+
public:
+
// Set the memory functions that should be used by all CScriptArrays
+
static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc);
+
+
// Factory functions
+
static CScriptArray *Create(asITypeInfo *arrayType);
+
static CScriptArray *Create(asITypeInfo *arrayType, asUINT length);
+
static CScriptArray *Create(asITypeInfo *arrayType, asUINT length, void *defaultValue);
+
static CScriptArray *Create(asITypeInfo *arrayType, void *listBuffer);
+
+
// Memory management
+
void AddRef() const;
+
void Release() const;
+
+
// Type information
+
asITypeInfo *GetArrayObjectType() const;
+
int GetArrayTypeId() const;
+
int GetElementTypeId() const;
+
+
// Get the current size
+
asUINT GetSize() const;
+
+
// Returns true if the array is empty
+
bool IsEmpty() const;
+
+
// Pre-allocates memory for elements
+
void Reserve(asUINT numElements);
+
+
// Resize the array
+
void Resize(asUINT numElements);
+
+
// Get a pointer to an element. Returns 0 if out of bounds
+
void *At(asUINT index);
+
const void *At(asUINT index) const;
+
+
// Set value of an element.
+
// The value arg should be a pointer to the value that will be copied to the element.
+
// Remember, if the array holds handles the value parameter should be the
+
// address of the handle. The refCount of the object will also be incremented
+
void SetValue(asUINT index, void *value);
+
+
// Copy the contents of one array to another (only if the types are the same)
+
CScriptArray &operator=(const CScriptArray&);
+
+
// Compare two arrays
+
bool operator==(const CScriptArray &) const;
+
+
// Array manipulation
+
void InsertAt(asUINT index, void *value);
+
void RemoveAt(asUINT index);
+
void InsertLast(void *value);
+
void RemoveLast();
+
void SortAsc();
+
void SortAsc(asUINT startAt, asUINT count);
+
void SortDesc();
+
void SortDesc(asUINT startAt, asUINT count);
+
void Sort(asUINT startAt, asUINT count, bool asc);
+
void Sort(asIScriptFunction *less, asUINT startAt, asUINT count);
+
void Reverse();
+
int Find(void *value) const;
+
int Find(asUINT startAt, void *value) const;
+
int FindByRef(void *ref) const;
+
int FindByRef(asUINT startAt, void *ref) const;
+
+
// Returns the address of the inner buffer for direct manipulation
+
void *GetBuffer();
+
};
+

+Public script interface

+
See also
Arrays in the script language
+

+C++ example

+

This function shows how a script array can be instantiated from the application and then passed to the script.

+
// Registered with AngelScript as 'array<string> @CreateArrayOfString()'
+
CScriptArray *CreateArrayOfStrings()
+
{
+
// If called from the script, there will always be an active
+
// context, which can be used to obtain a pointer to the engine.
+ +
if( ctx )
+
{
+
asIScriptEngine* engine = ctx->GetEngine();
+
+
// The script array needs to know its type to properly handle the elements.
+
// Note that the object type should be cached to avoid performance issues
+
// if the function is called frequently.
+
asITypeInfo* t = engine->GetTypeInfoByDecl("array<string>");
+
+
// Create an array with the initial size of 3 elements
+
CScriptArray* arr = CScriptArray::Create(t, 3);
+
for( asUINT i = 0; i < arr->GetSize(); i++ )
+
{
+
// Set the value of each element
+
string val("test");
+
arr->SetValue(i, &val);
+
}
+
+
// The ref count for the returned handle was already set in the array's constructor
+
return arr;
+
}
+
return 0;
+
}
+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
The engine interface.
Definition: angelscript.h:1092
+
virtual asIScriptEngine * GetEngine() const =0
Returns a pointer to the engine.
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
void(* asFREEFUNC_t)(void *)
The function signature for the custom memory deallocation function.
Definition: angelscript.h:637
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+
The interface for a script function description.
Definition: angelscript.h:3823
+
void *(* asALLOCFUNC_t)(size_t)
The function signature for the custom memory allocation function.
Definition: angelscript.h:635
+
virtual asITypeInfo * GetTypeInfoByDecl(const char *decl) const =0
Returns a type by declaration.
+
AS_API asIScriptContext * asGetActiveContext()
Returns the currently active context.
+ + + + diff --git a/docs/manual/doc_addon_autowrap.html b/docs/manual/doc_addon_autowrap.html new file mode 100644 index 0000000..b25ac4e --- /dev/null +++ b/docs/manual/doc_addon_autowrap.html @@ -0,0 +1,160 @@ + + + + + + + +AngelScript: Automatic wrapper functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Automatic wrapper functions
+
+
+

Path: /sdk/add_on/autowrapper/aswrappedcall.h

+

This header file declares some macros and template functions that will let the application developer automatically generate wrapper functions using the generic calling convention with a simple call to a preprocessor macro. This is useful for those platforms where the native calling conventions are not yet supported.

+

The macros are defined as:

+
// Wrap a global function with implicit or explicit signature
+
#define WRAP_FN(name)
+
#define WRAP_FN_PR(name, Parameters, ReturnType)
+
+
// Wrap a class method with implicit or explicit signature
+
#define WRAP_MFN(ClassType, name)
+
#define WRAP_MFN_PR(ClassType, name, Parameters, ReturnType)
+
+
// Wrap a global function that will emulate a class method and receives the 'this' pointer as the first argument
+
#define WRAP_OBJ_FIRST(name)
+
#define WRAP_OBJ_FIRST_PR(name, Parameters, ReturnType)
+
+
// Wrap a global function that will emulate a class method and receives the 'this' pointer as the last argument
+
#define WRAP_OBJ_LAST(name)
+
#define WRAP_OBJ_LAST_PR(name, Parameters, ReturnType)
+
+
// Wrap a constructor with an explicit signature
+
#define WRAP_CON(ClassType, Parameters)
+
+
// Wrap a destructor
+
#define WRAP_DES(ClassType)
+

As you can see they are very similar to the asFUNCTION and asMETHOD macros, and are used the same way.

+

Unfortunately the template functions needed to perform this generation are quite complex and older compilers may not be able to handle them. One such example is Microsoft Visual C++ 6, though luckily it has no need for them as AngelScript already supports native calling conventions for it.

+

+Example usage

+
#include "aswrappedcall.h"
+
+
// The application function that we want to register
+
void DoSomething(std::string param1, int param2);
+
+
// Registering the wrapper with AngelScript
+
void RegisterWrapper(asIScriptEngine *engine)
+
{
+
int r;
+
+
// The WRAP_FN macro automatically implements and returns the function pointer of the generic wrapper
+
// function. Observe, that the calling convention should be set as asCALL_GENERIC in this case.
+
r = engine->RegisterGlobalFunction("void DoSomething(string, int)", WRAP_FN(DoSomething), asCALL_GENERIC); assert( r >= 0 );
+
}
+

+Adding support for more parameters

+

The aswrappedcall.h header file is by default prepared to support functions with up to 4 arguments. If you have a need for more arguments then you can use the generator that you find in the sub-directory to prepare a new header file.

+

Open the generateheader.cpp in an editor and set the max_args variable to the number of arguments you need and then compile and run the code. It will print the new header file to the standard output so you just need to direct this to a file.

+
+
+
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
@ asCALL_GENERIC
A function using the generic calling convention.
Definition: angelscript.h:238
+ + + + diff --git a/docs/manual/doc_addon_build.html b/docs/manual/doc_addon_build.html new file mode 100644 index 0000000..1b8f228 --- /dev/null +++ b/docs/manual/doc_addon_build.html @@ -0,0 +1,267 @@ + + + + + + + +AngelScript: Script builder + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Script builder
+
+
+

Path: /sdk/add_on/scriptbuilder/

+

This class is a helper class for loading and building scripts, with a basic pre-processor that supports conditional compilation, include directives, and metadata declarations.

+

By default the script builder resolves include directives by loading the included file from the relative directory of the file it is included from. If you want to do this in another way, then you should implement the include callback which will let you process the include directive in a custom way, e.g. to load the included file from memory, or to support multiple search paths. The include callback should call the AddSectionFromFile or AddSectionFromMemory to include the section in the current build.

+

If you do not want process metadata then you can compile the add-on with the define AS_PROCESS_METADATA 0, which will exclude the code for processing this. This define can be made in the project settings or directly in the header.

+

+Public C++ interface

+
class CScriptBuilder
+
{
+
public:
+
// Start a new module
+
int StartNewModule(asIScriptEngine *engine, const char *moduleName);
+
+
// Load a script section from a file on disk
+
// Returns 1 if the file was included
+
// 0 if the file had already been included before
+
// <0 on error
+
int AddSectionFromFile(const char *filename);
+
+
// Load a script section from memory
+
// Returns 1 if the section was included
+
// 0 if a section with the same name had already been included before
+
// <0 on error
+
int AddSectionFromMemory(const char *sectionName,
+
const char *scriptCode,
+
unsigned int scriptLength = 0,
+
int lineOffset = 0);
+
+
// Build the added script sections
+
int BuildModule();
+
+
// Returns the script engine
+
asIScriptEngine *GetEngine();
+
+
// Returns the current module
+
asIScriptModule *GetModule();
+
+
// Register the callback for resolving include directive
+
void SetIncludeCallback(INCLUDECALLBACK_t callback, void *userParam);
+
+
// Register the callback for resolving pragma directive
+
void SetPragmaCallback(PRAGMACALLBACK_t callback, void *userParam);
+
+
// Add a pre-processor define for conditional compilation
+
void DefineWord(const char *word);
+
+
// Enumerate included script sections
+
unsigned int GetSectionCount() const;
+
string GetSectionName(unsigned int idx) const;
+
+
// Get metadata declared for classes, interfaces, and enums
+
// Each metadata block, i.e. [...], is returned as a separate string
+
std::vector<std::string> GetMetadataStringForType(int typeId);
+
+
// Get metadata declared for functions
+
// Each metadata block, i.e. [...], is returned as a separate string
+
std::vector<std::string> GetMetadataStringForFunc(asIScriptFunction *func);
+
+
// Get metadata declared for global variables
+
// Each metadata block, i.e. [...], is returned as a separate string
+
std::vector<std::string> GetMetadataStringForVar(int varIdx);
+
+
// Get metadata declared for a class method
+
// Each metadata block, i.e. [...], is returned as a separate string
+
std::vector<std::string> GetMetadataStringForTypeMethod(int typeId, asIScriptFunction *method);
+
+
// Get metadata declared for a class property
+
// Each metadata block, i.e. [...], is returned as a separate string
+
std::vector<std::string> GetMetadataStringForTypeProperty(int typeId, int varIdx);
+
};
+

+The include callback signature

+
// This callback will be called for each #include directive encountered by the
+
// builder. The callback should call the AddSectionFromFile or AddSectionFromMemory
+
// to add the included section to the script. If the include cannot be resolved
+
// then the function should return a negative value to abort the compilation.
+
typedef int (*INCLUDECALLBACK_t)(const char *include, const char *from, CScriptBuilder *builder, void *userParam);
+

+The pragma callback signature

+
// This callback will be called for each #pragma directive encountered by the builder.
+
// The application can interpret the pragmaText and decide what do to based on that.
+
// If the callback returns a negative value the builder will report an error and abort the compilation.
+
typedef int(*PRAGMACALLBACK_t)(const std::string &pragmaText, CScriptBuilder &builder, void *userParam);
+

+Include directives

+

Example script with include directive:

+
+  #include "commonfuncs.as"
  void main()
+  {
+    // Call a function from the included file
+    CommonFunc();
+  }
+

+Conditional programming

+

The builder supports conditional programming through the #if/#endif preprocessor directives. The application may define a word with a call to DefineWord(), then the scripts may check for this definition in the code in order to include/exclude parts of the code.

+

This is especially useful when scripts are shared between different binaries, for example, in a client/server application.

+

Example script with conditional compilation:

+
+  class CObject
+  {
+    void Process()
+    {
+  #if SERVER
+      // Do some server specific processing
+  #endif
  #if CLIENT
+      // Do some client specific processing
+  #endif
      // Do some common processing
+    }
+  }
+

+Metadata in scripts

+

Metadata can be added before script class, interface, function, and global variable declarations. The metadata is removed from the script by the builder class and stored for post build lookup by the type id, function id, or variable index.

+

Exactly what the metadata looks like is up to the application. The builder class doesn't impose any rules, except that the metadata should be added between brackets []. After the script has been built the application can obtain the metadata strings and interpret them as it sees fit. Multiple metadata blocks, i.e. [], can be defined for each entity.

+

Example script with metadata:

+
+  [factory func = CreateOgre]
+  class COgre
+  {
+    [editable] 
+    vector3 myPosition;
    [editable]
+    [range [10, 100]]
+    int     myStrength;
+  }
  [factory]
+  COgre @CreateOgre()
+  {
+    return @COgre();
+  }
+

Example usage:

+
CScriptBuilder builder;
+
int r = builder.StartNewModule(engine, "my module");
+
if( r >= 0 )
+
r = builder.AddSectionFromMemory(script);
+
if( r >= 0 )
+
r = builder.BuildModule();
+
if( r >= 0 )
+
{
+
// Find global variables that have been marked as editable by user
+
asIScriptModule *mod = engine->GetModule("my module");
+
int count = mod->GetGlobalVarCount();
+
for( int n = 0; n < count; n++ )
+
{
+
vector<string> metadata = builder.GetMetadataStringForVar(n);
+
for( int m = 0; m < metadata.size(); m++ )
+
{
+
if( metadata[m] == "editable" )
+
{
+
// Show the global variable in a GUI
+
...
+
}
+
}
+
}
+
}
+
+
+
+
virtual asUINT GetGlobalVarCount() const =0
Returns the number of global variables in the module.
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
The engine interface.
Definition: angelscript.h:1092
+
The interface for a script function description.
Definition: angelscript.h:3823
+
The interface to the script modules.
Definition: angelscript.h:2218
+ + + + diff --git a/docs/manual/doc_addon_ctxmgr.html b/docs/manual/doc_addon_ctxmgr.html new file mode 100644 index 0000000..42f68e9 --- /dev/null +++ b/docs/manual/doc_addon_ctxmgr.html @@ -0,0 +1,182 @@ + + + + + + + +AngelScript: Context manager + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Context manager
+
+
+

Path: /sdk/add_on/contextmgr/

+

The CContextMgr is a class designed to aid the management of multiple simultaneous scripts executing in parallel. It supports both concurrent script threads and co-routines.

+

If the application doesn't need multiple contexts, i.e. all scripts that are executed always complete before the next script is executed, then this class is not necessary.

+

The context manager uses asIScriptEngine::RequestContext to take advantage of any context callbacks registered with the engine, e.g. for debugging or pooling.

+

Multiple context managers can be used, for example when you have a group of scripts controlling in-game objects, and another group of scripts controlling GUI elements, then each of these groups may be managed by different context managers.

+

Observe that the context manager class hasn't been designed for multi-threading, so you need to be careful if your application needs to execute scripts from multiple threads.

+
See also
The samples Concurrent scripts and Co-routines for uses
+

+Public C++ interface

+
class CContextMgr
+
{
+
public:
+
CContextMgr();
+
~CContextMgr();
+
+
// Set the function that the manager will use to obtain the time in milliseconds.
+
void SetGetTimeCallback(TIMEFUNC_t func);
+
+
// Registers the following:
+
//
+
// void sleep(uint milliseconds)
+
//
+
// The application must set the get time callback for this to work
+
void RegisterThreadSupport(asIScriptEngine *engine);
+
+
// Registers the following:
+
//
+
// funcdef void coroutine(dictionary@)
+
// void createCoRoutine(coroutine @func, dictionary @args)
+
// void yield()
+
void RegisterCoRoutineSupport(asIScriptEngine *engine);
+
+
// Create a new context, prepare it with the function, then return
+
// it so that the application can pass the argument values. The context
+
// will be released by the manager after the execution has completed.
+
// Set keepCtxAfterExecution to true if the application needs to retrieve
+
// information from the context after it the script has finished.
+
asIScriptContext *AddContext(asIScriptEngine *engine, asIScriptContext *func, bool keepCtxAfterExecution = false);
+
+
// If the context was kept after the execution, this method must be
+
// called when the application is done with the context so it can be
+
// returned to the pool for reuse.
+
void DoneWithContext(asIScriptContext *ctx);
+
+
// Create a new context, prepare it with the function, then return
+
// it so that the application can pass the argument values. The context
+
// will be added as a co-routine in the same thread as the currCtx.
+
asIScriptContext *AddContextForCoRoutine(asIScriptContext *currCtx, asIScriptContext *func);
+
+
// Execute each script that is not currently sleeping. The function returns after
+
// each script has been executed once. The application should call this function
+
// for each iteration of the message pump, or game loop, or whatever.
+
// Returns the number of scripts still in execution.
+
int ExecuteScripts();
+
+
// Put a script to sleep for a while
+
void SetSleeping(asIScriptContext *ctx, asUINT milliSeconds);
+
+
// Switch the execution to the next co-routine in the group.
+
// Returns true if the switch was successful.
+
void NextCoRoutine();
+
+
// Abort all scripts
+
void AbortAll();
+
};
+

+Public script interface

+
See also
Co-routines
+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
The engine interface.
Definition: angelscript.h:1092
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+ + + + diff --git a/docs/manual/doc_addon_datetime.html b/docs/manual/doc_addon_datetime.html new file mode 100644 index 0000000..0a14acd --- /dev/null +++ b/docs/manual/doc_addon_datetime.html @@ -0,0 +1,158 @@ + + + + + + + +AngelScript: datetime object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
datetime object
+
+
+

Path: /sdk/add_on/datetime/

+

The CDateTime class provides a way for scripts to get the system date and time.

+

Register the type with the RegisterScriptDateTime(asIScriptEngine*) function.

+
Note
This class requires C++11 or later to compile.
+

+Public C++ interface

+
class CDateTime
+
{
+
public:
+
// Constructors
+
CDateTime();
+
CDateTime(const CDateTime &other);
+
CDateTime(asUINT year, asUINT month, asUINT day, asUINT hour, asUINT minute, asUINT second);
+
+
// Copy the stored value from another any object
+
CDateTime &operator=(const CDateTime &other);
+
+
// Accessors
+
asUINT getYear() const;
+
asUINT getMonth() const;
+
asUINT getDay() const;
+
asUINT getHour() const;
+
asUINT getMinute() const;
+
asUINT getSecond() const;
+
+
// Setters
+
// Returns true if valid
+
bool setDate(asUINT year, asUINT month, asUINT day);
+
bool setTime(asUINT hour, asUINT minute, asUINT second);
+
+
// Operators
+
// Return difference in seconds
+
asINT64 operator-(const CDateTime &other) const;
+
CDateTime operator+(asINT64 seconds) const;
+
friend CDateTime operator+(asINT64 seconds, const CDateTime &other);
+
CDateTime & operator+=(asINT64 seconds);
+
CDateTime operator-(asINT64 seconds) const;
+
friend CDateTime operator-(asINT64 seconds, const CDateTime &other);
+
CDateTime & operator-=(asINT64 seconds);
+
bool operator==(const CDateTime &other) const;
+
bool operator<(const CDateTime &other) const;
+
};
+

+Public script interface

+
See also
datetime in the script language
+
+
+
+
__int64 asINT64
64 bit integer
Definition: angelscript.h:620
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+ + + + diff --git a/docs/manual/doc_addon_debugger.html b/docs/manual/doc_addon_debugger.html new file mode 100644 index 0000000..dac0a55 --- /dev/null +++ b/docs/manual/doc_addon_debugger.html @@ -0,0 +1,184 @@ + + + + + + + +AngelScript: Debugger + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Debugger
+
+
+

Path: /sdk/add_on/debugger/

+

The CDebugger implements common debugging functionality for scripts, e.g. setting breakpoints, stepping through the code, examining values of variables, etc.

+

To use the debugger the line callback should be set in the context. This will allow the debugger to take over whenever a breakpoint is reached, so the script can be debugged.

+

By default the debugger uses the standard in and standard out streams to interact with the user, but this can be easily overloaded by deriving from the CDebugger class and implementing the methods TakeCommands and Output. With this it is possible to implement a graphical interface, or even remote debugging for an application.

+

The application developer may also be interested in registering to-string callbacks for registered types with calls to RegisterToStringCallback. Optionally the ToString method in the debugger can be overridden to implement custom to-string logic.

+
See also
The sample Command line runner for a complete example of how to use the debugger
+

+Public C++ interface

+
class CDebugger
+
{
+
public:
+
CDebugger();
+
virtual ~CDebugger();
+
+
// Register callbacks to handle to-string conversions of application types
+
// The expandMembersLevel is a counter for how many recursive levels the members should be expanded.
+
// If the object that is being converted to a string has members of its own the callback should call
+
// the debugger's ToString passing in expandMembersLevel - 1.
+
typedef std::string (*ToStringCallback)(void *obj, int expandMembersLevel, CDebugger *dbg);
+
virtual void RegisterToStringCallback(const asITypeInfo *type, ToStringCallback callback);
+
+
// User interaction
+
virtual void TakeCommands(asIScriptContext *ctx);
+
virtual void Output(const std::string &str);
+
+
// Line callback invoked by context
+
virtual void LineCallback(asIScriptContext *ctx);
+
+
// Commands
+
virtual void PrintHelp();
+
virtual void AddFileBreakPoint(const std::string &file, int lineNbr);
+
virtual void AddFuncBreakPoint(const std::string &func);
+
virtual void ListBreakPoints();
+
virtual void ListLocalVariables(asIScriptContext *ctx);
+
virtual void ListGlobalVariables(asIScriptContext *ctx);
+
virtual void ListMemberProperties(asIScriptContext *ctx);
+
virtual void ListStatistics(asIScriptContext *ctx);
+
virtual void PrintCallstack(asIScriptContext *ctx);
+
virtual void PrintValue(const std::string &expr, asIScriptContext *ctx);
+
+
// Helpers
+
virtual bool InterpretCommand(const std::string &cmd, asIScriptContext *ctx);
+
virtual bool CheckBreakPoint(asIScriptContext *ctx);
+
virtual std::string ToString(void *value, asUINT typeId, int expandMembersLevel, asIScriptEngine *engine);
+
+
// Optionally set the engine pointer in the debugger so it can be retrieved
+
// by callbacks that need it. This will hold a reference to the engine.
+
virtual void SetEngine(asIScriptEngine *engine);
+
virtual asIScriptEngine *GetEngine();
+
};
+

+Example usage

+
CDebugger dbg;
+
int ExecuteWithDebug(asIScriptContext *ctx)
+
{
+
// Tell the context to invoke the debugger's line callback
+
ctx->SetLineCallback(asMETHOD(CDebugger, LineCallback), &dbg, asCALL_THISCALL);
+
+
// Allow the user to initialize the debugging before moving on
+
dbg.TakeCommands(ctx);
+
+
// Execute the script normally. If a breakpoint is reached the
+
// debugger will take over the control loop.
+
return ctx->Execute();
+
}
+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual int Execute()=0
Executes the prepared function.
+
The engine interface.
Definition: angelscript.h:1092
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
virtual int SetLineCallback(asSFuncPtr callback, void *obj, int callConv)=0
Sets a line callback function. The function will be called for each executed script statement.
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+ + + + diff --git a/docs/manual/doc_addon_dict.html b/docs/manual/doc_addon_dict.html new file mode 100644 index 0000000..8452a9c --- /dev/null +++ b/docs/manual/doc_addon_dict.html @@ -0,0 +1,217 @@ + + + + + + + +AngelScript: dictionary object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
dictionary object
+
+
+

Path: /sdk/add_on/scriptdictionary/

+

The dictionary object maps string values to values or objects of other types.

+

Register with RegisterScriptDictionary(asIScriptEngine*).

+

Compile the add-on with the pre-processor define AS_USE_STLNAMES=1 to register the methods with the same names as used by C++ STL where the methods have the same significance. Not all methods from STL is implemented in the add-on, but many of the most frequent once are so a port from script to C++ and vice versa might be easier if STL names are used.

+

+Public C++ interface

+
typedef std::string dictKey;
+
+
class CScriptDictionary
+
{
+
public:
+
// Factory functions
+
static CScriptDictionary *Create(asIScriptEngine *engine);
+
+
// Reference counting
+
void AddRef() const;
+
void Release() const;
+
+
// Perform a shallow copy of the other dictionary
+
CScriptDictionary &operator=(const CScriptDictionary &other);
+
+
// Sets a key/value pair
+
void Set(const dictKey &key, void *value, int typeId);
+
void Set(const dictKey &key, asINT64 &value);
+
void Set(const dictKey &key, double &value);
+
+
// Gets the stored value. Returns false if the value isn't compatible with informed type
+
bool Get(const dictKey &key, void *value, int typeId) const;
+
bool Get(const dictKey &key, asINT64 &value) const;
+
bool Get(const dictKey &key, double &value) const;
+
+
// Index accessors. If the dictionary is not const it inserts the value if it doesn't already exist
+
// If the dictionary is const then a script exception is set if it doesn't exist and a null pointer is returned
+
CScriptDictValue *operator[](const dictKey &key);
+
const CScriptDictValue *operator[](const dictKey &key) const;
+
+
// Returns the type id of the stored value, or negative if it doesn't exist
+
int GetTypeId(const dictKey &key) const;
+
+
// Returns true if the key is set
+
bool Exists(const dictKey &key) const;
+
+
// Returns true if the dictionary is empty
+
bool IsEmpty() const;
+
+
// Returns the number of keys in the dictionary
+
asUINT GetSize() const;
+
+
// Deletes the key
+
bool Delete(const dictKey &key);
+
+
// Deletes all keys
+
void DeleteAll();
+
+
// Get an array of all keys
+
CScriptArray *GetKeys() const;
+
+
// STL style iterator
+
class CIterator
+
{
+
public:
+
void operator++(); // Pre-increment
+
void operator++(int); // Post-increment
+
+
bool operator==(const CIterator &other) const;
+
bool operator!=(const CIterator &other) const;
+
+
// Accessors
+
const dictKey &GetKey() const;
+
int GetTypeId() const;
+
bool GetValue(asINT64 &value) const;
+
bool GetValue(double &value) const;
+
bool GetValue(void *value, int typeId) const;
+
const void * GetAddressOfValue() const;
+
};
+
+
CIterator begin() const;
+
CIterator end() const;
+
CIterator find(const dictKey &key) const;
+
};
+

+Public script interface

+
See also
Dictionaries in the script language
+

+Example usage from C++

+

Here's a skeleton for iterating over the entries in the dictionary. For brevity the code doesn't show how to interpret the values, for more information on that see asETypeIdFlags and asIScriptEngine::GetTypeInfoById.

+
void iterateDictionary(CScriptDictionary *dict)
+
{
+
// Iterate over each entry
+
for (auto it : *dict)
+
{
+
// Determine the name of the key
+
std::string keyName = it.GetKey();
+
cout << "\"" << keyName << "\"" << " = ";
+
+
// Get the type and address of the value
+
int typeId = it.GetTypeId();
+
const void *addressOfValue = it.GetAddressOfValue();
+
+
// Cast the value to the correct C++ type according to the typeId and then print it
+
...
+
}
+
}
+
+
+
+
__int64 asINT64
64 bit integer
Definition: angelscript.h:620
+
The engine interface.
Definition: angelscript.h:1092
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+ + + + diff --git a/docs/manual/doc_addon_file.html b/docs/manual/doc_addon_file.html new file mode 100644 index 0000000..eec6ab8 --- /dev/null +++ b/docs/manual/doc_addon_file.html @@ -0,0 +1,181 @@ + + + + + + + +AngelScript: file object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
file object
+
+
+

Path: /sdk/add_on/scriptfile/

+

This object provides support for reading and writing files.

+

Register with RegisterScriptFile(asIScriptEngine*).

+

If you do not want to provide write access for scripts then you can compile the add on with the define AS_WRITE_OPS 0, which will disable support for writing. This define can be made in the project settings or directly in the header.

+

+Public C++ interface

+
class CScriptFile
+
{
+
public:
+
// Constructor
+
CScriptFile();
+
+
// Memory management
+
void AddRef() const;
+
void Release() const;
+
+
// Opening and closing file handles
+
// mode = "r" -> open the file for reading
+
// mode = "w" -> open the file for writing (overwrites existing files)
+
// mode = "a" -> open the file for appending
+
int Open(const std::string &filename, const std::string &mode);
+
int Close();
+
+
// Returns the size of the file
+
int GetSize() const;
+
+
// Returns true if the end of the file has been reached
+
bool IsEOF() const;
+
+
// Reads a specified number of bytes into the string
+
std::string ReadString(unsigned int length);
+
+
// Reads to the next new-line character
+
std::string ReadLine();
+
+
// Reads a signed integer
+
asINT64 ReadInt(asUINT bytes);
+
+
// Reads an unsigned integer
+
asQWORD ReadUInt(asUINT bytes);
+
+
// Reads a float
+
float ReadFloat();
+
+
// Reads a double
+
double ReadDouble();
+
+
// Writes a string to the file
+
int WriteString(const std::string &str);
+
+
int WriteInt(asINT64 v, asUINT bytes);
+
int WriteUInt(asQWORD v, asUINT bytes);
+
int WriteFloat(float v);
+
int WriteDouble(double v);
+
+
// File cursor manipulation
+
int GetPos() const;
+
int SetPos(int pos);
+
int MovePos(int delta);
+
+
// Determines the byte order of the binary values (default: false)
+
// Big-endian = most significant byte first
+
bool mostSignificantByteFirst;
+
};
+

+Public script interface

+
See also
file
+
+
+
+
__int64 asINT64
64 bit integer
Definition: angelscript.h:620
+
unsigned __int64 asQWORD
64 bit unsigned integer
Definition: angelscript.h:619
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+ + + + diff --git a/docs/manual/doc_addon_filesystem.html b/docs/manual/doc_addon_filesystem.html new file mode 100644 index 0000000..27686c3 --- /dev/null +++ b/docs/manual/doc_addon_filesystem.html @@ -0,0 +1,170 @@ + + + + + + + +AngelScript: filesystem object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
filesystem object
+
+
+

Path: /sdk/add_on/scriptfile/

+

This object provides support for inspecting directories on the filesystem.

+

Register with RegisterScriptFileSystem(asIScriptEngine*).

+

+Public C++ interface

+
class CScriptFileSystem
+
{
+
public:
+
CScriptFileSystem();
+
+
void AddRef() const;
+
void Release() const;
+
+
// Sets the current path that should be used in other calls when using relative paths
+
// It can use relative paths too, so moving up a directory is used by passing in ".."
+
bool ChangeCurrentPath(const std::string &path);
+
std::string GetCurrentPath() const;
+
+
// Returns true if the path is a directory. Input can be either a full path or a relative path.
+
// This method does not return the dirs '.' and '..'
+
bool IsDir(const std::string &path) const;
+
+
// Returns true if the path is a link. Input can be either a full path or a relative path
+
bool IsLink(const std::string &path) const;
+
+
// Returns the size of file. Input can be either a full path or a relative path
+
asINT64 GetSize(const std::string &path) const;
+
+
// Returns a list of the files in the current path
+
CScriptArray *GetFiles() const;
+
+
// Returns a list of the directories in the current path
+
CScriptArray *GetDirs() const;
+
+
// Creates a new directory. Returns 0 on success
+
int MakeDir(const std::string &path);
+
+
// Removes a directory. Will only remove the directory if it is empty. Returns 0 on success
+
int RemoveDir(const std::string &path);
+
+
// Deletes a file. Returns 0 on success
+
int DeleteFile(const std::string &path);
+
+
// Copies a file. Returns 0 on success
+
int CopyFile(const std::string &source, const std::string &target);
+
+
// Moves or renames a file or directory. Returns 0 on success
+
int Move(const std::string &source, const std::string &target);
+
+
// Gets the date and time of the file/dir creation
+
CDateTime GetCreateDateTime(const std::string &path) const;
+
+
// Gets the date and time of the file/dir modification
+
CDateTime GetModifyDateTime(const std::string &path) const;
+
};
+

+Public script interface

+
See also
filesystem
+
+
+
+
__int64 asINT64
64 bit integer
Definition: angelscript.h:620
+ + + + diff --git a/docs/manual/doc_addon_grid.html b/docs/manual/doc_addon_grid.html new file mode 100644 index 0000000..41f3c52 --- /dev/null +++ b/docs/manual/doc_addon_grid.html @@ -0,0 +1,198 @@ + + + + + + + +AngelScript: grid template object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
grid template object
+
+
+

Path: /sdk/add_on/scriptgrid/

+

The grid type is a template object that allow the scripts to declare 2D grids of any type. In many ways it is similar to the array template object, but it is specialized for use with areas.

+

The type is registered with RegisterScriptGrid(asIScriptEngine *engine).

+

+Public C++ interface

+
class CScriptGrid
+
{
+
public:
+
// Set the memory functions that should be used by all CScriptGrids
+
static void SetMemoryFunctions(asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc);
+
+
// Factory functions
+
static CScriptGrid *Create(asITypeInfo *gridType);
+
static CScriptGrid *Create(asITypeInfo *gridType, asUINT width, asUINT height);
+
static CScriptGrid *Create(asITypeInfo *gridType, asUINT width, asUINT height, void *defaultValue);
+
static CScriptGrid *Create(asITypeInfo *gridType, void *listBuffer);
+
+
// Memory management
+
void AddRef() const;
+
void Release() const;
+
+
// Type information
+
asITypeInfo *GetGridObjectType() const;
+
int GetGridTypeId() const;
+
int GetElementTypeId() const;
+
+
// Size
+
asUINT GetWidth() const;
+
asUINT GetHeight() const;
+
void Resize(asUINT width, asUINT height);
+
+
// Get a pointer to an element. Returns 0 if out of bounds
+
void *At(asUINT x, asUINT y);
+
const void *At(asUINT x, asUINT y) const;
+
+
// Set value of an element.
+
// The value arg should be a pointer to the value that will be copied to the element.
+
// Remember, if the grid holds handles the value parameter should be the
+
// address of the handle. The refCount of the object will also be incremented
+
void SetValue(asUINT x, asUINT y, void *value);
+
};
+

+Public script interface

+
+  class grid<T>
+  {
+    grid();
+    grid(uint width, uint height);
+    grid(uint width, uint height, const T &in fillValue);
    uint width() const;
+    uint height() const;
+    void resize(uint w, uint h);
    T &opIndex(uint x, uint y);
+    const T &opIndex(uint x, uint y) const;
+  }
+

grid()
+ grid(uint width, uint height)
+ grid(uint width, height, const T &in fillValue)
+

+

The constructors initializes the grid object. The default constructor will create an zero sized grid.

+

uint width() const
+ uint height() const
+

+

Returns the width and height of the grid.

+

void resize(uint w, uint h)

+

Resizes the grid to the new dimension. The elements that still fit in the grid will keep their values.

+

T &opIndex(uint x, uint y)
+ const T &opIndex(uint x, uint y) const
+

+

The index operator returns a reference to one of the elements. If the index is out of bounds a script exception will be raised.

+

+Example usage in script

+
+  // Initialize a 5x5 map
+  grid<int> map = {{1,0,1,1,1},
+                   {0,0,1,0,0},
+                   {0,1,1,0,1},
+                   {0,1,1,0,1},
+                   {0,0,0,0,1}};
  // A function to verify if the next area is walkable
+  bool canWalk(uint x, uint y)
+  {
+    // If the map in the destination is 
+    // clear, it is possible to wark there
+    return map[x,y] == 0;
+  }
+
+
+
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
void(* asFREEFUNC_t)(void *)
The function signature for the custom memory deallocation function.
Definition: angelscript.h:637
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+
void *(* asALLOCFUNC_t)(size_t)
The function signature for the custom memory allocation function.
Definition: angelscript.h:635
+ + + + diff --git a/docs/manual/doc_addon_handle.html b/docs/manual/doc_addon_handle.html new file mode 100644 index 0000000..bd5c1f4 --- /dev/null +++ b/docs/manual/doc_addon_handle.html @@ -0,0 +1,175 @@ + + + + + + + +AngelScript: ref object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
ref object
+
+
+

Path: /sdk/add_on/scripthandle/

+

The ref type is a generic container that can hold any handle. It is a value type, but behaves very much like an object handle.

+

The type is registered with RegisterScriptHandle(asIScriptEngine*).

+
See also
Registering a generic handle type
+

+Public C++ interface

+
class CScriptHandle
+
{
+
public:
+
// Constructors
+
CScriptHandle();
+
CScriptHandle(const CScriptHandle &other);
+
CScriptHandle(void *ref, int typeId);
+
~CScriptHandle();
+
+
// Copy the stored reference from another handle object
+
CScriptHandle &operator=(const CScriptHandle &other);
+
+
// Set the reference
+
void Set(void *ref, asITypeInfo *type);
+
+
// Compare equalness
+
bool operator==(const CScriptHandle &o) const;
+
bool operator!=(const CScriptHandle &o) const;
+
bool opEquals(void *ref, int typeId) const;
+
+
// Dynamic cast to desired handle type
+
void Cast(void **outRef, int typeId);
+
+
// Returns the type of the reference held
+
asITypeInfo *GetType() const;
+
int GetTypeId() const;
+
+
// Returns the reference
+
void *GetRef();
+
};
+

+Public script interface

+
See also
ref in the script language
+

+Example usage from C++

+

Even though the CScriptHandle is a value type, when registering properties of its type they should be registered as handles. The same goes for function arguments and return types.

+
CScriptHandle g_handle;
+
+
void Function(CScriptHandle handle)
+
{
+
... use the methods of CScriptHandle to determine the true object held in it
+
}
+
+
void Register(asIScriptEngine *engine)
+
{
+
int r;
+
r = engine->RegisterGlobalProperty("ref @g_handle", &g_handle); assert( r >= 0 );
+
r = engine->RegisterGlobalFunction("void Function(ref @)", asFUNCTION(Function), asCALL_CDECL); assert( r >= 0 );
+
}
+

To set an object pointer in the handle from the application, you'll use the Set() method passing a pointer to the object and the type of the object.

+

To retrieve an object pointer from the application you'll use the Cast() method passing in a pointer to the pointer and the wanted type id. If the type id given doesn't match the stored handle the returned pointer will be null.

+

To retrieve an object of an unknown type use the GetType() or GetTypeId() to determine the type stored in the handle, then use the Cast() method.

+
+
+
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
virtual int RegisterGlobalProperty(const char *declaration, void *pointer)=0
Registers a global property.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+ + + + diff --git a/docs/manual/doc_addon_helpers.html b/docs/manual/doc_addon_helpers.html new file mode 100644 index 0000000..e08e00d --- /dev/null +++ b/docs/manual/doc_addon_helpers.html @@ -0,0 +1,187 @@ + + + + + + + +AngelScript: Helper functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Helper functions
+
+
+

Path: /sdk/add_on/scripthelper/

+

These helper functions simplify the implementation of common tasks. They can be used as is or can serve as the starting point for your own framework.

+

+Public C++ interface

+
// Compare relation between two objects of the same type.
+
// Uses the object's opCmp method to perform the comparison.
+
// Returns a negative value if the comparison couldn't be performed.
+
int CompareRelation(asIScriptEngine *engine, void *leftObj, void *rightObj, int typeId, int &result);
+
+
// Compare equality between two objects of the same type.
+
// Uses the object's opEquals method to perform the comparison, or if that doesn't exist the opCmp method.
+
// Returns a negative value if the comparison couldn't be performed.
+
int CompareEquality(asIScriptEngine *engine, void *leftObj, void *rightObj, int typeId, bool &result);
+
+
// Compile and execute simple statements.
+
// The module is optional. If given the statements can access the entities compiled in the module.
+
// The caller can optionally provide its own context, for example if a context should be reused.
+
int ExecuteString(asIScriptEngine *engine, const char *code, asIScriptModule *mod = 0, asIScriptContext *ctx = 0);
+
+
// Compile and execute simple statements with option of return value.
+
// The module is optional. If given the statements can access the entitites compiled in the module.
+
// The caller can optionally provide its own context, for example if a context should be reused.
+
int ExecuteString(asIScriptEngine *engine, const char *code, void *ret, int retTypeId, asIScriptModule *mod = 0, asIScriptContext *ctx = 0);
+
+
// Format the details of the script exception into a human readable text.
+
// Whenever the asIScriptContext::Execute method returns asEXECUTION_EXCEPTION, the application
+
// can call this function to get more information about that exception in a human readable form.
+
// The information obtained includes the current function, the script source section,
+
// program position in the source section, and the exception description itself.
+
std::string GetExceptionInfo(asIScriptContext *ctx, bool showStack = false);
+
+
// Write registered application interface to file.
+
// This function creates a file with the configuration for the offline compiler, asbuild, in the samples.
+
// If you wish to use the offline compiler you should call this function from you application after the
+
// application interface has been fully registered. This way you will not have to create the configuration
+
// file manually.
+
int WriteConfigToFile(asIScriptEngine *engine, const char *filename);
+
+
// Write the registered application interface to a text stream.
+
int WriteConfigToStream(asIScriptEngine *engine, std::ostream &strm);
+
+
// Loads an interface from a text stream and configures the engine with it. This will not
+
// set the correct function pointers, so it is not possible to use this engine to execute
+
// scripts, but it can be used to compile scripts and save the byte code.
+
int ConfigEngineFromStream(asIScriptEngine *engine, std::istream &strm, const char *nameOfStream = "config", asIStringFactory *stringFactory = 0);
+

+Example

+

To compare two script objects the application can execute the following code:

+
void Compare(asIScriptObject *a, asIScriptObject *b)
+
{
+
asIScriptEngine *engine = a->GetEngine();
+
int typeId = a->GetTypeId();
+
+
int cmp;
+
int r = CompareRelation(engine, a, b, typeId, cmp);
+
if( r < 0 )
+
{
+
cout << "The relation between a and b cannot be established b" << endl;
+
}
+
else
+
{
+
if( cmp < 0 )
+
cout << "a is smaller than b" << endl;
+
else if( cmp == 0 )
+
cout << "a is equal to b" << endl;
+
else
+
cout << "a is greater than b" << endl;
+
}
+
}
+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual asIScriptEngine * GetEngine() const =0
Return the script engine.
+
The interface for the string factory.
Definition: angelscript.h:2150
+
The engine interface.
Definition: angelscript.h:1092
+
The interface to the script modules.
Definition: angelscript.h:2218
+
virtual int GetTypeId() const =0
Returns the type id of the object.
+
The interface for an instance of a script object.
Definition: angelscript.h:3413
+ + + + diff --git a/docs/manual/doc_addon_helpers_try.html b/docs/manual/doc_addon_helpers_try.html new file mode 100644 index 0000000..d0e4a6b --- /dev/null +++ b/docs/manual/doc_addon_helpers_try.html @@ -0,0 +1,123 @@ + + + + + + + +AngelScript: Exception routines + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Exception routines
+
+
+

Path: /sdk/add_on/scripthelper/

+

The exception handling routines are registered by the application with a call to RegisterExceptionRoutines.

+

+Public C++ interface

+
// Register the exception routines.
+
// 'void throw(const string &msg)'
+
// 'string getExceptionInfo()'
+
void RegisterExceptionRoutines(asIScriptEngine *engine);
+

+Public script interface

+
See also
Exception handling
+
+
+
+
The engine interface.
Definition: angelscript.h:1092
+ + + + diff --git a/docs/manual/doc_addon_math.html b/docs/manual/doc_addon_math.html new file mode 100644 index 0000000..9253fcd --- /dev/null +++ b/docs/manual/doc_addon_math.html @@ -0,0 +1,211 @@ + + + + + + + +AngelScript: math functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
math functions
+
+
+

Path: /sdk/add_on/scriptmath/

+

This add-on registers the math functions from the standard C runtime library with the script engine. Use RegisterScriptMath(asIScriptEngine*) to perform the registration.

+

By defining the preprocessor word AS_USE_FLOAT=0, the functions will be registered to take and return doubles instead of floats.

+

The function RegisterScriptMathComplex(asIScriptEngine*) registers a type that represents a complex number, i.e. a number with real and imaginary parts.

+

+Public script interface

+
+  // Trigonometric functions
+  float cos(float rad);
+  float sin(float rad);
+  float tan(float rad);
  // Inverse trigonometric functions
+  float acos(float val);
+  float asin(float val);
+  float atan(float val);
+  float atan2(float y, float x);
  // Hyperbolic functions
+  float cosh(float rad);
+  float sinh(float rad);
+  float tanh(float rad);
  // Logarithmic functions
+  float log(float val);
+  float log10(float val);
  // Power to
+  float pow(float val, float exp);
  // Square root
+  float sqrt(float val);
  // Absolute value
+  float abs(float val);
  // Ceil and floor functions
+  float ceil(float val);
+  float floor(float val);
  // Returns the fraction
+  float fraction(float val);
  // Approximate float comparison, to deal with numeric imprecision
+  bool closeTo(float a, float b, float epsilon = 0.00001f);
+  bool closeTo(double a, double b, double epsilon = 0.0000000001);
  // Conversion between floating point and IEEE 754 representations
+  float  fpFromIEEE(uint raw); 
+  double fpFromIEEE(uint64 raw);
+  uint   fpToIEEE(float fp);
+  uint64 fpToIEEE(double fp);
+

+Functions

+

cos, sin, tan

+

Calculates the trigonometric functions cosine, sine, and tangent. The input angle should be given in radian.

+

acos, asin, atan

+

Calculates the inverse of the trigonometric functions cosine, sine, and tangent. The returned angle is given in radian.

+

atan2

+

Calculates the inverse of the trigonometric function tangent. The input is the y and x proportions. The returned angle is given in radian.

+

cosh, sinh, tanh

+

Calculates the hyperbolic of the cosine, sine, and tangent. The input angle should be given in radian.

+

log, log10

+

Calculates the logarithm of the input value. log is the natural logarithm and log10 is the base-10 logarithm.

+

pow

+

Calculates the based raised to the power of exponent.

+

sqrt

+

Calculates the square root of the value.

+

abs

+

Returns the absolute value.

+

ceil, floor

+

ceil returns the closest integer number that is higher or equal to the input. Floor returns the closest integer number that is lower or equal to the input.

+

fraction

+

Returns the fraction of the number, i.e. what remains after taking away the integral number.

+

closeTo

+

Due to numerical errors with the binary representation of real numbers it is often difficult to do direct comparisons of two float values. The closeTo function will return true of the two values are almost equal, allowing for a small difference up to the size of the epsilon value.

+

fpFromIEEE, fpToIEEE

+

Translates the float to and from IEEE 754 representation. This can be used if one wishes to directly inspect or manipulate the floating point value in the binary representation.

+

+The complex type

+
+  // This type represents a complex number with real and imaginary parts
+  class complex
+  {
+    // Constructors
+    complex();
+    complex(const complex &in);
+    complex(float r);
+    complex(float r, float i);
    // Equality operator
+    bool opEquals(const complex &in) const;
    // Compound assignment operators
+    complex &opAddAssign(const complex &in);
+    complex &opSubAssign(const complex &in);
+    complex &opMulAssign(const complex &in);
+    complex &opDivAssign(const complex &in);
    // Math operators
+    complex opAdd(const complex &in) const;
+    complex opSub(const complex &in) const;
+    complex opMul(const complex &in) const;
+    complex opDiv(const complex &in) const;
    // Returns the absolute value (magnitude)
+    float abs() const;
    // Swizzle operators
+    complex get_ri() const;
+    void set_ri(const complex &in);
+    complex get_ir() const;
+    void set_ir(const complex &in);
    // The real and imaginary parts
+    float r;
+    float i;
+  }
+

complex

+

The constructors allow for implicit construction, making a copy, implicit conversion from float, and explicit initialization from two float values.

+

=, !=

+

Compares two complex values.

+

=, +=, -=, *=, /=

+

Assign and compound assignment of complex values.

+

+, -, *, /

+

Math operators on complex values.

+

abs

+

Returns the absolute (magnitude) of the complex value.

+

r, i

+

Retrieves the real and imaginary part of the complex value.

+

ri, ir

+

Swizzle operators return a complex value with the ordering of the real and imaginary parts as indicated by the name.

+
+
+
+ + + + diff --git a/docs/manual/doc_addon_script.html b/docs/manual/doc_addon_script.html new file mode 100644 index 0000000..f0715d5 --- /dev/null +++ b/docs/manual/doc_addon_script.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Script extensions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ + + + + + diff --git a/docs/manual/doc_addon_script.js b/docs/manual/doc_addon_script.js new file mode 100644 index 0000000..4566271 --- /dev/null +++ b/docs/manual/doc_addon_script.js @@ -0,0 +1,58 @@ +var doc_addon_script = +[ + [ "string object", "doc_addon_std_string.html", [ + [ "Public C++ interface", "doc_addon_std_string.html#doc_addon_std_string_1", null ], + [ "Public script interface", "doc_addon_std_string.html#doc_addon_std_string_2", null ] + ] ], + [ "array template object", "doc_addon_array.html", [ + [ "Public C++ interface", "doc_addon_array.html#doc_addon_array_1", null ], + [ "Public script interface", "doc_addon_array.html#doc_addon_array_2", null ], + [ "C++ example", "doc_addon_array.html#doc_addon_array_4", null ] + ] ], + [ "any object", "doc_addon_any.html", [ + [ "Public C++ interface", "doc_addon_any.html#doc_addon_any_1", null ], + [ "Public script interface", "doc_addon_any.html#doc_addon_any_2", null ], + [ "Example usage", "doc_addon_any.html#doc_addon_any_3", null ] + ] ], + [ "ref object", "doc_addon_handle.html", [ + [ "Public C++ interface", "doc_addon_handle.html#doc_addon_handle_1", null ], + [ "Public script interface", "doc_addon_handle.html#doc_addon_handle_3", null ], + [ "Example usage from C++", "doc_addon_handle.html#doc_addon_handle_4", null ] + ] ], + [ "weakref object", "doc_addon_weakref.html", [ + [ "Public C++ interface", "doc_addon_weakref.html#doc_addon_weakref_1", null ], + [ "Public script interface", "doc_addon_weakref.html#doc_addon_weakref_2", null ] + ] ], + [ "dictionary object", "doc_addon_dict.html", [ + [ "Public C++ interface", "doc_addon_dict.html#doc_addon_dict_1", null ], + [ "Public script interface", "doc_addon_dict.html#doc_addon_dict_2", null ], + [ "Example usage from C++", "doc_addon_dict.html#doc_addon_dict_3", null ] + ] ], + [ "file object", "doc_addon_file.html", [ + [ "Public C++ interface", "doc_addon_file.html#doc_addon_file_1", null ], + [ "Public script interface", "doc_addon_file.html#doc_addon_file_2", null ] + ] ], + [ "filesystem object", "doc_addon_filesystem.html", [ + [ "Public C++ interface", "doc_addon_filesystem.html#doc_addon_filesystem_1", null ], + [ "Public script interface", "doc_addon_filesystem.html#doc_addon_filesystem_2", null ] + ] ], + [ "math functions", "doc_addon_math.html", [ + [ "Public script interface", "doc_addon_math.html#doc_addon_math_1", [ + [ "Functions", "doc_addon_math.html#doc_addon_math_funcs", null ], + [ "The complex type", "doc_addon_math.html#doc_addon_math_complex", null ] + ] ] + ] ], + [ "grid template object", "doc_addon_grid.html", [ + [ "Public C++ interface", "doc_addon_grid.html#doc_addon_grid_1", null ], + [ "Public script interface", "doc_addon_grid.html#doc_addon_grid_2", null ], + [ "Example usage in script", "doc_addon_grid.html#doc_addon_grid_3", null ] + ] ], + [ "datetime object", "doc_addon_datetime.html", [ + [ "Public C++ interface", "doc_addon_datetime.html#doc_addon_datetime_1", null ], + [ "Public script interface", "doc_addon_datetime.html#doc_addon_datetime_2", null ] + ] ], + [ "Exception routines", "doc_addon_helpers_try.html", [ + [ "Public C++ interface", "doc_addon_helpers_try.html#doc_addon_helpers_try_1", null ], + [ "Public script interface", "doc_addon_helpers_try.html#doc_add_helpers_try_2", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_addon_serializer.html b/docs/manual/doc_addon_serializer.html new file mode 100644 index 0000000..4bc6d66 --- /dev/null +++ b/docs/manual/doc_addon_serializer.html @@ -0,0 +1,217 @@ + + + + + + + +AngelScript: Serializer + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Serializer
+
+
+

Path: /sdk/add_on/serializer/

+

The CSerializer implements support for serializing the values of global variables in a module, for example in order to reload a slightly modified version of the script without reinitializing everything. It will resolve primitives and script classes automatically, including references and handles. For application registered types, the application needs to implement callback objects to show how these should be serialized.

+

The implementation currently has some limitations:

+
    +
  • It can only serialize to memory, i.e. it is not possible to save the values to a file.
  • +
  • If the variables changed type when restoring, the serializer cannot restore the value.
  • +
  • The serializer will attempt to backup all objects, but in some cases an application may not want to backup the actual object, but only a reference to it, e.g. an internal application object referenced by the script. Currently there is no way of telling the serializer to do differently in this case.
  • +
  • If the module holds references to objects from another module it will probably fail in restoring the values.
  • +
+
Todo:
Show how to serialize extra objects too. And explain about memory management for restored objects
+
Todo:
Explain that handles to registered types without factories will be kept as-is
+
Todo:
Registered pod-types do not need a special user type as the serializer will simply keep a bitwise copy
+

+Public C++ interface

+
class CSerializer
+
{
+
public:
+
CSerializer();
+
~CSerializer();
+
+
// Add implementation for serializing user types
+
void AddUserType(CUserType *ref, const std::string &name);
+
+
// Store all global variables in the module
+
int Store(asIScriptModule *mod);
+
+
// Restore all global variables after reloading script
+
int Restore(asIScriptModule *mod);
+
+
// Store extra objects that are not seen from the module's global variables
+
void AddExtraObjectToStore(asIScriptObject *object);
+
+
// Return new pointer to restored object
+
void *GetPointerToRestoredObject(void *originalObject);
+
};
+

+Example usage

+
struct CStringType;
+
struct CArrayType;
+
+
void RecompileModule(asIScriptEngine *engine, asIScriptModule *mod)
+
{
+
string modName = mod->GetName();
+
+
// Tell the serializer how the user types should be serialized
+
// by adding the implementations of the CUserType interface
+
CSerializer backup;
+
backup.AddUserType(new CStringType(), "string");
+
backup.AddUserType(new CArrayType(), "array");
+
+
// Backup the values of the global variables
+
backup.Store(mod);
+
+
// Application can now recompile the module
+
CompileModule(modName);
+
+
// Restore the values of the global variables in the new module
+
mod = engine->GetModule(modName.c_str(), asGM_ONLY_IF_EXISTS);
+
backup.Restore(mod);
+
}
+
+
// This serializes the std::string type
+
struct CStringType : public CUserType
+
{
+
void Store(CSerializedValue *val, void *ptr)
+
{
+
val->SetUserData(new std::string(*(std::string*)ptr));
+
}
+
void Restore(CSerializedValue *val, void *ptr)
+
{
+
std::string *buffer = (std::string*)val->GetUserData();
+
*(std::string*)ptr = *buffer;
+
}
+
void CleanupUserData(CSerializedValue *val)
+
{
+
std::string *buffer = (std::string*)val->GetUserData();
+
delete buffer;
+
}
+
};
+
+
// This serializes the CScriptArray type
+
struct CArrayType : public CUserType
+
{
+
void Store(CSerializedValue *val, void *ptr)
+
{
+
CScriptArray *arr = (CScriptArray*)ptr;
+
+
for( unsigned int i = 0; i < arr->GetSize(); i++ )
+
val->m_children.push_back(new CSerializedValue(val ,"", "", arr->At(i), arr->GetElementTypeId()));
+
}
+
void Restore(CSerializedValue *val, void *ptr)
+
{
+
CScriptArray *arr = (CScriptArray*)ptr;
+
arr->Resize(asUINT(val->m_children.size()));
+
+
for( size_t i = 0; i < val->m_children.size(); ++i )
+
val->m_children[i]->Restore(arr->At(asUINT(i)), arr->GetElementTypeId());
+
}
+
};
+
+
+
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
The engine interface.
Definition: angelscript.h:1092
+
@ asGM_ONLY_IF_EXISTS
Don't return any module if it is not found.
Definition: angelscript.h:524
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+
The interface to the script modules.
Definition: angelscript.h:2218
+
The interface for an instance of a script object.
Definition: angelscript.h:3413
+
virtual const char * GetName() const =0
Gets the name of the module.
+ + + + diff --git a/docs/manual/doc_addon_std_string.html b/docs/manual/doc_addon_std_string.html new file mode 100644 index 0000000..8c6c034 --- /dev/null +++ b/docs/manual/doc_addon_std_string.html @@ -0,0 +1,123 @@ + + + + + + + +AngelScript: string object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
string object
+
+
+

Path: /sdk/add_on/scriptstdstring/

+

This add-on registers the std::string type as-is with AngelScript. This gives perfect compatibility with C++ functions that use std::string in parameters or as return type.

+

A potential drawback is that the std::string type is a value type, thus may increase the number of copies taken when string values are being passed around in the script code. However, this is most likely only a problem for scripts that perform a lot of string operations.

+

Register the type with RegisterStdString(asIScriptEngine*). Register the optional split method and global join function with RegisterStdStringUtils(asIScriptEngine*). The optional functions require that the array template object has been registered first.

+

Compile the add-on with the pre-processor define AS_USE_STLNAMES=1 to register the methods with the same names as used by C++ STL where the methods have the same significance. Not all methods from STL is implemented in the add-on, but many of the most frequent ones are so a port from script to C++ and vice versa might be easier if STL names are used.

+

Compile the add-on with the pre-processor define AS_USE_ACCESSORS=1 to register length as a virtual property instead of the method length().

+

+Public C++ interface

+

Refer to the std::string implementation for your compiler.

+

+Public script interface

+
See also
Strings in the script language
+
+
+
+ + + + diff --git a/docs/manual/doc_addon_weakref.html b/docs/manual/doc_addon_weakref.html new file mode 100644 index 0000000..4cf5fde --- /dev/null +++ b/docs/manual/doc_addon_weakref.html @@ -0,0 +1,151 @@ + + + + + + + +AngelScript: weakref object + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
weakref object
+
+
+

Path: /sdk/add_on/weakref/

+

The weakref type is a template type for holding weak references to objects, i.e. the references that will not keep the referred object alive.

+

The type is registered with RegisterScriptWeakRef(asIScriptEngine*).

+
See also
Weak references
+

+Public C++ interface

+
class CScriptWeakRef
+
{
+
public:
+
// Constructors
+
CScriptWeakRef(asITypeInfo *type);
+
CScriptWeakRef(const CScriptWeakRef &other);
+
CScriptWeakRef(void *ref, asITypeInfo *type);
+
+
~CScriptWeakRef();
+
+
// Copy the stored value from another weakref object
+
CScriptWeakRef &operator=(const CScriptWeakRef &other);
+
+
// Compare equalness
+
bool operator==(const CScriptWeakRef &o) const;
+
bool operator!=(const CScriptWeakRef &o) const;
+
+
// Sets a new reference
+
CScriptWeakRef &Set(void *newRef);
+
+
// Returns the object if it is still alive
+
// This will increment the refCount of the returned object
+
void *Get() const;
+
+
// Returns true if the contained reference is the same
+
bool Equals(void *ref) const;
+
+
// Returns the type of the reference held
+
asITypeInfo *GetRefType() const;
+
};
+

+Public script interface

+
See also
weakref in the script language
+
+
+
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+ + + + diff --git a/docs/manual/doc_adv_access_mask.html b/docs/manual/doc_adv_access_mask.html new file mode 100644 index 0000000..6fabd53 --- /dev/null +++ b/docs/manual/doc_adv_access_mask.html @@ -0,0 +1,163 @@ + + + + + + + +AngelScript: Access masks and exposing different interfaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Access masks and exposing different interfaces
+
+
+

An application may need to expose different interfaces to different types of scripts, e.g. a game entity may only have access to specific set of functions, while the GUI script can have access to a completely different set of functions.

+

To accomplish this the application can set a bitmask while registering the interface, and then use that bitmask when building the scripts to determine what the scripts should or should not be able to access.

+
void ConfigureEngine(asIScriptEngine *engine)
+
{
+
// Register the interface available to script type 1
+
engine->SetDefaultAccessMask(0x1);
+
r = engine->RegisterGlobalFunction("void func1()", asFUNCTION(func1), asCALL_CDECL); assert( r >= 0 );
+
+
// Register the interface available to script type 2
+
engine->SetDefaultAccessMask(0x2);
+
r = engine->RegisterGlobalFunction("void func2()", asFUNCTION(func2), asCALL_CDECL); assert( r >= 0 );
+
+
// Register the interface available to both script types
+
engine->SetDefaultAccessMask(0x3);
+
r = engine->RegisterGlobalFunction("void func3()", asFUNCTION(func3), asCALL_CDECL); assert( r >= 0 );
+
}
+
+
int CompileScript(asIScriptEngine *engine, const char *script, int type)
+
{
+
int r;
+
CScriptBuilder builder;
+
r = builder.StartNewModule(engine, script);
+
if( r < 0 ) return r;
+
+
// Set the access mask for the module, which will
+
// determine the functions from the application
+
// interface that can be called
+
asIScriptModule *mod = builder.GetModule();
+
mod->SetAccessMask(type);
+
+
// Add the script section and build the script
+
r = builder.AddSectionFromFile(script);
+
if( r < 0 ) return r;
+
+
return builder.BuildModule();
+
}
+

The access mask can be defined for the following entities in the application interface:

+ +
+
+
+
virtual asDWORD SetDefaultAccessMask(asDWORD defaultMask)=0
Sets the access mask that should be used for subsequent registered entities.
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual asDWORD SetAccessMask(asDWORD accessMask)=0
Sets the access mask that should be used during the compilation.
+
The interface to the script modules.
Definition: angelscript.h:2218
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+ + + + diff --git a/docs/manual/doc_adv_class_hierarchy.html b/docs/manual/doc_adv_class_hierarchy.html new file mode 100644 index 0000000..bfd11a5 --- /dev/null +++ b/docs/manual/doc_adv_class_hierarchy.html @@ -0,0 +1,213 @@ + + + + + + + +AngelScript: Class hierarchies + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Class hierarchies
+
+
+

AngelScript cannot automatically determine relationships between registered classes, so in order to establish the hierarchies for use within the script language it is necessary to do a bit more registration beyond the normal object registration.

+

Hierarchies can currently only be registered for reference types, not for value types.

+

+Establishing the relationship

+

In order to let AngelScript know that two types are related you need to register the reference cast operators opCast and opImplCast. The opCast should be used if you only want to allow the cast through an explicit call with the cast<class> operator. opImplCast should be used when you want to allow the compiler to implicitly perform the cast as necessary.

+

Usually you'll want to use opImplCast for casts from a derived type to the base type, and opCast for casts from a base type to a derived type.

+
// Example opCast behaviour
+
template<class A, class B>
+
B* refCast(A* a)
+
{
+
// If the handle already is a null handle, then just return the null handle
+
if( !a ) return 0;
+
+
// Now try to dynamically cast the pointer to the wanted type
+
B* b = dynamic_cast<B*>(a);
+
if( b != 0 )
+
{
+
// Since the cast was made, we need to increase the ref counter for the returned handle
+
b->addref();
+
}
+
return b;
+
}
+
+
// Example registration of the behaviour
+
r = engine->RegisterObjectMethod("base", "derived@ opCast()", asFUNCTION((refCast<base,derived>)), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+
r = engine->RegisterObjectMethod("derived", "base@ opImplCast()", asFUNCTION((refCast<derived,base>)), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+
+
// Also register the const overloads so the cast works also when the handle is read only
+
r = engine->RegisterObjectMethod("base", "const derived@ opCast() const", asFUNCTION((refCast<base,derived>)), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+
r = engine->RegisterObjectMethod("derived", "const base@ opImplCast() const", asFUNCTION((refCast<derived,base>)), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+

Note that it may be necessary to add extra parenthesis to the asFUNCTION macro so that the preprocessor doesn't interpret the , in the template declaration as the argument separator in the macro.

+

+Inherited methods and properties

+

Just as relationships cannot be determined, there is also no way to automatically let AngelScript add inherited methods and properties to derived types. The reason for this is that method pointers and property offsets may differ between the base class and derived class, especially when multiple inheritance is used, and there is no way to automatically determine exactly what the difference is.

+

For this reason the application needs to register all the inherited methods and properties for the derived classes, which may lead to a bit of duplicate code. However, you may be able to avoid the duplication through a bit of clever thinking. Here is an example of registering the methods and properties for a base class and the derived class (registration of behaviours has been omitted for briefness):

+
// The base class
+
class base
+
{
+
public:
+
virtual void aMethod();
+
+
int aProperty;
+
};
+
+
// The derived class
+
class derived : public base
+
{
+
public:
+
virtual void aNewMethod();
+
+
int aNewProperty;
+
};
+
+
// The code to register the classes
+
// This is implemented as a template function, to support multiple inheritance
+
template <class T>
+
void RegisterBaseMembers(asIScriptEngine *engine, const char *type)
+
{
+
int r;
+
+
r = engine->RegisterObjectMethod(type, "void aMethod()", asMETHOD(T, aMethod), asCALL_THISCALL); assert( r >= 0 );
+
+
r = engine->RegisterObjectProperty(type, "int aProperty", asOFFSET(T, aProperty)); assert( r >= 0 );
+
}
+
+
template <class T>
+
void RegisterDerivedMembers(asIScriptEngine *engine, const char *type)
+
{
+
int r;
+
+
// Register the inherited members by calling
+
// the registration of the base members
+
RegisterBaseMembers<T>(engine, type);
+
+
// Now register the new members
+
r = engine->RegisterObjectMethod(type, "void aNewMethod()", asMETHOD(T, aNewMethod), asCALL_THISCALL); assert( r >= 0 );
+
+
r = engine->RegisterObjectProperty(type, "int aProperty", asOFFSET(T, aProperty)); assert( r >= 0 );
+
}
+
+
void RegisterTypes(asIScriptEngine *engine)
+
{
+
int r;
+
+
// Register the base type
+
r = engine->RegisterObjectType("base", 0, asOBJ_REF); assert( r >= 0 );
+
RegisterBaseMembers<base>(engine, "base");
+
+
// Register the derived type
+
r = engine->RegisterObjectType("derived", 0, asOBJ_REF); assert( r >= 0 );
+
RegisterDerivedMembers<derived>(engine, "derived");
+
}
+
+
+
+
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
The engine interface.
Definition: angelscript.h:1092
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a property for the object type.
+
#define asOFFSET(s, m)
Returns the offset of an attribute in a struct.
Definition: angelscript.h:672
+ + + + diff --git a/docs/manual/doc_adv_concurrent.html b/docs/manual/doc_adv_concurrent.html new file mode 100644 index 0000000..4d5d959 --- /dev/null +++ b/docs/manual/doc_adv_concurrent.html @@ -0,0 +1,182 @@ + + + + + + + +AngelScript: Concurrent scripts + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Concurrent scripts
+
+
+

The script engine can run multiple scripts in parallel, i.e. concurrent scripts. This can be done easily using multithreading where each thread runs its own script context, but this article is going to explain how it is done without multithreading.

+

In order to execute multiple scripts in parallel, each script must have it's own asIScriptContext, where the context is set up as for a normal function call. Then the application needs to set a timeout for each context. When the timeout is reached, the context should be suspended, so that the next context can execute for a while.

+

Here's a very simple example of how this can be done:

+
// The contexts have already been prepared before this function is called
+
void ExecuteScripts(std::vector<asIScriptContext *> contexts)
+
{
+
// This function will run until all scripts have completed
+
while( contexts.size() > 0 )
+
{
+
for( asUINT n = 0; n < contexts.size(); n++ )
+
{
+
// Set a 10 millisecond timeout for this context
+
SetTimeoutForContext(contexts[n], 10);
+
+
// Resume the execution of this context by calling Execute
+
int r = contexts[n]->Execute();
+
+
// Remove the timeout so it won't be triggered accidentally
+
RemoveTimeoutForContext();
+
+
// Determine if the script completed, or was timed out
+ +
{
+
// The script will continue in the next iteration
+
}
+
else
+
{
+
// The script has completed the execution, so we take it out of the list of scripts
+
contexts[n--] = contexts.back();
+
contexts.pop_back();
+
}
+
}
+
}
+
}
+

The application can manage the execution of the scripts in a simple round-robin fashion, where each script gets equal amount of execution time, or a more intricate management algorithm can be built, e.g. to give more execution time to high priority scripts etc.

+

The time out function, i.e. SetTimeoutForContext in the example above, can be implemented in two different ways. Through the use of line callbacks, where the context will invoke the callback for each statement in the script. The callback can then check if the timeout limit has been reached and suspend the context.

+

The other way is through the use of a timeout thread, where the thread simply sleeps until the timeout limit has been reached, and when the thread wakes up it suspends the context (if it is still running).

+

The timeout thread is probably the easiest to implement, and also doesn't impact the performance as much as the line callback. The line callback may still have to be used if the target OS doesn't support multithreading though.

+

Here's a simple example of how to implement the timeout function with a separate thread:

+
static HANDLE thread_handle = 0;
+
static asIScriptContext *thread_ctx;
+
+
DWORD WINAPI TimeoutThread(void *sleeptime)
+
{
+
Sleep(*reinterpret_cast<int*>(sleeptime));
+
if( thread_ctx )
+
thread_ctx->Suspend();
+
+
return 0;
+
}
+
+
void SetTimeoutForContext(asIScriptContext *ctx, int milliseconds)
+
{
+
thread_ctx = ctx;
+
thread_handle = CreateThread(0, 50, TimeoutThread, reinterpret_cast<void*>(&milliseconds), 0, 0);
+
}
+
+
void RemoveTimeoutForContext()
+
{
+
// TerminateThread should be used with extreme care, but in this
+
// case the TimeoutThread can't do any harm even if interrupted
+
// in the middle of the execution
+
TerminateThread(thread_handle, 0);
+
thread_handle = 0;
+
}
+

Observe that the routines for multithreading usually differ a lot depending on the target system. The above code is for Windows and will most likely require adaption to work on any other system.

+
See also
Context manager, Concurrent scripts, Co-routines
+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
@ asEXECUTION_SUSPENDED
The execution is suspended and can be resumed.
Definition: angelscript.h:400
+
virtual int Suspend()=0
Suspends the execution, which can then be resumed by calling Execute again.
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+ + + + diff --git a/docs/manual/doc_adv_coroutine.html b/docs/manual/doc_adv_coroutine.html new file mode 100644 index 0000000..eb30f1e --- /dev/null +++ b/docs/manual/doc_adv_coroutine.html @@ -0,0 +1,195 @@ + + + + + + + +AngelScript: Co-routines + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Co-routines
+
+
+

Co-routines is a way to allow multiple execution paths in parallel, but without the hazards of pre-emptive scheduling in multithreading where one thread can be suspended at any moment so another can resume. Because co-routines always voluntarily suspend themselves in favor of the next co-routine, there is no need to worry about atomic instructions and critical sections.

+

Co-routines are not natively built-into the AngelScript library, but it can easily be implemented from the application side. In fact, the Context manager add-on already provides a default implementation for this.

+

To implement your own version of co-routines you will need a couple of pieces:

+
    +
  • The co-routine itself, which is just an instance of the asIScriptContext object. Each co-routine will have its own context object that holds the callstack of the co-routine.
  • +
  • A function that will permit the script to create, or spawn, new co-routines. This function will need to be able to refer to starting function of the new co-routine. This reference can be done by name, or perhaps more elegantly with a function pointer. Once invoked this function will instanciate the new context, and prepare it with the starting function.
  • +
  • A function that will permit a co-routine to yield control to the next co-routine. This function will simply suspend the current context so the next co-routine can be resumed.
  • +
  • A simple control algorithm for the co-routines. This can just be a loop that will iterate over an array of co-routines, i.e. contexts, until all of them have finished executing. When a new co-routine is created it is simply appended to the array to be picked up when the current co-routine yields the control.
  • +
+

A simple implementation of the function that spawns a new co-routine may look like this:

+
void CreateCoRoutine(string &func)
+
{
+ +
if( ctx )
+
{
+
asIScriptEngine *engine = ctx->GetEngine();
+
string mod = ctx->GetFunction()->GetModuleName();
+
+
// We need to find the function that will be created as the co-routine
+
string decl = "void " + func + "()";
+
asIScriptFunction *funcPtr = engine->GetModule(mod.c_str())->GetFunctionByDecl(decl.c_str());
+
if( funcPtr == 0 )
+
{
+
// No function could be found, raise an exception
+
ctx->SetException(("Function '" + decl + "' doesn't exist").c_str());
+
return;
+
}
+
+
// Create a new context for the co-routine
+
asIScriptContext *coctx = engine->CreateContext();
+
coctx->Prepare(funcPtr);
+
+
// Add the new co-routine context to the array of co-routines
+
coroutines.push_back(coctx);
+
}
+
}
+

The yield function is even simpler:

+
void Yield()
+
{
+ +
if( ctx )
+
{
+
// Suspend the context so the next co-routine can be resumed
+
ctx->Suspend();
+
}
+
}
+

A basic control algorithm might look like this:

+
std::vector<asIScriptContext *> coroutines;
+
void Execute()
+
{
+
int n = 0;
+
while( coroutines.size() > 0 )
+
{
+
// Resume the co-routine
+
int r = coroutines[n]->Execute();
+ +
{
+
// Resume the next co-routine
+
if( ++n == coroutines.size() )
+
n = 0;
+
}
+
else
+
{
+
// The co-routine finished so let's remove it
+
coroutines[n]->Release();
+
coroutines.erase(n);
+
}
+
}
+
}
+
See also
Context manager, Co-routines, Concurrent scripts
+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual asIScriptFunction * GetFunction(asUINT stackLevel=0)=0
Returns the function at the specified callstack level.
+
@ asEXECUTION_SUSPENDED
The execution is suspended and can be resumed.
Definition: angelscript.h:400
+
virtual asIScriptFunction * GetFunctionByDecl(const char *decl) const =0
Returns the function by its declaration.
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
The engine interface.
Definition: angelscript.h:1092
+
virtual const char * GetModuleName() const =0
Returns the name of the module where the function was implemented.
+
virtual asIScriptEngine * GetEngine() const =0
Returns a pointer to the engine.
+
virtual int Suspend()=0
Suspends the execution, which can then be resumed by calling Execute again.
+
virtual asIScriptContext * CreateContext()=0
Creates a new script context.
+
The interface for a script function description.
Definition: angelscript.h:3823
+
virtual int SetException(const char *info, bool allowCatch=true)=0
Sets an exception, which aborts the execution.
+
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
+
AS_API asIScriptContext * asGetActiveContext()
Returns the currently active context.
+ + + + diff --git a/docs/manual/doc_adv_custom_options.html b/docs/manual/doc_adv_custom_options.html new file mode 100644 index 0000000..2353ad0 --- /dev/null +++ b/docs/manual/doc_adv_custom_options.html @@ -0,0 +1,191 @@ + + + + + + + +AngelScript: Custom options + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Custom options
+
+
+

Most applications have different needs and AngelScript is meant to be as flexible as possible to suit everybody. For this reason there are several options for customizing the script engine for the best fit.

+

+Registerable types

+

Even types that one might normally expect to be built-in to a script language, e.g. string, array, and other container classes, are registered by the application. This is to allow the application to provide the exact implementation desired.

+

Of course, should the application developer want to use a premade implementation the add-ons provide just that.

+

+Language modifications

+

The engine method SetEngineProperty permits making runtime choices about several different behaviours in the engine.

+

The following modify the script language in one way or the other:

+

asEP_DISALLOW_EMPTY_LIST_ELEMENTS

+

By turning on this option the compiler will no longer accept empty list elements in initialization lists. The following will for example not be supported:

+
+  array<int> arr = {1,2,,4,5,};
+

When not turned on, the compiler will leave the empty list elements with the uninitialized value, just as an uninitialized variable of the same type.

+

asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE

+

By turning on this the compiler will no longer allow the use of value assignment operators on reference types. While it may seem drastic, it can help reduce risk for bugs in the scripts, as the script writer will no longer be able to do a value assignment by mistake when he meant to a handle assignment. Reference types should usually
+ not be copied, so the imposed restriction will likely not cause problems anyway.

+

asEP_ALLOW_UNSAFE_REFERENCES

+

By turning on unsafe references you allow in-out references to be used for primitives and value types too. Normally this will work fine, just as it does in ordinary languages such as C++, but know that it is quite possible to write scripts that will cause memory invasions or crashes if the references are not properly guarded. With this option turned on you cannot consider the scripts to be sand-boxed any longer.

+

asEP_USE_CHARACTER_LITERALS, asEP_ALLOW_MULTILINE_STRINGS, asEP_SCRIPT_SCANNER, asEP_STRING_ENCODING

+

These options are used to determine how strings are treated by the compiler. The details are described in Custom string type.

+

asEP_HEREDOC_TRIM_MODE

+

With this option the compiler can be set to always trim heredoc strings, only trim if it is multiple lines, or never trim them.

+

asEP_ALLOW_IMPLICIT_HANDLE_TYPES

+

This option is experimental. By turning it on script classes can be declared to always be treated as handles by declaring the class with @ before the name of the class. When this is done all variables of that type will be handles, and the assignment operator will always perform a handle assignment.

+

asEP_REQUIRE_ENUM_SCOPE

+

With this option all enum values must be prefixed with the enum type using the scope operator to qualify.

+

asEP_PROPERTY_ACCESSOR_MODE

+

By default virtual property accessors when declared as individual functions need to be marked as such with the keyword 'property', or else the compiler won't consider the functions as virtual properties. This behaviour was introduced in version 2.33.1.

+

Before this version, the compiler would automatically identify functions with the pre-fix 'get_' or 'set_' as virtual property accessors if the function signature was appropriate. This led to undesired behaviour when developers would declare such functions without the intention of them being used as virtual properties and yet the compiler used them as such.

+

For backwards compatibility it is still possible to configure the engine to use this behaviour by setting the engine property asEP_PROPERTY_ACCESSOR_MODE to 2.

+

If it also possible to disable virtual property accessors all together by setting the engine property to 0. Setting the option to 1 only allows virtual property accessors for registered functions, but still without requiring the keyword 'property'.

+

asEP_DISALLOW_GLOBAL_VARS

+

The application can disable the ability to declare global variables in scripts completely. This can be useful in such cases when the application wish to have full control of what can and cannot be stored by a script.
+

+

asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT

+

If this flag is set to true, the compiler will always provide a default constructor for classes even if it hasn't been implemented by the script. Normally this option is not recommended, because if a script class provides a non-default constructor but not the default constructor it is most likely because it is desired that the class should always be initialized with the non-default constructor.

+

asEP_ALTER_SYNTAX_NAMED_ARGS

+

If this flag is set to 1 or 2 the compiler will accept the '=' instead of ':' for naming arguments in function calls. When option 1 is used the compiler will warn about it, so the script writer can update the script to the correct ':' token. When option 2 is used both '=' and ':' are accepted silently.

+

Observe that the use of the '=' token for naming arguments may cause a bit of a confusion. Especially if there is a variable with the same name as the function argument as the script writer may think he's updating the value of the variable, but is just naming the function argument.

+

asEP_DISABLE_INTEGER_DIVISION

+

This option changes the default behaviour of the / and /= operators. When true, this option replaces integer division with floating-point division, e.g. 1/2 == 0.5 instead of 1/2 == 0

+

asEP_PRIVATE_PROP_AS_PROTECTED

+

When this option is set to true the compiler will not prevent the access to private properties inherited from the parent class. It will only write a warning.

+

This option is provided to give backwards compatibility for scripts written between versions 2.19.1, when support for private properties was added, albeit working more like protected properties, and version 2.30.0 when the behaviour was changed so that private properties work like in other languages, i.e. they can't be accessed by derived classes.

+

asEP_ALLOW_UNICODE_IDENTIFIERS

+

When this option is set to true the compiler will accept identifiers that contain characters with byte value higher than 127. This permits the use of international characters in the identifiers as the script can be encoded in UTF-8 format and compiler normally.

+

+Engine behaviours

+

There are also several options in SetEngineProperty for modifying the way the engine behaves.

+

asEP_MAX_NESTED_CALLS

+

This property defines how many recursive nested calls the engine should accept. In this context a nested call is when a script calls into an application registered function that in turn calls another script function. The second call is then said to be a nested call.

+

By default the engine will accept 100 nested calls.

+

asEP_OPTIMIZE_BYTECODE

+

Normally this option is only used for testing the library, but should you find that the compilation time takes too long, then it may be of interest to turn off the bytecode optimization pass by setting this option to false.

+

asEP_COPY_SCRIPT_SECTIONS

+

If you want to spare some dynamic memory and the script sections passed to the engine is already stored somewhere in memory then you can turn off this options. If you do you'll need to be careful not to modify or deallocate the script sections until module has been built.

+

asEP_MAX_STACK_SIZE, asEP_INIT_STACK_SIZE, asEP_MAX_CALL_STACK_SIZE, asEP_INIT_CALL_STACK_SIZE

+

The script context's data stack grows dynamically as needed during executions. By default there is no limit to how large it may grow, but if you wish to set this limit you can do with the asEP_MAX_STACK_SIZE option. The limit is given in bytes, but it is only an approximate limit. Setting the limit to 1MB doesn't mean the stack will grow exactly to 1MB, but you can be certain that it will not grow much beyond that.

+

Whenever a context attempts to grow the stack more than it is allowed, it will abort the execution and return a 'stack overflow' script exception.

+

Similarly the call stack also grows dynamically as needed during executions. The default here is also no limit, with the ability to limit maximum size by setting the asEP_MAX_CALL_STACK_SIZE. This limit is set in number of function calls.

+

In some cases it may be useful to set the initial stack size too, e.g. if you know beforehand that a large stack is needed, or if you wish to avoid any runtime memory allocations during an execution. In this case you can use the asEP_INIT_STACK_SIZE for the data stack, and asEP_INIT_CALL_STACK_SIZE for the call stack.

+

asEP_BUILD_WITHOUT_LINE_CUES

+

This option can be used to speed up the execution of scripts a bit. It is best described in Compile scripts without line cues.

+

asEP_INIT_GLOBAL_VARS_AFTER_BUILD

+

By default the global variables in the script modules are initialized immediately after building the scripts, but sometimes this is not desired. For example, if you debug the initialization of the variables, or if you're building an offline compiler, or even if you want to add extra validation of the variables to make sure the script doesn't declare any variables you don't want it to.

+
See also
Pre-compiled byte code
+

asEP_INCLUDE_JIT_INSTRUCTIONS

+

In order for JIT compilation to work properly it needs to have some hints in the bytecode so it can know where a switch from bytecode execution to JIT compiled execution shall be done. By default this option is turned off as it would just add an overhead to the bytecode, but when using JIT compilation this overhead will be compensated by the faster execution with direct machine code.

+
See also
How to build a JIT compiler
+

asEP_EXPAND_DEF_ARRAY_TO_TMPL

+

This option is to determine how the default array type is displayed in compiler messages and function declarations, e.g. int[] or array<int>.

+

asEP_AUTO_GARBAGE_COLLECT

+

By default AngelScript's incremental garbage collector is executed as scripts are invoked by the application. This does add a slight overhead to the execution, which is normally tolerable but in some applications the CPU cycles may be needed for other things. In this case the automatic execution of the garbage collector can be turned off to hold off on the execution until the CPU can be spared.

+
See also
Garbage collection
+

asEP_COMPILER_WARNINGS

+

Compiler warnings can be turned off or treated as errors by setting this engine property.

+

asEP_GENERIC_CALL_MODE

+

By default the generic calling convention treats the ref counts in the handles the same way that the native calling convention, i.e. releases any handles passed to a function if they have been marked as auto handles, and increments the returned handle if it has been marked as auto handle.

+

If the behaviour used before 2.33.0 is desired for backwards compatibility, then set this property to 0. In this case the generic calling convention will always release references for handles received in arguments, and never increment references for returned handles.

+
+
+
+ + + + diff --git a/docs/manual/doc_adv_dynamic_build.html b/docs/manual/doc_adv_dynamic_build.html new file mode 100644 index 0000000..eaa8aae --- /dev/null +++ b/docs/manual/doc_adv_dynamic_build.html @@ -0,0 +1,146 @@ + + + + + + + +AngelScript: Dynamic compilations + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Dynamic compilations
+
+
+

There are various forms of dynamic compilations of scripts. In the following subtopics I try to explain the theory of them and give some information on how they can be implemented.

+

+On demand builds

+

The most common form of dynamic compilations is building new modules on demand, i.e. as they are needed. When using this the application or game engine is typically designed to have separate scripts to perform different tasks, e.g. menu handling, different types of AI controllers, player controller, etc. If these separate scripts have an abstraction layer through the application to interact with each other it is very easy to build the scripts on demand.

+

To build a new script on demand, simply get a new module, add the needed script sections to it and build it just as you would when building the first script. As each module is independent the previously existing module will be unaffected.

+

Each module can be configured to see a different application interface, so there is no need to create different engine instances.

+

Though modules are independent, they can still interact with each other if the application provides the interface for that. To make the communication between modules easier one can chose to use shared script entities. Shared script entities will be compiled only once by the first module that includes the code. Any subsequent module that also include the code for the shared entity will reuse what was built by the first module, i.e. will share the internal type and bytecode.

+

Another option is to import global functions from a previously compiled module. In this case the application must make sure the function that exports the functions is compiled first, then after building the module that imports the function the application must call the asIScriptModule::BindAllImportedFunctions so conclude the imports.

+
See also
Game sample
+

+Incremental builds

+

Besides the ordinary compilation of scripts and subsequent executions, AngelScript also support dynamically compiling additional functions and global variables to incrementally add to the scope of a module. These functions and variables will become part of the scope, just as if they had been included in the initial script compilation which means that subsequent executions or incremental compilations can use them.

+

It is also possible to dynamically remove functions and variables. Doing so doesn't immediately discard the functions or variables, so other functions that still refer to them will not fail when executing them. They will however no longer be visible for new compilations or when searching for functions or variables in the module.

+

This kind of dynamic compilations is most useful when dealing with user interaction, e.g. an ingame console, or perhaps event handlers, e.g. a trigger on a GUI button click.

+
See also
ExecuteString() add-on, Console sample
+

+Hot reloading scripts

+

Hot reloading is most often used when quick change & test cycles are wanted. It is quite common for game engines to have a debug mode that continuously monitors the script files to detect any updates that are made, and when detected automatically reloads the scripts without restarting the game. This allows the developers, for example, to quickly change the behaviour of the AI and immediately see the result without having to play through the entire level over and over again.

+

Hot reloading without preserving the state of existing objects is quite trivial. Simply discard everything, reload the scripts, and create new objects. On the other hand, hot reloading scripts while preserving the state of existing objects can be quite tricky, but is also the most rewarding when implemented successfully.

+

The first part to reloading while preserving the state is keeping track of the object instances so the application knows which objects needs to be serialized when a module is hot reloaded. It is entirely up to the application to build and maintain this mapping.

+

The second part is knowing which script files that will trigger a reload when changed. When building the module the application needs to store the list of the files that were added to it. If you use the standard script builder add-on, then it provides methods to enumerate the included sections or files.

+

The third part is the hardest, and that is to implement the actual serialization. Serializing object members of value types is normally quite trivial, simply enumerate the object properties and store a name-value pair for each. Serializing object members of reference types needs some consideration, as depending on the object that is referred to, either you will be able to store the actual pointer, or you will need to store some kind of descriptor as the referred to object will also be recreated during the reload.

+

Once all the objects that will need to be recreated after the reload have been serialized for backup, the module can be rebuilt using the normal procedure for compiling a script. Afterwards the serialized objects needs to be recreated. Once created you'll enumerate the members and set their values or references according to the backed up data.

+

+Things to consider

+
    +
  • Design the engine and script interface with hot reloading in mind from the start. Hot reloading is much easier to implement the less complex interface you have, e.g. script objects that can only interact with other script objects indirectly through the application will not be able to hold references to objects unknown by the application.
  • +
  • Shared script entities will not be recompiled if some module or existing object (including those pending destruction in the garbage collector) still refers to the code. It's recommended that you minimize the use of shared entities to where necessary so as to minimize the need to modify them.
  • +
  • The asIScriptContext cannot be serialized so avoid reloading scripts that may still be referred to by a context, e.g. in a suspended state. It is quite likely that the application will crash if the module is reloaded while a context has one of the functions on the callstack.
  • +
  • Before discarding the original objects, consider doing a test compilation of the modified scripts in a temporary module first, and only go ahead with the hot reloading if the test compilation is successful. That way you can catch compilation errors that would otherwise cause the recreation of the new objects to fail.
  • +
  • When recreating object instances you can take advantage of the method asIScriptEngine::CreateUninitializedScriptObject to create the objects without actually executing the script class constructor, which may have unwanted side effects during the reload.
  • +
  • Decide what to do when the script modifications introduces new object properties or removes existing properties, as you will not be able to restore the exact same object state then. Perhaps the new property can be filled with some default value to allow the continuation of the execution? Or perhaps the script itself can have a special event handler to provide the initial value of the new member?
  • +
  • The Serializer add-on has been implemented to aid the implementation of hot reloading scripts, though it may not suit all types of applications.
  • +
+
See also
Serializer, Reflection
+
+
+
+ + + + diff --git a/docs/manual/doc_adv_dynamic_config.html b/docs/manual/doc_adv_dynamic_config.html new file mode 100644 index 0000000..ccde7ec --- /dev/null +++ b/docs/manual/doc_adv_dynamic_config.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Dynamic configurations + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Dynamic configurations
+
+
+

AngelScript supports the concept for configuration groups. This can be used for example by application plug-ins that wish to register their own interface with the script engine. When the plug-in is later removed, the configuration group for that plug-in can also be removed from the AngelScript interface without having to reinitialize everything.

+

To register part of the interface in a configuration group, the registration should be done between calls to BeginConfigGroup and EndConfigGroup. This can be done as many times as desired, but groups cannot be nested. Observe that object methods, behaviours, and properties will always be placed in the same group where the object type was placed even if another group has been specified between the calls.

+

To remove a configuration group the method RemoveConfigGroup should be called with the name given to the BeginConfigGroup. It is only possible to remove a config group that is not currently in use. Possible causes that prevents the removal of a group may be:

+
    +
  • Another registered a function outside the group uses a type from the group
  • +
  • A script is currently built that uses a type or function from the group
  • +
  • An instance of a script object that uses a type or function from the group is alive
  • +
+

It can be difficult to determine exactly where the use comes from so here's a few steps to do when RemoveConfigGroup returns asCONFIG_GROUP_IS_IN_USE.

+
    +
  • Run a full cycle on the garbage collector to destroy lingering objects
  • +
  • Discard any module that may have been compiled with the group
  • +
  • Double check that no other group uses the entities from the group
  • +
+
+
+
+ + + + diff --git a/docs/manual/doc_adv_generic_handle.html b/docs/manual/doc_adv_generic_handle.html new file mode 100644 index 0000000..88f99f5 --- /dev/null +++ b/docs/manual/doc_adv_generic_handle.html @@ -0,0 +1,123 @@ + + + + + + + +AngelScript: Registering a generic handle type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering a generic handle type
+
+
+

Sometimes it is useful to be able to take a reference to an object without having to force specific implementation on the object, e.g. when providing a generic storage class to scripts, or providing a generic messaging system.

+

In AngelScript there is no common denominator for all object types, the reasons for this is that script classes and application registered classes have completely different implementation and cannot be generalized under a single superclass.

+

Instead, AngelScript provides an alternative by allowing the application to register a generic handle type. This type would be implemented according to the application's needs, but to the script it would look like it was a generic handle that can reference any reference type. With this the type will be able to hold objects, functions, and arrays.

+

To register the generic handle type, the application should follow the same principles as for a value type, except for a few details, that will be described here.

+
    +
  • The type must be registered with the additional flag asOBJ_ASHANDLE. This is the flag that tells AngelScript that the type simulates a generic handle.
  • +
  • In order to allow assigning any handle to the type, the opHndlAssign method must be registered with a variable parameter type, e.g. 'ref &opHndlAssign(const ?&in)'.
  • +
  • The opEquals method must also be registered with a The variable parameter type in order to allow the is and !is operators to behave as expected for a handle, e.g. 'bool opEquals(const ?&in)'.
  • +
  • Finally the opCast must be registered with the signature 'void opCast(?&out)' in order to allow a dynamic cast to any other type.
  • +
+

As this is a quite useful type, with really very little need for customization, a standard add-on with this implementation has been provided with the SDK.

+
See also
ref object
+
+
+
+ + + + diff --git a/docs/manual/doc_adv_inheritappclass.html b/docs/manual/doc_adv_inheritappclass.html new file mode 100644 index 0000000..c8f5b6d --- /dev/null +++ b/docs/manual/doc_adv_inheritappclass.html @@ -0,0 +1,350 @@ + + + + + + + +AngelScript: Inheriting from application registered class + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Inheriting from application registered class
+
+
+

A script class cannot directly inherit from an application registered class, as the script classes are not compiled into native machine code like the application classes are.

+

It is however possible to emulate the inheritance by using a proxy class to hide the underlying differences in an abstract layer. The proxy class has two parts, one is the C++ side that the application sees, and the other is the script side that the scripts can see and inherit from.

+

The following is an example implementation of such a proxy class.

+
// On the C++ side
+
class FooScripted
+
{
+
public:
+
// Public interface that we want the script to be able to override
+
void CallMe()
+
{
+
// If the script side is still alive, then call the scripted function
+
if( !m_isDead->Get() )
+
{
+
asIScriptEngine *engine = m_obj->GetEngine();
+
asIScriptContext *ctx = engine->RequestContext();
+
+
// GetMethodByDecl returns the virtual function on the script class
+
// thus when calling it, the VM will execute the derived method
+
ctx->Prepare(m_obj->GetObjectType()->GetMethodByDecl("void CallMe()"));
+
ctx->SetObject(m_obj);
+
ctx->Execute();
+
+
engine->ReturnContext(ctx);
+
}
+
}
+
+
int m_value;
+
+
// A factory function that can be used by the script side to create
+
static FooScripted *Factory()
+
{
+ +
+
// Get the function that is calling the factory so we can be certain it is the FooScript script class
+
asIScriptFunction *func = ctx->GetFunction(0);
+
if( func->GetObjectType() == 0 || std::string(func->GetObjectType()->GetName()) != "FooScripted" )
+
{
+
ctx->SetException("Invalid attempt to manually instantiate FooScript_t");
+
return 0;
+
}
+
+
// Get the this pointer from the calling function so the FooScript C++
+
// class can be linked with the FooScript script class
+
asIScriptObject *obj = reinterpret_cast<asIScriptObject*>(ctx->GetThisPointer(0));
+
+
return new FooScripted(obj);
+
}
+
+
// Reference counting
+
void AddRef()
+
{
+
m_refCount++;
+
+
// Increment also the reference counter to the script side so
+
// it isn't accidentally destroyed before the C++ side
+
if( !m_isDead->Get() )
+
m_obj->AddRef();
+
}
+
void Release()
+
{
+
// Release the script instance too
+
if( !m_isDead->Get() )
+
m_obj->Release();
+
+
if( --m_refCount == 0 ) delete this;
+
}
+
+
// Assignment operator
+
FooScripted &operator=(const FooScripted &o)
+
{
+
// Copy only the content, not the script proxy class
+
m_value = o.m_value;
+
return *this;
+
}
+
+
protected:
+
+
// The constructor and destructor are indirectly called
+
FooScripted(asIScriptObject *obj) : m_obj(0), m_isDead(0), m_value(0), m_refCount(1)
+
{
+
// Get the weak ref flag for the script object to
+
// avoid holding a strong reference to the script class
+
m_isDead = obj->GetWeakRefFlag();
+
m_isDead->AddRef();
+
+
m_obj = obj;
+
}
+
+
~FooScripted()
+
{
+
// Release the weak ref flag
+
m_isDead->Release();
+
}
+
+
// Reference count
+
int m_refCount;
+
+
// The C++ side holds a weak link to the script side to
+
// avoid a circular reference between the C++ side and
+
// script side
+ + +
};
+

This type is registered with the engine as the following:

+
void RegisterFooScripted(asIScriptEngine *engine)
+
{
+
engine->RegisterObjectType("FooScripted_t", 0, asOBJ_REF);
+
engine->RegisterObjectBehaviour("FooScripted_t", asBEHAVE_FACTORY, "FooScripted_t @f()", asFUNCTION(FooScripted::Factory), asCALL_CDECL);
+
engine->RegisterObjectBehaviour("FooScripted_t", asBEHAVE_ADDREF, "void f()", asMETHOD(FooScripted, AddRef), asCALL_THISCALL);
+
engine->RegisterObjectBehaviour("FooScripted_t", asBEHAVE_RELEASE, "void f()", asMETHOD(FooScripted, Release), asCALL_THISCALL);
+
engine->RegisterObjectMethod("FooScripted_t", "FooScripted_t &opAssign(const FooScripted_t &in)", asMETHOD(FooScripted, operator=), asCALL_THISCALL);
+
engine->RegisterObjectMethod("FooScripted_t", "void CallMe()", asMETHOD(FooScripted, CallMe), asCALL_THISCALL);
+
engine->RegisterObjectProperty("FooScripted_t", "int m_value", asOFFSET(FooScripted, m_value));
+
}
+

The script side is declared as shared so it can be used in all script modules. It is also declared as abstract so it cannot be instantiated by itself, only as a parent class of another script class.

+

This script section should preferably be included automatically by the application in all the modules that should be able to derive from the FooScripted class.

+
+  // On the script side
+  shared abstract class FooScripted
+  {
+    // Allow scripts to create instances
+    FooScripted()
+    {
+      // Create the C++ side of the proxy
+      @m_obj = FooScripted_t();  
+
+ + }
    // The copy constructor performs a deep copy
+    FooScripted(const FooScripted &o)
+    {
+      // Create a new C++ instance and copy content
+      @m_obj = FooScripted_t();
+      m_obj = o.m_obj; 
+" + }
    // Do a deep a copy of the C++ object
+    FooScripted &opAssign(const FooScripted &o)
+    {
+      // copy content of C++ instance
+      m_obj = o.m_obj;
+      return this;
+    }
    // The script side forwards the call to the C++ side
+    void CallMe() { m_obj.CallMe(); }
    // The C++ side property is exposed to the script through accessors
+    int m_value 
+    {
+      get { return m_obj.m_value; }
+      set { m_obj.m_value = value; }
+    }
    // The script class can be implicitly cast to the C++ type through the opImplCast method
+    FooScripted_t @opImplCast() { return m_obj; }
    // Hold a reference to the C++ side of the proxy
+    private FooScripted_t @m_obj;
+  }
+

Now the scripts classes can derive from the FooScripted class
+ and access the properties and methods of the parent class normally.

+
+  // Implement a script class that derives from the application class
+  class FooDerived : FooScripted
+  {
+    void CallMe()
+    {
+       m_value += 1;
+    }
+  }
  void main()
+  {
+    // When newly created the m_value is 0
+    FooDerived d;
+    assert( d.m_value == 0 );
    // When calling the method the m_value is incremented with 1
+    d.CallMe();
+    assert( d.m_value == 1 );
+  }
+

It is of course also possible to create an instance of the scripted class from the application and access it through the FooScripted C++ proxy, thus making it transparent from the rest of the application that the implementation is actually in the script.

+
FooScripted *CreateFooDerived(asIScriptEngine *engine)
+
{
+
// Create an instance of the FooDerived script class that inherits from the FooScripted C++ class
+
asIScriptObject *obj = reinterpret_cast<asIScriptObject*>(engine->CreateScriptObject(mod->GetTypeInfoByName("FooDerived")));
+
+
// Get the pointer to the C++ side of the FooScripted class
+
FooScripted *obj2 = *reinterpret_cast<FooScripted**>(obj->GetAddressOfProperty(0));
+
+
// Increase the reference count to the C++ object, as this is what will
+
// be used to control the life time of the object from the application side
+
obj2->AddRef();
+
+
// Release the reference to the script side
+
obj->Release();
+
+
return obj2;
+
}
+
+
void Foo(asIScriptEngine *engine)
+
{
+
FooScripted *obj = CreateFooDerived(engine);
+
+
// Once the object is created the application can access it normally through
+
// the FooScripted pointer, without having to know that the implementation
+
// is actually done in the script.
+
+
// When newly created the m_value is 0
+
assert( obj->m_value == 0 );
+
+
// When calling the method the m_value is incremented with 1 by the script
+
obj->CallMe();
+
assert( obj->m_value == 1 );
+
+
// Release the object to destroy the instance (this will also destroy the script side)
+
obj->Release();
+
}
+
+
+
+
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
+
virtual int AddRef() const =0
Adds a reference to the shared boolean.
+
virtual asIScriptContext * RequestContext()=0
Request a context.
+
@ asBEHAVE_FACTORY
Factory.
Definition: angelscript.h:362
+
@ asBEHAVE_RELEASE
Release.
Definition: angelscript.h:368
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual asIScriptFunction * GetFunction(asUINT stackLevel=0)=0
Returns the function at the specified callstack level.
+
virtual const char * GetName() const =0
Returns a temporary pointer to the name of the datatype.
+
virtual int Execute()=0
Executes the prepared function.
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
virtual int SetObject(void *obj)=0
Sets the object for a class method call.
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
+
virtual asILockableSharedBool * GetWeakRefFlag() const =0
Returns the weak ref flag for the object.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual void * CreateScriptObject(const asITypeInfo *type)=0
Creates an object defined by its type.
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
virtual void ReturnContext(asIScriptContext *ctx)=0
Return a context when it won't be used anymore.
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
A lockable shared boolean.
Definition: angelscript.h:4077
+
The interface for a script function description.
Definition: angelscript.h:3823
+
@ asBEHAVE_ADDREF
AddRef.
Definition: angelscript.h:366
+
virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a property for the object type.
+
virtual int SetException(const char *info, bool allowCatch=true)=0
Sets an exception, which aborts the execution.
+
The interface for an instance of a script object.
Definition: angelscript.h:3413
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
+
virtual int Release() const =0
Decrease reference counter.
+
virtual asITypeInfo * GetObjectType() const =0
Returns the object type for class or interface method.
+
virtual void * GetThisPointer(asUINT stackLevel=0)=0
Returns a pointer to the object, if a class method is being executed.
+
virtual void * GetAddressOfProperty(asUINT prop)=0
Returns a pointer to the property referenced by prop.
+
#define asOFFSET(s, m)
Returns the offset of an attribute in a struct.
Definition: angelscript.h:672
+
AS_API asIScriptContext * asGetActiveContext()
Returns the currently active context.
+ + + + diff --git a/docs/manual/doc_adv_jit.html b/docs/manual/doc_adv_jit.html new file mode 100644 index 0000000..9c4b79f --- /dev/null +++ b/docs/manual/doc_adv_jit.html @@ -0,0 +1,210 @@ + + + + + + + +AngelScript: How to build a JIT compiler + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
How to build a JIT compiler
+
+
+

AngelScript doesn't provide a built-in JIT compiler, instead it permits an external JIT compiler to be implemented through a public interface.

+

To use JIT compilation, the scripts must be compiled with a few extra instructions that provide hints to the JIT compiler and also entry points so that the VM will know when to pass control to the JIT compiled function. By default this is turned off, and must thus be turned on by setting the engine property asEP_INCLUDE_JIT_INSTRUCTIONS.

+

If the application sets the JIT compiler with SetJITCompiler AngelScript will automatically invoke it to provide the JIT functions with each compilation or loading of pre-compiled bytecode.

+

+The structure of the JIT function

+

The JIT compiled function must follow certain rules in order to behave well with the virtual machine. The intention is that the VM will pass the control to the JIT function, and when the execution is to be suspended the JIT function returns the control to the VM, updating the internal state of the VM so that the VM can resume the execution when requested. Each time the JIT function returns control to the VM it must make sure that the VM registers and stack values have been updated according to the code that was executed.

+

The byte code will have a special instruction, JitEntry, which defines the positions where the VM can pass the control to the JIT function. These are usually placed for every script statement, and after each instruction that calls another function. This implies that the JIT compiled function needs to be able to start the execution at different points based on the argument in the JitEntry instruction. The value of the argument is defined by the JIT compiler and how it is interpreted is also up to the JIT compiler, with the exception of 0 that means that the control should not be passed to the JIT function.

+

Some byte code instructions are not meant to be converted into native code. These are usually the ones that have a more global effect on the VM, e.g. the instructions that setup a call to a new script function, or that return from a previous instruction. When these functions are encountered, the JIT function should return the control to the VM, and then the VM will execute the instruction.

+

Other byte code instructions may be partially implemented by the JIT function, for example those that can throw an exception based on specific conditions. One such example is the instructions for divisions, if the divider is 0 the VM will set an exception and abort the execution. For these instructions the JIT compiler should preferrably implement the condition that doesn't throw an exception, and if an exception is to be thrown the JIT function will instead break out to the VM.

+

The following shows a possible structure of a JIT compiled function:

+
+  void jitCompiledFunc(asSVMRegisters *regs, asPWORD jitArg)
+  {
+    Read desired VM registers into CPU registers.
+    Jump to the current position of the function based on the 'jitArg' argument.
+  1:
+    Execute code in block 1.
+    Jump to exit if an illegal operation is done, e.g. divide by zero. 
+    Jump to exit if block ends with an instruction that should not be executed by JIT function. 
+  2:
+    ...
+  3:
+    ...
+  exit:
+    Update the VM registers before returning control to VM.
+    If necessary the function can invoke the methods of the context informed 
+    in the regs, e.g. to suspend the execution, or to set a script exception.
+  }
+

+Traversing the byte code

+
int CJITCompiler::CompileFunction(asIScriptFunction *func, asJITFunction *output)
+
{
+
bool success = StartNewCompilation();
+
+
// Get the script byte code
+
asUINT length;
+
asDWORD *byteCode = func->GetByteCode(&length);
+
asDWORD *end = byteCode + length;
+
+
while( byteCode < end )
+
{
+
// Determine the instruction
+
asEBCInstr op = asEBCInstr(*(asBYTE*)byteCode);
+
switch( op )
+
{
+
// Translate each byte code instruction into native code.
+
// The codes that cannot be translated should return the control
+
// to the VM, so that it can continue the processing. When
+
// the VM encounters the next JitEntry instruction it will
+
// transfer the control back to the JIT function.
+
...
+
+ +
// Update the argument for the JitEntry instruction with
+
// the argument that should be sent to the jit function.
+
// Remember that 0 means that the VM should not pass
+
// control to the JIT function.
+
asBC_PTRARG(byteCode) = DetermineJitEntryArg();
+
break;
+
}
+
+
// Move to next instruction
+
byteCode += asBCTypeSize[asBCInfo[op].type];
+
}
+
+
if( success )
+
{
+
*output = GetCompiledFunction();
+
return 0;
+
}
+
+
return -1;
+
}
+

The following macros should be used to read the arguments from the bytecode instruction. The layout of the arguments is determined from the asBCInfo array.

+ +

What each byte code instruction does is described in Byte code instructions, but the exact implementation of each byte code instruction is best determined from the implementation in the VM, i.e. the asCScriptContext::ExecuteNext method.

+
+
+
+
unsigned long asDWORD
32 bit unsigned integer
Definition: angelscript.h:614
+
const asSBCInfo asBCInfo[256]
Information on each bytecode instruction.
Definition: angelscript.h:4884
+
asEBCInstr
The bytecode instructions used by the VM.
Definition: angelscript.h:4351
+
unsigned char asBYTE
8 bit unsigned integer
Definition: angelscript.h:598
+
void(* asJITFunction)(asSVMRegisters *registers, asPWORD jitArg)
The function signature of a JIT compiled function.
Definition: angelscript.h:4316
+
@ asBC_JitEntry
If a JIT function is available and the argument is not 0 then call the JIT function.
Definition: angelscript.h:4703
+
virtual asDWORD * GetByteCode(asUINT *length=0)=0
Returns the byte code buffer and length.
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+
The interface for a script function description.
Definition: angelscript.h:3823
+
const int asBCTypeSize[21]
Lookup table for determining the size of each type of bytecode instruction.
Definition: angelscript.h:4815
+
#define asBC_PTRARG(x)
Macro to access the first pointer argument in the bytecode instruction.
Definition: angelscript.h:5156
+
asEBCType type
Instruction argument layout.
Definition: angelscript.h:4855
+ + + + diff --git a/docs/manual/doc_adv_jit_1.html b/docs/manual/doc_adv_jit_1.html new file mode 100644 index 0000000..8743733 --- /dev/null +++ b/docs/manual/doc_adv_jit_1.html @@ -0,0 +1,527 @@ + + + + + + + +AngelScript: Byte code instructions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Byte code instructions
+
+
+

This page gives a brief description of each of the byte code instructions that the virtual machine has.

+ +

+Object management

+

Perform a bitwise copy of a memory buffer to another

+ +

Push the address and length of a string on the stack

+ +

Allocate the memory for an object and setup the VM to execute the constructor

+ +

Release the memory of an object or list buffer

+ +

Move the address in an object variable to the object register. The address in the variable is then cleared.

+ +

Move the address from the object register to an object variable. The address in the object register is then cleared.

+ +

Copy the object handle from one address to another. The reference count of the object is updated to reflect the copy.

+ +

Copy the object handle on stack to a handle in a variable. The reference count of the object is updated to reflect the copy.

+ +

Push the pointer of an object type on the stack

+ +

Push the type id on the stack

+ +

Pop an address to a script object from the stack. If the desired cast can be made store the address in the object register.

+ +

Push the function pointer on the stack

+ +

Load the address to a property of the object into the value register. Substitutes the sequence PshV4/8, ADDSi, PopRPtr.

+ +

Load the address to a property of a value object into the value register. Substitutes the sequence PSF, ADDSi, PopRPtr.

+ +

+Math instructions

+

Negate the value in the variable. The original value is overwritten.

+ +

Perform the operation with the value of two variables and store the result in a third variable.

+ +

Perform the operation with a constant value and the value of the variable. The original value is overwritten.

+ +

+Bitwise instructions

+

Perform a boolean not operation on the value in the variable. The original value is overwritten.

+ +

Perform a bitwise complement on the value in the variable. The original value is overwritten.

+ +

Perform the operation with the value of two variables and store the result in a third variable.

+ +

+Comparisons

+

Compare the value of two variables and store the result in the value register.

+ +

Compare the value of a variable with a constant and store the result in the value register.

+ +

Test the value in the value register. Update the value register according to the result.

+ +

+Type conversions

+

Convert the value in the variable. The original value is overwritten.

+ +

Convert the value of a variable and store the result in another variable.

+ +

+Increment and decrement

+

Increment or decrement the value pointed to by the address in the value register.

+ +

Increment or decrement the value in the variable.

+ +

+Flow control

+

Setup the VM to begin execution of the other script function

+ +

Setup the VM to return to the calling function

+ +

Make an unconditional jump to a relative position

+ +

Make a jump to a relative position depending on the value in the value register

+ +

Call an application registered function

+ +

Save the state and suspend execution, then return control to the application

+ +

Give control of execution to the JIT compiled function

+ +

+Stack and data management

+

Push a constant value on the stack.

+ +

Push the stack frame pointer on the stack.

+ +

Swap the top values on the stack.

+ +

Dereference top pointer on stack. Raises exception if pointer is null.

+ +

Add an offset to the top address on the stack. Raises exception if address is null.

+ +

Push the value of a variable on the stack.

+ +

Initialize the value of a variable with a constant.

+ +

Copy the value of one variable to another.

+ +

Validate that an expected pointer is not null.

+ +

Push the variable index with the size of a pointer on the stack.

+ +

Replace a variable index on the stack with an address.

+ +

Pop and discard an address from the stack.

+ +

Pop or push an address to or from the value register.

+ +

Copy a value between value register and a variable.

+ +

Copy a value from a variable to the address held in the value register

+ +

Copy a value from the address held in the value register to a variable

+ +

Load the address of the variable into the value register

+ +

Clear the upper bytes of the value register

+ +

+Global variables

+

Push the value of a global variable on the stack

+ +

Load the address of a global variable into the value register

+ +

Load the address of a global variable into the value register and copy the value of the global variable to local variable

+ +

Copy a value between local variable and global variable.

+ +

Push the address of the global variable on the stack.

+ +

Initialize the variable of a global variable with a constant.

+ +

+Initialization list management

+

Allocates the memory for the initialization list buffer

+ +

Sets the number of elements that will be repeated afterwards

+ +

Sets the type of the next element

+ +

Pushes the address of the list element on the stack

+ +
+
+
+ + + + diff --git a/docs/manual/doc_adv_jit_topic.html b/docs/manual/doc_adv_jit_topic.html new file mode 100644 index 0000000..ed867ce --- /dev/null +++ b/docs/manual/doc_adv_jit_topic.html @@ -0,0 +1,115 @@ + + + + + + + +AngelScript: JIT compilation + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
JIT compilation
+
+ +
+
+ + + + diff --git a/docs/manual/doc_adv_jit_topic.js b/docs/manual/doc_adv_jit_topic.js new file mode 100644 index 0000000..ce73b18 --- /dev/null +++ b/docs/manual/doc_adv_jit_topic.js @@ -0,0 +1,19 @@ +var doc_adv_jit_topic = +[ + [ "How to build a JIT compiler", "doc_adv_jit.html", [ + [ "The structure of the JIT function", "doc_adv_jit.html#doc_adv_jit_3", null ], + [ "Traversing the byte code", "doc_adv_jit.html#doc_adv_jit_2", null ] + ] ], + [ "Byte code instructions", "doc_adv_jit_1.html", [ + [ "Object management", "doc_adv_jit_1.html#doc_adv_jit_1_1", null ], + [ "Math instructions", "doc_adv_jit_1.html#doc_adv_jit_1_2", null ], + [ "Bitwise instructions", "doc_adv_jit_1.html#doc_adv_jit_1_3", null ], + [ "Comparisons", "doc_adv_jit_1.html#doc_adv_jit_1_4", null ], + [ "Type conversions", "doc_adv_jit_1.html#doc_adv_jit_1_5", null ], + [ "Increment and decrement", "doc_adv_jit_1.html#doc_adv_jit_1_6", null ], + [ "Flow control", "doc_adv_jit_1.html#doc_adv_jit_1_7", null ], + [ "Stack and data management", "doc_adv_jit_1.html#doc_adv_jit_1_8", null ], + [ "Global variables", "doc_adv_jit_1.html#doc_adv_jit_1_9", null ], + [ "Initialization list management", "doc_adv_jit_1.html#doc_adv_jit_1_10", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_adv_multithread.html b/docs/manual/doc_adv_multithread.html new file mode 100644 index 0000000..32ff5ac --- /dev/null +++ b/docs/manual/doc_adv_multithread.html @@ -0,0 +1,130 @@ + + + + + + + +AngelScript: Multithreading + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Multithreading
+
+
+

AngelScript supports multithreading, though not yet on all platforms. You can determine if multithreading is supported on your platform by calling the asGetLibraryOptions function and checking the returned string for "AS_NO_THREADS". If the identifier is in the returned string then multithreading is not supported.

+

Even if you don't want or can't use multithreading, you can still write applications that execute multiple scripts simultaneously.

+

+Things to think about with a multithreaded environment

+
    +
  • If you plan on creating engines in multiple threads, the application should call asPrepareMultithread before the first engine is created, and asUnprepareMultithread after the last engine has been released. This is to avoid race conditions when the engine creates the internal shared thread manager. If only one script engine is used, then it is not necessary to do go through these extra steps.
  • +
  • Always call asThreadCleanup before terminating a thread that accesses the script engine. If this is not done, the memory allocated specifically for that thread will be lost until the script engine is freed.
  • +
  • If the application is composed of multiple application modules (dlls) then it may be necessary to share a single thread manager across the modules. Do this by calling asGetThreadManager in the main module and then call asPrepareMultithread on the secondary modules with the returned pointer.
  • +
  • Multiple threads may execute scripts in separate contexts. The contexts may execute scripts from the same module, but if the module has global variables you need to make sure the scripts perform proper access control so that they do not get corrupted, if multiple threads try to update them simultaneously.
  • +
  • The engine will only allow one thread to build scripts at any one time, since this is something that changes the internal state of the engine and cannot safely be done in multiple threads simultaneously.
  • +
  • Reference counters for objects that will be referred to by scripts in different threads must be thread safe in order to avoid race conditions as multiple threads attempt to update the same reference counter. The library provides a pair of functions to facilitate the implementation of thread safe reference counters. See asAtomicInc and asAtomicDec.
  • +
  • Resources that are shared by script modules such as registered properties and objects must be protected by the application for simultaneous access, as the script engine doesn't do this automatically. A read-write lock is provided by the library that can be used for this. See asAcquireExclusiveLock, asReleaseExclusiveLock, asAcquireSharedLock, and asReleaseSharedLock.
  • +
  • If you use automatic garbage collection (turned on by default) then you must make sure the behaviours registered for types to support garbage collection must be thread safe as the garbage collector can be invoked from any thread that is executing a script.
  • +
  • Many of the add-ons are not thread safe. Either create your own or make sure you review the add-ons you wish to use to guarantee thread safety.
  • +
+

+Fibers

+

AngelScript can be used with fibers as well. However, as fibers are not real threads you need to be careful if multiple fibers need to execute scripts. AngelScript keeps track of active contexts by pushing and popping the context pointers on a stack. With fibers you can easily corrupt this stack if you do not pay attention to where and when script executions are performed.

+

Try to avoid switching fibers when a script is executing, instead you should suspend the current script execution and only switch to the other fiber when the context's Execute method returns. If you really must switch fibers while executing a script, then make sure the second fiber initiates and concludes its own script execution before switching back to the original fiber.

+
+
+
+ + + + diff --git a/docs/manual/doc_adv_namespace.html b/docs/manual/doc_adv_namespace.html new file mode 100644 index 0000000..e958308 --- /dev/null +++ b/docs/manual/doc_adv_namespace.html @@ -0,0 +1,156 @@ + + + + + + + +AngelScript: Using namespaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Using namespaces
+
+
+

Namespaces can be used to group related functions and other entities together. Doing so avoids potential conflicts with other entities that happen to use the same name, but is otherwise unrelated.

+

Namespaces can be used in the application registered interface, as well as in the scripts.

+

+Registering the interface with namespaces

+

To register a function, or other entity in a specific namespace, the application should first call the method SetDefaultNamespace to define the desired namespace. After that the registration follows the normal procedure as described in the chapter on registering the interface.

+
void RegisterInNamespace(asIScriptEngine *engine)
+
{
+
int r;
+
+
// Register the type and function in the namespace
+
r = engine->SetDefaultNamespace("myspace"); assert( r >= 0 );
+
r = engine->RegisterObjectType("mytype", 0, asOBJ_REF); assert( r >= 0 );
+
r = engine->RegisterGlobalFunction("void myfunc()", asFUNCTION(myfunc), asCALL_CDECL); assert( r >= 0 );
+
}
+

If desired nested namespaces can also be used by separating them with the scoping token, ::, e.g. SetDefaultNamespace("outer::inner");

+

+Finding entities in namespaces

+

As namespaces allow multiple declarations with the same signature, it is necessary to specify in which namespace a search for an entity is to be done. This is also done with the SetDefaultNamespace method. This applies to both the engine and the module interfaces.

+
void FindFuncInNamespace(asIScriptModule *module)
+
{
+
int r;
+
+
// Look for the function in the namespace, i.e. myspace::myfunc
+
r = module->SetDefaultNamespace("myspace"); assert( r >= 0 );
+
asIScriptFunction *func1 = module->GetFunctionByName("myfunc");
+
+
// When searching for a matching declaration the default namespace is also
+
// used unless an explicit namespace is given in the declaration itself.
+
asIScriptFunction *funcA = module->GetFunctionByDecl("void myfunc()");
+
asIScriptFunction *funcB = module->GetFunctionByDecl("void myspace::myfunc()");
+
+
assert( funcA == funcB );
+
}
+
+
+
+
virtual asIScriptFunction * GetFunctionByDecl(const char *decl) const =0
Returns the function by its declaration.
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
virtual int SetDefaultNamespace(const char *nameSpace)=0
Sets the current default namespace for registrations and searches.
+
The engine interface.
Definition: angelscript.h:1092
+
virtual asIScriptFunction * GetFunctionByName(const char *name) const =0
Returns the function by its name.
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
The interface for a script function description.
Definition: angelscript.h:3823
+
The interface to the script modules.
Definition: angelscript.h:2218
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
virtual int SetDefaultNamespace(const char *nameSpace)=0
Sets the default namespace that should be used in the following calls.
+ + + + diff --git a/docs/manual/doc_adv_precompile.html b/docs/manual/doc_adv_precompile.html new file mode 100644 index 0000000..eafab72 --- /dev/null +++ b/docs/manual/doc_adv_precompile.html @@ -0,0 +1,151 @@ + + + + + + + +AngelScript: Pre-compiled byte code + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Pre-compiled byte code
+
+
+

Sometimes it may be useful to use pre-compiled bytecode instead of re-building the scripts every time a script is loaded. This can for example reduce load times, or if scripts are transferred over the net, it can reduce the transfer time for large scripts.

+

To save already compiled code you should call the SaveByteCode method on the asIScriptModule, passing in a pointer to the object that implements the asIBinaryStream interface. The script module will then push all the bytecode and related data onto this object with the Write method.

+

When loading the pre-compiled bytecode you should first get an instance of the asIScriptModule, just as if compiling a new script. Instead of calling AddScriptSection followed by Build you will call the LoadByteCode method, passing it a pointer to the binary stream object. The script module will then pull all the bytecode and related data from that object with the Read method to reconstruct the script module.

+

Here's a very simple example of how to implement the asIBinaryStream interface:

+
class CBytecodeStream : public asIBinaryStream
+
{
+
public:
+
CBytecodeStream(FILE *fp) : f(fp) {}
+
+
void Write(const void *ptr, asUINT size)
+
{
+
if( size == 0 ) return;
+
fwrite(ptr, size, 1, f);
+
}
+
void Read(void *ptr, asUINT size)
+
{
+
if( size == 0 ) return;
+
fread(ptr, size, 1, f);
+
}
+
+
protected:
+
FILE *f;
+
};
+
See also
Generic compiler
+

+Things to remember

+
    +
  • All the objects, methods, properties, etc, used when compiling the bytecode must also be registered when loading the precompiled bytecode, otherwise the load will fail when not finding the correct entity.
  • +
  • The script engine doesn't perform validation of the pre-compiled bytecode, so the application is responsible for authenticating the source. If this authentication isn't performed by the application you'll have potential security risks in your application as the bytecode may have been manually manipulated to perform otherwise illegal tasks.
  • +
  • If the application that compiles the script code is separate from the application that will execute them, then you may register the functions and methods with null pointers so you don't need to actually implement all of them. Object properties must be registered with different offsets so that they can be differentiated by the bytecode loader. You should also set the engine property asEP_INIT_GLOBAL_VARS_AFTER_BUILD to false with asIScriptEngine::SetEngineProperty, so the script engine doesn't attempt to initialize the global variables after the script has been built. The helper add-on has a couple of functions to facilitate building an offline compiler.
  • +
  • If the application is not going to compile scripts from source code, but only load pre-compiled scripts, then it may be beneficial to compile the library with the AS_NO_COMPILER define so as to reduce the size of the executable.
  • +
  • To reduce the size of the saved bytecode you can strip the debug information from the code. This will skip saving information that is not necessary for executing the scripts, such as the name of script sections, line numbers, and the name and type of local variables.
  • +
  • If the scripts use shared entities then the size of the saved bytecode can be further reduced if the entities are declared as external. To allow the offline compiler to compile scripts with external shared entities, the offline compiler must first build another module with all the shared entities that should be allowed to be declared as external.
  • +
  • The saved bytecode is platform independent with only a couple of exceptions that is unlikely to affect application developers. The exceptions are 1) difference in size of primitive types (e.g. bool on older Mac PPC platforms) and 2) CPU floating point representation (i.e. IEEE 754 versus non-IEEE 754). Differences in pointer size (32bit vs 64bit), CPU endianess, different size of registered types and offsets of registered properties are all handled to provide platform independence.
  • +
  • The saved bytecode is not guaranteed to be compatible for different versions of the AngelScript library so make sure you use the same library version when saving the bytecode that will be used when loading it.
  • +
+
+
+
+
virtual int Read(void *ptr, asUINT size)=0
Read size bytes from the stream into the memory pointed to by ptr.
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+
A binary stream interface.
Definition: angelscript.h:4051
+
virtual int Write(const void *ptr, asUINT size)=0
Write size bytes to the stream from the memory pointed to by ptr.
+ + + + diff --git a/docs/manual/doc_adv_reflection.html b/docs/manual/doc_adv_reflection.html new file mode 100644 index 0000000..a854e85 --- /dev/null +++ b/docs/manual/doc_adv_reflection.html @@ -0,0 +1,131 @@ + + + + + + + +AngelScript: Reflection + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Reflection
+
+
+

While the script language doesn't offer built-in functionality for reflection, the application interface do provide all the necessary methods to enumerate everything within the scripts.

+

The article on debugging shows a little of these interfaces with the focus on debugging rather than reflection. The article on dynamic compilations shows another aspect where scripts may be partially modified at runtime.

+

The following will do an overview of the available methods for enumerating the various entities in a script.

+

+Enumerating variables and properties

+

Global variables in a script module are enumerated with the interface asIScriptModule. Specifically the methods GetGlobalVarCount and GetGlobalVar. GetGlobalVarIndexByName and GetGlobalVarIndexByDecl can be used if the name and/or declaration of the desired variable is known before hand. To inspect or even modify the value of the global variable the method GetAddressOfGlobalVar should be used.

+

The engine interface asIScriptEngine has a similar set of methods for enumerating application registered global properties, i.e. GetGlobalPropertyCount, GetGlobalPropertyByIndex, GetGlobalPropertyIndexByName, and GetGlobalPropertyIndexByDecl.

+

Member properties of classes are accessed through the asIScriptObject interface for live object instances, and asITypeInfo interface for inspecting the class declarations without any live object instance.

+

Local variables within functions can also be enumerated as long as the script has been compiled with debug information. These are then enumerated through the asIScriptFunction interface for inspecting the declarations, and directly through asIScriptContext for inspecting and/or modifying them on the stack.

+

+Enumerating functions and methods

+

Global functions in a script are enumerated with the interface asIScriptModule, using the methods GetFunctionCount, GetFunctionByIndex, GetFunctionByName, and GetFunctionByDecl.

+

The engine interface asIScriptEngine also exposes methods for enumerating application registered functions in a similar manner.

+

To enumerate methods of classes the interface asITypeInfo should be used.

+

+Enumerating types

+

asIScriptModule is of course used to enumerate the types declared in the scripts too. The methods GetObjectTypeCount, GetObjectTypeByIndex, and GetTypeInfoByName are for enumerating classes and interfaces. The methods GetEnumCount and GetEnumByIndex are for enumerating enums.

+

The asIScriptEngine interface has near identical methods for enumerating the application registered types.

+

Many of the above methods return values called type ids that describes the type of the respective variable, property, or function argument. In many cases the type id can be directly inspected as a bitfield to get necessary information on the what the type is. The lower bits are just a sequence number where the first 12 numbers represents the built-in primitives, and anything higher represents either application registered types or script declared types. The higher bits indicate if the type represents a primitive, object, or handle. Use the flags in asETypeIdFlags to do the necessary verifications on the type id.

+

For type ids that represent object types it may be necessary to obtain the asITypeInfo instance to get further information on what the type is. The method GetTypeInfoById is used to do this translate from type id to asITypeInfo.

+
+
+
+ + + + diff --git a/docs/manual/doc_adv_scoped_type.html b/docs/manual/doc_adv_scoped_type.html new file mode 100644 index 0000000..c9758f3 --- /dev/null +++ b/docs/manual/doc_adv_scoped_type.html @@ -0,0 +1,156 @@ + + + + + + + +AngelScript: Registering a scoped reference type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering a scoped reference type
+
+
+

Some C++ value types have special requirements for the memory where they are located, e.g. specific alignment needs, or memory pooling. Since AngelScript doesn't provide that much control over where and how value types are allocated, they must be registered as reference types. In this case you'd register the type as a scoped reference type.

+

A scoped reference type will have the life time controlled by the scope of the variable that instanciate it, i.e. as soon as the variable goes out of scope the instance is destroyed. This means that the type doesn't permit handles to be taken for the type.

+

A scoped reference type requires only that the release behaviour is registered. The addref behaviour is not permitted. If the factory behaviour is not registered the script will not be able to instanciate objects of this type, but it can still receive them as parameters from the application.

+

Since no handles can be taken for the object type, there is no need to keep track of the number of references held to the object. This means that the release behaviour should simply destroy and deallocate the object as soon as it's called.

+
scoped *Scoped_Factory()
+
{
+
return new scoped;
+
}
+
+
void Scoped_Release(scoped *s)
+
{
+
if( s ) delete s;
+
}
+
+
// Registering a scoped reference type
+
r = engine->RegisterObjectType("scoped", 0, asOBJ_REF | asOBJ_SCOPED); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_FACTORY, "scoped @f()", asFUNCTION(Scoped_Factory), asCALL_CDECL); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("scoped", asBEHAVE_RELEASE, "void f()", asFUNCTION(Scoped_Release), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+

Unfortunately any function that either takes or returns the type by value in C++ must be wrapped in order to permit AngelScript to manage the life time of the values.

+

Here's an example of a function that takes a value and returns another and the corresponding wrapper.

+
scoped Foo(scoped a)
+
{
+
scoped b;
+
return b;
+
}
+
+
scoped *Foo_wrapper(const scoped &a)
+
{
+
return new scoped(Foo(a));
+
}
+
+
// Registering the function
+
r = engine->RegisterGlobalFunction("scoped @Foo(const scoped &in)", asFUNCTION(Foo_wrapper), asCALL_CDECL); assert( r >= 0 );
+

Observe how the function is registered to return the scoped value by handle even though the scoped types really don't support handles. This is done because AngelScript will call Release on the returned instance after it is done with the value it received.

+
See also
Registering a reference type
+
+
+
+
@ asOBJ_SCOPED
The life time of objects of this type are controlled by the scope of the variable....
Definition: angelscript.h:260
+
@ asBEHAVE_FACTORY
Factory.
Definition: angelscript.h:362
+
@ asBEHAVE_RELEASE
Release.
Definition: angelscript.h:368
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+ + + + diff --git a/docs/manual/doc_adv_single_ref_type.html b/docs/manual/doc_adv_single_ref_type.html new file mode 100644 index 0000000..32e4d13 --- /dev/null +++ b/docs/manual/doc_adv_single_ref_type.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Registering a single-reference type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering a single-reference type
+
+
+

A variant of the uninstanciable reference types is the single-reference type. This is a type that have only 1 reference accessing it, i.e. the script cannot store any extra references to the object during execution. The script is forced to use the reference it receives from the application at the moment the application passes it on to the script.

+

The reference can be passed to the script through a property, either global or a class member, or it can be returned from an application registered function or class method.

+

The script engine will not permit declaration of functions that take this type as a parameter, neither as a reference nor as a handle. If that was allowed it would mean that a reference to the instance is placed on the stack, which in turn means that it is no longer a single-reference type.

+
// Registering the type so that it cannot be instanciated
+
// by the script, nor allow scripts to store references to the type
+
r = engine->RegisterObjectType("single", 0, asOBJ_REF | asOBJ_NOHANDLE); assert( r >= 0 );
+

This sort of type is most useful when you want to have complete control over references to an object, for example so that the application can destroy and recreate objects of the type without having to worry about potential references held by scripts. This allows the application to control when a script has access to an object and it's members.

+
See also
Registering a reference type
+
+
+
+
@ asOBJ_NOHANDLE
This reference type doesn't allow handles to be held. Only valid for reference types.
Definition: angelscript.h:258
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+ + + + diff --git a/docs/manual/doc_adv_template.html b/docs/manual/doc_adv_template.html new file mode 100644 index 0000000..573843d --- /dev/null +++ b/docs/manual/doc_adv_template.html @@ -0,0 +1,209 @@ + + + + + + + +AngelScript: Template types + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Template types
+
+
+

A template type in AngelScript works similarly to how templates work in C++. The scripts will be able to instantiate different forms of the template type by specifying which subtype that should be used. The methods for the instance will then be adapted to this subtype, so that the correct handling of parameters and return types will be applied.

+

The implementation of the template type is not a C++ template though, instead it must be implemented as a generic class that can determine what to do dynamically at runtime based on the subtype for which it was instantiated. This is obviously a lot less efficient than having specific implementations for each type, and for that reason AngelScript permits the application to register a template specialization where the extra performance is needed.

+

This gives the best of both worlds, performance where the subtype is known before hand, and support for all other types that cannot be pre-determined.

+

+Registering the template type

+

Template types can be either reference types or value types. Both are registered in a similar manner with only a few differences.

+

The name of the type is formed by the name of the template type plus the name of the subtype with angle brackets. Multiple subtypes can be informed, separated by comma. The type flag asOBJ_TEMPLATE must used to tell AngelScript that it is a template type that is being registered.

+
// Register the template type as a garbage collected reference type
+
r = engine->RegisterObjectType("myTemplate<class T>", 0, asOBJ_REF | asOBJ_GC | asOBJ_TEMPLATE); assert( r >= 0 );
+
+
// Register another template type as a value type
+
r = engine->RegisterObjectType("myValueTemplate<class T>", sizeof(MyValueTempl), asOBJ_VALUE | asOBJ_TEMPLATE | asGetTypeTraits<MyValueTempl>()); assert( r >= 0 );
+

The template type doesn't have to be garbage collected, but since you may not know which subtypes it will be instantiated for, it is usually best to implement that support.

+

When registering the behaviours, methods, and properties for the template type the type is identified with the name and subtype within angle brackets, but without the class token, e.g. myTemplate<T>. The sub type is identified by just the name of the subtype as it was declared in the call to RegisterObjectType.

+

The factory/construct behaviour for the template type is also different. In order for the implementation to know which subtype it is instantiated for, the factory/constructor receives the asITypeInfo of the template instance as a hidden first parameter. When registering the factory/constructor this hidden parameter is reflected in the declaration, for example as int &in.

+
// Register the factory behaviour
+
r = engine->RegisterObjectBehaviour("myTemplate<T>", asBEHAVE_FACTORY, "myTemplate<T>@ f(int&in)", asFUNCTIONPR(myTemplateFactory, (asITypeInfo*), myTemplate*), asCALL_CDECL); assert( r >= 0 );
+
+
// Register the construct behaviour
+
r = engine->RegisterObjectBehaviour("myValueTemplate<T>", asBEHAVE_CONSTRUCT, "void f(int&in)", asFUNCTIONPR(myValueTemplConstructor, (asITypeInfo*, void*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+

The list factory/constructor, used to instantiate objects with initialization lists, is registered in the same way, i.e.:

+
// Register the list factory behaviour
+
r = engine->RegisterObjectBehaviour("myTemplate<T>", asBEHAVE_LIST_FACTORY, "myTemplate<T>@ f(int&in, uint)", asFUNCTIONPR(myTemplateListFactory, (asITypeInfo*, unsigned int), myTemplate*), asCALL_CDECL); assert( r >= 0 );
+
+
// Register the list constructor behaviour
+
r = engine->RegisterObjectBehaviour("myValueTemplate<T>", asBEHAVE_LIST_CONSTRUCT, "void f(int&in, uint)", asFUNCTIONPR(myValueTemplListConstruct, (asITypeInfo*, unsigned int, void*), void), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+

Remember that since the subtype must be determined dynamically at runtime, it is not possible to declare functions to receive the subtype by value, nor to return it by value. Instead you'll have to design the methods and behaviours to take the type by reference. It is possible to use object handles, but then the script engine won't be able to instantiate the template type for primitives and other values types.

+

The same goes for object properties. Templates can have properties just like any other class, but the properties must not be of the template subtype, since it is not known at the time of registration the size of this type.

+
See also
array template object
+

+On subtype replacement for template instances

+

When a template type is instanced in a declaration, e.g. a variable, the compiler enumerates all the members of the template type to verify if any subtype is used which requires replacement. In most cases the replacement is a direct one-to-one mapping, but in cases where the subtype is used as a const parameter reference, then an additional instruction may be needed to get the expected behaviour.

+

The following shows a method registered to take the subtype T as a const ref.

+
r = engine->RegisterObjectMethod("array<T>", "int find(const T&in value) const", ...);
+

If this template is instantiated with a handle as a subtype, e.g. array<Obj@>, then the method will become:

+
+  int find(Obj @const &in value) const
+

This means that that the parameter takes the handle to a non-read only Obj. The actual handle cannot be modified, but the object the handle refers to can still be modified by the method. This in turn makes it impossible for a script to call the method if the handle the script has is read only.

+

To allow the application developer to say that the method should allow handles to read only objects, a special keyword if_handle_then_const should be used.

+
r = engine->RegisterObjectMethod("array<T>", "int find(const T&in if_handle_then_const value) const", ...);
+

Now this becomes:

+
+  int find(const Obj @const &in value) const
+

This means that the parameter takes a const handle to a read only Obj, i.e. both the handle itself and the object instance it refers to cannot be modified by the method. Now the script will be able to call the method both with read only handles and non-read only handles.

+

+Validating template instantiations at compile time

+

In order to avoid unnecessary runtime validations of invalid template instantiations, the application should preferably register the asBEHAVE_TEMPLATE_CALLBACK behaviour. This is a special behaviour function that the script engine will invoke every time a new template instance type is generated. The callback function can then perform necessary validations to verify if the type can be handled, and if not tell the engine that the instance isn't supported.

+

The callback function must be a global function that receives an asITypeInfo pointer, and should return a boolean. If the template instance is valid the return value should be true.

+

The function should also take a second parameter with an output reference to a boolean. This parameter should be set to true by the function if the template instance should not be garbage collected, which will make AngelScript clear the asOBJ_GC flag for the object type. If the template instance cannot form any circular references, then it doesn't need to be garbage collected, which reduces the work that has to be done by the garbage collector.

+
// Register the template callback
+
// Observe that the asITypeInfo pointer argument is represented by the int reference
+
r = engine->RegisterObjectBehaviour("myTemplate<T>", asBEHAVE_TEMPLATE_CALLBACK, "bool f(int &in, bool&out)", asFUNCTION(myTemplateCallback), asCALL_CDECL); assert( r >= 0 );
+

Here's an example callback function:

+
bool myTemplateCallback(asITypeInfo *ot, bool &dontGarbageCollect)
+
{
+
// This template will only support primitive types
+
int typeId = ot->GetSubTypeId();
+
if( typeId & asTYPEID_MASK_OBJECT )
+
{
+
// The script is attempting to instantiate the
+
// template with an object type, this is not allowed.
+
return false;
+
}
+
+
// Tell AngelScript that this instance doesn't require garbage collection
+
dontGarbageCollect = true;
+
+
// Primitive types are allowed
+
return true;
+
}
+

+Template specializations

+

When registering a template specialization you override the template instance that AngelScript would normally do when compiling a declaration with the template type. This allow the application to register a completely different object with its own implementation for template specializations. Obviously it is recommended that the template specialization is registered so that to the script writer it is transparent, i.e. try to avoid having different method names or behaviours for the template type and template specializations.

+

With the exception of the type name, a template specialization is registered exactly like a normal type.

+
// Register a template specialization for the float subtype
+
r = engine->RegisterObjectType("myTemplate<float>", 0, asOBJ_REF); assert( r >= 0 );
+
+
// Register the factory (there are no hidden parameters for specializations)
+
r = engine->RegisterObjectBehaviour("myTemplate<float>", asBEHAVE_FACTORY, "myTemplate<float>@ f()", asFUNCTIONPR(myTemplateFloatFactory, (), myTemplateFloat*), asCALL_CDECL); assert( r >= 0 );
+
+
+
+
@ asBEHAVE_LIST_FACTORY
Factory used exclusively for initialization lists.
Definition: angelscript.h:364
+
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
+
@ asBEHAVE_FACTORY
Factory.
Definition: angelscript.h:362
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
@ asBEHAVE_LIST_CONSTRUCT
Constructor used exclusively for initialization lists.
Definition: angelscript.h:356
+
@ asBEHAVE_CONSTRUCT
Constructor.
Definition: angelscript.h:354
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
virtual int GetSubTypeId(asUINT subTypeIndex=0) const =0
Returns the type id of the template sub type.
+
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
+
#define asFUNCTIONPR(f, p, r)
Returns an asSFuncPtr representing the function specified by the name, parameter list,...
Definition: angelscript.h:684
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
@ asOBJ_GC
A garbage collected type. Only valid for reference types.
Definition: angelscript.h:254
+
@ asOBJ_VALUE
A value type.
Definition: angelscript.h:252
+
@ asOBJ_TEMPLATE
A template type.
Definition: angelscript.h:262
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
@ asBEHAVE_TEMPLATE_CALLBACK
Callback for validating template instances.
Definition: angelscript.h:374
+
@ asTYPEID_MASK_OBJECT
If any of these bits are set, then the type is an object.
Definition: angelscript.h:492
+ + + + diff --git a/docs/manual/doc_adv_timeout.html b/docs/manual/doc_adv_timeout.html new file mode 100644 index 0000000..1dd6805 --- /dev/null +++ b/docs/manual/doc_adv_timeout.html @@ -0,0 +1,191 @@ + + + + + + + +AngelScript: Timeout long running scripts + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Timeout long running scripts
+
+
+

To prevent long running scripts to freeze the application it may be necessary to add a way to timeout the execution. This article presents two different ways to do so.

+

+With the line callback

+

The line callback feature can be used to perform some special treatment during execution of the scripts. The callback is called for every script statement, which makes it possible to verify if the script has
+ executed for too long time and if so suspend the execution to be resumed at a later time.

+

Before calling the context's Execute method, set the callback function like so:

+
int ExecuteScriptWithTimeOut(asIScriptContext *ctx)
+
{
+
// Define the timeout as 1 second
+
DWORD timeOut = timeGetTime() + 1000;
+
+
// Set up the line callback that will timout the script
+
ctx->SetLineCallback(asFUNCTION(LineCallback), &timeOut, asCALL_CDECL);
+
+
// Execute the script
+
int status = ctx->Execute();
+
+
// If the status is asEXECUTION_SUSPENDED the script can
+
// be resumed by calling this function again.
+
return status;
+
}
+
+
// The line callback function is called by the VM for each statement that is executed
+
void LineCallback(asIScriptContext *ctx, DWORD *timeOut)
+
{
+
// If the time out is reached we suspend the script
+
if( *timeOut < timeGetTime() )
+
ctx->Suspend();
+
}
+

Take a look at the sample Events to see this working.

+

Observe that if the script is compiled with asEP_BUILD_WITHOUT_LINE_CUES, the line callback will be invoked less frequently, though it is guaranteed to be invoked at least for every loop or function call.

+

+With a secondary thread

+

A second thread can be set up to suspend the execution after the timeout. This thread can then be put to sleep so that it doesn't impact performance during the execution. When the thread wakes up it should call the context's Suspend method.

+

The below shows some possible code for doing this. Note that the code for setting up the thread is fictive, as this is different for each target OS.

+
// The variables that are shared between the threads
+
asIScriptContext *threadCtx;
+
int threadId;
+
+
// This function will be executed in the secondary thread
+
void SuspendThread()
+
{
+
// Put the thread to sleep until the timeout (1 second)
+
Sleep(1000);
+
+
// When we wake-up we call the context's Suspend method
+
ctx->Suspend();
+
}
+
+
// This function sets up the timeout thread and executes the script
+
int ExecuteScriptWithTimeOut(asIScriptContext *ctx)
+
{
+
// Set the shared context pointer before creating the thread
+
threadCtx = ctx;
+
+
// Create the thread that will immediately go to sleep
+
threadId = CreateThread(SuspendThread);
+
+
// Execute the script
+
int status = ctx->Execute();
+
+
// Destroy the secondary thread before releasing the context
+
DestroyThread(threadId);
+
+
// Clear the global variables
+
threadId = 0;
+
threadCtx = 0;
+
+
// If the status is asEXECUTION_SUSPENDED the script can
+
// be resumed by calling this function again.
+
+
return status;
+
}
+

Observe that this way of doing it is safe even if the AngelScript library has been built without multithread support.

+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual int Execute()=0
Executes the prepared function.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual int SetLineCallback(asSFuncPtr callback, void *obj, int callConv)=0
Sets a line callback function. The function will be called for each executed script statement.
+
virtual int Suspend()=0
Suspends the execution, which can then be resumed by calling Execute again.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+ + + + diff --git a/docs/manual/doc_adv_var_type.html b/docs/manual/doc_adv_var_type.html new file mode 100644 index 0000000..77ec8f4 --- /dev/null +++ b/docs/manual/doc_adv_var_type.html @@ -0,0 +1,151 @@ + + + + + + + +AngelScript: The variable parameter type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
The variable parameter type
+
+
+

The application can register functions that take a reference to a variable type, which means that the function can receive a reference to a variable of any type. This is useful when making generic containers.

+

When a function is registered with this special parameter type, the function will receive both the reference and an extra argument with the type id of the variable type. The reference refers to the actual value that the caller sent, i.e. if the expression is an object handle then the reference will refer to the handle, not the actual object.

+
// An example usage with a native function
+
engine->RegisterGlobalFunction("void func_c(?&in)", asFUNCTION(func_c), asCALL_CDECL);
+
+
void func_c(void *ref, int typeId)
+
{
+
// Do something with the reference
+
+
// The type of the reference is determined through the type id
+
}
+
+
// An example usage with a generic function
+
engine->RegisterGlobalFunction("void func_g(?&in)", asFUNCTION(func_g), asCALL_GENERIC);
+
+
void func_g(asIScriptGeneric *gen)
+
{
+
void *ref = gen->GetArgAddress(0);
+
int typeId = gen->GetArgTypeId(0);
+
+
func_c(ref, typeId);
+
}
+

The variable type can also be used with out references, but not with inout references. Currently it can only be used with global functions, object constructors, and object methods. It cannot be used with other behaviours and operators.

+

The variable type is not available within scripts, so it can only be used to register application functions.

+
See also
any object and dictionary object for examples
+

+Variable conversion operators

+

The variable parameter type can also be used in special versions of the opConv and opCast operator overloads. This is especially useful for generic container types that need to be able to hold any type of content.

+
    +
  • void opCast(?&out)
  • +
  • void opConv(?&out)
  • +
+
See also
ref object and dictionary object for examples
+
+
+
+
virtual void * GetArgAddress(asUINT arg)=0
Returns the address held in a reference or handle argument.
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
@ asCALL_GENERIC
A function using the generic calling convention.
Definition: angelscript.h:238
+
The interface for the generic calling convention.
Definition: angelscript.h:3242
+
virtual int GetArgTypeId(asUINT arg, asDWORD *flags=0) const =0
Returns the type id of the argument.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+ + + + diff --git a/docs/manual/doc_adv_weakref.html b/docs/manual/doc_adv_weakref.html new file mode 100644 index 0000000..0fd8b62 --- /dev/null +++ b/docs/manual/doc_adv_weakref.html @@ -0,0 +1,193 @@ + + + + + + + +AngelScript: Weak references + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Weak references
+
+
+

Even though AngelScript uses a garbage collector to resolve cyclic references weak references may still come in handy. Weak references are especifically useful in scenarios were an object wants to be able to access other objects, but do not want to kept them alive longer than necessary.

+

AngelScript supports weak references with the use of shared booleans. The code that wants to keep a weak reference to an object should obtain the weakref flag from that object, which is a shared boolean, and before using the pointer to the object it should check if this flag has been set to indicate that the object is no longer alive.

+

Script classes automatically supports weak references without the script writing having to do anything. Application registered types on the other hand must register the behaviour asBEHAVE_GET_WEAKREF_FLAG and implement the logic to set the flag upon destroying the object.

+

The following code shows how to do a thread safe implementation:

+
class MyClass
+
{
+
public:
+
MyClass() { refCount = 1; weakRefFlag = 0; }
+
void AddRef() { asAtomicInc(refCount); }
+
void Release()
+
{
+
// If the weak ref flag exists it is because someone held a weak ref
+
// and that someone may add a reference to the object at any time. It
+
// is ok to check the existance of the weakRefFlag without locking here
+
// because if the refCount is 1 then no other thread is currently
+
// creating the weakRefFlag.
+
if( refCount == 1 && weakRefFlag )
+
{
+
// Set the flag to tell others that the object is no longer alive
+
// We must do this before decreasing the refCount to 0 so we don't
+
// end up with a race condition between this thread attempting to
+
// destroy the object and the other that temporary added a strong
+
// ref from the weak ref.
+
weakRefFlag->Set(true);
+
}
+
+
if( asAtomicDec(refCount) == 0 )
+
delete this;
+
}
+
asILockableSharedBool *GetWeakRefFlag()
+
{
+
if( !weakRefFlag )
+
{
+
// Lock globally so no other thread can attempt
+
// to create a shared bool at the same time
+ +
+
// Make sure another thread didn't create the
+
// flag while we waited for the lock
+
if( !weakRefFlag )
+
weakRefFlag = asCreateLockableSharedBool();
+
+ +
}
+
+
return weakRefFlag;
+
}
+
+
static MyClass *Factory() { return new MyClass(); }
+
+
protected:
+
~MyClass()
+
{
+
// Release the weak reference flag that may still
+
// be accessed by the code that holds a weak reference
+
if( weakRefFlag )
+
weakRefFlag->Release();
+
}
+
+
int refCount;
+
asILockableSharedBool *weakRefFlag;
+
};
+

The asBEHAVE_GET_WEAKREF_FLAG behaviour for this class is registered like this:

+
engine->RegisterObjectType("MyClass", 0, asOBJ_REF);
+
engine->RegisterObjectBehaviour("MyClass", asBEHAVE_ADDREF, "void f()", asMETHOD(MyClass, AddRef), asCALL_THISCALL);
+
engine->RegisterObjectBehaviour("MyClass", asBEHAVE_RELEASE, "void f()", asMETHOD(MyClass, Release), asCALL_THISCALL);
+
engine->RegisterObjectBehaviour("MyClass", asBEHAVE_GET_WEAKREF_FLAG, "int &f()", asMETHOD(MyClass, GetWeakRefFlag), asCALL_THISCALL);
+

The script language doesn't have a built-in syntax for weak references. Instead a standard weakref add-on has been implemented to provide this for the applications that wants to provide this support in the scripts.

+
+
+
+
@ asBEHAVE_RELEASE
Release.
Definition: angelscript.h:368
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
+
AS_API int asAtomicInc(int &value)
Increments the value by one and returns the result as a single atomic instruction.
+
AS_API void asAcquireExclusiveLock()
Acquire an exclusive lock.
+
@ asBEHAVE_GET_WEAKREF_FLAG
Obtain weak ref flag.
Definition: angelscript.h:370
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
AS_API void asReleaseExclusiveLock()
Release an exclusive lock.
+
AS_API int asAtomicDec(int &value)
Decrements the value by one and returns the result as a single atomic instruction.
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
A lockable shared boolean.
Definition: angelscript.h:4077
+
AS_API asILockableSharedBool * asCreateLockableSharedBool()
Create a lockable shared boolean.
+
@ asBEHAVE_ADDREF
AddRef.
Definition: angelscript.h:366
+ + + + diff --git a/docs/manual/doc_advanced.html b/docs/manual/doc_advanced.html new file mode 100644 index 0000000..b59b52b --- /dev/null +++ b/docs/manual/doc_advanced.html @@ -0,0 +1,130 @@ + + + + + + + +AngelScript: Advanced topics + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ + + + + + diff --git a/docs/manual/doc_advanced.js b/docs/manual/doc_advanced.js new file mode 100644 index 0000000..2a8fdba --- /dev/null +++ b/docs/manual/doc_advanced.js @@ -0,0 +1,62 @@ +var doc_advanced = +[ + [ "Debugging scripts", "doc_debug.html", [ + [ "Setting line breaks", "doc_debug.html#doc_debug_1", null ], + [ "Viewing the call stack", "doc_debug.html#doc_debug_2", null ], + [ "Inspecting variables", "doc_debug.html#doc_debug_3", null ], + [ "Debugging internally executed scripts", "doc_debug.html#doc_debug_4", null ] + ] ], + [ "Timeout long running scripts", "doc_adv_timeout.html", [ + [ "With the line callback", "doc_adv_timeout.html#doc_adv_timeout_1", null ], + [ "With a secondary thread", "doc_adv_timeout.html#doc_adv_timeout_2", null ] + ] ], + [ "Garbage collection", "doc_gc.html", [ + [ "Callback for detected circular references", "doc_gc.html#doc_gc_circcallback", null ], + [ "Garbage collection and multi-threading", "doc_gc.html#doc_gc_threads", null ] + ] ], + [ "Multithreading", "doc_adv_multithread.html", [ + [ "Things to think about with a multithreaded environment", "doc_adv_multithread.html#doc_adv_multithread_1", null ], + [ "Fibers", "doc_adv_multithread.html#doc_adv_fibers", null ] + ] ], + [ "Concurrent scripts", "doc_adv_concurrent.html", null ], + [ "Co-routines", "doc_adv_coroutine.html", null ], + [ "Dynamic compilations", "doc_adv_dynamic_build.html", [ + [ "On demand builds", "doc_adv_dynamic_build.html#doc_adv_dynamic_build_ondemand", null ], + [ "Incremental builds", "doc_adv_dynamic_build.html#doc_adv_dynamic_build_incr", null ], + [ "Hot reloading scripts", "doc_adv_dynamic_build.html#doc_adv_dynamic_build_hot", [ + [ "Things to consider", "doc_adv_dynamic_build.html#doc_adv_dynamic_build_hot_1", null ] + ] ] + ] ], + [ "Pre-compiled byte code", "doc_adv_precompile.html", [ + [ "Things to remember", "doc_adv_precompile.html#doc_adv_precompile_1", null ] + ] ], + [ "Fine tuning", "doc_finetuning.html", [ + [ "Cache the functions and types", "doc_finetuning.html#doc_finetuning_1", null ], + [ "Reuse the context object", "doc_finetuning.html#doc_finetuning_2", [ + [ "Context pool", "doc_finetuning.html#doc_finetuning_2_1", null ], + [ "Nested calls", "doc_finetuning.html#doc_finetuning_2_2", null ] + ] ], + [ "Compile scripts without line cues", "doc_finetuning.html#doc_finetuning_3", null ], + [ "Disable thread safety", "doc_finetuning.html#doc_finetuning_4", null ], + [ "Turn off automatic garbage collection", "doc_finetuning.html#doc_finetuning_5", null ], + [ "Compare native calling convention versus generic calling convention", "doc_finetuning.html#doc_finetuning_6", null ] + ] ], + [ "Access masks and exposing different interfaces", "doc_adv_access_mask.html", null ], + [ "Using namespaces", "doc_adv_namespace.html", [ + [ "Registering the interface with namespaces", "doc_adv_namespace.html#doc_adv_namespace_reg", null ], + [ "Finding entities in namespaces", "doc_adv_namespace.html#doc_adv_namespace_enum", null ] + ] ], + [ "Dynamic configurations", "doc_adv_dynamic_config.html", null ], + [ "Custom options", "doc_adv_custom_options.html", [ + [ "Registerable types", "doc_adv_custom_options.html#doc_adv_custom_options_reg_types", null ], + [ "Language modifications", "doc_adv_custom_options.html#doc_adv_custom_options_lang_mod", null ], + [ "Engine behaviours", "doc_adv_custom_options.html#doc_adv_custom_options_engine", null ] + ] ], + [ "Reflection", "doc_adv_reflection.html", [ + [ "Enumerating variables and properties", "doc_adv_reflection.html#doc_adv_reflection_vars", null ], + [ "Enumerating functions and methods", "doc_adv_reflection.html#doc_adv_reflection_funcs", null ], + [ "Enumerating types", "doc_adv_reflection.html#doc_adv_reflection_types", null ] + ] ], + [ "Inheriting from application registered class", "doc_adv_inheritappclass.html", null ], + [ "JIT compilation", "doc_adv_jit_topic.html", "doc_adv_jit_topic" ] +]; \ No newline at end of file diff --git a/docs/manual/doc_advanced_api.html b/docs/manual/doc_advanced_api.html new file mode 100644 index 0000000..27c0c24 --- /dev/null +++ b/docs/manual/doc_advanced_api.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Advanced application interface + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ + + + + + diff --git a/docs/manual/doc_advanced_api.js b/docs/manual/doc_advanced_api.js new file mode 100644 index 0000000..5ace9e3 --- /dev/null +++ b/docs/manual/doc_advanced_api.js @@ -0,0 +1,43 @@ +var doc_advanced_api = +[ + [ "Custom string type", "doc_strings.html", [ + [ "Registering the custom string type", "doc_strings.html#doc_string_register", null ], + [ "Unicode vs ASCII", "doc_strings.html#doc_strings_1", null ], + [ "Multiline string literals", "doc_strings.html#doc_string_2", null ], + [ "Character literals", "doc_strings.html#doc_string_3", null ] + ] ], + [ "Custom array type", "doc_arrays.html", null ], + [ "Garbage collected objects", "doc_gc_object.html", [ + [ "GC support behaviours", "doc_gc_object.html#doc_reg_gcref_1", null ], + [ "Factory for garbage collection", "doc_gc_object.html#doc_reg_gcref_2", null ], + [ "Addref and release for garbage collection", "doc_gc_object.html#doc_reg_gcref_3", null ], + [ "GC behaviours for value types", "doc_gc_object.html#doc_reg_gcref_value", null ], + [ "Garbage collected objects and multi-threading", "doc_gc_object.html#doc_reg_gcref_4", null ] + ] ], + [ "The generic calling convention", "doc_generic.html", [ + [ "Extracting function arguments", "doc_generic.html#doc_generic_1", null ], + [ "Returning values", "doc_generic.html#doc_generic_2", null ] + ] ], + [ "Registering a generic handle type", "doc_adv_generic_handle.html", null ], + [ "Registering a scoped reference type", "doc_adv_scoped_type.html", null ], + [ "Registering a single-reference type", "doc_adv_single_ref_type.html", null ], + [ "Class hierarchies", "doc_adv_class_hierarchy.html", [ + [ "Establishing the relationship", "doc_adv_class_hierarchy.html#doc_adv_class_hierarchy_1", null ], + [ "Inherited methods and properties", "doc_adv_class_hierarchy.html#doc_adv_class_hierarchy_2", null ] + ] ], + [ "The variable parameter type", "doc_adv_var_type.html", [ + [ "Variable conversion operators", "doc_adv_var_type.html#doc_adv_var_type_1", null ] + ] ], + [ "Template types", "doc_adv_template.html", [ + [ "Registering the template type", "doc_adv_template.html#doc_adv_template_1", [ + [ "On subtype replacement for template instances", "doc_adv_template.html#doc_adv_template_1_1", null ] + ] ], + [ "Validating template instantiations at compile time", "doc_adv_template.html#doc_adv_template_4", null ], + [ "Template specializations", "doc_adv_template.html#doc_adv_template_2", null ] + ] ], + [ "Weak references", "doc_adv_weakref.html", null ], + [ "C++ exceptions and longjmp", "doc_cpp_exceptions.html", [ + [ "Exceptions", "doc_cpp_exceptions.html#doc_cpp_exceptions_1", null ], + [ "longjmp", "doc_cpp_exceptions.html#doc_cpp_exceptions_2", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_api.html b/docs/manual/doc_api.html new file mode 100644 index 0000000..267561c --- /dev/null +++ b/docs/manual/doc_api.html @@ -0,0 +1,120 @@ + + + + + + + +AngelScript: The API reference + + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
The API reference
+
+
+

This is the reference documentation for the AngelScript application programming interface.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_api.js b/docs/manual/doc_api.js new file mode 100644 index 0000000..751b9c9 --- /dev/null +++ b/docs/manual/doc_api.js @@ -0,0 +1,14 @@ +var doc_api = +[ + [ "Functions", "doc_api_functions.html", [ + [ "Principal functions", "doc_api_functions.html#doc_api_funcs_1", null ], + [ "Multithread support", "doc_api_functions.html#doc_api_funcs_2", null ], + [ "Custom memory management", "doc_api_functions.html#doc_api_funcs_3", null ], + [ "Auxiliary functions", "doc_api_functions.html#doc_api_funcs_4", null ] + ] ], + [ "Interfaces", "doc_api_interfaces.html", [ + [ "Principal interfaces", "doc_api_interfaces.html#doc_api_intf_1", null ], + [ "Secondary interfaces", "doc_api_interfaces.html#doc_api_intf_2", null ], + [ "Auxiliary interfaces", "doc_api_interfaces.html#doc_api_intf_3", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_api_functions.html b/docs/manual/doc_api_functions.html new file mode 100644 index 0000000..12159dd --- /dev/null +++ b/docs/manual/doc_api_functions.html @@ -0,0 +1,145 @@ + + + + + + + +AngelScript: Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ + + + + + diff --git a/docs/manual/doc_api_interfaces.html b/docs/manual/doc_api_interfaces.html new file mode 100644 index 0000000..e9fbc4d --- /dev/null +++ b/docs/manual/doc_api_interfaces.html @@ -0,0 +1,134 @@ + + + + + + + +AngelScript: Interfaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Interfaces
+
+ +
+
+ + + + diff --git a/docs/manual/doc_arrays.html b/docs/manual/doc_arrays.html new file mode 100644 index 0000000..6fd5c28 --- /dev/null +++ b/docs/manual/doc_arrays.html @@ -0,0 +1,115 @@ + + + + + + + +AngelScript: Custom array type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Custom array type
+
+
+

Like the string type, AngelScript doesn't have a built-in dynamic array type. Instead the application developers that wishes to allow dynamic arrays in the scripts should register this in the way that is best suited for the application. To save time a readily usable add-on is provided with a fully implemented dynamic array type.
+

+

If you wish to create your own array type, you'll need to understand how template types work. A template type is a special form of registering a type that the engine can then use to instanciate the true types based on the desired sub-types. This allow a single type registration to cover all possible array types that the script may need, instead of the application having to register a specific type for each type of array.

+

Of course, a generic type like this will have a drawback in performance due to runtime checks to determine the actual type, so the application should consider registering template specializations of the most common array types. This will allow the best optimizations for those types, and will also permit better interaction with the application as the template specialization can better match the actual array types that the application uses.

+
+
+
+ + + + diff --git a/docs/manual/doc_as_vs_cpp_types.html b/docs/manual/doc_as_vs_cpp_types.html new file mode 100644 index 0000000..f8481fd --- /dev/null +++ b/docs/manual/doc_as_vs_cpp_types.html @@ -0,0 +1,187 @@ + + + + + + + +AngelScript: Datatypes in AngelScript and C++ + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Datatypes in AngelScript and C++
+
+
+

+Primitives

+

Primitives in AngelScript have direct matches in C++.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
AngelScriptC++Size (bits)
void void 0
int8 signed char 8
int16 signed short 16
int signed int (*) 32
int64 signed int64_t 64
uint8 unsigned char 8
uint16unsigned short 16
uint unsigned int (*) 32
uint64unsigned uint64_t 64
float float 32
doubledouble 64
bool bool 8 (**)
+

(*) An int can actually be of varying size on different platforms in C++, but most commonly it is 32 bits long. AngelScript will always assume 32 bits though.

+

(**) On 32 bit PowerPC platforms the bool type commonly have the size of 32 bit, when compiled on such platforms AngelScript also uses 32 bits for the bool type

+

+Strings

+

AngelScript expects the application to register its own string type, so the string types should match perfectly.

+

The char* string type that is so convenient in C++ is however very difficult to use in a scripted environment where you do not have full control over how it is used. For that reason it is recommended that you wrap any functions that use the char* string type so that the string is properly converted to an object that can be safely handled by both the application and the script engine, e.g. std::string or another class of your preference.

+

+Arrays

+

AngelScript also expects the application to register the type that should be used for dynamic arrays. Normally this is done by registering the array template object add-on, but the application is free to do it differently.

+

It is also possible to have different object types for different array types, so the application can match the array type exactly with the types used in C++.

+

+Object handles

+

The AngelScript object handles are reference counted pointers to objects. This means that for object handles to work, the object must have some way of counting references, for example an AddRef/Release method pair.

+

When AngelScript passes an object handle by value to a function it increases the reference count to count for the argument instance, thus the function is responsible for releasing the reference once it is finished with it. In the same manner AngelScript expects any handle returned from a function to already have the reference accounted for.

+

However, when registering functions/methods with AngelScript the application can tell the library that it should automatically take care of releasing the handle references once a function return, likewise for returned handles. This is done by adding a + sign to the @ type modifier. When doing this an object handle can be safely passed to a C++ function that expects a normal pointer, but don't release it afterwards.

+
See also
Object handles to the application
+

+Script classes and interfaces

+

All script classes and interfaces are seen as the asIScriptObject type by the application. The asIScriptObject interface has methods to determine the actual type of the script class or interface, as well as to interact with the actual object instance.

+
See also
Using script classes
+

+Function pointers

+

All script function pointers are seen as the asIScriptFunction type by the application. The asIScriptFunction type has methods to obtain the name of the function and the parameter and return types, etc.

+

+Parameter references

+

Because AngelScript needs to guarantee validity of pointers at all times, it doesn't always pass references to the true object to the function parameter. Instead it creates a copy of the object, whose reference is passed to the function, and if the reference is marked to return a value, the clone is copied back to the original object (if it still exists) once the function returns.

+

Because of this, AngelScript's parameter references are mostly compatible with C++ references, or pointers, except that the address normally shouldn't be stored for later use, since the object may be destroyed once the function returns.

+

If it is necessary to store the address of the object, then object handles should be used instead.

+ + + + + + + + + + + + + + + +
ReferenceDescription
&inA copy of the value is always taken and the reference to the copy is passed to the function. For script functions this is not useful, but it is maintained for compatibility with application registered functions.
const &inIf the life time of the value can be guaranteed to be valid during the execution of the function, the reference to the true object is passed to the function, otherwise a copy is made.
&outA reference to an unitialized value is passed to the function. When the function returns the value is copied to the true reference. The argument expression is evaluated only after the function call. This is the best way to have functions return multiple values.
const &outUseless as the function wouldn't be able to modify the value.
&inoutThe true reference is always passed to the function. Only objects that support object handles can be used with this type as they can always be guaranteed to stay alive during the call.
const &inoutThe referred to object will be read-only.
+

If the application wants parameter references that work like they do in C++, then this can be allowed by setting an engine property.

+
+
+
+ + + + diff --git a/docs/manual/doc_call_script_func.html b/docs/manual/doc_call_script_func.html new file mode 100644 index 0000000..450c9b4 --- /dev/null +++ b/docs/manual/doc_call_script_func.html @@ -0,0 +1,251 @@ + + + + + + + +AngelScript: Calling a script function + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Calling a script function
+
+
+

+Preparing context and executing the function

+

Normally a script function is executed in a few steps:

+
    +
  1. +Prepare the context
  2. +
  3. +Set the function arguments
  4. +
  5. +Execute the function
  6. +
  7. +Retrieve the return value
  8. +
+

The code for this might look something like this:

+
// Get a script context instance. Usually you'll want to reuse a previously
+
// created instance to avoid the overhead of allocating the instance with
+
// each call.
+ +
+
// Obtain the function from the module. This should preferrably
+
// be cached if the same function is called multiple times.
+
asIScriptFunction *func = engine->GetModule(module_name)->GetFunctionByDecl(function_declaration);
+
+
// Prepare() must be called to allow the context to prepare the stack
+
ctx->Prepare(func);
+
+
// Set the function arguments
+
ctx->SetArgDWord(...);
+
+
int r = ctx->Execute();
+ +
{
+
// The return value is only valid if the execution finished successfully
+
asDWORD ret = ctx->GetReturnDWord();
+
}
+
+
// Release the context when you're done with it
+
ctx->Release();
+

If your application allows the execution to be suspended, either by using the callback function or registering a function that allow the script to manually suspend the execution, then the execution function may return before finishing with the return code asEXECUTION_SUSPENDED. In that case you can later resume the execution by simply calling the execution function again.

+

Note that the return value retrieved with GetReturnValue() is only valid if the script function returned successfully, i.e. if Execute() returned asEXECUTION_FINISHED.

+

+Passing and returning primitives

+

When calling script functions that take arguments, the values of these arguments must be set after the call to Prepare() and before Execute(). The arguments are set using a group of SetArg methods:

+
int SetArgDWord(int arg, asDWORD value);
+
int SetArgQWord(int arg, asQWORD value);
+
int SetArgFloat(int arg, float value);
+
int SetArgDouble(int arg, double value);
+
int SetArgByte(int arg, asBYTE value);
+
int SetArgWord(int arg, asWORD value);
+

arg is the argument number, where the first argument is on 0, the second on 1, and so on. value is the value of the argument. What method to use is determined by the type of the parameter. For primitive types you can use any of these. If the parameter type is a reference to a primitive type it is recommended to use the SetArgAddress() method and pass the pointer as the value. For non-primitive types the method SetArgObject() should be used, which will be described in the next section.

+
// The context has been prepared for a script
+
// function with the following signature:
+
// int function(int, double, bool, int &out)
+
+
// Put the arguments on the context stack, starting with the first one
+
ctx->SetArgDWord(0, 1);
+
ctx->SetArgDouble(1, 3.141592);
+
ctx->SetArgByte(2, true);
+
int val;
+
ctx->SetArgAddress(3, &val);
+

Once the script function has been executed the return value is retrieved in a similar way using the group of GetReturn methods:

+
asDWORD GetReturnDWord();
+
asQWORD GetReturnQWord();
+
float GetReturnFloat();
+
double GetReturnDouble();
+
asBYTE GetReturnByte();
+
asWORD GetReturnWord();
+

Note that you must make sure the returned value is in fact valid, for example if the script function was interrupted by a script exception the value would not be valid. You do this by verifying the return code from Execute() or GetState(), where the return code should be asEXECUTION_FINISHED.

+

+Passing and returning objects

+

Passing registered object types to a script function is done in a similar way to how primitive types are passed. The function to use is SetArgObject():

+
int SetArgObject(int arg, void *object);
+

arg is the argument number, just like the other SetArg methods. object is a pointer to the object you wish to pass.

+

This same method is used both for parameters passed by value and for those passed by reference. The library will automatically make a copy of the object if the parameter is defined to be passed by value.

+
// The complex object we wish to pass to the script function
+
CObject obj;
+
+
// Pass the object to the function
+
ctx->SetArgObject(0, &obj);
+

Getting an object returned by a script function is done in a similar way, using GetReturnObject():

+
void *GetReturnObject();
+

This method will return a pointer to the object returned by the script function. The library will still hold a reference to the object, which will only be freed as the context is released.

+
// The object where we want to store the return value
+
CObject obj;
+
+
// Execute the function
+
int r = ctx->Execute();
+ +
{
+
// Get a pointer to the returned object and copy it to our object
+
obj = *(CObject*)ctx->GetReturnObject();
+
}
+

It is important to make a copy of the returned object, or if it is managed by reference counting add a reference to it. If this is not done the pointer obtained with GetReturnObject() will be invalidated as the context is released, or reused for another script function call.

+

+Exception handling

+

If the script performs an illegal action, e.g. calling a method on a null handle, then the script engine will throw a script exception. The virtual machine will then abort the execution and the Execute method will return with the value asEXECUTION_EXCEPTION.

+

At this time it is possible to obtain information about the exception through the asIScriptContext's methods. Example:

+
void PrintExceptionInfo(asIScriptContext *ctx)
+
{
+
asIScriptEngine *engine = ctx->GetEngine();
+
+
// Determine the exception that occurred
+
printf("desc: %s\n", ctx->GetExceptionString());
+
+
// Determine the function where the exception occurred
+
const asIScriptFunction *function = ctx->GetExceptionFunction();
+
printf("func: %s\n", function->GetDeclaration());
+
printf("modl: %s\n", function->GetModuleName());
+
printf("sect: %s\n", function->GetScriptSectionName());
+
+
// Determine the line number where the exception occurred
+
printf("line: %d\n", ctx->GetExceptionLineNumber());
+
}
+

If desired, it is also possible to register a callback function that will be called at the moment the exception occurred, before the Execute method returns. The exception callback can then use WillExceptionBeCaught to determine if the exception will be caught within the script or if it will abort the execution.

+
See also
Debugging scripts for information on examining the callstack, and GetExceptionInfo for a helper function to get information on exceptions.
+
+
+
+
virtual int SetArgAddress(asUINT arg, void *addr)=0
Sets the address of a reference or handle argument.
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual int GetExceptionLineNumber(int *column=0, const char **sectionName=0)=0
Returns the line number where the exception occurred.
+
unsigned long asDWORD
32 bit unsigned integer
Definition: angelscript.h:614
+
virtual asIScriptFunction * GetFunctionByDecl(const char *decl) const =0
Returns the function by its declaration.
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
virtual int Execute()=0
Executes the prepared function.
+
virtual int SetArgDouble(asUINT arg, double value)=0
Sets a double argument value.
+
virtual void * GetReturnObject()=0
Return a pointer to the returned object.
+
unsigned char asBYTE
8 bit unsigned integer
Definition: angelscript.h:598
+
The engine interface.
Definition: angelscript.h:1092
+
virtual const char * GetExceptionString()=0
Returns the exception string text.
+
virtual asIScriptEngine * GetEngine() const =0
Returns a pointer to the engine.
+
@ asEXECUTION_FINISHED
The context has successfully completed the execution.
Definition: angelscript.h:398
+
unsigned __int64 asQWORD
64 bit unsigned integer
Definition: angelscript.h:619
+
virtual int SetArgObject(asUINT arg, void *obj)=0
Sets the object argument value.
+
virtual asIScriptContext * CreateContext()=0
Creates a new script context.
+
virtual int SetArgByte(asUINT arg, asBYTE value)=0
Sets an 8-bit argument value.
+
The interface for a script function description.
Definition: angelscript.h:3823
+
virtual asIScriptFunction * GetExceptionFunction()=0
Returns the function where the exception occurred.
+
virtual int SetArgDWord(asUINT arg, asDWORD value)=0
Sets a 32-bit integer argument value.
+
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
+
virtual asDWORD GetReturnDWord()=0
Returns the 32-bit return value.
+
unsigned short asWORD
16 bit unsigned integer
Definition: angelscript.h:599
+
virtual int Release() const =0
Decrease reference counter.
+ + + + diff --git a/docs/manual/doc_callbacks.html b/docs/manual/doc_callbacks.html new file mode 100644 index 0000000..0255cb0 --- /dev/null +++ b/docs/manual/doc_callbacks.html @@ -0,0 +1,207 @@ + + + + + + + +AngelScript: Funcdefs and script callback functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Funcdefs and script callback functions
+
+
+

Funcdefs are used to define a function signature for callbacks. This funcdef is then used to declare variables or function parameters that can hold handles to functions of matching signature.

+

The application can also register funcdefs as part of the application interface if the intention is for the script to set callbacks that will be called from the application. Once this is done, the application can receive the function handles as an asIScriptFunction pointer which can then be executed normally.

+

+An example

+

Let's say the application needs to allow the script to set a callback that will then be called at some event. To do this the application would first register the funcdef that defines the signature of the callback. Then it needs to register the function that will be used to set the callback from the script.

+
// Register a simple funcdef for the callback
+
engine->RegisterFuncdef("void CallbackFunc()");
+
+
// Register a function for setting the callback
+
engine->RegisterGlobalFunction("void SetCallback(CallbackFunc @cb)", asFUNCTION(SetCallback), asCALL_CDECL);
+

With this interface, the script would be able to inform the callback like this:

+
+  void main()
+  {
+    // Tell the application what script function to call
+    SetCallback(MyCallback);
+  }
  // The signature matches the registered CallbackFunc funcdef
+  void MyCallback()
+  {
+    ...
+  }
+

The implementation for the SetCallback function might look something like this.

+
// The callback is a script function.
+
// Don't forget to release this before cleaning up the engine.
+
asIScriptFunction *callback = 0;
+
+
void SetCallback(asIScriptFunction *cb)
+
{
+
// Release the previous callback, if any
+
if( callback )
+
callback->Release();
+
+
// Store the received handle for later use
+
callback = cb;
+
+
// Do not release the received script function
+
// until it won't be used any more
+
}
+

To call the actual callback when it is time, the application uses the script context just like for any other call to a script function.

+

+Delegates

+

Of course, callbacks can be used with delegates as well. Delegates are special function objects that holds a reference to an object and the method it should call on it. If this is exactly how the application should treat them, then the above example will work exactly the same and the application never needs to worry about whether the callback is actually a global function or a delegate object.

+

Sometimes however, it may be beneficial to break up the delegate, and have the application store the actual object and method separately, for example if the application should use a weak reference to avoid keeping the object alive longer than desired. The following shows how to retrieve the internals of the delegate:

+
// The callback, and accompanying object, if the callback is a class method
+
asIScriptFunction *callback = 0;
+
void *callbackObject = 0;
+
asITypeInfo *callbackObjectType = 0;
+
+
void SetCallback(asIScriptFunction *cb)
+
{
+
// Release the previous callback, if any
+
if( callback )
+
callback->Release();
+
if( callbackObject )
+
engine->ReleaseScriptObject(callbackObject, callbackObjectType);
+
callback = 0;
+
callbackObject = 0;
+
callbackObjectType = 0;
+
+
if( cb && cb->GetFuncType() == asFUNC_DELEGATE )
+
{
+
callbackObject = cb->GetDelegateObject();
+
callbackObjectType = cb->GetDelegateObjectType();
+
callback = cb->GetDelegateFunction();
+
+
// Hold on to the object and method
+
engine->AddRefScriptObject(callbackObject, callbackObjectType);
+
callback->AddRef();
+
+
// Release the delegate, since it won't be used anymore
+
cb->Release();
+
}
+
else
+
{
+
// Store the received handle for later use
+
callback = cb;
+
+
// Do not release the received script function
+
// until it won't be used any more
+
}
+
}
+
+
+
+
virtual void ReleaseScriptObject(void *obj, const asITypeInfo *type)=0
Release the object pointer.
+
virtual int AddRef() const =0
Increases the reference counter.
+
virtual int Release() const =0
Decrease reference counter.
+
virtual int RegisterFuncdef(const char *decl)=0
Registers a function definition.
+
virtual asITypeInfo * GetDelegateObjectType() const =0
Returns the type of the delegated object.
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual asIScriptFunction * GetDelegateFunction() const =0
Returns the function for the delegate.
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
virtual void * GetDelegateObject() const =0
Returns the object for the delegate.
+
The interface for a script function description.
Definition: angelscript.h:3823
+
virtual void AddRefScriptObject(void *obj, const asITypeInfo *type)=0
Increase the reference counter for the script object.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
@ asFUNC_DELEGATE
A function delegate.
Definition: angelscript.h:557
+
virtual asEFuncType GetFuncType() const =0
Returns the type of the function.
+ + + + diff --git a/docs/manual/doc_compile_lib.html b/docs/manual/doc_compile_lib.html new file mode 100644 index 0000000..97fe974 --- /dev/null +++ b/docs/manual/doc_compile_lib.html @@ -0,0 +1,229 @@ + + + + + + + +AngelScript: Compile the library + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Compile the library
+
+
+

In the sdk/angelscript/projects directory you'll find project files for many of the popular compilers. However, these project files are not always up to date with the latest version of the library. If you get any compiler or linker errors please make sure the project file include all the files in the sdk/angelscript/source directory, and that the project settings are set according to this article.

+

If you don't find a project file for your compiler, you can easily create your own project by adding all the files in the sdk/angelscript/source directory, and configuring the project apropriately. If you have a new compiler/target that hasn't been used with AngelScript before, you may need to edit the as_config.h file to make sure the library is compiled properly.

+
See also
Considerations for specific platforms
+

+Set compile time options

+

The code tries to contain compiler differences in as few places as possible. The header as_config.h was created for that purpose. There you will find some #defines that allow different compilers to work. You'll probably not have to change this file, but if you're using a compiler not previously used and you're getting compiler errors it might be worth it to take a look at this file.

+

There are also a couple of other #defines used in the code to alter the compilation. When compiling the library you might want to define ANGELSCRIPT_EXPORT so that library functions are exported. If you include the library source code directly in your application project you shouldn't have to define this flag.

+

If AS_DEPRECATED is defined then some backwards compatibility is maintained, this can help you do the upgrade to the latest version a little more smoothly. There is no guarantee that the backwards compatibility will be maintained though so try to remove use of deprecated functions as soon as possible.

+

+Linking with the library

+

There are four ways of compiling and linking with AngelScript in order to use it. I recommend linking with a static library. Note that all four ways are interchangable with only a small change in your code, i.e a defined flag before including the header file, and possibly a routine for manually loading the dll. The rest of your code should look exactly the same for each of the alternatives.

+

+1. Include library source files in project

+

You can take the source files for AngelScript and include them directly in your own project. The advantage of this is that you can be sure that the same compiler options are used for the library and the host applications, e.g. multi-threaded or single-threaded CRT. The disadvantage is that your project will be poluted with the library files.

+

The files that need to use the library should include the angelscript.h header with no need for any special settings.

+
// Include the library interface
+
#include "angelscript.h"
+
+
// ... Start using the library
+

+2. Compile a static library and link into project

+

The most recommended way is to compile a static library that your project will link with. When compiling the static library you have to make sure that the correct compiler settings are used so that you don't get conflicts in linkage with the CRT functions. This happens if you for example compile the library with dynamically linked multi-threaded CRT and your application with statically linked single-threaded CRT. (For Visual C++ you'll find these settings under Project -> Settings -> C/C++ -> Category: Code Generation)

+

To use the library you only need to include the angelscript.h header file.

+
// Include the library interface
+
#include "angelscript.h"
+
+
// ... Start using the library
+

+3. Compile a dynamically loaded library with an import library

+

With Microsoft Visual C++ it is possible to compile a dynamically loaded library with an import library. The import library will then take care of the work needed to load the dll and bind the functions. A possible disadvantage of this method is that you are not able to give any user-friendly error messages in case loading the library fails.

+

To use the library you'll have to define ANGELSCRIPT_DLL_LIBRARY_IMPORT before including the angelscript.h header file.

+
// Include the library interface
+
#define ANGELSCRIPT_DLL_LIBRARY_IMPORT
+
#include "angelscript.h"
+
+
// ... Start using the library
+

+4. Load the dynamically loaded library manually

+

If you want to use a dll, e.g. to share code between applications, I recommend loading the library manually as you can treat any failures to load or bind functions graciously.

+

To use manually loaded dll, you should define ANGELSCRIPT_DLL_MANUAL_IMPORT before including the angelscript.h header file. This will insure that the header file doesn't declare the function prototypes, as you will most likely want to use these names for the function pointers.

+
// Include the library interface
+
#define ANGELSCRIPT_DLL_MANUAL_IMPORT
+
#include "angelscript.h"
+
+
// Declare the function pointers
+
typedef asIScriptEngine * AS_CALL t_asCreateScriptEngine(int);
+
t_asCreateScriptEngine *asCreateScriptEngine = 0;
+
+
// ... Declare the rest of the functions
+
+
// Load the dll and bind the functions (error handling left out for clarity)
+
HMODULE dll = LoadLibrary("angelscript.dll");
+
asCreateScriptEngine = (t_asCreateScriptEngine*)GetProcAddress(dll, "_asCreateScriptEngine");
+
+
// ... Bind the other functions
+
+
// ... Start using the library
+

+Considerations for specific platforms

+

As mentioned before, for most platforms the compilation of the library is as easy as including all source files and compiling them. However, on some platforms specific actions needs to be performed to compile the library correctly.

+

+Windows 64bit

+

The MSVC compiler doesn't support inline assembler for the x86 64bit CPU family. To support this platform a separate assembler file has been created: as_callfunc_x64_msvc_asm.asm.

+

To compile this file it is necessary to configure a custom build command with the following:

+
ml64.exe /c /nologo /Fo$(OutDir)\as_callfunc_x64_msvc_asm.obj /W3 /Zi /Ta $(InputDir)\$(InputFileName)
+

+Microsoft Visual C++

+

While AngelScript doesn't use Microsoft's language extensions you may still face trouble compiling the library if you disable the language extensions. This is because Microsoft's own SDK may have code that relies on the language extensions, e.g. in version 6.0a you might get compiler errors due to the existance of $ in the macro definitions in the specstrings.h header from the Platform SDK. This particular problem was fixed by Microsoft in version 6.1 of their SDK, but there may be others so it might just easier to leave the language extensions turned on.

+

+GNUC based compilers

+

In order to properly intergrate with C++ without the need for wrappers AngelScript uses a lot of pointer casts. Unfortunately it is not possible to always guarantee strict aliasing because of this, so on GNUC based compilers it is necessary to disable compiler optimizations that assume strict aliasing.

+

Use the following compiler argument to disable this:

+
-fno-strict-aliasing
+

+Pocket PC with ARM CPU

+

The MSVC compiler doesn't support inline assembler for the ARM CPU, so a separate assembler file has been written with this code: as_callfunc_arm_msvc.asm.

+

In order to compile this file properly it is necessary to configure a custom build command with the following:

+
armasm -g $(InputPath)
+

+Marmalade

+

Marmalade is a cross platform SDK created with mobile devices in mind. It functions by abstracting the underlying OS with its own C runtime library even though it uses the common C++ compilers, e.g. MSVC on Windows, and GNUC on Linux and Mac.

+

When compiling AngelScript with Marmalade for iOS and Android scons must be used in order to properly compile the native ARM assembler routines. For Windows Phone you should be able to use MSVC normally.

+

+Size of the library

+

The size of the library depends on many different factors, such as compiler brand, compiler flags, and also what features of AngelScript that are included. However, to give an idea of how much space the library will take up on the disk and memory I've compiled the asrun sample in a few different ways and noted down the size.

+ + + + + + + + + + + + + + + + + + + +
OptionsSize of binary on disk
32 bit / multithreaded dll / optimize for speed
+Without including AngelScript
14KB
32 bit / multithreaded dll / optimize for speed
+Using AngelScript and add-ons
796KB
32 bit / multithreaded dll / optimize for speed
+AngelScript without compiler (AS_NO_COMPILER) and add-ons
453KB
32 bit / multithreaded static / optimize for speed
+Using AngelScript but without add-ons
867KB
32 bit / multithreaded static / optimize for speed
+Using AngelScript and add-ons
1015KB
64 bit / multithreaded static / optimize for speed
+Using AngelScript and add-ons
1336KB
32 bit / multithreaded static / optimize for size
+Using AngelScript and add-ons
797KB
32 bit / multithreaded dll / optimize for size
+Using AngelScript and add-ons
582KB
+

Based on this we can draw the conclusion that the engine and VM takes up about 300KB when optimized for speed, the compiler adds another 350KB, and the add-ons yet another 150KB.

+
Note
These tests were made with MSVC 2012 and version 2.30.2 of the library.
+
+
+
+
The engine interface.
Definition: angelscript.h:1092
+
AS_API asIScriptEngine * asCreateScriptEngine(asDWORD version=ANGELSCRIPT_VERSION)
Creates the script engine.
+
The API definition for AngelScript.
+ + + + diff --git a/docs/manual/doc_compile_script.html b/docs/manual/doc_compile_script.html new file mode 100644 index 0000000..782a15a --- /dev/null +++ b/docs/manual/doc_compile_script.html @@ -0,0 +1,187 @@ + + + + + + + +AngelScript: Compiling scripts + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Compiling scripts
+
+
+

After registering the application interface it's time to compile the scripts that will be executed.

+

+Message callback

+

Before starting the compilation, remember to have the message callback set in the engine so that you can get more information on compilation errors than just an error code. In fact, it is recommended to set the message callback right after creating the script engine, as the message callback may even be helpful while registering the application interface.

+

The message callback has been designed so that it doesn't output anything if there are no errors or warnings, so when everything is ok, you shouldn't get anything from it. But if the Build method returns an error, the message callback will have received detailed information about the error.

+

If desired, the application may send its own messages to the callback via the WriteMessage method on the engine.

+
// Implement a simple message callback function
+
void MessageCallback(const asSMessageInfo *msg, void *param)
+
{
+
const char *type = "ERR ";
+
if( msg->type == asMSGTYPE_WARNING )
+
type = "WARN";
+
else if( msg->type == asMSGTYPE_INFORMATION )
+
type = "INFO";
+
printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message);
+
}
+
+
// Set the message callback when creating the engine
+ +
engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL);
+

+Loading and compiling scripts

+

To build a script module you first obtain a module from the engine, then add the script sections, and finally compile them. A compiled script module may be composed of one or more script sections, so your application may store each section in different files, or even generate them dynamically. It doesn't matter in which order the script sections are added to the module, as the compiler is able to resolve all names regardless of where they are declared in the script.

+
// Create a new script module
+
asIScriptModule *mod = engine->GetModule("module", asGM_ALWAYS_CREATE);
+
+
// Load and add the script sections to the module
+
string script;
+
LoadScriptFile("script.as", script);
+
mod->AddScriptSection("script.as", script.c_str());
+
+
// Build the module
+
int r = mod->Build();
+
if( r < 0 )
+
{
+
// The build failed. The message stream will have received
+
// compiler errors that shows what needs to be fixed
+
}
+

AngelScript doesn't provide built-in functions for loading script files as most applications have their own way of loading files. However, it is quite easy to write your own routines for loading script files, for example:

+
// Load the entire script file into a string buffer
+
void LoadScriptFile(const char *fileName, string &script)
+
{
+
// Open the file in binary mode
+
FILE *f = fopen("test.as", "rb");
+
+
// Determine the size of the file
+
fseek(f, 0, SEEK_END);
+
int len = ftell(f);
+
fseek(f, 0, SEEK_SET);
+
+
// Load the entire file in one call
+
script.resize(len);
+
fread(&script[0], len, 1, f);
+
+
fclose(f);
+
}
+

As AngelScript doesn't load the files itself, it also doesn't have built-in support for including other files from within the script. However, if you look in the add-on directory, you'll find a CScriptBuilder class that provides this support and more. It is a helper class for loading files, perform a pre-processing pass, and then building the module. You can a see an example of how to use the script builder in Your first script.

+
See also
Pre-compiled byte code
+
+
+
+
int col
The column.
Definition: angelscript.h:773
+
@ asMSGTYPE_INFORMATION
The message is informational only.
Definition: angelscript.h:424
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
@ asGM_ALWAYS_CREATE
Always create a new module, discarding the existing one.
Definition: angelscript.h:528
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv)=0
Sets a message callback that will receive compiler messages.
+
int row
The row number.
Definition: angelscript.h:771
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
AS_API asIScriptEngine * asCreateScriptEngine(asDWORD version=ANGELSCRIPT_VERSION)
Creates the script engine.
+
const char * section
The script section where the message is raised.
Definition: angelscript.h:769
+
@ asMSGTYPE_WARNING
The message is a warning.
Definition: angelscript.h:422
+
The interface to the script modules.
Definition: angelscript.h:2218
+
virtual int Build()=0
Build the previously added script sections.
+
virtual int AddScriptSection(const char *name, const char *code, size_t codeLength=0, int lineOffset=0)=0
Add a script section for the next build.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
const char * message
The message text.
Definition: angelscript.h:777
+
asEMsgType type
The type of message.
Definition: angelscript.h:775
+
Represents a compiler message.
Definition: angelscript.h:767
+ + + + diff --git a/docs/manual/doc_cpp_exceptions.html b/docs/manual/doc_cpp_exceptions.html new file mode 100644 index 0000000..52647d2 --- /dev/null +++ b/docs/manual/doc_cpp_exceptions.html @@ -0,0 +1,165 @@ + + + + + + + +AngelScript: C++ exceptions and longjmp + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
C++ exceptions and longjmp
+
+
+

+Exceptions

+

Application functions and class methods registered with the script engine are allowed to throw C++ exceptions. The virtual machine will automatically catch any C++ exception, abort the script execution, and return control to the application.

+
+
ctx->Prepare(engine->GetModule("test")->GetFunctionByName("func"));
+
int r = ctx->Execute();
+ +
{
+
string err = ctx->GetExceptionString();
+
if( err == "Caught an exception from the application" )
+
{
+
// An application function threw an exception while being invoked from the script
+
...
+
}
+
}
+

By default the VM has no way of distinguishing between different types of exceptions and will just give a standard exception string for all of them. If desired a callback can be registered with the engine to provide a translation of the exception type to a more informative exception string.

+
void TranslateException(asIScriptContext *ctx, void* /*userParam*/)
+
{
+
try
+
{
+
// Retrow the original exception so we can catch it again
+
throw;
+
}
+
catch( std::exception &e )
+
{
+
// Tell the VM the type of exception that occurred
+
ctx->SetException(e.what());
+
}
+
catch(...)
+
{
+
// The callback must not allow any exception to be thrown, but it is not necessary
+
// to explicitly set an exception string if the default exception string is sufficient
+
}
+
}
+
+
// Register the callback with the engine
+
engine->SetTranslateAppExceptionCallback(asFUNCTION(TranslateException), 0, asCALL_CDECL);
+
See also
GetExceptionInfo helper function
+
Note
The ability to catch exceptions can be turned off by compiling the library with the AS_NO_EXCEPTIONS defined. If this is done, the application should not register any functions that may throw exceptions, as the end result will be undefined should an exception occur.
+

+longjmp

+

Some applications uses longjmp to do error handling. When performing a longjmp to a previously saved state, there is no chance for the code to do a cleanup of all that happened after the saved state. Because of that the application must not register functions that can perform a longjmp out from the function, as that can leave the virtual machine in an undefined state.

+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
virtual int Execute()=0
Executes the prepared function.
+
@ asEXECUTION_EXCEPTION
The execution was terminated by an unhandled script exception.
Definition: angelscript.h:404
+
virtual const char * GetExceptionString()=0
Returns the exception string text.
+
virtual asIScriptFunction * GetFunctionByName(const char *name) const =0
Returns the function by its name.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual asIScriptContext * CreateContext()=0
Creates a new script context.
+
virtual int SetTranslateAppExceptionCallback(asSFuncPtr callback, void *param, int callConv)=0
Register the exception translation callback.
+
virtual int SetException(const char *info, bool allowCatch=true)=0
Sets an exception, which aborts the execution.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
+ + + + diff --git a/docs/manual/doc_datatypes.html b/docs/manual/doc_datatypes.html new file mode 100644 index 0000000..fbc5e9c --- /dev/null +++ b/docs/manual/doc_datatypes.html @@ -0,0 +1,120 @@ + + + + + + + +AngelScript: Data types + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Data types
+
+
+

Note that the host application may add types specific to that application, refer to the application's manual for more information.

+ +
See also
Standard library
+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes.js b/docs/manual/doc_datatypes.js new file mode 100644 index 0000000..0146d54 --- /dev/null +++ b/docs/manual/doc_datatypes.js @@ -0,0 +1,18 @@ +var doc_datatypes = +[ + [ "Primitives", "doc_datatypes_primitives.html", [ + [ "void", "doc_datatypes_primitives.html#void", null ], + [ "bool", "doc_datatypes_primitives.html#bool", null ], + [ "Integer numbers", "doc_datatypes_primitives.html#int", null ], + [ "Real numbers", "doc_datatypes_primitives.html#real", null ] + ] ], + [ "Objects and handles", "doc_datatypes_obj.html", [ + [ "Objects", "doc_datatypes_obj.html#objects", null ], + [ "Object handles", "doc_datatypes_obj.html#handles", null ] + ] ], + [ "Function handles", "doc_datatypes_funcptr.html", [ + [ "Delegates", "doc_datatypes_funcptr.html#doc_datatypes_delegate", null ] + ] ], + [ "Strings", "doc_datatypes_strings.html", null ], + [ "Auto declarations", "doc_datatypes_auto.html", null ] +]; \ No newline at end of file diff --git a/docs/manual/doc_datatypes_arrays.html b/docs/manual/doc_datatypes_arrays.html new file mode 100644 index 0000000..b0b9f5d --- /dev/null +++ b/docs/manual/doc_datatypes_arrays.html @@ -0,0 +1,227 @@ + + + + + + + +AngelScript: array + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
array
+
+
+
Note
Arrays are only available in the scripts if the application registers the support for them. The syntax for using arrays may differ for the application you're working with so consult the application's manual for more details.
+

It is possible to declare array variables with the array identifier followed by the type of the elements within angle brackets.

+

Example:

+
+  array<int> a, b, c;
+  array<Foo@> d;
+

a, b, and c are now arrays of integers, and d is an array of handles to objects of the Foo type.

+

When declaring arrays it is possible to define the initial size of the array by passing the length as a parameter to the constructor. The elements can also be individually initialized by specifying an initialization list. Example:

+
+  array<int> a;           // A zero-length array of integers
+  array<int> b(3);        // An array of integers with 3 elements
+  array<int> c(3, 1);     // An array of integers with 3 elements, all set to 1 by default
+  array<int> d = {5,6,7}; // An array of integers with 3 elements with specific values
+

Multidimensional arrays are supported as arrays of arrays, for example:

+
+  array<array<int>> a;                     // An empty array of arrays of integers
+  array<array<int>> b = {{1,2},{3,4}}      // A 2 by 2 array with initialized values
+  array<array<int>> c(10, array<int>(10)); // A 10 by 10 array of integers with uninitialized values
+

Each element in the array is accessed with the indexing operator. The indices are zero based, i.e. the range of valid indices are from 0 to length - 1.

+
+  a[0] = some_value;
+

When the array stores handles the elements are assigned using the handle assignment.

+
+  // Declare an array with initial length 1
+  array<Foo@> arr(1);
  // Set the first element to point to a new instance of Foo
+  @arr[0] = Foo();
+

Arrays can also be created and initialized within expressions as anonymous objects.

+
+  // Call a function that expects an array of integers as input
+  foo({1,2,3,4});
  // If the function has multiple overloads supporting different types with 
+  // initialization lists it is necessary to explicitly inform the array type
+  foo2(array<int> = {1,2,3,4});
+

+Supporting array object

+

The array object supports a number of operators and has several class methods to facilitate the manipulation of strings.

+

The array object is a reference type even if the elements are not, so it's possible to use handles to the array object when passing it around to avoid costly copies.

+

+Operators

+

= assignment

+

The assignment operator performs a shallow copy of the content.

+

[] index operator

+

The index operator returns the reference of an element allowing it to be inspected or modified. If the index is out of range, then an exception will be raised.

+

==, != equality

+

Performs a value comparison on each of the elements in the two arrays and returns true if all match the used operator.

+

+Methods

+

uint length() const

+

Returns the length of the array.

+

void resize(uint)

+

Sets the new length of the array.

+

void reverse()

+

Reverses the order of the elements in the array.

+

void insertAt(uint index, const T& in value)
+ void insertAt(uint index, const array<T>& arr)
+

+

Inserts a new element, or another array of elements, into the array at the specified index.

+

void insertLast(const T& in)

+

Appends an element at the end of the array.

+

void removeAt(uint index)

+

Removes the element at the specified index.

+

void removeLast()

+

Removes the last element of the array.

+

void removeRange(uint start, uint count)

+

Removes count elements starting from start.

+

void sortAsc()
+ void sortAsc(uint startAt, uint count)
+

+

Sorts the elements in the array in ascending order. For object types, this will use the type's opCmp method.

+

The second variant will sort only the elements starting at index startAt and the following count elements.

+

void sortDesc()
+ void sortDesc(uint startAt, uint count)
+

+

These does the same thing as sortAsc except sorts the elements in descending order.

+

void sort(const less &in compareFunc, uint startAt = 0, uint count = uint(-1))
+

+

This method takes as input a callback function to use for comparing two elements when sorting the array.

+

The callback function should take as parameters two references of the same type of the array elements and it should return a bool. The return value should be true if the first argument should be placed before the second argument.

+
+  array<int> arr = {3,2,1};
+  arr.sort(function(a,b) { return a < b; });
+

The example shows how to use the sort method with a callback to an anonymous function.

+

Here's another example where the callback function is declared explicitly:

+
+  bool lessForInt(const int &in a, const int &in b)
+  {
+    return a < b;
+  }
+  bool lessForHandle(const obj @&in a, const obj @&in b)
+  {
+    return a < b;
+  }
+  void sortArrayOfInts(array<int> @arr) { arr.sort(lessForInt); }
+  void sortArrayOfHandles(array<obj@> @arr) { arr.sort(lessForHandle); }
+

int find(const T& in)
+ int find(uint startAt, const T& in)
+

+

These will return the index of the first element that has the same value as the wanted value.

+

For object types, this will use the type's opEquals or opCmp method to compare the value. For arrays of handles any null handle will be skipped.

+

If no match is found the methods will return a negative value.

+

int findByRef(const T& in)
+ int findByRef(uint startAt, const T& in)
+

+

These will search for a matching address. These are especially useful for arrays of handles where specific instances of objects are desired, and not just objects that happen to have equal value.

+

If no match is found the methods will return a negative value.

+

+Script example

+
+  int main()
+  {
+    array<int> arr = {1,2,3}; // 1,2,3
+    arr.insertLast(0);        // 1,2,3,0
+    arr.insertAt(2,4);        // 1,2,4,3,0
+    arr.removeAt(1);          // 1,4,3,0
    arr.sortAsc();            // 0,1,3,4
    int sum = 0;
+    for( uint n = 0; n < arr.length(); n++ )
+      sum += arr[n];
    return sum;
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_auto.html b/docs/manual/doc_datatypes_auto.html new file mode 100644 index 0000000..a5b45bd --- /dev/null +++ b/docs/manual/doc_datatypes_auto.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Auto declarations + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Auto declarations
+
+
+

It is possible to use 'auto' as the data type of an assignment-style variable declaration.

+

The appropriate type for the variable(s) will be automatically determined.

+
+  auto i = 18;         // i will be an integer
+  auto f = 18 + 5.f;   // the type of f resolves to float
+  auto o = getLongObjectTypeNameById(id); // avoids redundancy for long type names
+

Auto can be qualified with const to force a constant value:

+
+  const auto i = 2;  // i will be typed as 'const int'
+

For types that support handles, auto will always become a handle as it is more efficient than doing a value assignment. If the variable must not be a handle for some reason, then do not use the 'auto' keyword.

+
+  auto  a = getObject();  // auto is typed 'obj@'
+  auto@ b = getObject();  // this is still allowed if you want to be more explicit
+

Auto handles can not be used to declare class members, since their resolution is dependent on the constructor.

+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_dictionary.html b/docs/manual/doc_datatypes_dictionary.html new file mode 100644 index 0000000..c25561a --- /dev/null +++ b/docs/manual/doc_datatypes_dictionary.html @@ -0,0 +1,205 @@ + + + + + + + +AngelScript: dictionary + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
dictionary
+
+
+
Note
Dictionaries are only available in the scripts if the application registers the support for them. The syntax for using dictionaries may differ for the application you're working with so consult the application's manual for more details.
+

The dictionary stores key-value pairs, where the key is a string, and the value can be of any type. Key-value pairs can be added or removed dynamically, making the dictionary a good general purpose container object.

+
+  obj object;
+  obj @handle;
  // Initialize with a list
+  dictionary dict = {{'one', 1}, {'object', object}, {'handle', @handle}};
  // Examine and access the values through get or set methods ...
+  if( dict.exists('one') )
+  {
+    // get returns true if the stored type is compatible with the requested type
+    bool isValid = dict.get('handle', @handle);
+    if( isValid )
+    {
+      dict.delete('object');
+      dict.set('value', 1);
+    }
+  }
+

Dictionary values can also be accessed or added by using the index operator.

+
+  // Read and modify an integer value
+  int val = int(dict['value']);
+  dict['value'] = val + 1;
  // Read and modify a handle to an object instance
+  @handle = cast<obj>(dict['handle']);
+  if( handle is null )
+    @dict['handle'] = object;
+

Dictionaries can also be created and initialized within expressions as anonymous objects.

+
+  // Call a function that expects a dictionary as input and no other overloads
+  // In this case it is possible to inform the initialization list without explicitly giving the type
+  foo({{'a', 1},{'b', 2}});
  // Call a function where there are multiple overloads expecting different
+  // In this case it is necessary to explicitly define the type of the initialization list
+  foo2(dictionary = {{'a', 1},{'b', 2}});
+

Dictionaries of dictionaries are created using anonymous objects as well.

+
+  dictionary d2 = {{'a', dictionary = {{'aa', 1}, {'ab', 2}}}, 
+                   {'b', dictionary = {{'ba', 1}, {'bb', 2}}}};
+

+Supporting dictionary object

+

The dictionary object is a reference type, so it's possible to use handles to the dictionary object when passing it around to avoid costly copies.

+

+Operators

+

= assignment
+

+

The assignment operator performs a shallow copy of the content.

+

[] index operator
+

+

The index operator takes a string for the key, and returns a reference to the value. If the key/value pair doesn't exist it will be inserted with a null value.

+

+Methods

+

void set(const string &in key, ? &in value)
+ void set(const string &in key, int64 &in value)
+ void set(const string &in key, double &in value)
+

+

Sets a key/value pair in the dictionary. If the key already exists, the value will be changed.

+

bool get(const string &in key, ? &out value) const
+ bool get(const string &in key, int64 &out value) const
+ bool get(const string &in key, double &out value) const
+

+

Retrieves the value corresponding to the key. The methods return false if the key is not found, and in this case the value will maintain its default value based on the type.

+

array<string> @getKeys() const
+

+

This method returns an array with all of the existing keys in the dictionary. The order of the keys in the array is undefined.

+

bool exists(const string &in key) const
+

+

Returns true if the key exists in the dictionary.

+

bool delete(const string &in key)
+

+

Removes the key and the corresponding value from the dictionary. Returns false if the key wasn't found.

+

void deleteAll()
+

+

Removes all entries in the dictionary.

+

bool isEmpty() const
+

+

Returns true if the dictionary doesn't hold any entries.

+

uint getSize() const
+

+

Returns the number of keys in the dictionary.

+

+Supporting dictionaryValue object

+

The dictionaryValue type is how the dictionary object stores the values. When accessing the values through the dictionary index operator a reference to a dictionaryValue is returned.

+

The dictionaryValue type itself is a value type, i.e. no handles to it can be held, but it can hold handles to other objects as well as values of any type.

+

+Operators

+

= assignment
+

+

The value assignment operator should be used to copy a value into the dictionaryValue.

+

@= handle assignment
+

+

The handle assignment operator should be used to set the dictionaryValue to refer to an object instance.

+

cast<type> cast operator
+

+

The cast operator is used to dynamically cast the handle held in the dictionaryValue to the desired type. If the dictionaryValue doesn't hold a handle, or the handle is not compatible with the desired type, the cast operator will return a null handle.

+

type() conversion operator
+

+

The conversion operator is used to return a new value of the desired type. If no value conversion is found, an uninitialized value of the desired type is returned.

+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_funcptr.html b/docs/manual/doc_datatypes_funcptr.html new file mode 100644 index 0000000..077b49d --- /dev/null +++ b/docs/manual/doc_datatypes_funcptr.html @@ -0,0 +1,166 @@ + + + + + + + +AngelScript: Function handles + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Function handles
+
+
+

A function handle is a data type that can be dynamically set to point to a global function that has a matching function signature as that defined by the variable declaration. Function handles are commonly used for callbacks, i.e. where a piece of code must be able to call back to some code based on some conditions, but the code that needs to be called is not known at compile time.

+

To use function handles it is first necessary to define the function signature that will be used at the global scope or as a member of a class. Once that is done the variables can be declared using that definition.

+

Here's an example that shows the syntax for using function handles

+
+  // Define a function signature for the function handle
+  funcdef bool CALLBACK(int, int);
  // An example function that shows how to use this
+  void main()
+  {
+    // Declare a function handle, and set it 
+    // to point to the myCompare function.
+    CALLBACK @func = @myCompare;
    // The function handle can be compared with the 'is' operator
+    if( func is null )
+    {
+      print("The function handle is null\n");
+      return;
+    }
    // Call the function through the handle, just as if it was a normal function
+    if( func(1, 2) )
+    {
+      print("The function returned true\n");
+    }
+    else
+    {
+      print("The function returned false\n");
+    }
+  }
  // This function matches the CALLBACK definition, since it has 
+  // the same return type and parameter types.
+  bool myCompare(int a, int b)
+  {
+    return a > b;
+  }
+

+Delegates

+

It is also possible to take function handles to class methods, but in this case the class method must be bound to the object instance that will be used for the call. To do this binding is called creating a delegate, and is done by performing a construct call for the declared function definition passing the class method as the argument.

+
+  class A
+  {
+    bool Cmp(int a, int b)
+    {
+       count++;
+       return a > b;
+    }
+    int count = 0;
+  }
  void main()
+  {
+    A a;
    // Create the delegate for the A::Cmp class method
+    CALLBACK @func = CALLBACK(a.Cmp);
    // Call the delegate normally as if it was a global function
+    if( func(1,2) )
+    {
+      print("The function returned true\n");
+    }
+    else
+    {
+      print("The function returned false\n");
+    }
    printf("The number of comparisons performed is "+a.count+"\n");
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_obj.html b/docs/manual/doc_datatypes_obj.html new file mode 100644 index 0000000..d7c4a43 --- /dev/null +++ b/docs/manual/doc_datatypes_obj.html @@ -0,0 +1,133 @@ + + + + + + + +AngelScript: Objects and handles + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Objects and handles
+
+
+

+Objects

+

There are two forms of objects, reference types and value types.

+

Value types behave much like the primitive types, in that they are allocated on the stack and deallocated when the variable goes out of scope. Only the application can register these types, so you need to check with the application's documentation for more information about the registered types.

+

Reference types are allocated on the memory heap, and may outlive the initial variable that allocates them if another reference to the instance is kept. All script declared classes are reference types. Interfaces are a special form of reference types, that cannot be instantiated, but can be used to access the objects that implement the interfaces without knowing exactly what type of object it is.

+
+  obj o;      // An object is instantiated
+  o = obj();  // A temporary instance is created whose 
+              // value is assigned to the variable
+

+Object handles

+

Object handles are a special type that can be used to hold references to other objects. When calling methods or accessing properties on a variable that is an object handle you will be accessing the actual object that the handle references, just as if it was an alias. Note that unless initialized with the handle of an object, the handle is null.

+
+  obj o;
+  obj@ a;           // a is initialized to null
+  obj@ b = @o;      // b holds a reference to o
  b.ModifyMe();     // The method modifies the original object
  if( a is null )   // Verify if the object points to an object
+  {
+    @a = @b;        // Make a hold a reference to the same object as b
+  }
+

Not all types allow a handle to be taken. Neither of the primitive types can have handles, and there may exist some object types that do not allow handles. Which objects allow handles or not, are up to the application that registers them.

+

Object handle and array type modifiers can be combined to form handles to arrays, or arrays of handles, etc.

+
See also
Object handles
+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_primitives.html b/docs/manual/doc_datatypes_primitives.html new file mode 100644 index 0000000..73dc69c --- /dev/null +++ b/docs/manual/doc_datatypes_primitives.html @@ -0,0 +1,154 @@ + + + + + + + +AngelScript: Primitives + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Primitives
+
+
+

+void

+

void is not really a data type, more like lack of data type. It can only be used to tell the compiler that a function doesn't return any data.

+

+bool

+

bool is a boolean type with only two possible values: true or false. The keywords true and false are constants of type bool that can be used as such in expressions.

+

+Integer numbers

+ + + + + + + + + + + + + + + + + + + +
typemin valuemax value
int8 -128127
int16 -32,76832,767
int -2,147,483,6482,147,483,647
int64 -9,223,372,036,854,775,8089,223,372,036,854,775,807
uint8 0255
uint16065,535
uint 04,294,967,295
uint64018,446,744,073,709,551,615
+

As the scripting engine has been optimized for 32 bit datatypes, using the smaller variants is only recommended for accessing application specified variables. For local variables it is better to use the 32 bit variant.

+

int32 is an alias for int, and uint32 is an alias for uint.

+

+Real numbers

+ + + + + + + +
typerange of valuessmallest positive value maximum digits
float +/- 3.402823466e+38 1.175494351e-38 6
double +/- 1.79769313486231e+308 2.22507385850720e-308 15
+
Note
These numbers assume the platform uses the IEEE 754 to represent floating point numbers in the CPU
+

Rounding errors may occur if more digits than the maximum number of digits are used.

+

Curiousity: Real numbers may also have the additional values of positive and negative 0 or infinite, and NaN (Not-a-Number). For float NaN is represented by the 32 bit data word 0x7fc00000.

+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_ref.html b/docs/manual/doc_datatypes_ref.html new file mode 100644 index 0000000..7e0f34a --- /dev/null +++ b/docs/manual/doc_datatypes_ref.html @@ -0,0 +1,152 @@ + + + + + + + +AngelScript: ref + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
ref
+
+
+
Note
ref is only available in the scripts if the application registers the support for it.
+

The ref type works like a generic object handle. Normally a handle can only refer to objects of a specific type or those related to it, however not all object types are related, and this is where ref comes in. Being completely generic it can refer to any object type (as long as it is a reference type).

+
+  // Two unrelated types
+  class car {}
+  class banana {}
  // A function that take the ref type as argument can work on both types
+  void func(ref @handle)
+  {
+    // Cast the handle to the expected type and check which cast work
+    car @c = cast<car>(handle);
+    banana @b = cast<banana>(handle);
+    if( c !is null )
+      print('The handle refers to a car\n');
+    else if( b !is null )
+      print('The handle refers to a banana\n');
+    else if( handle !is null )
+      print('The handle refers to a different object\n');
+    else
+      print('The handle is null\n');
+  }
  void main()
+  {
+    // Assigning a ref handle works the same way as ordinary handles
+    ref @r = car();
+    func(r);
+    @r = banana();
+    func(r);
+  }
+

+Supporting ref object

+

The ref object supports only a few operators as it is just a place holder for handles.

+

+Operators

+

@= handle assignment
+

+

The handle assignment operator is used to set the object that the referred to by the ref type.

+

is, !is identity operator
+

+

The identity operators are used to compare the address of the object referred to by the ref type.

+

cast<type> cast operator
+

+

The cast operator is used to perform a dynamic cast to the desired type. If the type is not compatible with the object referred to by the ref type this will return null.

+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_strings.html b/docs/manual/doc_datatypes_strings.html new file mode 100644 index 0000000..87d65f5 --- /dev/null +++ b/docs/manual/doc_datatypes_strings.html @@ -0,0 +1,160 @@ + + + + + + + +AngelScript: Strings + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Strings
+
+
+
Note
Strings are only available in the scripts if the application registers the support for them. The syntax for using strings may differ for the application you're working with so consult the application's manual for more details.
+

Strings hold an array of bytes or 16bit words depending on the application settings. Normally they are used to store text but can really store any kind of binary data.

+

There are two types of string constants supported in the AngelScript language, the normal quoted string, and the documentation strings, called heredoc strings.

+

The normal strings are written between double quotation marks (") or single quotation marks ('). Inside the constant strings some escape sequences can be used to write exact byte values that might not be possible to write in your normal editor.

+ + + + + + + + + + + + + + + + + + + + + + + +
sequence value

description

+

+
\0  0 null character
\\  92 back-slash
\'  39 single quotation mark (apostrophe)
\"  34 double quotation mark
\n  10 new line feed
\r  13 carriage return
\t  9 tab character
\xFFFF  0xFFFF FFFF should be exchanged for a 1 to 4 digit hexadecimal number representing the value wanted. If the application uses 8bit strings then only values up to 255 is accepted.
\uFFFF  0xFFFF FFFF should be exchanged for the hexadecimal number representing the unicode code point
\UFFFFFFFF  0xFFFFFFFF FFFFFFFF should be exchanged for the hexadecimal number representing the unicode code point
+
+  string str1 = "This is a string with \"escape sequences" .";
+  string str2 = 'If single quotes are used then double quotes can be included without "escape sequences".';
+

The heredoc strings are designed for inclusion of large portions of text without processing of escape sequences. A heredoc string is surrounded by triple double-quotation marks ("""), and can span multiple lines of code. If the characters following the start of the string until the first linebreak only contains white space, it is automatically removed by the compiler. Likewise if the characters following the last line break until the end of the string only contains white space this is also removed.

+
+  string str = """
+  This is some text without "escape sequences". This is some text.
+  This is some text. This is some text. This is some text. This is
+  some text. This is some text. This is some text. This is some
+  text. This is some text. This is some text. This is some text.
+  This is some text.
+  """;
+

If more than one string constants are written in sequence with only whitespace or comments between them the compiler will concatenate them into one constant.

+
+  string str = "First line.\n"
+               "Second line.\n"
+               "Third line.\n";
+

The escape sequences \u and \U will add the specified unicode code point as a UTF-8 or UTF-16 encoded sequence depending on the application settings. Only valid unicode 5.1 code points are accepted, i.e. code points between U+D800 and U+DFFF (reserved for surrogate pairs) or above U+10FFFF are not accepted.

+
See also
string
+
+
+
+ + + + diff --git a/docs/manual/doc_datatypes_weakref.html b/docs/manual/doc_datatypes_weakref.html new file mode 100644 index 0000000..54d1526 --- /dev/null +++ b/docs/manual/doc_datatypes_weakref.html @@ -0,0 +1,146 @@ + + + + + + + +AngelScript: weakref + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
weakref
+
+
+
Note
weakref is only available in the scripts if the application registers the support for it.
+

An object handle will keep the object it refers to alive as long as the handle itself exists. A weakref object can be used in place of the handle where the reference to the object is needed but the object shouldn't be kept alive.

+
+  class MyClass {}
+  MyClass @obj1 = MyClass();
  // Keep a weakref to the object
+  weakref<MyClass> r1(obj1);
  // Keep a weakref to a readonly object
+  const_weakref<MyClass> r2(obj1);
  // As long as there is a strong reference to the object, 
+  // the weakref will be able to return a handle to the object
+  MyClass @obj2 = r1.get();
+  assert( obj2 !is null );
  // After all strong references are removed the
+  // weakref will only return null
+  @obj1 = null;
+  @obj2 = null;
  const MyClass @obj3 = r2.get();
+  assert( obj3 is null );
+

+Supporting weakref object

+

+Operators

+

@= handle assignment
+

+

The handle assignment operator is used to set the object that the referred to by the ref type.

+

= value assignment
+

+

The value assignment operator is used when one weakref object is copied to another.

+

is, !is identity operator
+

+

The identity operators are used to compare the address of the object referred to by the ref type.

+

cast<type> implicit cast operator
+

+

The implicit cast operator is used to cast the weak ref type to strong reference of the type. If the object referred to by the weakref is already dead this operator will return null.

+

+Methods

+

T@ get() const
+

+

This does the exact same thing as the implicit cast operator. It is just a more explicit way of writing it.

+
+
+
+ + + + diff --git a/docs/manual/doc_debug.html b/docs/manual/doc_debug.html new file mode 100644 index 0000000..de98b3a --- /dev/null +++ b/docs/manual/doc_debug.html @@ -0,0 +1,239 @@ + + + + + + + +AngelScript: Debugging scripts + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Debugging scripts
+
+
+

AngelScript offers a rich interface to support the debugging of scripts. It is easy to build an embedded debugger that can set break points, inspect/manipulate variables in functions, visualize the call stack, etc.

+

Observe that the CDebugMgr class used in the examples below doesn't exist. It is only used as an abstraction to avoid having to write fictional debug routines.

+
See also
Debugger for a standard implementation
+

+Setting line breaks

+

In order to break at a specified line in the code the debugger can set the line callback function in the script context. The VM will then invoke the callback for each statement executed, allowing the debugger to decide whether to proceed to the next statement or not.

+
// An example line callback
+
void DebugLineCallback(asIScriptContext *ctx, CDebugMgr *dbg)
+
{
+
// Determine if we have reached a break point
+
const char *scriptSection;
+
int line = ctx->GetLineNumber(0, 0, &scriptSection);
+
asIScriptFunction *function = ctx->GetFunction();
+
+
// Now let the debugger check if a breakpoint has been set here
+
if( dbg->IsBreakpoint(scriptSection, line, function) )
+
{
+
// A break point has been reached so the execution of the script should be suspended
+
ctx->Suspend();
+
}
+
}
+

The line callback is set on the context with the following call:

+
// Set the line callback with the address of the debug manager as parameter
+
ctx->SetLineCallback(asFUNCTION(DebugLineCallback), dbg, asCALL_CDECL);
+

When the line callback suspends the execution the context's Execute function will return with the code asEXECUTION_SUSPENDED. The application can then go into a special message loop where the debug routines can be handled, e.g. to view the call stack, examine variables, etc. Once the execution should continue, simply call the Execute method again to resume it.

+

An alternative to suspending the script execution might be to start the message loop directly within the line callback, in which case resuming the execution is done simply by returning from the line callback function. Which is the easiest to implement depends on how you have implemented your application.

+

+Viewing the call stack

+

The asIScriptContext exposes the call stack for viewing purposes, so that you can easily track the origin of calls. It is also possible to print the value of variables at each level in the callstack.

+

Here's an example of how the entire call stack can be printed:

+
void PrintCallstack(asIScriptContext *ctx)
+
{
+
// Show the call stack
+
for( asUINT n = 0; n < ctx->GetCallstackSize(); n++ )
+
{
+ +
const char *scriptSection;
+
int line, column;
+
func = ctx->GetFunction(n);
+
line = ctx->GetLineNumber(n, &column, &scriptSection);
+
printf("%s:%s:%d,%d\n", scriptSection,
+
func->GetDeclaration(),
+
line, column);
+
}
+
}
+

+Inspecting variables

+

Through the context interface it is possible to inspect and even modify the value of the local variables on the stack. This can be done for each level in the call stack, and not just the current function that is being executed.

+

Here is an example for how the variables may be printed:

+
void PrintVariables(asIScriptContext *ctx, asUINT stackLevel)
+
{
+
asIScriptEngine *engine = ctx->GetEngine();
+
+
// First print the this pointer if this is a class method
+
int typeId = ctx->GetThisTypeId(stackLevel);
+
void *varPointer = ctx->GetThisPointer(stackLevel);
+
if( typeId )
+
{
+
printf(" this = 0x%x\n", varPointer);
+
}
+
+
// Print the value of each variable, including parameters
+
int numVars = ctx->GetVarCount(stackLevel);
+
for( int n = 0; n < numVars; n++ )
+
{
+
int typeId = ctx->GetVarTypeId(n, stackLevel);
+
void *varPointer = ctx->GetAddressOfVar(n, stackLevel);
+
if( typeId == asTYPEID_INT32 )
+
{
+
printf(" %s = %d\n", ctx->GetVarDeclaration(n, stackLevel), *(int*)varPointer);
+
}
+
else if( typeId == asTYPEID_FLOAT )
+
{
+
printf(" %s = %f\n", ctx->GetVarDeclaration(n, stackLevel), *(float*)varPointer);
+
}
+
else if( typeId & asTYPEID_SCRIPTOBJECT )
+
{
+
asIScriptObject *obj = (asIScriptObject*)varPointer;
+
if( obj )
+
printf(" %s = {...}\n", ctx->GetVarDeclaration(n, stackLevel));
+
else
+
printf(" %s = <null>\n", ctx->GetVarDeclaration(n, stackLevel));
+
}
+
else if( typeId == engine->GetTypeIdByDecl("string") )
+
{
+
string *str = (string*)varPointer;
+
if( str )
+
printf(" %s = '%s'\n", ctx->GetVarDeclaration(n, stackLevel), str->c_str());
+
else
+
printf(" %s = <null>\n", ctx->GetVarDeclaration(n, stackLevel));
+
}
+
else
+
{
+
printf(" %s = {...}\n", ctx->GetVarDeclaration(n, stackLevel));
+
}
+
}
+
}
+

The above code is only an example to give an idea of how it can be done. It is not complete and only recognizes a few types. To make it useful it would have to be expanded to recognize all types, and perhaps add some generic way of converting an object to human readable string for printing.

+

For script objects that conversion can be done by enumerating the members of an object through the asIScriptObject interface.

+

The debugger may also need to be able to inspect the global variables that the functions access. As the global variables are stored in the module, there is the place to look for them. The asIScriptModule interface can be obtained by querying the module name from the function, and then getting the module pointer from the engine. Once the module is determined the global variables are enumerated much the same way as in the example above, except that the appropriate methods on the asIScriptModule interface are used instead.

+

+Debugging internally executed scripts

+

Some script execution is not initiated by the application, e.g. the initialization of global variables or the call to the script class destructor when destroying objects from the garbage collector. If these executions should be debugged, the application must set the context callback functions with a call to asIScriptEngine::SetContextCallbacks. The engine will invoke these callbacks to request a context from the application when it will execute a script internally. The application can then
+ attach the debugger to the context it provides to the engine.

+
+
+
+
@ asTYPEID_SCRIPTOBJECT
The bit that shows if the type is a script class.
Definition: angelscript.h:496
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual asIScriptFunction * GetFunction(asUINT stackLevel=0)=0
Returns the function at the specified callstack level.
+
@ asTYPEID_FLOAT
The type id for float.
Definition: angelscript.h:484
+
virtual void * GetAddressOfVar(asUINT varIndex, asUINT stackLevel=0)=0
Returns a pointer to a local variable at the specified callstack level.
+
virtual int GetLineNumber(asUINT stackLevel=0, int *column=0, const char **sectionName=0)=0
Returns the line number at the specified callstack level.
+
virtual int GetVarCount(asUINT stackLevel=0)=0
Returns the number of local variables at the specified callstack level.
+
@ asTYPEID_INT32
The type id for int.
Definition: angelscript.h:472
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int GetTypeIdByDecl(const char *decl) const =0
Returns a type id by declaration.
+
virtual asIScriptEngine * GetEngine() const =0
Returns a pointer to the engine.
+
virtual const char * GetDeclaration(bool includeObjectName=true, bool includeNamespace=false, bool includeParamNames=false) const =0
Returns the function declaration.
+
virtual asUINT GetCallstackSize() const =0
Returns the size of the callstack, i.e. the number of functions that have yet to complete.
+
virtual const char * GetVarDeclaration(asUINT varIndex, asUINT stackLevel=0, bool includeNamespace=false)=0
Returns the declaration of a local variable at the specified callstack level.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual int SetLineCallback(asSFuncPtr callback, void *obj, int callConv)=0
Sets a line callback function. The function will be called for each executed script statement.
+
virtual int Suspend()=0
Suspends the execution, which can then be resumed by calling Execute again.
+
unsigned int asUINT
32 bit unsigned integer
Definition: angelscript.h:600
+
The interface for a script function description.
Definition: angelscript.h:3823
+
The interface for an instance of a script object.
Definition: angelscript.h:3413
+
virtual int GetThisTypeId(asUINT stackLevel=0)=0
Returns the type id of the object, if a class method is being executed.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
virtual void * GetThisPointer(asUINT stackLevel=0)=0
Returns a pointer to the object, if a class method is being executed.
+
virtual int GetVarTypeId(asUINT varIndex, asUINT stackLevel=0)=0
Returns the type id of a local variable at the specified callstack level.
+ + + + diff --git a/docs/manual/doc_expressions.html b/docs/manual/doc_expressions.html new file mode 100644 index 0000000..d43a119 --- /dev/null +++ b/docs/manual/doc_expressions.html @@ -0,0 +1,346 @@ + + + + + + + +AngelScript: Expressions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Expressions
+
+
+
+

+Assignments

+
  lvalue = rvalue;

lvalue must be an expression that evaluates to a memory location where the expression value can be stored, e.g. a variable. An assignment evaluates to the same value and type of the data stored. The right hand expression is always computed before the left.

+

+Function call

+
+  func();
+  func(arg);
+  func(arg1, arg2);
+  lvalue = func();
+

Functions are called to perform an action, and possibly return a value that can be used in further operations. If a function takes more than one argument, the argument expressions are evaluated in the reverse order, i.e. the last argument is evaluated first.

+

Some functions are declared with output reference parameters to return multiple values. When calling such functions the output parameter must be given as an expression that can be assigned with the returned value. If the additional output value won't be used use the special argument 'void' to tell the compiler that.

+
+  // This function returns a value in the output parameter
+  void func(int &out outputValue)
+  {
+    outputValue = 42;
+  }
  // Call the function with a valid lvalue expression to receive the output value
+  int value;
+  func(value);
  // Call the function with 'void' argument to ignore the output value
+  func(void);
+

Arguments can also be named and passed to a specific argument independent of the order the parameters were declared in. No positional arguments may follow any named arguments.

+
+  void func(int flagA = false, int flagB = false, int flagC = false) {}
  // Call the function, setting only a subset of its parameters
+  func(flagC: true);
+  func(flagB: true, flagA: true);
+

+Math operators

+
+  c = -(a + b);
+
+ + + + + + + + + + + + + + + + + + +
operatordescriptionleft handright handresult
+ unary positive   NUM NUM
- unary negative   NUM NUM
+ addition NUM NUM NUM
- subtraction NUM NUM NUM
* multiplication NUM NUM NUM
/ division NUM NUM NUM
% modulos NUM NUM NUM
** exponent NUM NUM NUM
+

Plus and minus can be used as unary operators as well. NUM can be exchanged for any numeric type, e.g. int or float. Both terms of the dual operations will be implicitly converted to have the same type. The result is always the same type as the original terms. One exception is unary negative which is not available for uint.

+

+Bitwise operators

+
+  c = ~(a | b);
+
+ + + + + + + + + + + + + + + + +
operator description left handright handresult
~ bitwise complement   NUM NUM
& bitwise and NUM NUM NUM
| bitwise or NUM NUM NUM
^ bitwise xor NUM NUM NUM
<< left shift NUM NUM NUM
>> right shift NUM NUM NUM
>>>arithmetic right shiftNUM NUM NUM
+

All except ~ are dual operators.

+

Both operands will be converted to integers while keeping the sign of the original type before the operation. The resulting type will be the same as the left hand operand.

+

+Compound assignments

+
+  lvalue += rvalue;
+  lvalue = lvalue + rvalue;
+

A compound assignment is a combination of an operator followed by the assignment. The two expressions above means practically the same thing. Except that first one is more efficient in that the lvalue is only evaluated once, which can make a difference if the lvalue is complex expression in itself.

+

Available operators: += -= *= /= %= **= &= |= ^= <<= >>= >>>=

+

+Logic operators

+
+  if( a and b or not c )
+  {
+    // ... do something
+  }
+
+ + + + + + + + + + +
operator description left hand right handresult
notlogical not   boolbool
andlogical and boolboolbool
or logical or boolboolbool
xorlogical exclusive orboolboolbool
+

Boolean operators only evaluate necessary terms. For example in expression a and b, b is only evaluated if a is true.

+

Each of the logic operators can be written as symbols as well, i.e. || for or, && for and, ^^ for xor, and ! for not.

+

+Equality comparison operators

+
+  if( a == b )
+  {
+    // ... do something
+  }
+

The operators == and != are used to compare two values to determine if they are equal or not equal, respectively. The result of this operation is always a boolean value.

+

+Relational comparison operators

+
+  if( a > b )
+  {
+    // ... do something
+  }
+

The operators <, >, <=, and >= are used to compare two values to determine their relationship. The result is always a boolean value.

+

+Identity comparison operators

+
+  if( a is null )
+  {
+    // ... do something
+  }
+  else if( a is b )
+  {
+    // ... do something
+  }
+

The operators is and !is are used to compare the identity of two objects, i.e. to determine if the two are the same object or not. These operators are only valid for reference types as they compare the address of two objects. The result is always a boolean value.

+

+Increment operators

+
+  // The following means a = i; i = i + 1;
+  a = i++;
  // The following means i = i - 1; b = i;
+  b = --i;
+

These operators can be placed either before or after an lvalue to increment/decrement its value either before or after the value is used in the expression. The value is always incremented or decremented with 1.

+

+Indexing operator

+
+  arr[i] = 1;
+

This operator is used to access an element contained within the object. Depending on the object type, the expression between the [] needs to be of different types.

+

+Conditional expression

+
+  choose ? a : b;
+

If the value of choose is true then the expression returns a otherwise it will return b. Both a and b must be of the same type.

+

If they are not of the same type the compiler will attempt an implicit conversion using the following rules. If the a expression is 0 or null, then the compiler will attempt to convert it to the type of b, otherwise it will attempt to convert b to the type of a.

+

If the conversion doesn't work, then the compiler will give an error.

+

The conditional expression can be used as an lvalue, i.e. on the left value of an assignment expression, if both a and b are lvalues of the same type.

+
+  int a, b;
+  (expr ? a : b) = 42;
+

+Member access

+
+  object.property = 1;
+  object.method();
+

object must be an expression resulting in a data type that have members. property is the name of a member variable that can be read/set directly. method is the name of a member method that can be called on the object.

+

+Handle-of

+
+  // Make handle reference the object instance
+  @handle = @object;
  // Clear the handle and release the object it references
+  @handle = null;
+

Object handles are references to an object. More than one handle can reference the same object, and only when no more handles reference an object is the object destroyed.

+

The members of the object that the handle references are accessed the same way through the handle as if accessed directly through the object variable, i.e. with . operator.

+
See also
Object handles
+

+Parenthesis

+
+  a = c * (a + b);
+  if( (a or b) and c )
+  {
+    // ... do something
+  }
+

Parenthesis are used to group expressions when the operator precedence does not give the desired order of evaluation.

+

+Scope resolution

+
+  int value;
+  void function()
+  {
+    int value;       // local variable overloads the global variable
+    ::value = value; // use scope resolution operator to refer to the global variable 
+  } 
+

The scope resolution operator :: can be used to access variables or functions from another scope when the name is overloaded by a local variable or function. Write the scope name on the left (or blank for the global scope) and the name of the variable/function on the right.

+
See also
Namespaces
+

+Type conversions

+
+  // implicitly convert the clss handle to a intf handle
+  intf @a = @clss();
  // explicitly convert the intf handle to a clss handle
+  clss @b = cast<clss>(a);
+

Object handles can be converted to other object handles with the cast operator. If the cast is valid, i.e. the true object implements the class or interface being requested, the operator returns a valid handle. If the cast is not valid, the cast returns a null handle.

+

The above is called a reference cast, and only works for types that support object handles. In this case the handle still refers to the same object, it is just exposed through a different interface.

+

Types that do not support object handles can be converted with a value cast instead. In this case a new value is constructed, or in case of objects a new instance of the object is created.

+
+  // implicit value cast
+  int a = 1.0f;
  // explicit value cast
+  float b = float(a)/2;
+

In most cases an explicit cast is not necessary for primitive types, however, as the compiler is usually able to do an implicit cast to the correct type.

+

+Anonymous objects

+

Anonymous objects, i.e. objects that are created without being declared as variables, can be instantiated in expressions by calling invoking the object's constructor as if it was a function. Both reference types and value types can be created like this.

+
+  // Call the function with a new object of the type MyClass
+  func(MyClass(1,2,3));
+

For types that support it, the anonymous objects can also be initialized with initialization lists.

+
+  // Call the function with a dictionary, explicitly informing the type of the initialization list
+  func(dictionary = {{'banana',1}, {'apple',2}, {'orange',3}});
  // When there is only one possible type that support initialization lists it is possible  
+  // to omit the type and let the compiler implicitly determine it based on the use
+  funcExpectsAnArrayOfInts({1,2,3,4});
+
+
+
+ + + + diff --git a/docs/manual/doc_finetuning.html b/docs/manual/doc_finetuning.html new file mode 100644 index 0000000..97b0b3c --- /dev/null +++ b/docs/manual/doc_finetuning.html @@ -0,0 +1,200 @@ + + + + + + + +AngelScript: Fine tuning + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Fine tuning
+
+
+

Here's a few recommendations to get the most performance out of AngelScript.

+

+Cache the functions and types

+

Doing searches by function declaration or name is rather time consuming and should not be done more than once per function that will be called. The same goes for the types that you might use it.

+

Also try to use the actual asIScriptFunction or asITypeInfo pointers instead of the ids where possible. This will save the engine from translating the
+ id to the actual object.

+

You may use the user data in the various engine interfaces to store the cached information. For example, store a structure with the commonly used class methods as user data in the asITypeInfo interface. This way you will have quick access to the functions when they need to be called.

+

+Reuse the context object

+

The context object is a heavy weight object and you should avoid allocating new instances for each call. The object has been designed to be reused for multiple calls.

+

+Context pool

+

Ideally the application will keep a simple memory pool of allocated context objects, where new objects are only allocated if the is no free objects in the pool.

+

By using the engine's context callbacks, this context pool will also be automatically available to the engine for use in internal calls and the add-ons.

+

The code that wants to use a context from the pool should use the RequestContext and ReturnContext methods instead of the CreateContext method.

+

Here's a simple implementation of a context pool.

+
std::vector<asIScriptContext *> pool;
+
asIScriptContext *RequestContextCallback(asIScriptEngine *engine, void *param)
+
{
+
// Get a context from the pool, or create a new
+
asIScriptContext *ctx = 0;
+
if( pool.size() )
+
{
+
ctx = *pool.rbegin();
+
pool.pop_back();
+
}
+
else
+
ctx = engine->CreateContext();
+
+
return ctx;
+
}
+
+
void ReturnContextToPool(asIScriptEngine *engine, asIScriptContext *ctx, void *param)
+
{
+
pool.push_back(ctx);
+
+
// Unprepare the context to free non-reusable resources
+
ctx->Unprepare();
+
}
+

+Nested calls

+

Another form of reusing a context is to use nested calls.

+

Whenever an application registered function that is called from a script needs to execute another script it can reuse the already active context for a nested call. This way it is not necessary to look for an available context from a pool or allocate a new context just for this call.

+
void Func()
+
{
+
// Get the active context
+ +
+
// Store the current context state so we can restore it later
+
if( ctx && ctx->PushState() > 0 )
+
{
+
// Use the context normally, e.g.
+
// ctx->Prepare(...);
+
// ctx->Execute(...);
+
+
// Once done, restore the previous state
+
ctx->PopState();
+
}
+
}
+

+Compile scripts without line cues

+

The line cues are normally placed in the bytecode between each script statement. These are where the VM will allow the execution to be suspended, and also where the line callback is invoked.

+

If you do not need to receive a callback for every statement executed in a script then you may get a little more performance out of the script by compiling without the line cues.

+

The line callback will still work and is guaranteed to be invoked at least once per loop and every function call in the script to allow the application to interrupt infinite loops or infinitely recursive calls.

+

+Disable thread safety

+

If your application only uses one thread to invoke the script engine, then it may be worth it to compile the library without the thread safety to gain a little more performance.

+

To do this, define the AS_NO_THREADS flag in the as_config.h header or in the project settings when compiling the library.

+

+Turn off automatic garbage collection

+

While garbage collection is important in long running applications, it may be of interest to turn off the automatic garbage collection and then run the garbage collector manually in a controlled manner. The garbage collector is incremental so you shouldn't see long stalls while it is running, but it will consume CPU cycles that may be needed for other things.

+

To turn off the automatic garbage collector set the engine property asEP_AUTO_GARBAGE_COLLECT to false.

+
See also
Garbage collection
+

+Compare native calling convention versus generic calling convention

+

If you have specific functions that are called very frequently it may be worth comparing the performance between binding the functions using native calling convention versus the generic calling convention. It is not possible to generalize and say that one is always faster than the other, as it will vary depending on the function signature and the platforms ABI complexity.

+
See also
The generic calling convention, Calling convention
+
+
+
+
virtual int PopState()=0
Restores the state to resume previous script execution.
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
@ asEP_AUTO_GARBAGE_COLLECT
Enable or disable automatic garbage collection. Default: true.
Definition: angelscript.h:186
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int Unprepare()=0
Frees resources held by the context.
+
virtual asIScriptContext * CreateContext()=0
Creates a new script context.
+
@ asEP_BUILD_WITHOUT_LINE_CUES
Remove SUSPEND instructions between each statement. Default: false.
Definition: angelscript.h:170
+
virtual int SetEngineProperty(asEEngineProp property, asPWORD value)=0
Dynamically change some engine properties.
+
virtual int PushState()=0
Backups the current state to prepare the context for a nested call.
+
AS_API asIScriptContext * asGetActiveContext()
Returns the currently active context.
+ + + + diff --git a/docs/manual/doc_gc.html b/docs/manual/doc_gc.html new file mode 100644 index 0000000..01d66c9 --- /dev/null +++ b/docs/manual/doc_gc.html @@ -0,0 +1,126 @@ + + + + + + + +AngelScript: Garbage collection + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Garbage collection
+
+
+

Though AngelScript uses reference counting for memory management, there is still need for a garbage collector to take care of the few cases where circular referencing between objects prevents the reference counter from reaching zero. By default AngelScript automatically runs a few incremental steps of the garbage collector every time a new garbage collected object is created, this allows the destruction of garbage in an automatic way, yet doesn't waste time or disrupts the responsiveness of the application.

+

The automatic execution may not always be enough to clean up the garbage, for example, if the scripts create a lot of garbage with circular references. In this case the application may need to manually invoke the garbage collector from time to time. For this reason it is recommended that the application monitor the statistics for the garbage collector and adjust the frequency of the manual calls as necessary. The statistics is obtained through a call to GetGCStatistics, which returns the number of objects currently known to the garbage collector as well as the number of objects that have been destroyed and the number of object that have been detected as garbage with circular references.

+

The garbage collector implemented in AngelScript is incremental, so it can be executed for short periods of time without requiring the entire application to halt. For this reason, it is recommended that one or more calls to GarbageCollect(asGC_ONE_STEP) is made at least once during the normal event processing. The number of calls that should be made depends on how much garbage is created.

+

If the scripts produce a lot of garbage but only a low number of garbage with circular references, the application can make a call to GarbageCollect(asGC_FULL_CYCLE | asGC_DESTROY_GARBAGE), which will only destroy the known garbage without trying to detect circular references. This call is relatively fast as the garbage collector only has to make a trivial local check to determine if an object is garbage without circular references.

+

Finally, if the application goes into a state where responsiveness is not so critical, it might be a good idea to do a full cycle on the garbage collector, thus cleaning up all garbage at once. To do this, call GarbageCollect(asGC_FULL_CYCLE).

+

Should the automatic garbage collections not be desired, e.g. in critical inner loops where maximum performance is needed, it can easily be turned off with a call to SetEngineProperty(asEP_AUTO_GARBAGE_COLLECT, false).

+
See also
Memory management
+

+Callback for detected circular references

+

During the testing phase of your project it is wise to try to identify situations that create circular references as these have a potential of significantly impacting the performance. While the GetGCStatistics will tell you if circular references have been detected and destroyed, it will not tell you much about the actual objects involved in the circular references. To aid in this the application can set a callback for when circular references is detected with SetCircularRefDetectedCallback.

+

When this callback is invoked the objects in the circular reference have not yet been destroyed, so the application can inspect the content to get valuable hints on where and when they were created. The application must not however try to modify the objects at this time as would lead to undefined behaviour, and possibly even application crashes.

+

+Garbage collection and multi-threading

+

The garbage collector itself is thread safe, but in order to be able to safely use the garbage collector in a multi-threaded environment the application must make sure all the objects that may be in the garbage collector has thread safe implementations of the GC behaviours.

+
See also
Garbage collected objects and multi-threading
+
+
+
+ + + + diff --git a/docs/manual/doc_gc_object.html b/docs/manual/doc_gc_object.html new file mode 100644 index 0000000..f1e2c94 --- /dev/null +++ b/docs/manual/doc_gc_object.html @@ -0,0 +1,251 @@ + + + + + + + +AngelScript: Garbage collected objects + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Garbage collected objects
+
+
+

Reference counting as memory management has a drawback in that it is difficult to detect circular references when determining dead objects. AngelScript allows the application to register types with special behaviours to support the garbage collection for detecting circular references. These behaviours make the class a bit more complex, but you should only have to register them for a few types, e.g. generic container classes.

+
// Registering the garbage collected reference type
+
r = engine->RegisterObjectType("ref_type", 0, asOBJ_REF | asOBJ_GC); assert( r >= 0 );
+

The difference between the garbage collected and non-garbage collected types is in the addref and release behaviours, the class constructor, and the extra support behaviours.

+
See also
The dictionary add-on for an example of a garbage collected object
+

+GC support behaviours

+

The GC determines when objects should be destroyed by counting the references it can follow for each object. If the GC can see all references that points to an object, it knows that the object is part of a circular reference. If all the objects involved in that circular reference have no outside references it means that they should be destroyed.

+

The process of determining the dead objects uses the first four of the behaviours below, while the destruction of the objects is done by forcing the release of the object's references.

+
void CGCRef::SetGCFlag()
+
{
+
// Set the gc flag as the high bit in the reference counter
+
refCount |= 0x80000000;
+
}
+
+
bool CGCRef::GetGCFlag()
+
{
+
// Return the gc flag
+
return (refCount & 0x80000000) ? true : false;
+
}
+
+
int CGCRef::GetRefCount()
+
{
+
// Return the reference count, without the gc flag
+
return (refCount & 0x7FFFFFFF);
+
}
+
+
void CGCRef::EnumReferences(asIScriptEngine *engine)
+
{
+
// Call the engine::GCEnumCallback for all references to other objects held
+
engine->GCEnumCallback(myref);
+
}
+
+
void CGCRef::ReleaseAllReferences(asIScriptEngine *engine)
+
{
+
// When we receive this call, we are as good as dead, but
+
// the garbage collector will still hold a references to us, so we
+
// cannot just delete ourself yet. Just free all references to other
+
// objects that we hold
+
if( myref )
+
{
+
myref->Release();
+
myref = 0;
+
}
+
}
+
+
// Register the GC support behaviours
+
r = engine->RegisterObjectBehaviour("ref_type", asBEHAVE_SETGCFLAG, "void f()", asMETHOD(CGCRef,SetGCFlag), asCALL_THISCALL); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("ref_type", asBEHAVE_GETGCFLAG, "bool f()", asMETHOD(CGCRef,GetGCFlag), asCALL_THISCALL); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("ref_type", asBEHAVE_GETREFCOUNT, "int f()", asMETHOD(CGCRef,GetRefCount), asCALL_THISCALL); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("ref_type", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(CGCRef,EnumReferences), asCALL_THISCALL); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("ref_type", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(CGCRef,ReleaseAllReferences), asCALL_THISCALL); assert( r >= 0 );
+

+Factory for garbage collection

+

Whenever a garbage collected class is created, the garbage collector must be notified of it's existence. The easiest way of doing that is to have the factory behaviour, or the class constructor call the NotifyGarbageCollectorOfNewObject() method on the engine when initializing the class.

+
CGCRef *GCRef_Factory()
+
{
+
// Create the object and then notify the GC of its existence
+
CGCRef *obj = new CGCRef();
+
asITypeInfo *type = engine->GetTypeInfoByName("gc");
+ +
return obj;
+
}
+

You may want to consider caching the typeId, so that it doesn't have to be looked up through the relatively expensive call to GetTypeIdByDecl every time an object of this type is created.

+

Note, if you create objects of this type from the application side, you must also notify the garbage collector of its existence, so it's a good idea to make sure all code use the same way of creating objects of this type.

+

+Addref and release for garbage collection

+

For garbage collected objects it is important to make sure the AddRef and Release behaviours clear the GC flag. Otherwise it is possible that the GC incorrectly determine that the object should be destroyed.

+
void CGCRef::AddRef()
+
{
+
// Clear the gc flag and increase the reference counter
+
refCount = (refCount&0x7FFFFFFF) + 1;
+
}
+
+
void CGCRef::Release()
+
{
+
// Clear the gc flag, decrease ref count and delete if it reaches 0
+
refCount &= 0x7FFFFFFF;
+
if( --refCount == 0 )
+
delete this;
+
}
+
+
// Registering the addref/release behaviours
+
r = engine->RegisterObjectBehaviour("ref_type", asBEHAVE_ADDREF, "void f()", asMETHOD(CGCRef,AddRef), asCALL_THISCALL); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("ref_type", asBEHAVE_RELEASE, "void f()", asMETHOD(CGCRef,Release), asCALL_THISCALL); assert( r >= 0 );
+

+GC behaviours for value types

+

Value types are normally not thought of as being part of circular references as they themselves cannot be referenced, however if a value type can hold a reference to a type, and then that type can have the value type as a member then a circular reference can be established preventing the reference type from being released.

+

To solve these situations the value types can also be registered with some of the garbage collector behaviours.

+
// Registering the value type with garbage collected behaviour
+
r = engine->RegisterObjectType("value_type", sizeof(value_type), asOBJ_VALUE | asOBJ_GC | ...); assert( r >= 0 );
+
+
// Register the garbage collector behaviours
+
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ENUMREFS, "void f(int&in)", asMETHOD(value_type,EnumReferences), asCALL_THISCALL); assert(r >= 0);
+
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASEREFS, "void f(int&in)", asMETHOD(value_type, ReleaseReferences), asCALL_THISCALL); assert(r >= 0);
+

Only the asBEHAVE_ENUMREFS and asBEHAVE_RELEASEREFS should be registered for value types. These work the same way as for reference types, i.e. the asBEHAVE_ENUMREFS should call the engine's GCEnumCallback for all references held, and asBEHAVE_RELEASEREFS should clear all references held.

+

Reference types that contain value types that have GC behaviours need to have the asBEHAVE_ENUMREFS and asBEHAVE_RELEASEREFS behaviours adapted for this by forwarding the enum and release call to the value type. This forward is done by calling the engine's ForwardGCEnumReferences or ForwardGCReleaseReferences respectively.

+
void CGCRef2::EnumReferences(asIScriptEngine *engine)
+
{
+
// Forward the enum call to the member value type
+
engine->ForwardGCEnumReferences(valueObj, valueType);
+
}
+
+
void CGCRef2::ReleaseAllReferences(asIScriptEngine *engine)
+
{
+
// When we receive this call, we are as good as dead, but
+
// the garbage collector will still hold a references to us, so we
+
// cannot just delete ourself yet. Just free all references to other
+
// objects that we hold
+
+
// Forward the release call to the member value type
+
engine->ForwardGCReleaseReferences(valueObj, valueType);
+
}
+
See also
The ref object for a value type with GC behaviours, and the dictionary object for a ref type that can contain value types with GC behaviours.
+

+Garbage collected objects and multi-threading

+

If you plan on executing scripts from multiple threads with automatic garbage collection turned on, or if you plan on running the garbage collector manually from a background thread, then you must make sure that the object type behaviours that support the garbage collector are thread-safe. Especially the ADDREF, RELEASE, and ENUMREFS behaviours have a high probability of being invoked from multiple threads simultaneously. The RELEASEREFS behaviour will only be invoked when the Garbage Collector has determined that the object is already dead so it is guaranteed not to be invoked by multiple threads. The others, GETREFCOUNT, SETGCFLAG, and GETGCFLAG, are not sensitive as the garbage collector just use the information as a hint.

+

Making the ADDREF and RELEASE behaviours thread-safe is easy with the use of asAtomicInc and asAtomicDec. If the object is static container, i.e. the memory layout of the contents cannot change, then ENUMREFS is already thread-safe, but if memory layout can change, e.g. dynamic arrays or hash maps, then the iteration over the content in ENUMREFS must be protected so that it doesn't break in case the memory happen to change in the middle of the iteration.

+
See also
Garbage collection and multi-threading
+
+
+
+
@ asBEHAVE_RELEASE
Release.
Definition: angelscript.h:368
+
@ asBEHAVE_SETGCFLAG
(GC) Set GC flag
Definition: angelscript.h:381
+
@ asBEHAVE_RELEASEREFS
(GC) Release all references
Definition: angelscript.h:387
+
@ asBEHAVE_ENUMREFS
(GC) Enumerate held references
Definition: angelscript.h:385
+
virtual asITypeInfo * GetTypeInfoByName(const char *name) const =0
Returns the type interface by name.
+
@ asBEHAVE_GETREFCOUNT
(GC) Get reference count
Definition: angelscript.h:379
+
virtual void ForwardGCReleaseReferences(void *ref, asITypeInfo *type)=0
Used to forward GC callback to held value types that may contain references.
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
+
virtual void GCEnumCallback(void *reference)=0
Used by the garbage collector to enumerate all references held by an object.
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
@ asOBJ_GC
A garbage collected type. Only valid for reference types.
Definition: angelscript.h:254
+
@ asOBJ_VALUE
A value type.
Definition: angelscript.h:252
+
@ asBEHAVE_ADDREF
AddRef.
Definition: angelscript.h:366
+
virtual int NotifyGarbageCollectorOfNewObject(void *obj, asITypeInfo *type)=0
Notify the garbage collector of a new object that needs to be managed.
+
virtual void ForwardGCEnumReferences(void *ref, asITypeInfo *type)=0
Used to forward GC callback to held value types that may contain references.
+
@ asBEHAVE_GETGCFLAG
(GC) Get GC flag
Definition: angelscript.h:383
+ + + + diff --git a/docs/manual/doc_generic.html b/docs/manual/doc_generic.html new file mode 100644 index 0000000..0e92a0b --- /dev/null +++ b/docs/manual/doc_generic.html @@ -0,0 +1,146 @@ + + + + + + + +AngelScript: The generic calling convention + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
The generic calling convention
+
+
+

The generic calling convention is available for those situations where the application's native calling convention doesn't work, for example on platforms where support for native calling conventions haven't been added yet. You can detect if native calling conventions isn't supported on your target platform by calling the asGetLibraryOptions function and checking the returned string for "AS_MAX_PORTABILITY". If the identifier is in the returned string, then native calling conventions is not supported.

+

Functions implementing the generic calling conventions are always global functions (or static class methods), that take as parameter a pointer to an asIScriptGeneric interface and returns void.

+
// The function has been registered with signature:
+
// MyIntf @func(int, float, MyIntf @+)
+
void MyGenericFunction(asIScriptGeneric *gen)
+
{
+
// Extract the arguments
+
int arg0 = gen->GetArgDWord(0);
+
float arg1 = gen->GetArgFloat(1);
+
asIScriptObject *arg2 = reinterpret_cast<asIScriptObject*>(gen->GetArgObject(2));
+
+
// Call the real function
+
asIScriptObject *ret = MyFunction(arg0, arg1, arg2);
+
+
// Set the return value
+
gen->SetReturnObject(ret);
+
}
+

Functions using the generic calling convention can be registered anywhere the script engine is expecting global functions or class methods (except where explicitly written otherwise).

+

Writing the functions for the generic calling convention requires extracting each argument from the AngelScript stack, and then manually giving the return value back. For that reason it may be desired to use the automatic wrapper functions rather than writing the functions yourself.

+

+Extracting function arguments

+

To extract functions arguments from the generic interface you should call one of the GetArg methods that will return the value of the argument, or the GetAddressOfArg method. The GetAddressOfArg method returns a pointer to the actual value. The application should then cast this pointer to a pointer of the correct type so that the value can be read from the address.

+

If the function you're implementing represents a class method, the pointer to the object instance should be obtained with a call to GetObject.

+

The asIScriptGeneric interfaces treats the ref count the same way as in native calling conventions, i.e. the application function is responsible to releasing any handle received as a handle (or register the function with +).

+

+Returning values

+

To return a value from the function one of the SetReturn methods can be called to pass the value to the generic interface. Returning primitive values is straight forward, but care must be taken when returning object types, either by value, reference, or as object handle. Depending on the type and the function used it may be necessary to increment the reference count, or even make a copy of the object first. Carefully read the instructions for SetReturnAddress and SetReturnObject to determine what needs to be done to get the expected result.

+

It is also possible to use the GetAddressOfReturnLocation method to obtain the address of the memory where the return value will be stored. The memory is not initialized, so you should use the placement new operator to initialize this memory with a call to the constructor. This also works for primitive types, which makes this ideal for template implementations, such as that in the automatic wrapper functions.

+

If the function is registered to return a +, then the script engine will automatically increment the ref count, just as is done for native calling conventions.

+
+
+
+
virtual int SetReturnObject(void *obj)=0
Sets the object return value.
+
virtual float GetArgFloat(asUINT arg)=0
Returns the value of a float argument.
+
virtual void * GetArgObject(asUINT arg)=0
Returns a pointer to the object in a object argument.
+
The interface for the generic calling convention.
Definition: angelscript.h:3242
+
virtual asDWORD GetArgDWord(asUINT arg)=0
Returns the value of a 32-bit integer argument.
+
The interface for an instance of a script object.
Definition: angelscript.h:3413
+ + + + diff --git a/docs/manual/doc_global_class.html b/docs/manual/doc_global_class.html new file mode 100644 index 0000000..7629000 --- /dev/null +++ b/docs/manual/doc_global_class.html @@ -0,0 +1,118 @@ + + + + + + + +AngelScript: Script classes + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Script classes
+
+
+

Script classes are normally used to group together functions with values that will be operated upon by those functions. Multiple instances of a class can exists where each instance has different values.

+
+  class Foo
+  {
+    void bar() { value++; }
+    int value;
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_global_enums.html b/docs/manual/doc_global_enums.html new file mode 100644 index 0000000..29255af --- /dev/null +++ b/docs/manual/doc_global_enums.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Enums + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Enums
+
+
+

Enums are a convenient way of registering a family of integer constants that may be used throughout the script as named literals instead of numeric constants. Using enums often help improve the readability of the code, as the named literal normally explains what the intention is without the reader having to look up what a numeric value means in the manual.

+

Even though enums list the valid values, you cannot rely on a variable of the enum type to only contain values from the declared list. Always have a default action in case the variable holds an unexpected value.

+

The enum values are declared by listing them in an enum statement. Unless a specific value is given for an enum constant it will take the value of the previous constant + 1. The first constant will receive the value 0, unless otherwise specified.

+
+  enum MyEnum
+  {
+    eValue0,
+    eValue2 = 2,
+    eValue3,
+    eValue200 = eValue2 * 100
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_global_func.html b/docs/manual/doc_global_func.html new file mode 100644 index 0000000..812afc7 --- /dev/null +++ b/docs/manual/doc_global_func.html @@ -0,0 +1,117 @@ + + + + + + + +AngelScript: Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Functions
+
+
+

Global functions provide the mean to implement routines that should operate on some input and produce a result.

+
+  void foo()
+  {
+    // Do something
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_global_funcdef.html b/docs/manual/doc_global_funcdef.html new file mode 100644 index 0000000..216fded --- /dev/null +++ b/docs/manual/doc_global_funcdef.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Funcdefs + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Funcdefs
+
+
+

Funcdefs are used to define a function signature that will be used to store pointers to functions with matching signatures. With this a function pointer can be created, which is able to store dynamic pointers that can be invoked at a later time as a normal function call.

+
+  // Define a function signature for the function pointer
+  funcdef bool CALLBACK(int, int);
+
See also
Function handles for more information on how to use this
+
+
+
+ + + + diff --git a/docs/manual/doc_global_import.html b/docs/manual/doc_global_import.html new file mode 100644 index 0000000..58098e3 --- /dev/null +++ b/docs/manual/doc_global_import.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Imports + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Imports
+
+
+

Sometimes it may be useful to load script modules dynamically without having to recompile the main script, but still let the modules interact with each other. In that case the script may import functions from another module. This declaration is written using the import keyword, followed by the function signature, and then specifying which module to import from.

+

This allows the script to be compiled using these imported functions, without them actually being available at compile time. The application can then bind the functions at a later time, and even unbind them again.

+

If a script is calling an imported function that has not yet been bound the script will be aborted with a script exception.

+
+  import void MyFunction(int a, int b) from "Another module";
+
+
+
+ + + + diff --git a/docs/manual/doc_global_interface.html b/docs/manual/doc_global_interface.html new file mode 100644 index 0000000..908877b --- /dev/null +++ b/docs/manual/doc_global_interface.html @@ -0,0 +1,126 @@ + + + + + + + +AngelScript: Interfaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Interfaces
+
+
+

An interface works like a contract, the classes that implements an interface are guaranteed to implement the methods declared in the interface. This allows for the use of polymorphism in that a function can specify that it wants an object handle to an object that implements a certain interface. The function can then call the methods on this interface without having to know the exact type of the object that it is working with.

+
+  // The interface declaration
+  interface MyInterface
+  {
+    void DoSomething();
+  }
  // A class that implements the interface MyInterface
+  class MyClass : MyInterface
+  {
+    void DoSomething()
+    {
+      // Do something
+    }
+  }
+

A class can implement multiple interfaces; Simply list all the interfaces separated by a comma.

+
+
+
+ + + + diff --git a/docs/manual/doc_global_namespace.html b/docs/manual/doc_global_namespace.html new file mode 100644 index 0000000..3ce27b1 --- /dev/null +++ b/docs/manual/doc_global_namespace.html @@ -0,0 +1,151 @@ + + + + + + + +AngelScript: Namespaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Namespaces
+
+
+

Namespaces can be used to organize large projects in logical units that may be easier to remember. When using namespaces it is also not necessary to worry about using names for entities that may exist in a different part of the project under a different namespace.

+
+  namespace A
+  {
+    // Entities in a namespace see each other normally.
+    void function() { variable++; }
+    int variable;
+  }
  namespace B
+  {
+    // Entities in different namespaces don't immediately see each other and 
+    // can reuse the same name without causing name conflicts. By using the 
+    // scoping operator the entity from the desired namespace can be explicitly
+    // informed.
+    void function() { A::function(); }
+  }
+

Observe that in order to refer to an entity from a different namespace the scoping operator must be used, unless it is a parent namespace in which case it is only necessary if the child namespace declare the same entity.

+
+  int var;
+  namespace Parent
+  {
+    int var;
+    namespace Child
+    {
+      int var;
+      void func()
+      {
+        // Accessing variable in parent namespace requires 
+        // specifying the scope if an entity in a child namespace
+        // uses the same name
+        var = Parent::var;
        // To access variables in global scope the scoping 
+        // operator without any name should be used
+        Parent::var = ::var;
+      }
+    }
+  }
  void func()
+  {
+    // Access variable in a nested namespace requires 
+    // fully qualified scope specifier
+    int var = Parent::Child::var;
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_global_typedef.html b/docs/manual/doc_global_typedef.html new file mode 100644 index 0000000..0ade269 --- /dev/null +++ b/docs/manual/doc_global_typedef.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Typedefs + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Typedefs
+
+
+

Typedefs are used to define aliases for other types.

+

Currently a typedef can only be used to define an alias for primitive types, but a future version will have more complete support for all kinds of types.

+
+  typedef float  real32;
+  typedef double real64;
+
+
+
+ + + + diff --git a/docs/manual/doc_global_variable.html b/docs/manual/doc_global_variable.html new file mode 100644 index 0000000..4052d73 --- /dev/null +++ b/docs/manual/doc_global_variable.html @@ -0,0 +1,118 @@ + + + + + + + +AngelScript: Variables + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Variables
+
+
+

Global variables may be declared in the scripts, which will then be shared between all contexts accessing the script module.

+

Variables declared globally like this are accessible from all functions. The value of the variables are initialized at compile time and any changes are maintained between calls. If a global variable holds a memory resource, e.g. a string, its memory is released when the module is discarded or the script engine is reset.

+
+  int MyValue = 0;
+  const uint Flag1 = 0x01;
+

Variables of primitive types are initialized before variables of non-primitive types. This allows class constructors to access other global variables already with their correct initial value. The exception is if the other global variable also is of a non-primitive type, in which case there is no guarantee which variable is initialized first, which may lead to null-pointer exceptions being thrown during initialization.

+

Be careful with calling functions that may access global variables from within the initialization expression of global variables. While the compiler tries to initialize the global variables in the order they are needed, there is no guarantee that it will always succeed. Should a function access a global variable that has not yet been initialized you will get unpredictable behaviour or a null-pointer exception.

+
+
+
+ + + + diff --git a/docs/manual/doc_global_virtprop.html b/docs/manual/doc_global_virtprop.html new file mode 100644 index 0000000..ee6904a --- /dev/null +++ b/docs/manual/doc_global_virtprop.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Virtual properties + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Virtual properties
+
+
+

Virtual properties is a property with special behaviour for reading and writing to it. These can be declared globally, but are most usually found as members of classes.

+
+  int prop
+  {
+    get { return SomeValue(); }
+    set { UpdateValue(value); }
+  }
+
See also
Property accessors
+
+
+
+ + + + diff --git a/docs/manual/doc_good_practice.html b/docs/manual/doc_good_practice.html new file mode 100644 index 0000000..be16cbb --- /dev/null +++ b/docs/manual/doc_good_practice.html @@ -0,0 +1,130 @@ + + + + + + + +AngelScript: Good practices + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Good practices
+
+
+

This article will try to explain some good practices, that will help you get going faster and easier find the solution when a problem occurs.

+

+Always check return values for registrations

+

When configuring the script engine you should always check the return values, at least in debug mode. All error codes are negative so a simple assert( r >= 0 ) where r is the returned value is sufficient to pinpoint where the configuration failed.

+

If a function failed during the configuration, the Build method will always fail with a return code of asINVALID_CONFIGURATION. Unless you already verified the error codes for all the configuration calls, it will not be possible to determine what the error was.

+
// Verifying the return code with an assert is simple and won't pollute the code
+
r = engine->RegisterGlobalFunction("void func()", asFUNCTION(func), asCALL_CDECL); assert( r >= 0 );
+

assert() can safely be used with engine registrations, since the engine will set the internal state to invalid configuration if a function fails. Even in release mode the failure is discovered when a script is built.

+

+Use the message callback to receive detailed error messages

+

The return code from the register functions, Build, and CompileFunction, can only tell you that something was wrong, not what it was. To help identify the exact problem the message callback should be used. The script library will then send messages explaining the error or warning in clear text.

+

See Message callback for more information on the message callback.

+

+Always verify return value after executing script function

+

The VM can provide detailed information on any exception that occur in the script, for example in which function and line of code the problem occurred. It is also possible to enumerate the callstack and even the local variables.

+

See Exception handling

+
+
+
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+ + + + diff --git a/docs/manual/doc_hello_world.html b/docs/manual/doc_hello_world.html new file mode 100644 index 0000000..1bc118f --- /dev/null +++ b/docs/manual/doc_hello_world.html @@ -0,0 +1,233 @@ + + + + + + + +AngelScript: Your first script + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Your first script
+
+
+

This tutorial will show you the basics on how to configure the engine, compile a script, and then execute it. The code in this article is not complete, it only contains the relevant parts to explain the basic structure for using the script library. For complete source codes see the samples that come with the SDK.

+

In this tutorial a couple of add-ons are used to make the code easier. You are not required to use these in your own application, but they will most likely let you get your project up and running faster. You'll want to take a look at the rest of the add-ons later on to see what else may be useful for you.

+
// Include the definitions of the script library and the add-ons we'll use.
+
// The project settings may need to be configured to let the compiler where
+
// to find these headers. Don't forget to add the source modules for the
+
// add-ons to your project as well so that they will be compiled into the
+
// application.
+
#include <angelscript.h>
+
#include <scriptstdstring/scriptstdstring.h>
+
#include <scriptbuilder/scriptbuilder.h>
+

Being an embedded scripting library there isn't much that AngelScript allows the scripts to do by themselves, so the first thing the application must do is to register the interface that the script will have to interact with the application. The interface may consist of functions, variables, and even complete classes.

+

Pay special attention to how the message callback is registered right after the engine is created. The message callback is used by the engine to give human readable error messages when something isn't working as it should, e.g. a registration is done incorrectly, or a script has an error that fails to compile. While you still need to verify the return codes, the message callback can give you valuable information that will let you figure out what is wrong without much effort.

+
// Create the script engine
+ +
+
// Set the message callback to receive information on errors in human readable form.
+
int r = engine->SetMessageCallback(asFUNCTION(MessageCallback), 0, asCALL_CDECL); assert( r >= 0 );
+
+
// AngelScript doesn't have a built-in string type, as there is no definite standard
+
// string type for C++ applications. Every developer is free to register its own string type.
+
// The SDK do however provide a standard add-on for registering a string type, so it's not
+
// necessary to implement the registration yourself if you don't want to.
+
RegisterStdString(engine);
+
+
// Register the function that we want the scripts to call
+
r = engine->RegisterGlobalFunction("void print(const string &in)", asFUNCTION(print), asCALL_CDECL); assert( r >= 0 );
+

After the engine has been configured, the next step is to compile the scripts that should be executed.

+

The following is our script that will call the registered print function to write Hello world on the standard output stream. Let's say it's stored in the file test.as.

+
+  void main()
+  {
+    print("Hello world\n");
+  }
+

Here's the code for loading the script file and compiling it. The AngelScript engine itself doesn't have access to the filesystem so the loading the files has to be done by the application. Here we're going to use the script builder add-on, which does the loading of the script files, and some preprocessing, such as handling #include directives.

+
// The CScriptBuilder helper is an add-on that loads the file,
+
// performs a pre-processing pass if necessary, and then tells
+
// the engine to build a script module.
+
CScriptBuilder builder;
+
int r = builder.StartNewModule(engine, "MyModule");
+
if( r < 0 )
+
{
+
// If the code fails here it is usually because there
+
// is no more memory to allocate the module
+
printf("Unrecoverable error while starting a new module.\n");
+
return;
+
}
+
r = builder.AddSectionFromFile("test.as");
+
if( r < 0 )
+
{
+
// The builder wasn't able to load the file. Maybe the file
+
// has been removed, or the wrong name was given, or some
+
// preprocessing commands are incorrectly written.
+
printf("Please correct the errors in the script and try again.\n");
+
return;
+
}
+
r = builder.BuildModule();
+
if( r < 0 )
+
{
+
// An error occurred. Instruct the script writer to fix the
+
// compilation errors that were listed in the output stream.
+
printf("Please correct the errors in the script and try again.\n");
+
return;
+
}
+

The last step is to identify the function that is to be called, and set up a context for executing it.

+
// Find the function that is to be called.
+
asIScriptModule *mod = engine->GetModule("MyModule");
+
asIScriptFunction *func = mod->GetFunctionByDecl("void main()");
+
if( func == 0 )
+
{
+
// The function couldn't be found. Instruct the script writer
+
// to include the expected function in the script.
+
printf("The script must have the function 'void main()'. Please add it and try again.\n");
+
return;
+
}
+
+
// Create our context, prepare it, and then execute
+ +
ctx->Prepare(func);
+
int r = ctx->Execute();
+ +
{
+
// The execution didn't complete as expected. Determine what happened.
+ +
{
+
// An exception occurred, let the script writer know what happened so it can be corrected.
+
printf("An exception '%s' occurred. Please correct the code and try again.\n", ctx->GetExceptionString());
+
}
+
}
+

The exception handling above is very basic. The application may also obtain information about line number, function, call stack, and even values of local and global variables if wanted.

+

Don't forget to clean up after you're done with the engine.

+
// Clean up
+
ctx->Release();
+ +

+Helper functions

+

The print function is implemented as a very simple wrapper on the printf function.

+
// Print the script string to the standard output stream
+
void print(string &msg)
+
{
+
printf("%s", msg.c_str());
+
}
+
See also
Message callback, Script builder, string object, Samples
+
+
+
+
The interface to the virtual machine.
Definition: angelscript.h:2717
+
virtual asIScriptFunction * GetFunctionByDecl(const char *decl) const =0
Returns the function by its declaration.
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
virtual int Execute()=0
Executes the prepared function.
+
@ asEXECUTION_EXCEPTION
The execution was terminated by an unhandled script exception.
Definition: angelscript.h:404
+
The engine interface.
Definition: angelscript.h:1092
+
virtual const char * GetExceptionString()=0
Returns the exception string text.
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
virtual int SetMessageCallback(const asSFuncPtr &callback, void *obj, asDWORD callConv)=0
Sets a message callback that will receive compiler messages.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
@ asEXECUTION_FINISHED
The context has successfully completed the execution.
Definition: angelscript.h:398
+
virtual asIScriptContext * CreateContext()=0
Creates a new script context.
+
AS_API asIScriptEngine * asCreateScriptEngine(asDWORD version=ANGELSCRIPT_VERSION)
Creates the script engine.
+
The API definition for AngelScript.
+
The interface for a script function description.
Definition: angelscript.h:3823
+
The interface to the script modules.
Definition: angelscript.h:2218
+
virtual int ShutDownAndRelease()=0
Shuts down the engine then decrease the reference counter.
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
+
virtual int Release() const =0
Decrease reference counter.
+ + + + diff --git a/docs/manual/doc_license.html b/docs/manual/doc_license.html new file mode 100644 index 0000000..c954f66 --- /dev/null +++ b/docs/manual/doc_license.html @@ -0,0 +1,128 @@ + + + + + + + +AngelScript: License + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
License
+
+
+

+AngelCode Scripting Library

+

Copyright © 2003-2020 Andreas Jönsson

+

This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software.

+

Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions:

+
    +
  1. +

    The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.

    +

    +
  2. +
  3. +

    Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.

    +

    +
  4. +
  5. +This notice may not be removed or altered from any source distribution.
  6. +
+
+
+
+ + + + diff --git a/docs/manual/doc_memory.html b/docs/manual/doc_memory.html new file mode 100644 index 0000000..c39e23b --- /dev/null +++ b/docs/manual/doc_memory.html @@ -0,0 +1,162 @@ + + + + + + + +AngelScript: Memory management + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Memory management
+
+
+

This article will explain the memory management in AngelScript in detail. It's probably more detail than most developers need to know, but some may want to know exactly how it works in order to evaluate AngelScript better.

+

+Overview of the memory management

+

AngelScript uses a hybrid method with both reference counting and garbage collection, where reference counting is the main method and the garbage collection is only for backup when circular references needs to be resolved.

+

This design was chosen because reference counting is the easiest way of passing objects between script engine and application while still keeping track of live objects. If pure garbage collection was used, the script engine would have to know about the entire memory space of the application where script objects could be stored, otherwise it wouldn't be able to know if the objects are still alive or not.

+

The garbage collector is only used for those object types that have a possibility of forming a circular reference with itself or other objects, e.g. objects that have a member variable as a handle to the same type as itself. Whenever such an object is created, the garbage collector is informed so that it can keep track of the object.

+

The garbage collector can be executed automatically by the engine, but the application may also choose to do it manually to have better control over when it is done. The garbage collector is incremental, so it can be executed in small steps throughout the application execution without halting the rest of the processing for longer periods.

+
See also
Garbage collection
+

+Reference counting algorithm

+

All built-in script objects are automatically reference counted, and the application just need to make sure to call the AddRef and Release methods appropriately if it is storing any references to the objects outside the script engine.

+

Application registered objects may or may not be reference counted. Those that should be reference counted must implement the ADDREF and RELEASE behaviours so that AngelScript can notify the objects of the changes to the reference count. The application needs to keep track of the reference counter itself and free the memory when there are no more references to the object. This is usually done by having an integer member variable in the object structure itself to hold the reference count. It can also be implemented with a separate structure for holding the reference counter, but it adds extra overhead as the reference counter must be searched for with each change.

+
See also
Registering an object type
+

+Garbage collector algorithm

+

The garbage collector, used to handle the scenarios where reference counting isn't enough, uses the following algorithm.

+
    +
  1. +

    Destroy garbage: Free all objects with only one reference. This reference is held by the GC itself so therefore it is known that nobody else is referencing the object.

    +

    +
  2. +
  3. +

    Clear counters: Clear the GC counter for the remaining objects. This counter will be used to count the references to the object reachable from the GC. At the same time the objects are also flagged, so that we can detect if the references change while the garbage collector is running. This flag is automatically cleared when incrementing or decrementing the reference counter.

    +

    +
  4. +
  5. +

    Count GC references: For each of the objects in the GC, tell it to increment the GC counter for all objects it holds references to. This is only done for objects still flagged, because if the flag is no longer set we know it has been referenced by the application, thus it is considered alive along with all objects it holds references to.

    +

    +
  6. +
  7. +

    Mark live objects: Build a list of all objects in the GC that are not flagged or that doesn't have the GC count equal to the reference counter. These are objects that are considered alive. For each of the objects in the list, add all of the references in the object to the list as well, unless they are already in the list. As the list is traversed it will grow with new objects, these objects will also have their references added to the list. This way we're following the chain of references so we're gathering all objects that are alive.

    +

    +
  8. +
  9. +

    Verify unmarked objects: Make one more pass over the list of objects in the GC to see if any of the objects that were not marked as alive has had the flag cleared, if it has then the run the 'mark live objects' step again.

    +

    +
  10. +
  11. +

    Break circular references: All objects that have not been marked as alive by this time are involved in unreachable circular references and must be destroyed. The objects are destroyed by telling the objects to release the references they hold, thus breaking the circular references. When all circular references have been broken, the entire GC routine is restarted which will free the objects. If there were no dead objects, then the GC is finished.

    +

    +
  12. +
+

All of the steps are incremental, i.e. they can be interrupted to allow the application and scripts to execute before continuing the garbage collection. Step 1 can also be executed individually at any time during the cycle, this permits to free up memory for objects that are not involved in cyclic memory without having to wait for the detection cycle to complete.

+

The GC also has a notion of new and old generations. All new objects are placed in the new generation. In this generation, only trivial garbage collection is done, i.e. the 'destroy garbage' step above. Once the objects in the new generation have survived a few iterations without being destroyed, they are moved to the old generation. In the old generation the full garbage collection algorithm is executed.

+

This division of new and old generations help reduce the work done by the GC to detect circular references, and thus improve the performance of the application.

+
See also
Garbage collected objects
+

+Memory heap

+

By default AngelScript uses the memory heap accessed through the standard malloc and free global functions when allocating memory. Usually this means that AngelScript shares the memory heap with the application, though if the AngelScript library is compiled as a DLL or a shared object the heap may actually be separate from the application heap.

+

Some applications need extra control over the memory heap that the standard C/C++ library doesn't provide. This is common with video games for consoles, that have limited memory and cannot afford loosing space due to fragmentation or many small allocations. AngelScript aids these applications as well as it is possible to register custom memory allocation routines with the library, giving the application exact control over the memory used by AngelScript.

+
See also
asSetGlobalMemoryFunctions
+
+
+
+ + + + diff --git a/docs/manual/doc_module.html b/docs/manual/doc_module.html new file mode 100644 index 0000000..ceb0223 --- /dev/null +++ b/docs/manual/doc_module.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Script modules + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Script modules
+
+
+

Each module is an independent unit with it's own scope of script functions, global variables, and classes. All scripts executed from a module will work on the same global variables contained within that module. In this sense a module can be thought of as a shared library that is loaded into an application.

+

+Single module versus multiple modules

+

Whether it is better to use a single module with all the script code, or multiple modules with smaller and more specialized scripts, depends on the needs of the application.

+

A single module can be easier to implement, as all script code is in the same scope and can interact with full freedom. On the other hand the entire script must be compiled together, making it more difficult to exchange parts of the script or load only the logic that is needed at the moment.

+

With multiple modules an application can also expose different interfaces to scripts with different tasks, e.g. a script that controls the graphical user interface in an application should perhaps not have access to the same interface used by the script that controls the artificial intelligence, and vice versa.

+

Multiple modules can also use the same script code, in this case they will be completely distinct, each with their own set of global variables, functions, and types, even though the same source code was used. There may be valid reasons for using this in an application, but usually it is better to use a single module with script classes. The bytecode, functions, and types will then be shared, and the variables that should be distinct for each instance should be declared as class members.

+

+Exchanging information between modules

+

While modules are independent, it may sometimes be necessary to exchange information between them. This can be accomplished in many different ways. One way is through function binding, where one module imports functions from another module and call those directly. Another way is with shared script entities, where handles to objects or functions can be exchanged between the modules. A third alternative is through messaging or proxy functions exposed by the application.

+

All of these alternatives require a little code from the application, as one module doesn't automatically see another without the application's knowledge.

+
+
+
+ + + + diff --git a/docs/manual/doc_obj_handle.html b/docs/manual/doc_obj_handle.html new file mode 100644 index 0000000..743700d --- /dev/null +++ b/docs/manual/doc_obj_handle.html @@ -0,0 +1,162 @@ + + + + + + + +AngelScript: Object handles to the application + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Object handles to the application
+
+
+

In AngelScript an object handle is a reference counted pointer to an object. In the scripts they are used to pass the objects around by reference instead of by value. Depending on how an application type is registered the type will support handles.

+
See also
Registering an object type, Object handles in the script language
+

+Managing the reference counter in functions

+

Whenever the object handle is passed by value from the application to the script engine, or vice versa its reference should be accounted for. This means that the application must release any object handles it receives as parameters when it no longer needs them, it also means that the application must increase the reference counter for any object handle being returned to the script engine. This also applies to the generic calling convention.

+

A function that creates an object and returns it to the script engine might look like this:

+
// Registered as "obj@ CreateObject()"
+
obj *CreateObject()
+
{
+
// The constructor already initializes the ref count to 1
+
return new obj();
+
}
+

A function that receives an object handle from the script and stores it in a global variable might look like this:

+
// Registered as "void StoreObject(obj@)"
+
obj *o = 0;
+
void StoreObject(obj *newO)
+
{
+
// Release the old object handle
+
if( o ) o->Release();
+
+
// Store the new object handle
+
o = newO;
+
}
+

A function that retrieves a previously stored object handle might look like this:

+
// Registered as "obj@ RetrieveObject()"
+
obj *RetrieveObject()
+
{
+
// Increase the reference counter to account for the returned handle
+
if( o ) o->AddRef();
+
+
// It is ok to return null if there is no previous handle stored
+
return o;
+
}
+

A function that receives an object handle in the parameter, but doesn't store it looks like this:

+
// Registered as "void DoSomething(obj@)"
+
void DoSomething(obj *o)
+
{
+
// When finished with the object it must be released
+
if( o ) o->Release();
+
}
+

+Auto handles can make it easier

+

The application can use auto handles (@+) to alleviate some of the work of managing the reference counter. When registering the function or method with AngelScript, add a plus sign to the object handles that AngelScript should automatically manage. For parameters AngelScript will then release the reference after the function returns, and for the return value AngelScript will increase the reference on the returned pointer. The reference for the returned value is increased before the parameters are released, so it is possible to have the function return one of the parameters.

+
// Registered as "obj@+ ChooseObj(obj@+, obj@+)"
+
obj *ChooseObj(obj *a, obj *b)
+
{
+
// Because of the auto handles AngelScript will
+
// automatically manage the reference counters
+
return some_condition ? a : b;
+
}
+

The auto handles works the same way for the generic calling convention.

+
+
+
+ + + + diff --git a/docs/manual/doc_operator_precedence.html b/docs/manual/doc_operator_precedence.html new file mode 100644 index 0000000..8be9176 --- /dev/null +++ b/docs/manual/doc_operator_precedence.html @@ -0,0 +1,168 @@ + + + + + + + +AngelScript: Operator precedence + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Operator precedence
+
+
+

In expressions, the operator with the highest precedence is always computed first.

+

+Unary operators

+

Unary operators have the higher precedence than other operators, and between unary operators the operator closest to the actual value has the highest precedence. Post-operators have higher precedence than pre-operators.

+

This list shows the available unary operators.

+ + + + + + + + + + + + + + + + + + + +
:: scope resolution operator
[] indexing operator
++ -- post increment and decrement
. member access
++ -- pre increment and decrement
not ! logical not
+ - unary positive and negative
~ bitwise complement
@ handle of
+

+Binary and ternary operators

+

This list shows the dual and ternary operator precedence in decreasing order.

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
** exponent
* / % multiply, divide, and modulo
+ - add and subtract
<< >> >>> left shift, right shift, and arithmetic right shift
& bitwise and
^ bitwise xor
| bitwise or
<= < >= > comparison
== != is !is xor ^^ equality, identity, and logical exclusive or
and && logical and
or || logical or
?: condition
= += -= *= /= %= **= &=
+ |= ^= <<= >>= >>>=
assignment and compound assignments
+
+
+
+ + + + diff --git a/docs/manual/doc_overview.html b/docs/manual/doc_overview.html new file mode 100644 index 0000000..d56ab33 --- /dev/null +++ b/docs/manual/doc_overview.html @@ -0,0 +1,115 @@ + + + + + + + +AngelScript: Overview + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Overview
+
+
+

AngelScript is structured around an engine where the application should register the functions, properties, and even types, that the scripts will be able to use. The scripts are then compiled into modules, where the application may have one or more modules, depending on the need of the application. The application can also expose a different interface to each module through the use of access profiles. This is especially useful when the application works with multiple types of scripts, e.g. GUI, AI control, etc.

+

As the scripts are compiled into bytecode AngelScript also provides a virtual machine, also known as a script context, for executing the bytecode. The application can have any number of script context at the same time, though most applications will probably only need one. The contexts support suspending the execution and then resuming it, so the application can easily implement features such as concurrent scripts and co-routines. The script context also provides an interface for extracting run-time information, useful for debugging scripts.

+

The script language is based on the well known syntax of C++ and more modern languages such as Java, C#, and D. Anyone with some knowledge of those languages, or other script languages with similar syntax, such as Javascript and ActionScript, should feel right at home with AngelScript. Contrary to most script languages, AngelScript is a strongly typed language, which permits faster execution of the code and smoother interaction with the host application as there will be less need for runtime evaluation of the true type of values.

+

The memory management in AngelScript is based on reference counting with an incremental garbage collector for detecting and freeing objects with circular references. This provides for a controlled environment without application freezes as the garbage collector steps in to free up memory.

+
+
+
+ + + + diff --git a/docs/manual/doc_reg_basicref.html b/docs/manual/doc_reg_basicref.html new file mode 100644 index 0000000..a32dab3 --- /dev/null +++ b/docs/manual/doc_reg_basicref.html @@ -0,0 +1,209 @@ + + + + + + + +AngelScript: Registering a reference type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering a reference type
+
+
+

The basic reference type should be registered with the following behaviours: asBEHAVE_FACTORY, asBEHAVE_ADDREF, and asBEHAVE_RELEASE.

+
// Registering the reference type
+
r = engine->RegisterObjectType("ref", 0, asOBJ_REF); assert( r >= 0 );
+
See also
The any add-on for an example of a reference type.
+
+Garbage collected objects, Class hierarchies, Registering a scoped reference type, and Registering a single-reference type for more advanced types.
+

+Factory function

+

The factory function is the one that AngelScript will use to instantiate objects of this type when a variable is declared. It is responsible for allocating and initializing the object memory.

+

The default factory function doesn't take any parameters and should return an object handle for the new object. Make sure the object's reference counter is accounting for the reference being returned by the factory function, so that the object is properly released when all references to it are removed.

+
CRef::CRef()
+
{
+
// Let the constructor initialize the reference counter to 1
+
refCount = 1;
+
}
+
+
CRef *Ref_Factory()
+
{
+
// The class constructor is initializing the reference counter to 1
+
return new CRef();
+
}
+
+
// Registering the factory behaviour
+
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_FACTORY, "ref@ f()", asFUNCTION(Ref_Factory), asCALL_CDECL); assert( r >= 0 );
+

You may also register factory functions that take parameters, which may then be used when initializing the object.

+

The factory function must be registered as a global function, but can be implemented as a static class method, common global function, or a global function following the generic calling convention.

+

Even though a factory function returns an object handle, it must not return a null handle unless it also sets an exception to signal that the instantiation of the object failed.

+

The behaviour is undefined if a factory function returns null without setting an exception.

+

See also List factory function.

+

+Addref and release behaviours

+
void CRef::Addref()
+
{
+
// Increase the reference counter
+
refCount++;
+
}
+
+
void CRef::Release()
+
{
+
// Decrease ref count and delete if it reaches 0
+
if( --refCount == 0 )
+
delete this;
+
}
+
+
// Registering the addref/release behaviours
+
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_ADDREF, "void f()", asMETHOD(CRef,AddRef), asCALL_THISCALL); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("ref", asBEHAVE_RELEASE, "void f()", asMETHOD(CRef,Release), asCALL_THISCALL); assert( r >= 0 );
+

If the instances of this object will be shared between multiple threads, remember to guarantee that the reference counter is thread safe by making the increments and decrements with atomic instructions.

+
See also
Multithreading
+

+Reference types without reference counting

+

If the application provides its own memory management that isn't based on reference counting, then it is possible to register the type without the addref and release behaviours if the flag, asOBJ_NOCOUNT is informed in the call to RegisterObjectType, i.e.

+
// Registering the reference type
+
r = engine->RegisterObjectType("ref", 0, asOBJ_REF | asOBJ_NOCOUNT); assert( r >= 0 );
+

Without the addref and release behaviours the application must be careful to not destroy any objects that may potentially still be referenced by the script engine, e.g. in a global variable, or other location.

+

Unless the objects are guaranteed to stay alive as long as the script engine is instantiated, you may want to consider disabling global variables with engine property asEP_DISALLOW_GLOBAL_VARS. This will make it much easier for the application to know where references to the objects are kept. An alternative to disabling all global variables, is to selectively disallow only the global variables, that can eventually store a reference to the object type. This can be done by enumerating the compiled global variables after script has been built and giving an error to the user in case he includes a variable he shouldn't.

+

+List factory function

+

The list factory function is a special factory function that can be registered to allow a type to be created from an initialization list. The list factory function takes only a single pointer as argument. AngelScript will pass a pointer to the initialization list buffer in that argument. The buffer will contain all the values necessary to create and initialize the object.

+

In order for the script engine to know what information must be placed in the buffer the application must provide the list pattern when registering the list factory. The list pattern is declared with a special syntax involving datatypes and the following tokens: {, }, ?, repeat, and repeat_same.

+

The tokens { } are used to declare that the list pattern expects a list of values or a sublist of values. The repeat token is used to signal that the next type or sub list can be repeated 0 or more times. The repeat_same token is similar to repeat except that it also tells the compiler that every time the same list is repeated it should have the same length. Any data type can be used in the list pattern, as long as it can be passed by value. When a variable type is desired the token ? can be used.

+

Here's a couple of examples for registering list factories with list patterns:

+
// The array type can be initialized for example with: intarray a = {1,2,3};
+ +
"intarray@ f(int &in) {repeat int}", ...);
+
+
// The dictionary type can be initialized with: dictionary d = {{'a',1}, {'b',2}, {'c',3}};
+ +
"dictionary @f(int &in) {repeat {string, ?}}", ...);
+
+
// The grid type can be initialized with: grid a = {{1,2},{3,4}};
+
engine->RgisterObjectBehaviour("grid", asBEHAVE_LIST_FACTORY,
+
"grid @f(int &in) {repeat {repeat_same int}}", ...);
+

The list buffer passed to the factory function will be populated using the following rules:

+
    +
  • Whenever the pattern expects a repeat, the buffer will contain a 32bit integer with the number of repeated values that will come afterwards
  • +
  • Whenever the pattern expects a ?, then the buffer will contain a 32bit integer representing the typeId of the value that comes after.
  • +
  • Whenever the pattern expects a reference type, the buffer will contain a pointer to the object
  • +
  • Whenever the pattern expects a value type, the buffer will contain the object itself
  • +
  • All values in the buffer will be aligned to a 32bit boundary, unless the size of the value placed in the buffer is smaller than 32bits.
  • +
+
See also
array template object and dictionary object for example implementations of list factories.
+

+Registering an uninstantiable reference type

+

Sometimes it may be useful to register types that cannot be instantiated by the scripts, yet can be interacted with. You can do this by registering the type as a normal reference type, but omit the registration of the factory behaviour. You can later register global properties, or functions that allow the scripts to access objects created by the application via object handles.

+

This would be used when the application has a limited number of objects available and doesn't want to create new ones. For example singletons, or pooled objects.

+
+
+
+
@ asOBJ_NOCOUNT
The type doesn't use reference counting. Only valid for reference types.
Definition: angelscript.h:318
+
@ asBEHAVE_LIST_FACTORY
Factory used exclusively for initialization lists.
Definition: angelscript.h:364
+
@ asBEHAVE_FACTORY
Factory.
Definition: angelscript.h:362
+
@ asBEHAVE_RELEASE
Release.
Definition: angelscript.h:368
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
@ asOBJ_REF
A reference type.
Definition: angelscript.h:250
+
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
@ asBEHAVE_ADDREF
AddRef.
Definition: angelscript.h:366
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+ + + + diff --git a/docs/manual/doc_reg_objmeth.html b/docs/manual/doc_reg_objmeth.html new file mode 100644 index 0000000..dd03130 --- /dev/null +++ b/docs/manual/doc_reg_objmeth.html @@ -0,0 +1,151 @@ + + + + + + + +AngelScript: Registering object methods + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering object methods
+
+
+

Class methods are registered with the RegisterObjectMethod call. Both non-virtual and virtual methods are registered the same way.

+

Static class methods are in reality global functions so those should be registered as global functions and not as object methods.

+
// Register a class method
+
void MyClass::ClassMethod()
+
{
+
// Do something
+
}
+
+
r = engine->RegisterObjectMethod("mytype", "void ClassMethod()", asMETHOD(MyClass,ClassMethod), asCALL_THISCALL); assert( r >= 0 );
+

It is also possible to register a global function that takes a pointer to the object as a class method. This can be used to extend the functionality of a class when accessed via AngelScript, without actually changing the C++ implementation of the class.

+
// Register a global function as an object method
+
void MyClass_MethodWrapper(MyClass *obj)
+
{
+
// Access the object
+
obj->DoSomething();
+
}
+
+
r = engine->RegisterObjectMethod("mytype", "void MethodWrapper()", asFUNCTION(MyClass_MethodWrapper), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+
See also
Registering a function for more details on how the macros work.
+

+Composite members

+

If the application class that is being registered uses composition, then it is possible to register the methods of the composite members like this:

+
struct Component
+
{
+
int DoSomething();
+
};
+
+
struct Object
+
{
+
Component *comp;
+
};
+
+
r = engine->RegisterObjectMethod("object", "int DoSomething()", asMETHOD(Component, DoSomething), asCALL_THISCALL, 0, asOFFSET(Object, comp), true); assert( r >= 0 );
+

The last parameter indicates that to reach the composite member it is necessary to dereference the pointer. If the composite member is inlined, then the parameter should be set to false.

+
+
+
+
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
#define asOFFSET(s, m)
Returns the offset of an attribute in a struct.
Definition: angelscript.h:672
+ + + + diff --git a/docs/manual/doc_reg_objprop.html b/docs/manual/doc_reg_objprop.html new file mode 100644 index 0000000..2a8d366 --- /dev/null +++ b/docs/manual/doc_reg_objprop.html @@ -0,0 +1,172 @@ + + + + + + + +AngelScript: Registering object properties + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering object properties
+
+
+

Class member variables can be registered so that they can be directly accessed by the script without the need for any method calls.

+
struct MyStruct
+
{
+
int a;
+
};
+
+
r = engine->RegisterObjectProperty("mytype", "int a", asOFFSET(MyStruct,a)); assert( r >= 0 );
+

If a class member is indirect, i.e. the class holds a pointer to the member that is allocated on the heap, then it is possible to registered the property using & to tell the script engine that an dereference is needed to access the member.

+
struct MyStruct
+
{
+
OtherStruct *a;
+
};
+
+
r = engine->RegisterObjectProperty("mytype", "othertype &a", asOFFSET(MyStruct,a)); assert( r >= 0 );
+

Of course, the application must make sure the pointer is valid during the whole time that it may be accessed from the script.

+

+Composite members

+

If the application class that is being registered uses composition, then it is possible to register the properties of the composite members like this:

+
struct Component
+
{
+
int a;
+
};
+
+
struct Object
+
{
+
Component *comp;
+
};
+
+
r = engine->RegisterObjectProperty("object", "comp_a", asOFFSET(Component, a), asOFFSET(Object, comp), true); assert( r >= 0 );
+

The last parameter indicates that to reach the property of the composite member it is necessary to dereference the pointer. If the composite member is inlined, then the parameter should be set to false.

+

+Property accessors

+

It is also possible to expose properties through property accessors, which are a pair of class methods with prefixes 'get_' and 'set_' and the function decorator 'property' for getting and setting the property value. These methods should be registered with RegisterObjectMethod. This is especially useful when the offset of the property cannot be determined, or if the type of the property is not registered in the script and some translation must occur, i.e. from char* to string.

+

If the application class contains a C++ array as a member, it may be advantageous to expose the array through indexed property accessors rather than attempting to matching the C++ array type to a registered type in AngelScript. To do this you can create a couple of simple proxy functions that will translate to the array access.

+
Note
The behaviour of virtual properties can be customized with the engine property asEP_PROPERTY_ACCESSOR_MODE.
+
struct MyStruct
+
{
+
int array[16];
+
};
+
+
// Write a couple of proxy
+
int MyStruct_get_array(unsigned int idx, MyStruct *o)
+
{
+
if( idx >= 16 ) return 0;
+
return o->array[idx];
+
}
+
+
void MyStruct_set_array(unsigned int idx, int value, MyStruct *o)
+
{
+
if( idx >= 16 ) return;
+
o->array[idx] = value;
+
}
+
+
// Register the proxy functions as member methods
+
r = engine->RegisterObjectMethod("mytype", "int get_array(uint) property", asFUNCTION(MyStruct_get_array), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+
r = engine->RegisterObjectMethod("mytype", "void set_array(uint, int) property", asFUNCTION(MyStruct_set_array), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+
+
+
+
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual int RegisterObjectProperty(const char *obj, const char *declaration, int byteOffset, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a property for the object type.
+
#define asOFFSET(s, m)
Returns the offset of an attribute in a struct.
Definition: angelscript.h:672
+ + + + diff --git a/docs/manual/doc_reg_opbeh.html b/docs/manual/doc_reg_opbeh.html new file mode 100644 index 0000000..3c169e3 --- /dev/null +++ b/docs/manual/doc_reg_opbeh.html @@ -0,0 +1,145 @@ + + + + + + + +AngelScript: Registering operator behaviours + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering operator behaviours
+
+
+

In order for AngelScript to know how to work with the application registered types, it is necessary to register some behaviours, for example for memory management.

+

The memory management behaviours are described with the registration of reference types and value types.

+

Other advanced behaviours are described with the advanced types.

+

Most behaviours are implemented as ordinary class methods, except with specific names that the compiler can understand.

+

+Operator overloads

+

In AngelScript all operator overloads are implemented as class methods with predefined names, which is different from C++ where both class methods and global functions may be used. Especially the dual operators, i.e. those that take two operands, usually has one implemented as a class method, and a global function for the reverse order.

+

To register C++ operator overloads you'll use the methods described in How to get the address of the application function or method.

+

Example on how to register operator overloads

+
class MyClass
+
{
+
...
+
+
// The operator 'MyClass - int' has been implemented as a method
+
MyClass operator-(int) const;
+
+
// The operator 'int - MyClass' has been implemented as a global function
+
static MyClass operator-(int, const MyClass &);
+
}
+
+
void RegisterMyClass(asIScriptEngine *engine)
+
{
+
// Registering the operator 'MyClass - int'
+
engine->RegisterObjectMethod("MyClass", "MyClass opSub(int) const", asMETHODPR(MyClass, operator-, (int) const, MyClass), asCALL_THISCALL);
+
+
// Registering the operator 'int - MyClass'
+
engine->RegisterObjectMethod("MyClass", "MyClass opSub_r(int) const", asFUNCTIONPR(operator-, (int, const MyClass &), MyClass), asCALL_CDECL_OBJLAST);
+
}
+
+
+
+
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
The engine interface.
Definition: angelscript.h:1092
+
#define asFUNCTIONPR(f, p, r)
Returns an asSFuncPtr representing the function specified by the name, parameter list,...
Definition: angelscript.h:684
+
#define asMETHODPR(c, m, p, r)
Returns an asSFuncPtr representing the class method specified by class, method name,...
Definition: angelscript.h:742
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+ + + + diff --git a/docs/manual/doc_register_api.html b/docs/manual/doc_register_api.html new file mode 100644 index 0000000..fd2f389 --- /dev/null +++ b/docs/manual/doc_register_api.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: What can be registered + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
What can be registered
+
+
+

AngelScript requires the application developer to register the interface that the scripts should use to interact with anything outside the script itself.

+

It's possible to register global functions and global properties that can be used directly by the scripts.

+

For more complex scripts it may be useful to register new object types to complement the built-in data types.

+

AngelScript doesn't have a built-in string type as there is no de-facto standard for string types in C++. Instead AngelScript permits the application to register its own preferred string type, and a string factory that the script engine will use to instanciate the strings.

+

There is also no default built-in array type as this too is something that most developers may want to have their own version of. The array type is registered as a template, which is then set as the default array type. A standard array add-on is provided for those that do not want to implement their own array type.

+

Class interfaces can be registered if you want to guarantee that script classes implement a specific set of class methods. Interfaces can be easier to use when working with script classes from the application, but they are not necessary as the application can easily enumerate available methods and properties even without the interfaces.

+

Function definitions can be registered when you wish to allow the script to pass function pointers to the application, e.g. to implement callback routines.

+

Enumeration types and typedefs can also be registered to improve readability of the scripts.

+
+
+
+ + + + diff --git a/docs/manual/doc_register_api_topic.html b/docs/manual/doc_register_api_topic.html new file mode 100644 index 0000000..84c53e2 --- /dev/null +++ b/docs/manual/doc_register_api_topic.html @@ -0,0 +1,118 @@ + + + + + + + +AngelScript: Registering the application interface + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ + +
+ + + + diff --git a/docs/manual/doc_register_api_topic.js b/docs/manual/doc_register_api_topic.js new file mode 100644 index 0000000..cf91125 --- /dev/null +++ b/docs/manual/doc_register_api_topic.js @@ -0,0 +1,13 @@ +var doc_register_api_topic = +[ + [ "What can be registered", "doc_register_api.html", null ], + [ "Registering a function", "doc_register_func.html", [ + [ "How to get the address of the application function or method", "doc_register_func.html#doc_register_func_1", null ], + [ "Calling convention", "doc_register_func.html#doc_register_func_2", null ], + [ "A little on type differences", "doc_register_func.html#doc_register_func_3", null ], + [ "Virtual inheritance is not supported", "doc_register_func.html#doc_register_func_4", null ] + ] ], + [ "Registering global properties", "doc_register_prop.html", null ], + [ "Registering an object type", "doc_register_type.html", "doc_register_type" ], + [ "Advanced application interface", "doc_advanced_api.html", "doc_advanced_api" ] +]; \ No newline at end of file diff --git a/docs/manual/doc_register_func.html b/docs/manual/doc_register_func.html new file mode 100644 index 0000000..d1ae928 --- /dev/null +++ b/docs/manual/doc_register_func.html @@ -0,0 +1,201 @@ + + + + + + + +AngelScript: Registering a function + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering a function
+
+
+

This article aims to explain the way functions are registered with AngelScript, and some of the differences between C++ and AngelScript that the developer needs to be aware of in order to be successful in registering the application interface that the scripts will use. The principles learned here are used in several locations, such as RegisterGlobalFunction, RegisterObjectMethod, RegisterObjectBehaviour, etc.

+

+How to get the address of the application function or method

+

The macros asFUNCTION, asFUNCTIONPR, asMETHOD, and asMETHODPR have been implemented to facilitate the task of getting the function pointer and passing them on to the script engine.

+

The asFUNCTION takes the function name as the parameter, which works for all global functions that do not have any overloads. If you use overloads, i.e. multiple functions with the same name but with different parameters, then you need to use asFUNCTIONPR instead. This macro takes as parameter the function name, parameter list, and return type, so that the C++ compiler can resolve exactly which overloaded function to take the address of.

+
// Global function
+
void globalFunc();
+
r = engine->RegisterGlobalFunction("void globalFunc()", asFUNCTION(globalFunc), asCALL_CDECL); assert( r >= 0 );
+
+
// Overloaded global functions
+
void globalFunc2(int);
+
void globalFunc2(float);
+
r = engine->RegisterGlobalFunction("void globalFunc2(int)", asFUNCTIONPR(globalFunc2, (int), void), asCALL_CDECL); assert( r >= 0 );
+

The same goes for asMETHOD and asMETHODPR. The difference between these and asFUNCTION/asFUNCTIONPR is that the former take the class name as well as parameter.

+
class Object
+
{
+
// Class method
+
void method();
+
+
// Overloaded method
+
void method2(int input);
+
void method2(int input, int &output);
+
+
// Const method
+
int getAttr(int) const;
+
};
+
+
// Registering the class method
+
r = engine->RegisterObjectMethod("object", "void method()", asMETHOD(Object,method), asCALL_THISCALL); assert( r >= 0 );
+
+
// Registering the overloaded methods
+
r = engine->RegisterObjectMethod("object", "void method2(int)", asMETHODPR(Object, method2, (int), void), asCALL_THISCALL); assert( r >= 0 );
+
r = engine->RegisterObjectMethod("object", "void method2(int, int &out)", asMETHODPR(Object, method2, (int, int&), void), asCALL_THISCALL); assert( r >= 0 );
+
+
// Registering a const method
+
r = engine->RegisterObjectMethod("object", "int getAttr(int) const", asMETHODPR(Object, getAttr, (int) const, int), asCALL_THISCALL); assert( r >= 0 );
+
Note
asMETHOD doesn't work well for classes with multiple inheritances. On some compilers the method pointer ends up referring to the wrong base class due to a limitation in the C++ compiler. The solution then is to use the asMETHODPR macro.
+

It is possible to register a class method to be called from the script as if it was a global function. This is commonly done when exposing a singleton to the script interface, as the singleton's methods then look like ordinary global functions. When this is done the application must have a reference to the object at the time of the registration and the application must guarantee that the object is alive until it is no longer possible for the scripts to call the method.

+
class MySingleton
+
{
+
// Class method to be called from script as if a global function
+
void MyGlobalFunc(int arg1, int arg2);
+
};
+
+
MySingleton single;
+
+
// Registering the singleton's method as if a global function
+
r = engine->RegisterGlobalFunction("void MyGlobalFunc(int, int)", asMETHOD(MySingleton, MyGlobalFunc), asCALL_THISCALL_ASGLOBAL, &single); assert( r >= 0 );
+

+Calling convention

+

AngelScript accepts most common calling conventions that C++ uses, i.e. cdecl, stdcall, and thiscall. There is also a generic calling convention that can be used for example when native calling conventions are not supported on the target platform.

+

All functions and behaviours must be registered with the asCALL_CDECL, asCALL_STDCALL, asCALL_THISCALL, or asCALL_GENERIC flags to tell AngelScript which calling convention the application function uses. The special conventions asCALL_CDECL_OBJLAST and asCALL_CDECL_OBJFIRST can also be used wherever asCALL_THISCALL is accepted, in order to simulate a class method through a global function. Functor objects can also be used to emulate global functions with the convention asCALL_THISCALL_ASGLOBAL, or class methods with the conventions asCALL_THISCALL_OBJFIRST and asCALL_THISCALL_OBJLAST.

+

If the incorrect calling convention is given on the registration you'll very likely see the application crash with a stack corruption whenever the script engine calls the function. cdecl is the default calling convention for all global functions in C++ programs, so if in doubt try with asCALL_CDECL first. The calling convention only differs from cdecl if the function is explicitly declared to use a different convention, or if you've set the compiler options to default to another convention.

+

For class methods there is only the thiscall convention, except when the method is static, as those methods are in truth global functions in the class namespace. Normal methods, virtual methods, and methods for classes with multiple inheritance are all registered the same way, with asCALL_THISCALL.

+

Classes with virtual inheritance are not supported natively, and for these it will be necessary to create wrapper functions. These wrapper functions can either be implemented manually, or the template based automatic wrappers from the add-on can be used.

+
See also
The generic calling convention
+

+A little on type differences

+

AngelScript supports most of the same types that C++ has, but there are differences that you'll need to know when registering functions, methods, and behaviours. Make sure you read and understand the article Datatypes in AngelScript and C++.

+

When registering functions that take references, you must make sure to inform the correct keyword that informs the intention of the data in the reference. For example, a parameter reference that is meant to be used as input should have the keyword 'in' defined after the & character, and an output reference should have the keyword 'out'. Reference types can be passed as both input and output references, in which case the keyword 'inout' can be used, or simply no keyword at all. Value types on the other hand cannot use 'inout' references, as AngelScript cannot guarantee that the reference will be valid during the whole execution of the function.

+

When registering functions that take pointers, you need to determine what the pointer represents. If the pointer is to a value type though, then it can only be registered as a reference. If the pointer is to a reference type, then it can be registered as an object handle, or as a plain reference. If you choose to use the object handle then you need to pay attention to the reference counter in the type so you don't get problems with memory leaks or crashes due to objects being destroyed too early.

+

+Virtual inheritance is not supported

+

Registering class methods for classes with virtual inheritance is not supported due to the high complexity involved with them. Each compiler implements the method pointers for these classes differently, and keeping the code portable would be very difficult. This is not a great loss though, as classes with virtual inheritance are relatively rare, and it is easy to write simple proxy functions where the classes to exist.

+
class A { void SomeMethodA(); };
+
class B : virtual A {};
+
class C : virtual A {};
+
class D : public B, public C {};
+
+
// Need a proxy function for registering SomeMethodA for class D
+
void D_SomeMethodA_proxy(D *d)
+
{
+
// The C++ compiler will resolve the virtual method for us
+
d->SomeMethodA();
+
}
+
+
// Register the global function as if it was a class method,
+
// but with calling convention asCALL_CDECL_OBJLAST
+
engine->RegisterObjectMethod("D", "void SomeMethodA()", asFUNCTION(D_SomeMethodA_proxy), asCALL_CDECL_OBJLAST);
+

If you have a lot of classes with virtual inheritance, you should probably think about writing a template proxy function, so you don't have to manually write all the proxy functions.

+
+
+
+
virtual int RegisterObjectMethod(const char *obj, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a method for the object type.
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
#define asFUNCTIONPR(f, p, r)
Returns an asSFuncPtr representing the function specified by the name, parameter list,...
Definition: angelscript.h:684
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
#define asMETHOD(c, m)
Returns an asSFuncPtr representing the class method specified by class and method name.
Definition: angelscript.h:740
+
#define asMETHODPR(c, m, p, r)
Returns an asSFuncPtr representing the class method specified by class, method name,...
Definition: angelscript.h:742
+
@ asCALL_THISCALL
A thiscall class method.
Definition: angelscript.h:232
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
@ asCALL_THISCALL_ASGLOBAL
A thiscall class method registered as a global function.
Definition: angelscript.h:230
+ + + + diff --git a/docs/manual/doc_register_prop.html b/docs/manual/doc_register_prop.html new file mode 100644 index 0000000..31e986f --- /dev/null +++ b/docs/manual/doc_register_prop.html @@ -0,0 +1,144 @@ + + + + + + + +AngelScript: Registering global properties + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering global properties
+
+
+

By registering global properties with the script engine you can allow the scripts to inspect and/or modify variables within the application directly, without the need to write special functions to do this.

+

To register the property, you just need to call the RegisterGlobalProperty method, passing the declaration and a pointer to the property. Remember that the registered property must stay alive as long as its registration is valid in the engine.

+

Make sure you give the correct pointer to AngelScript. The pointer should be to value that the declaration refers to, i.e. if the declaration is an integer then the pointer should be to the integer value, if the declaration is an object handle then the pointer should be to the pointer to the object, etc. Unfortunately there is no way for AngelScript to validate that the pointer is correct, so if the wrong pointer is given, you will only detect it at runtime when seeing unexpected behaviours from the application.

+
// Variables that should be accessible through the script.
+
int g_number = 0;
+
CObject *g_object = 0;
+
Vector3 g_vector = {0,0,0};
+
bool g_readOnlyFlag = false;
+
+
// A function to register the global properties.
+
void RegisterProperties(asIScriptEngine *engine)
+
{
+
int r;
+
+
// Register a primitive property that can be read and written to from the script.
+
r = engine->RegisterGlobalProperty("int g_number", &g_number); assert( r >= 0 );
+
+
// Register variable where the script can store a handle to a CObject type.
+
// Assumes that the CObject type has been registered with the engine already as a reference type.
+
r = engine->RegisterGlobalProperty("CObject @g_object", &g_object); assert( r >= 0 );
+
+
// Register a 3D vector variable.
+
// Assumes that the Vector3 type has been registered already as a value type.
+
r = engine->RegisterGlobalProperty("Vector3 g_vector", &g_vector); assert( r >= 0 );
+
+
// Register a boolean flag that can be read, but not modified by the script.
+
r = engine->RegisterGlobalProperty("const bool g_readOnlyFlag", &g_readOnlyFlag); assert( r >= 0 );
+
}
+

It is also possible to expose properties through property accessors, which are a pair of functions with the prefixes 'get_' and 'set_' and the function decorator 'property' for getting and setting the property value. These functions should be registered with RegisterGlobalFunction. This is especially useful when the offset of the property cannot be determined, or if the type of the property is not registered in the script and some translation must occur, i.e. from char* to string.

+
Note
The behaviour of virtual properties can be customized with the engine property asEP_PROPERTY_ACCESSOR_MODE.
+
See also
Registering an object type
+
+
+
+
The engine interface.
Definition: angelscript.h:1092
+
virtual int RegisterGlobalProperty(const char *declaration, void *pointer)=0
Registers a global property.
+ + + + diff --git a/docs/manual/doc_register_type.html b/docs/manual/doc_register_type.html new file mode 100644 index 0000000..9485381 --- /dev/null +++ b/docs/manual/doc_register_type.html @@ -0,0 +1,120 @@ + + + + + + + +AngelScript: Registering an object type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering an object type
+
+
+

The are two principal paths to take when registering a new type, either the type is a reference type that is located in dynamic memory, or the type is a value type that is located on the stack or locally as members of other objects. A reference type support object handles (unless restricted by application) but cannot be passed by value to application registered functions, a value type doesn't support handles and can be passed by value or reference to application registered functions.

+

There is no given rule when to use one or the other, but in general you'll use reference types when the type must be able to outlive the scope in which it is created, and value types when the type is normally used to perform quick calculations after which the object can be discarded. If the type is large or complex, then it is likely it should be a reference type.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_register_type.js b/docs/manual/doc_register_type.js new file mode 100644 index 0000000..ab7ff1b --- /dev/null +++ b/docs/manual/doc_register_type.js @@ -0,0 +1,27 @@ +var doc_register_type = +[ + [ "Registering a reference type", "doc_reg_basicref.html", [ + [ "Factory function", "doc_reg_basicref.html#doc_reg_basicref_1", null ], + [ "Addref and release behaviours", "doc_reg_basicref.html#doc_reg_basicref_2", null ], + [ "Reference types without reference counting", "doc_reg_basicref.html#doc_reg_nocount", null ], + [ "List factory function", "doc_reg_basicref.html#doc_reg_basicref_4", null ], + [ "Registering an uninstantiable reference type", "doc_reg_basicref.html#doc_reg_noinst", null ] + ] ], + [ "Registering a value type", "doc_register_val_type.html", [ + [ "Constructor and destructor", "doc_register_val_type.html#doc_reg_val_1", null ], + [ "Value types and native calling conventions", "doc_register_val_type.html#doc_reg_val_2", [ + [ "For compilers that don't support C++11", "doc_register_val_type.html#doc_reg_val_2_nocpp11", null ] + ] ], + [ "List constructor", "doc_register_val_type.html#doc_reg_val_3", null ] + ] ], + [ "Registering operator behaviours", "doc_reg_opbeh.html", [ + [ "Operator overloads", "doc_reg_opbeh.html#doc_reg_opbeh_1", null ] + ] ], + [ "Registering object methods", "doc_reg_objmeth.html", [ + [ "Composite members", "doc_reg_objmeth.html#doc_reg_objmeth_composite", null ] + ] ], + [ "Registering object properties", "doc_reg_objprop.html", [ + [ "Composite members", "doc_reg_objprop.html#doc_reg_objprop_composite", null ], + [ "Property accessors", "doc_reg_objprop.html#doc_reg_objprop_accessor", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_register_val_type.html b/docs/manual/doc_register_val_type.html new file mode 100644 index 0000000..2c0e9f9 --- /dev/null +++ b/docs/manual/doc_register_val_type.html @@ -0,0 +1,208 @@ + + + + + + + +AngelScript: Registering a value type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Registering a value type
+
+
+

When registering a value type, the size of the type must be given so that AngelScript knows how much space is needed for it. If the type doesn't require any special treatment, i.e. doesn't contain any pointers or other resource references that must be maintained, then the type can be registered with the flag asOBJ_POD. In this case AngelScript doesn't require the default constructor, assignment behaviour, or destructor as it will be able to automatically handle these cases the same way it handles built-in primitives.

+

If you plan on passing or returning the type by value to registered functions that uses native calling convention, you also need to inform how the type is implemented in the application, but if you only plan on using generic calling conventions, or don't pass these types by value then you don't need to worry about that.

+
// Register a primitive type, that doesn't need any special management of the content
+
r = engine->RegisterObjectType("pod", sizeof(pod), asOBJ_VALUE | asOBJ_POD); assert( r >= 0 );
+
+
// Register a class that must be properly initialized and uninitialized
+
r = engine->RegisterObjectType("val", sizeof(val), asOBJ_VALUE); assert( r >= 0 );
+
See also
The string object or the complex type in the math add-on for examples of value types
+
+Registering a generic handle type for a more specific example of a value type
+
+Garbage collected objects for when the type may form circular references when being a member of another type
+

+Constructor and destructor

+

If a constructor or destructor is needed they shall be registered the following way:

+
void Constructor(void *memory)
+
{
+
// Initialize the pre-allocated memory by calling the
+
// object constructor with the placement-new operator
+
new(memory) Object();
+
}
+
+
void Destructor(void *memory)
+
{
+
// Uninitialize the memory by calling the object destructor
+
((Object*)memory)->~Object();
+
}
+
+
// Register the behaviours
+
r = engine->RegisterObjectBehaviour("val", asBEHAVE_CONSTRUCT, "void f()", asFUNCTION(Constructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+
r = engine->RegisterObjectBehaviour("val", asBEHAVE_DESTRUCT, "void f()", asFUNCTION(Destructor), asCALL_CDECL_OBJLAST); assert( r >= 0 );
+

Remember to use unique names or namespaces for the wrapper functions, even if you create templated implementations. Otherwise the linker may end up taking the address of the wrong function when registering the wrapper with AngelScript, which is sure to result in unexpected behaviours.

+

Note that you may need to include the <new> header to declare the placement new operator that is used to initialize a preallocated memory block.

+
See also
List constructor.
+

+Value types and native calling conventions

+

If the type will be passed to or from the application by value using native calling conventions it is important to inform AngelScript of its real type in C++, otherwise AngelScript won't be able to determine exactly how C++ is treating the type in a parameter or return value.

+

To inform AngelScript of actual type in C++ the template function asGetTypeTraits should preferably be used as it will automatically determine the correct flags to pass to RegisterObjectType together with the asOBJ_VALUE flag.

+
// With C++11 the type can be registered with GetTypeTraits
+
r = engine->RegisterObjectType("complex", sizeof(complex), asOBJ_VALUE | asGetTypeTraits<complex>()); assert( r >= 0 );
+

On some platforms the native calling convention may require further knowledge about the class and its members that asGetTypeTraits cannot determine in order to work properly. Whether or not the flags are needed depends on the compiler and target platform, but if the flags are not needed AngelScript will simply ignore them so there is no harm in informing them.

+

AngelScript lets the application give information that cover the most common variants, e.g. the class should be treated as if all members are integers (or non-float primitives), or it should be treated as if all members are floats. It is also possible to inform if the class has more constructors than the traditional default and copy constructors. This last one normally only has importance if the default and copy constructors are defaulted.

+ + + + + + + + + +
asOBJ_APP_CLASS_MORE_CONSTRUCTORS   The C++ class has additional constructors beyond the default and copy constructors
asOBJ_APP_CLASS_ALLINTS   The C++ class members can be treated as if all integers
asOBJ_APP_CLASS_ALLFLOATS   The C++ class members can be treated as if all floats or doubles
asOBJ_APP_CLASS_ALIGN8   The C++ class contains members that may require 8byte alignment, e.g. a double.
+

If the flags that inform about the members are not informed and AngelScript needs them on the platform, you'll get an error message like "Don't support passing/returning type 'MyType' by value to application in native calling convention on this platform".

+

It is difficult to explain exactly when one or the other should be used as it requires in-depth knowledge of the ABI for the respective system, so if you find that you really need to use these flags, make sure you perform adequate testing to guarantee that your functions are called correctly by the script engine. If neither of these flags work, and you're not able to change the class to work without them, then the only other option is to use the generic calling convention, preferably with the auto wrappers.

+

+For compilers that don't support C++11

+

If your compiler doesn't support C++11 features the asGetTypeTraits function will not be available. In this case you have no option but to inform the correct flags manually. Be careful to inform the correct flags, because if the wrong flags are used you may get unexpected behaviour when calling registered functions that passes or returns these types by value. Common problems are stack corruptions or invalid memory accesses. In some cases you may face more silent errors that may be difficult to detect, e.g. the function is not returning the expected values.

+

There are a few different flags:

+ + + + + + + + + + + + + + + + + +
asOBJ_APP_CLASS   The C++ type is a class, struct, or union
asOBJ_APP_CLASS_CONSTRUCTOR   The C++ type has a default constructor
asOBJ_APP_CLASS_DESTRUCTOR   The C++ type has a destructor
asOBJ_APP_CLASS_ASSIGNMENT   The C++ type has a copy assignment operator
asOBJ_APP_CLASS_COPY_CONSTRUCTOR   The C++ type has a copy constructor
asOBJ_APP_PRIMITIVE   The C++ type is a C++ primitive, but not a float or double
asOBJ_APP_FLOAT   The C++ type is a float or double
asOBJ_APP_ARRAY   The C++ type is an array
+

Note that these don't represent how the type will behave in the script language, only what the real type is in the host application. So if you want to register a C++ class that you want to behave as a primitive type in the script language you should still use the flag asOBJ_APP_CLASS. The same thing for the flags to identify that the class has a constructor, destructor, assignment operator, or copy constructor. These flags tell AngelScript that the class has the respective function, but not that the type in the script language should have these behaviours.

+

Observe that the C++ compiler may provide these functions automatically if one of the members of the class is of a type that requires it. So even if the type you want to register doesn't have a declared default constructor it may still be necessary to register the type with the flag asOBJ_APP_CLASS_CONSTRUCTOR. The same for the other functions.

+

For class types there is also a shorter form of the flags for each combination of the 5 flags. They are of the form asOBJ_APP_CLASS_CDAK, where the existence of the last letters determine if the constructor, destructor, and/or assignment behaviour are available. For example asOBJ_APP_CLASS_CDAK is defined as asOBJ_APP_CLASS | asOBJ_APP_CLASS_CONSTRUCTOR | asOBJ_APP_CLASS_DESTRUCTOR | asOBJ_APP_CLASS_ASSIGNMENT | asOBJ_APP_CLASS_COPY_CONSTRUCTOR.

+
// Register a complex type that will be passed by value to the application
+
r = engine->RegisterObjectType("complex", sizeof(complex), asOBJ_VALUE | asOBJ_APP_CLASS_CDAK); assert( r >= 0 );
+

+List constructor

+

The list constructor is similar to the list factory function for reference types. The constructor will receive a pointer to the initialization list buffer in the exact same way, and the expected list pattern should be registered in the same way. The difference is that the list constructor should be registered like a method, just as done for other constructors.

+

Example registration of a list constructor:

+
engine->RegisterObjectBehaviour("vector3", asBEHAVE_LIST_CONSTRUCT, "void f(int &in) {float, float, float}", ...);
+
See also
The complex math add-on for an example value type with a list constructor.
+
+
+
+
@ asOBJ_POD
A plain-old-data type. Only valid for value types.
Definition: angelscript.h:256
+
@ asBEHAVE_DESTRUCT
Destructor.
Definition: angelscript.h:358
+
@ asCALL_CDECL_OBJLAST
A cdecl function that takes the object pointer as the last parameter.
Definition: angelscript.h:234
+
@ asBEHAVE_LIST_CONSTRUCT
Constructor used exclusively for initialization lists.
Definition: angelscript.h:356
+
@ asBEHAVE_CONSTRUCT
Constructor.
Definition: angelscript.h:354
+
virtual int RegisterObjectType(const char *obj, int byteSize, asDWORD flags)=0
Registers a new object type.
+
virtual int RegisterObjectBehaviour(const char *obj, asEBehaviours behaviour, const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0, int compositeOffset=0, bool isCompositeIndirect=false)=0
Registers a behaviour for the object type.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
@ asOBJ_VALUE
A value type.
Definition: angelscript.h:252
+
@ asOBJ_APP_CLASS_CDAK
The C++ type is a class with a constructor, destructor, assignment operator, and copy constructor.
Definition: angelscript.h:290
+ + + + diff --git a/docs/manual/doc_reserved_keywords.html b/docs/manual/doc_reserved_keywords.html new file mode 100644 index 0000000..88b8b4b --- /dev/null +++ b/docs/manual/doc_reserved_keywords.html @@ -0,0 +1,255 @@ + + + + + + + +AngelScript: Reserved keywords and tokens + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Reserved keywords and tokens
+
+
+

These are the keywords that are reserved by the language, i.e. they can't be used by any script defined identifiers. Remember that the host application may reserve additional keywords that are specific to that application.

+ + + +
and
+ abstract*
+ auto
+ bool
+ break
+ case
+ cast
+ catch
+ class
+ const
+ continue
+ default
+ do
+
double
+ else
+ enum
+ explicit*
+ external*
+ false
+ final*
+ float
+ for
+ from*
+ funcdef
+ function*
+ get*
+
if
+ import
+ in
+ inout
+ int
+ interface
+ int8
+ int16
+ int32
+ int64
+ is
+ mixin
+ namespace
+
not
+ null
+ or
+ out
+ override*
+ private
+ property*
+ protected
+ return
+ set*
+ shared*
+ super*
+ switch
+
this*
+ true
+ try
+ typedef
+ uint
+ uint8
+ uint16
+ uint32
+ uint64
+ void
+ while
+ xor
+
+

* Not really a reserved keyword, but is recognized by the compiler as a built-in keyword.

+

These are the non-alphabetical tokens that are also used in the language syntax.

+ + + +
*
+ **
+ /
+ %
+ +
+ -
+ <=
+ <
+ >=
+ >
+ (
+
)
+ ==
+ !=
+ ?
+ :
+ =
+ +=
+ -=
+ *=
+ /=
+ %=
+
**=
+ ++
+ --
+ &
+ ,
+ {
+ }
+ ;
+ |
+ ^
+
~
+ <<
+ >>
+ >>>
+ &=
+ |=
+ ^=
+ <<=
+ >>=
+ >>>=
+
.
+ &&
+ ||
+ !
+ [
+ ]
+ ^^
+ @
+ !is
+ ::
+
+

Other than the above tokens there are also numerical, string, identifier, and comment tokens.

+
+123456789
+123.123e123
+123.123e123f
+0x1234FEDC
+0d123987
+0o1276
+0b1010
+'abc'
+"abc"
+"""heredoc"""
+_Abc123
+//
+/*
+*/
+

The characters space (32), tab (9), carriage return (13), line feed (10), and the UTF8 byte-order-mark (U+FEFF) are all recognized as whitespace.

+
+
+
+ + + + diff --git a/docs/manual/doc_samples.html b/docs/manual/doc_samples.html new file mode 100644 index 0000000..4b64721 --- /dev/null +++ b/docs/manual/doc_samples.html @@ -0,0 +1,123 @@ + + + + + + + +AngelScript: Samples + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Samples
+
+
+

This page gives a brief description of the samples that you'll find in the /sdk/samples/ folder.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_samples.js b/docs/manual/doc_samples.js new file mode 100644 index 0000000..2aa1185 --- /dev/null +++ b/docs/manual/doc_samples.js @@ -0,0 +1,12 @@ +var doc_samples = +[ + [ "Tutorial", "doc_samples_tutorial.html", null ], + [ "Concurrent scripts", "doc_samples_concurrent.html", null ], + [ "Console", "doc_samples_console.html", null ], + [ "Co-routines", "doc_samples_corout.html", null ], + [ "Events", "doc_samples_events.html", null ], + [ "Include directive", "doc_samples_incl.html", null ], + [ "Generic compiler", "doc_samples_asbuild.html", null ], + [ "Game", "doc_samples_game.html", null ], + [ "Command line runner", "doc_samples_asrun.html", "doc_samples_asrun" ] +]; \ No newline at end of file diff --git a/docs/manual/doc_samples_asbuild.html b/docs/manual/doc_samples_asbuild.html new file mode 100644 index 0000000..458b615 --- /dev/null +++ b/docs/manual/doc_samples_asbuild.html @@ -0,0 +1,123 @@ + + + + + + + +AngelScript: Generic compiler + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Generic compiler
+
+
+

Path: /sdk/samples/asbuild/

+

This sample shows how a generic bytecode compiler can be built to provide offline compilation of scripts. It takes as input a configuration file that defines the application interface, registers it using dummy functions and properties, then it compiles the script and saves the bytecode to a file on disk.

+

The configuration file should preferably be created automatically by calling the WriteConfigToFile helper function. This function should be called from the application that will execute the bytecode, after the application interface has been fully registered.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_samples_asrun.html b/docs/manual/doc_samples_asrun.html new file mode 100644 index 0000000..37ac0a3 --- /dev/null +++ b/docs/manual/doc_samples_asrun.html @@ -0,0 +1,131 @@ + + + + + + + +AngelScript: Command line runner + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Command line runner
+
+
+

Path: /sdk/samples/asrun/

+

This samples gives a very basic command line runner for AngelScripts.

+

It also implements a fully functional command line debugger, with support for setting breakpoints, stepping through the code, examining variables, etc.

+ +
See also
asrun manual
+
+
+
+ + + + diff --git a/docs/manual/doc_samples_asrun.js b/docs/manual/doc_samples_asrun.js new file mode 100644 index 0000000..cea33cf --- /dev/null +++ b/docs/manual/doc_samples_asrun.js @@ -0,0 +1,8 @@ +var doc_samples_asrun = +[ + [ "asrun manual", "doc_samples_asrun_manual.html", [ + [ "Usage", "doc_samples_asrun_manual.html#doc_samples_asrun_usage", null ], + [ "Scripts", "doc_samples_asrun_manual.html#doc_samples_asrun_script", null ], + [ "How to debug scripts", "doc_samples_asrun_manual.html#doc_samples_asrun_debug", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_samples_asrun_manual.html b/docs/manual/doc_samples_asrun_manual.html new file mode 100644 index 0000000..cfdd0ab --- /dev/null +++ b/docs/manual/doc_samples_asrun_manual.html @@ -0,0 +1,133 @@ + + + + + + + +AngelScript: asrun manual + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asrun manual
+
+
+

asrun is a simple command-line tool that supports executing AngelScript files directly in order to perform simple batch tasks. The API provided by the tool allow the script to interact with the system to read and write files, and execute other system commands.

+

On Windows it can be associated, for example with the file extension .as, to allow scripts to be executed directly from the file browser with a double click. This makes it a handy tool even without a terminal for command-line input.

+

+Usage

+
+asrun [-d] <script file> [<args>]
+ -d             inform if the script should be runned with debug
+ <script file>  is the script file that should be runned
+ <args>         zero or more args for the script
+

These usage instructions are also presented if the tool is executed without any arguments.

+

+Scripts

+

As entry point for executing the scripts, asrun looks for one of the functions int main() or void main(). If neither of these functions are found an error will be reported.

+

The scripts can use the full set of the script language and standard library described in the script language section of this manual.

+

The script file informed as input on the command line may include additional files with the include directive #include "<file name>", so that the script files can be better organized and common logic shared between multiple scripts.

+

+How to debug scripts

+

To run a script with the debugger, either add the command line argument -d or include #pragma debug in the script. When this is done, the debugger will show a prompt like this:

+
+Debugging, waiting for commands. Type 'h' for help.
+[dbg]>
+

This will then let you set up breakpoints, step through the code, inspect variables, etc. Type h on the prompt to get the list of commands available.

+
+
+
+ + + + diff --git a/docs/manual/doc_samples_concurrent.html b/docs/manual/doc_samples_concurrent.html new file mode 100644 index 0000000..14afe8c --- /dev/null +++ b/docs/manual/doc_samples_concurrent.html @@ -0,0 +1,120 @@ + + + + + + + +AngelScript: Concurrent scripts + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Concurrent scripts
+
+
+

Path: /sdk/samples/concurrent/

+

This sample shows how to execute two or more long running scripts concurrently. The scripts voluntarily hand over the control to the next script in the queue by calling the function sleep().

+
    +
  • Context manager
  • +
  • Multiple scripts running in parallel
  • +
  • sleep()
  • +
  • Strings
  • +
  • Registered global functions
  • +
+
+
+
+ + + + diff --git a/docs/manual/doc_samples_console.html b/docs/manual/doc_samples_console.html new file mode 100644 index 0000000..184be11 --- /dev/null +++ b/docs/manual/doc_samples_console.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Console + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Console
+
+
+

Path: /sdk/samples/console/

+

This sample implements a simple interactive console, which lets the user type in commands and also evaluate simple script statements to manipulate the application.

+

The user is also able to define new variables and functions from the command line. These functions can then be executed to perform automated tasks.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_samples_corout.html b/docs/manual/doc_samples_corout.html new file mode 100644 index 0000000..6c507a3 --- /dev/null +++ b/docs/manual/doc_samples_corout.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Co-routines + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Co-routines
+
+
+

Path: /sdk/samples/coroutine/

+

This sample shows how co-routines can be implemented with AngelScript. Co-routines are threads that can be created from the scripts, and that work together by voluntarily passing control to each other by calling yield().

+
    +
  • Context manager
  • +
  • Co-routines created from the scripts with variable parameter structure.
  • +
  • string object
  • +
  • Registered global functions
  • +
  • Handling the variable argument type
  • +
  • Passing arguments to script functions
  • +
  • dictionary object
  • +
+
+
+
+ + + + diff --git a/docs/manual/doc_samples_events.html b/docs/manual/doc_samples_events.html new file mode 100644 index 0000000..2a26a26 --- /dev/null +++ b/docs/manual/doc_samples_events.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Events + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Events
+
+
+

Path: /sdk/samples/events/

+

This sample has the script engine execute a long running script. The script execution is regularly interrupted by the application so that keyboard events can be processed, which execute another short script before resuming the execution of the main script. The event handling scripts change the state of the long running script.

+
    +
  • LineCallback() function which suspends execution when the time is up
  • +
  • string object
  • +
  • Registered global functions
  • +
  • Scripted event handlers
  • +
+
+
+
+ + + + diff --git a/docs/manual/doc_samples_game.html b/docs/manual/doc_samples_game.html new file mode 100644 index 0000000..f6087ae --- /dev/null +++ b/docs/manual/doc_samples_game.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Game + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Game
+
+
+

Path: /sdk/samples/game/

+

This sample shows one way of integrating the scripting library in a game engine. It is a simple game where the player is trying to avoid getting eaten by zombies. Each game object type has it's own script that controls its behaviour, these are loaded independently into separately modules.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_samples_incl.html b/docs/manual/doc_samples_incl.html new file mode 100644 index 0000000..9de7dee --- /dev/null +++ b/docs/manual/doc_samples_incl.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Include directive + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Include directive
+
+
+

Path: /sdk/samples/include/

+

This sample shows how to implement a very simple preprocessor to add support for the #include directive, which allow the script writer to reuse common script code. The preprocessor simply adds the included scripts as multiple script sections, which is ok as AngelScript is able to resolve global declarations independently of their order. The preprocessor also makes sure that a script file is only included once, so the script writer doesn't have to take extra care to avoid multiple includes or even complicated circular includes.

+
    +
  • Script builder
  • +
  • LineCallback() functions which aborts execution when the time is up
  • +
  • Processing the #include directive
  • +
  • Circular #includes are resolved automatically
  • +
+
+
+
+ + + + diff --git a/docs/manual/doc_samples_tutorial.html b/docs/manual/doc_samples_tutorial.html new file mode 100644 index 0000000..647330c --- /dev/null +++ b/docs/manual/doc_samples_tutorial.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Tutorial + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Tutorial
+
+
+

Path: /sdk/samples/tutorial/

+

This sample was written with the intention of explaining the basics of AngelScript, that is, how to configure the engine, load and compile a script, and finally execute a script function with parameters and return value.

+
    +
  • asIScriptEngine::SetMessageCallback
  • +
  • LineCallback() function which aborts execution when the time is up
  • +
  • Strings
  • +
  • Registered global functions
  • +
  • Script function parameters and return value
  • +
  • Retrieving information about script exceptions
  • +
  • asIScriptGeneric for when the library doesn't support native calling convention
  • +
+
+
+
+ + + + diff --git a/docs/manual/doc_script.html b/docs/manual/doc_script.html new file mode 100644 index 0000000..2001c95 --- /dev/null +++ b/docs/manual/doc_script.html @@ -0,0 +1,126 @@ + + + + + + + +AngelScript: The script language + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
The script language
+
+ +
+
+ + + + diff --git a/docs/manual/doc_script.js b/docs/manual/doc_script.js new file mode 100644 index 0000000..a847bb8 --- /dev/null +++ b/docs/manual/doc_script.js @@ -0,0 +1,55 @@ +var doc_script = +[ + [ "Global entities", "doc_script_global.html", "doc_script_global" ], + [ "Statements", "doc_script_statements.html", [ + [ "Variable declarations", "doc_script_statements.html#variable", null ], + [ "Expression statement", "doc_script_statements.html#expression", null ], + [ "Conditions: if / if-else / switch-case", "doc_script_statements.html#if", null ], + [ "Loops: while / do-while / for", "doc_script_statements.html#while", null ], + [ "Loop control: break / continue", "doc_script_statements.html#break", null ], + [ "Return statement", "doc_script_statements.html#return", null ], + [ "Statement blocks", "doc_script_statements.html#block", null ], + [ "Try-catch blocks", "doc_script_statements.html#try", null ] + ] ], + [ "Expressions", "doc_expressions.html", [ + [ "Assignments", "doc_expressions.html#assignment", null ], + [ "Function call", "doc_expressions.html#function", null ], + [ "Math operators", "doc_expressions.html#math", null ], + [ "Bitwise operators", "doc_expressions.html#bits", null ], + [ "Compound assignments", "doc_expressions.html#compound", null ], + [ "Logic operators", "doc_expressions.html#logic", null ], + [ "Equality comparison operators", "doc_expressions.html#equal", null ], + [ "Relational comparison operators", "doc_expressions.html#relation", null ], + [ "Identity comparison operators", "doc_expressions.html#identity", null ], + [ "Increment operators", "doc_expressions.html#increment", null ], + [ "Indexing operator", "doc_expressions.html#opindex", null ], + [ "Conditional expression", "doc_expressions.html#condition", null ], + [ "Member access", "doc_expressions.html#member", null ], + [ "Handle-of", "doc_expressions.html#handle", null ], + [ "Parenthesis", "doc_expressions.html#parenthesis", null ], + [ "Scope resolution", "doc_expressions.html#scope", null ], + [ "Type conversions", "doc_expressions.html#conversion", null ], + [ "Anonymous objects", "doc_expressions.html#anonobj", null ] + ] ], + [ "Data types", "doc_datatypes.html", "doc_datatypes" ], + [ "Functions", "doc_script_func.html", "doc_script_func" ], + [ "Script classes", "doc_script_class.html", "doc_script_class" ], + [ "Object handles", "doc_script_handle.html", [ + [ "General usage", "doc_script_handle.html#doc_script_handle_1", null ], + [ "Object life times", "doc_script_handle.html#doc_script_handle_2", null ], + [ "Object relations and polymorphing", "doc_script_handle.html#doc_script_handle_3", null ], + [ "Const handles", "doc_script_handle.html#doc_script_handle_4", null ] + ] ], + [ "Shared script entities", "doc_script_shared.html", [ + [ "How to declare shared entities", "doc_script_shared.html#doc_script_shared_1", null ], + [ "External shared entities", "doc_script_shared.html#doc_script_shared_external", null ], + [ "What can be shared", "doc_script_shared.html#doc_script_shared_2", null ] + ] ], + [ "Operator precedence", "doc_operator_precedence.html", [ + [ "Unary operators", "doc_operator_precedence.html#unary", null ], + [ "Binary and ternary operators", "doc_operator_precedence.html#binary", null ] + ] ], + [ "Reserved keywords and tokens", "doc_reserved_keywords.html", null ], + [ "Script language grammar", "doc_script_bnf.html", null ], + [ "Standard library", "doc_script_stdlib.html", "doc_script_stdlib" ] +]; \ No newline at end of file diff --git a/docs/manual/doc_script_anonfunc.html b/docs/manual/doc_script_anonfunc.html new file mode 100644 index 0000000..4d87f49 --- /dev/null +++ b/docs/manual/doc_script_anonfunc.html @@ -0,0 +1,134 @@ + + + + + + + +AngelScript: Anonymous functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Anonymous functions
+
+
+

Anonymous functions, or lambdas as they are sometimes called, are functions that are declared locally for use with function handles.

+

The following is a quick demonstration on how to use anonymous functions.

+
+  funcdef bool CMP(int first, int second);
  void main()
+  {
+    int valueA = 1, valueB = 2;
    bool result1 = func(valueA, valueB, function(a,b){ return a == b; });
+    bool result2 = func(valueA, valueB, function(a,b){ return a != b; });
+  }
  bool func(int a, int b, CMP @f)
+  {
+    return f(a,b);
+  }
+

The anonymous function takes on the signature of the function handle it is assigned to, so the type of the arguments and the return type doesn't have to be explicitly declared.

+

It is not yet possible for anonymous functions to access variables declared in the same scope as the function, i.e. they cannot be used as closures.

+

If there are multiple matching uses for the anonymous function it will be necessary to explicitly inform the parameter types, so the ambiguity can be resolved.

+
+  funcdef void A(int);
+  funcdef void B(float);
+  void func(A@) {}
+  void func(B@) {}
  void main()
+  {
+    // Explicitly specify the type to tell the compiler that A is wanted
+    func(function(int a) {});
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_bnf.html b/docs/manual/doc_script_bnf.html new file mode 100644 index 0000000..73e1486 --- /dev/null +++ b/docs/manual/doc_script_bnf.html @@ -0,0 +1,178 @@ + + + + + + + +AngelScript: Script language grammar + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Script language grammar
+
+
+

This is language grammar in Backus-Naur Form (BNF).

+

The following convention is used:

+
+ ( )  - used for grouping
+ { }  - 0 or more repetitions
+ [ ]  - optional
+  |   - or
+ ' '  - token
+
+SCRIPT        ::= {IMPORT | ENUM | TYPEDEF | CLASS | MIXIN | INTERFACE | FUNCDEF | VIRTPROP | VAR | FUNC | NAMESPACE | ';'}
+CLASS         ::= {'shared' | 'abstract' | 'final' | 'external'} 'class' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | FUNC | VAR | FUNCDEF} '}'))
+TYPEDEF       ::= 'typedef' PRIMTYPE IDENTIFIER ';'
+NAMESPACE     ::= 'namespace' IDENTIFIER '{' SCRIPT '}'
+FUNC          ::= {'shared' | 'external'} ['private' | 'protected'] [((TYPE ['&']) | '~')] IDENTIFIER PARAMLIST ['const'] FUNCATTR (';' | STATBLOCK)
+INTERFACE     ::= {'external' | 'shared'} 'interface' IDENTIFIER (';' | ([':' IDENTIFIER {',' IDENTIFIER}] '{' {VIRTPROP | INTFMTHD} '}'))
+VAR           ::= ['private'|'protected'] TYPE IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST] {',' IDENTIFIER [( '=' (INITLIST | EXPR)) | ARGLIST]} ';'
+IMPORT        ::= 'import' TYPE ['&'] IDENTIFIER PARAMLIST FUNCATTR 'from' STRING ';'
+ENUM          ::= {'shared' | 'external'} 'enum' IDENTIFIER (';' | ('{' IDENTIFIER ['=' EXPR] {',' IDENTIFIER ['=' EXPR]} '}'))
+FUNCDEF       ::= {'external' | 'shared'} 'funcdef' TYPE ['&'] IDENTIFIER PARAMLIST ';'
+VIRTPROP      ::= ['private' | 'protected'] TYPE ['&'] IDENTIFIER '{' {('get' | 'set') ['const'] FUNCATTR (STATBLOCK | ';')} '}'
+MIXIN         ::= 'mixin' CLASS
+INTFMTHD      ::= TYPE ['&'] IDENTIFIER PARAMLIST ['const'] ';'
+STATBLOCK     ::= '{' {VAR | STATEMENT} '}'
+PARAMLIST     ::= '(' ['void' | (TYPE TYPEMOD [IDENTIFIER] ['=' EXPR] {',' TYPE TYPEMOD [IDENTIFIER] ['=' EXPR]})] ')'
+TYPEMOD       ::= ['&' ['in' | 'out' | 'inout']]
+TYPE          ::= ['const'] SCOPE DATATYPE ['<' TYPE {',' TYPE} '>'] { ('[' ']') | ('@' ['const']) }
+INITLIST      ::= '{' [ASSIGN | INITLIST] {',' [ASSIGN | INITLIST]} '}'
+SCOPE         ::= ['::'] {IDENTIFIER '::'} [IDENTIFIER ['<' TYPE {',' TYPE} '>'] '::']
+DATATYPE      ::= (IDENTIFIER | PRIMTYPE | '?' | 'auto')
+PRIMTYPE      ::= 'void' | 'int' | 'int8' | 'int16' | 'int32' | 'int64' | 'uint' | 'uint8' | 'uint16' | 'uint32' | 'uint64' | 'float' | 'double' | 'bool'
+FUNCATTR      ::= {'override' | 'final' | 'explicit' | 'property'}
+STATEMENT     ::= (IF | FOR | WHILE | RETURN | STATBLOCK | BREAK | CONTINUE | DOWHILE | SWITCH | EXPRSTAT | TRY)
+SWITCH        ::= 'switch' '(' ASSIGN ')' '{' {CASE} '}'
+BREAK         ::= 'break' ';'
+FOR           ::= 'for' '(' (VAR | EXPRSTAT) EXPRSTAT [ASSIGN {',' ASSIGN}] ')' STATEMENT
+WHILE         ::= 'while' '(' ASSIGN ')' STATEMENT
+DOWHILE       ::= 'do' STATEMENT 'while' '(' ASSIGN ')' ';'
+IF            ::= 'if' '(' ASSIGN ')' STATEMENT ['else' STATEMENT]
+CONTINUE      ::= 'continue' ';'
+EXPRSTAT      ::= [ASSIGN] ';'
+TRY           ::= 'try' STATBLOCK 'catch' STATBLOCK
+RETURN        ::= 'return' [ASSIGN] ';'
+CASE          ::= (('case' EXPR) | 'default') ':' {STATEMENT}
+EXPR          ::= EXPRTERM {EXPROP EXPRTERM}
+EXPRTERM      ::= ([TYPE '='] INITLIST) | ({EXPRPREOP} EXPRVALUE {EXPRPOSTOP})
+EXPRVALUE     ::= 'void' | CONSTRUCTCALL | FUNCCALL | VARACCESS | CAST | LITERAL | '(' ASSIGN ')' | LAMBDA
+CONSTRUCTCALL ::= TYPE ARGLIST
+EXPRPREOP     ::= '-' | '+' | '!' | '++' | '--' | '~' | '@'
+EXPRPOSTOP    ::= ('.' (FUNCCALL | IDENTIFIER)) | ('[' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':' ASSIGN} ']') | ARGLIST | '++' | '--'
+CAST          ::= 'cast' '<' TYPE '>' '(' ASSIGN ')'
+LAMBDA        ::= 'function' '(' [[TYPE TYPEMOD] IDENTIFIER {',' [TYPE TYPEMOD] IDENTIFIER}] ')' STATBLOCK
+LITERAL       ::= NUMBER | STRING | BITS | 'true' | 'false' | 'null'
+FUNCCALL      ::= SCOPE IDENTIFIER ARGLIST
+VARACCESS     ::= SCOPE IDENTIFIER
+ARGLIST       ::= '(' [IDENTIFIER ':'] ASSIGN {',' [IDENTIFIER ':'] ASSIGN} ')'
+ASSIGN        ::= CONDITION [ ASSIGNOP ASSIGN ]
+CONDITION     ::= EXPR ['?' ASSIGN ':' ASSIGN]
+EXPROP        ::= MATHOP | COMPOP | LOGICOP | BITOP
+BITOP         ::= '&' | '|' | '^' | '<<' | '>>' | '>>>'
+MATHOP        ::= '+' | '-' | '*' | '/' | '' | '**'
+COMPOP        ::= '==' | '!=' | '<' | '<=' | '>' | '>=' | 'is' | '!is'
+LOGICOP       ::= '&&' | '||' | '^^' | 'and' | 'or' | 'xor'
+ASSIGNOP      ::= '=' | '+=' | '-=' | '*=' | '/=' | '|=' | '&=' | '^=' | '%=' | '**=' | '<<=' | '>>=' | '>>>='
+IDENTIFIER    ::= single token:  starts with letter or _, can include any letter and digit, same as in C++
+NUMBER        ::= single token:  includes integers and real numbers, same as C++
+STRING        ::= single token:  single quoted ', double quoted ", or heredoc multi-line string """
+BITS          ::= single token:  binary 0b or 0B, octal 0o or 0O, decimal 0d or 0D, hexadecimal 0x or 0X
+
+
+
+ + + + diff --git a/docs/manual/doc_script_class.html b/docs/manual/doc_script_class.html new file mode 100644 index 0000000..7be0ff3 --- /dev/null +++ b/docs/manual/doc_script_class.html @@ -0,0 +1,120 @@ + + + + + + + +AngelScript: Script classes + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Script classes
+
+
+

Script classes are declared globally and provides an easy way of grouping properties and methods into logical units. The syntax for classes is similar to C++ and Java.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_script_class.js b/docs/manual/doc_script_class.js new file mode 100644 index 0000000..e111400 --- /dev/null +++ b/docs/manual/doc_script_class.js @@ -0,0 +1,26 @@ +var doc_script_class = +[ + [ "Script class overview", "doc_script_class_desc.html", [ + [ "Class constructors", "doc_script_class_desc.html#doc_script_class_construct", null ], + [ "Class destructor", "doc_script_class_desc.html#doc_script_class_destruct", null ], + [ "Const methods", "doc_script_class_desc.html#doc_script_class_const", null ] + ] ], + [ "Inheritance and polymorphism", "doc_script_class_inheritance.html", [ + [ "Extra control with final, abstract, and override", "doc_script_class_inheritance.html#doc_script_class_inheritance_2", null ] + ] ], + [ "Protected and private class members", "doc_script_class_private.html", null ], + [ "Operator overloads", "doc_script_class_ops.html", [ + [ "Prefixed unary operators", "doc_script_class_ops.html#doc_script_class_unary_ops", null ], + [ "Postfixed unary operators", "doc_script_class_ops.html#doc_script_class_unary2_ops", null ], + [ "Comparison operators", "doc_script_class_ops.html#doc_script_class_cmp_ops", null ], + [ "Assignment operators", "doc_script_class_ops.html#doc_script_class_assign_ops", null ], + [ "Binary operators", "doc_script_class_ops.html#doc_script_class_binary_ops", null ], + [ "Index operators", "doc_script_class_ops.html#doc_script_class_index_op", null ], + [ "Functor operator", "doc_script_class_ops.html#doc_script_class_call", null ], + [ "Type conversion operators", "doc_script_class_ops.html#doc_script_class_conv", null ] + ] ], + [ "Property accessors", "doc_script_class_prop.html", [ + [ "Indexed property accessors", "doc_script_class_prop.html#doc_script_class_prop_index", null ] + ] ], + [ "Initialization of class members", "doc_script_class_memberinit.html", null ] +]; \ No newline at end of file diff --git a/docs/manual/doc_script_class_desc.html b/docs/manual/doc_script_class_desc.html new file mode 100644 index 0000000..2076b29 --- /dev/null +++ b/docs/manual/doc_script_class_desc.html @@ -0,0 +1,186 @@ + + + + + + + +AngelScript: Script class overview + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Script class overview
+
+
+

With classes the script writer can declare new data types that hold groups of properties and methods to manipulate them.

+

Script classes are reference types, which means that multiple references or handles can be held for the same object instance. The classes uses automatic memory management so the object instances are only destroyed when the last reference to the instance is cleared.

+

The class methods are implemented the same way as global functions, with the addition that the class method can access the class instance properties through either directly or through the 'this' keyword in the case a local variable has the same name.

+
+  // The class declaration
+  class MyClass
+  {
+    // A class method
+    void DoSomething()
+    {
+      // The class properties can be accessed directly
+      a *= 2;
      // The declaration of a local variable may hide class properties
+      int b = 42;
      // In this case the class property have to be accessed explicitly
+      this.b = b;
+    }
    // Class properties
+    int a;
+    int b;
+  }
+

A class can implement specific methods to overload operators. This can simplify how the object instances are used in expressions, so that it is not necessary to explicitly name each function, e.g. the opAdd method translates to the + operator.

+

Another useful feature is the ability to implement property accessors, which can be used either to provide virtual properties, i.e. that look like properties but really aren't, or to implement specific routines that must be executed everytime a property is accessed.

+

A script class can also inherit from other classes, and implement interfaces.

+

+Class constructors

+

Class constructors are specific methods that will be used to create new instances of the class. It is not required for a class to declare constructors, but doing so may make it easier to use the class as it will not be necessary to first instanciate the class and then manually set the properties.

+

The constructors are declared without a return type, and must have the same name as the class itself. Multiple constructors with different parameter lists can be implemented for different forms of initializations.

+
+  class MyClass
+  {
+    // Implement a default constructor
+    MyClass()
+    {
+    }
    // Implement the copy constructor
+    MyClass(const MyClass &in other)
+    {
+      // Copy the value of the other instance
+    }
    // Implement other constructors with different parameter lists
+    MyClass(int a, string b) {}
+    MyClass(float x, float y, float z) {}
+  }
+

The copy constructor is a specific constructor that the compiler can use to build more performatic code when copies of an object must be made. Without the copy constructor the compiler will be forced to first instanciate the copy using the default constructor, and then copy the attributes with the opAssign method.

+

One constructor cannot call another constructor. If you wish to share implementations in the constructors you should use a specific method for that.

+

If a class isn't explicitly declared with any constructor, the compiler will automatically provide a default constructor for the class. This automatically generated constructor will simply call the default constructor for all object members, and set all handles to null. If a member cannot be initialized with a default constructor, then a compiler error will be emitted.

+

How the members shall be initialized can also be defined directly in the declaration of the members. When this is done the initialization expression will automatically be compiled in the constructor without the need to write the initialization again.

+
See also
Initialization of class members
+

+Class destructor

+

It is normally not necessary to implement the class destructor as AngelScript will by default free up any resources the objects holds when it is destroyed. However, there may be situations where a more explicit cleanup routine must be done as part of the destruction of the object.

+

The destructor is declared similarly to the constructor, except that it must be prefixed with the ~ symbol (also known as the bitwise not operator).

+
+  class MyClass
+  {
+    // Implement the destructor if explicit cleanup is needed
+    ~MyClass()
+    {
+      // Perform explicit cleanup here
+    }
+  }
+

Observe that AngelScript uses automatic memory management with garbage collection so it may not always be easy to predict when the destructor is executed. AngelScript will also call the destructor only once, even if the object is resurrected by adding a reference to it while executing the destructor.

+

It is not possible to directly invoke the destructor. If you need to be able to directly invoke the cleanup, then you should implement a public method for that.

+

+Const methods

+

Classes add a new type of function overload, i.e. const overload. When a class method is accessed through a read-only reference or handle, only methods that have been marked as constant can be invoked. When the reference or handle is writable, then both types can be invoked, with the preference being the non-const version in case both matches.

+
+  class CMyClass
+  {
+    int method()       { a++; return a; } 
+    int method() const {      return a; }
+    int a;
+  }
+  void Function()
+  {
+     CMyClass o;
+     const CMyClass @h = o;
     o.method(); // invokes the non-const version that increments the member a
+     h.method(); // invokes the const version that doesn't increment the member a
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_class_inheritance.html b/docs/manual/doc_script_class_inheritance.html new file mode 100644 index 0000000..ca7d7ff --- /dev/null +++ b/docs/manual/doc_script_class_inheritance.html @@ -0,0 +1,173 @@ + + + + + + + +AngelScript: Inheritance and polymorphism + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Inheritance and polymorphism
+
+
+

AngelScript supports single inheritance, where a derived class inherits the properties and methods of its base class. Multiple inheritance is not supported, but polymorphism is supported by implementing interfaces, and code reuse is provided by including mixin classes.

+

All the class methods are virtual, so it is not necessary to specify this manually. When a derived class overrides an implementation, it can extend the original implementation by specifically calling the base class' method using the scope resolution operator. When implementing the constructor for a derived class the constructor for the base class is called using the super keyword. If none of the base class' constructors is manually called, the compiler will automatically insert a call to the default constructor in the beginning. The base class' destructor will always be called after the derived class' destructor, so there is no need to manually do this.

+
+  // A derived class
+  class MyDerived : MyBase
+  {
+    // The default constructor
+    MyDerived()
+    {
+      // Calling the non-default constructor of the base class
+      super(10);
      b = 0;
+    }
    // Overloading a virtual method
+    void DoSomething()
+    {
+      // Call the base class' implementation
+      MyBase::DoSomething();
      // Do something more
+      b = a;
+    }
    int b;
+  }
+

A class that is derived from another can be implicitly cast to the base class. The same works for interfaces that are implemented by a class. The other direction requires an explicit cast, as it is not known at compile time if the cast is valid.

+
+  class A {}
+  class B : A {}
+  void Foo()
+  {
+    A @handle_to_A;
+    B @handle_to_B;
    @handle_to_A = A(); // OK
+    @handle_to_A = B(); // OK. The reference will be implicitly cast to A@
    @handle_to_B = A(); // Not OK. This will give a compilation error
+    @handle_to_B = B(); // OK
    @handle_to_A = handle_to_B; // OK. The reference will be implicitly cast to A@
+    @handle_to_B = handle_to_A; // Not OK. This will give a compilation error
    @handle_to_B = cast<B>(handle_to_A); // OK. Though, the explicit cast will return null 
+                                         // if the object in handle_to_a is not really an
+                                         // instance of B
+  }
+

+Extra control with final, abstract, and override

+

A class can be marked as 'final' to prevent the inheritance of it. This is an optional feature and mostly used in larger projects where there are many classes and it may be difficult to manually control the correct use of all classes. It is also possible to mark individual class methods of a class as 'final', in which case it is still possible to inherit from the class, but the finalled method cannot be overridden.

+

Another keyword that can be used to mark a class is 'abstract'. Abstract classes cannot be instantiated, but they can be derived from. Abstract classes are most frequently used when you want to create a family of classes by deriving from a common base class, but do not want the base class to be instantiated by itself. It is currently not possible to mark methods as abstract so all methods must have an implementation even for abstract classes.

+
+  // A final class that cannot be inherited from
+  final class MyFinal
+  {
+    MyFinal() {}
+    void Method() {}
+  }
  // A class with individual methods finalled
+  class MyPartiallyFinal
+  {
+    // A final method that cannot be overridden
+    void Method1() final {}
    // Normal method that can still be overridden by derived class
+    void Method2() {}
+  }
  // An abstract class
+  abstract class MyAbstractBase {}
+

When deriving a class it is possible to tell the compiler that a method is meant to override a method in the inherited base class. When this is done and there is no matching method in the base class the compiler will emit an error, as it knows that something wasn't implemented quite the way it was meant. This is especially useful to catch errors in large projects where a base class might be modified, but the derived classes was forgotten.

+
+  class MyBase
+  {
+    void Method() {}
+    void Method(int) {}
+  }
  class MyDerived : MyBase
+  {
+    void Method() override {}      // OK. The method is overriding a method in the base class
+    void Method(float) override {} // Not OK. The method isn't overriding a method in base class
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_class_memberinit.html b/docs/manual/doc_script_class_memberinit.html new file mode 100644 index 0000000..a439a17 --- /dev/null +++ b/docs/manual/doc_script_class_memberinit.html @@ -0,0 +1,168 @@ + + + + + + + +AngelScript: Initialization of class members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Initialization of class members
+
+
+

The order in which the class members are initialized during the construction of an object becomes important when using inheritance, or when defining the initialization of the members directly in the declaration. If a member is accessed before it has been initialized the script may cause a null handle access exception, which will abort the execution of the script.

+

For a simple class, the order in which the members are initialized is the same as the order in which they were declared. When explicit initializations are given in the declaration of the members, these members will be initialized last.

+
+  // The order of this class will be: a, c, b, d
+  class Foo
+  {
+    string a;
+    string b = a;
+    string c;
+    string d = b;
+  }
+

When inheritance is used, the derived class' members without explicit initialization will be initialized before the base class' members, and the members with explicit initialization will be initialized after the base class' members.

+
+  // The order of this class will be: a, b
+  class Bar
+  {
+    string a;
+    string b = a;
+  }
  // The order of this class will be: d, a, b, c
+  class Foo : Bar
+  {
+    string c = a;
+    string d;
+  }
+

This order of initialization has been chosen to avoid most problems with accessing members before they have been initialized.

+

All members are initialized immediately in the beginning of the defined constructor, so the rest of the code in the constructor can access members without worry. The exception is when the constructor explicitly initializes a base class by calling super(), in this case the members with explicit initialization will remain uninitialized until after the base class has been fully constructed.

+
+  class Bar
+  {
+    Bar(string val) { a = val; }
+    string a;
+  }
  class Foo : Bar
+  {
+    Foo()
+    {
+      // b is already initialized here
      super(b); // a will be initialized in this call
      // c is initialized right after super() returns
+    }
    string b;
+    string c = a;
+  }
+

Be wary about cases where a constructor or member initialization calls class methods. As class methods can be overridden by derived classes it is possible for a base class to unwittingly access a member of the derived class before it has been initialized.

+
+  class Bar
+  {
+    Bar() 
+    {
+      DoSomething();
+    }
    void DoSomething() {}
+  }
  // This class will cause a null handle exception, because the Bar's constructor calls 
+  // the DoSomething() method that accesses the member msg before it has been initialized. 
+  class Foo : Bar
+  {
+    string msg = 'hello';
+    void DoSomething() 
+    { 
+      print(msg); 
+    }
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_class_ops.html b/docs/manual/doc_script_class_ops.html new file mode 100644 index 0000000..87703a5 --- /dev/null +++ b/docs/manual/doc_script_class_ops.html @@ -0,0 +1,299 @@ + + + + + + + +AngelScript: Operator overloads + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Operator overloads
+
+
+

It is possible to define what should be done when an operator is used with a script class. While not necessary in most scripts it can be useful to improve readability of the code.

+

This is called operator overloading, and is done by implementing specific class methods. The compiler will recognize and use these
+ methods when it compiles expressions involving the overloaded operators and the script class.

+

+Prefixed unary operators

+ + + + + + + + + + + +
opopfunc
- opNeg
~ opCom
++ opPreInc
-- opPreDec
+

When the expression op a is compiled, the compiler will rewrite it as a.opfunc() and compile that instead.

+

+Postfixed unary operators

+ + + + + + + +
opopfunc
++ opPostInc
-- opPostDec
+

When the expression a op is compiled, the compiler will rewrite it as a.opfunc() and compile that instead.

+

+Comparison operators

+ + + + + + + + + + + + + + + + + + + +
opopfunc
== opEquals
!= opEquals
< opCmp
<= opCmp
> opCmp
>= opCmp
is opEquals
!is opEquals
+

The a == b expression will be rewritten as a.opEquals(b) and b.opEquals(a) and then the best match will be used. != is treated similarly, except that the result is negated. The opEquals method must be implemented to return a bool in order to be considered by the compiler.

+

The comparison operators are rewritten as a.opCmp(b) op 0 and 0 op b.opCmp(a) and then the best match is used. The opCmp method must be implemented to return a int in order to be considered by the compiler. If the method argument is to be considered larger than the object then the method should return a negative value. If they are supposed to be equal the return value should be 0.

+

If an equality check is made and the opEquals method is not available the compiler looks for the opCmp method instead. So if the opCmp method is available it is really not necesary to implement the opEquals method, except for optimization reasons.

+

The identity operator, is, expects opEquals to take a handle, @, so the addresses can be compared to be able to return if it is the same object, in contrast two different objects that have the same value.

+

+Assignment operators

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
opopfunc
= opAssign
+= opAddAssign
-= opSubAssign
*= opMulAssign
/= opDivAssign
%= opModAssign
**= opPowAssign
&= opAndAssign
|= opOrAssign
^= opXorAssign
<<= opShlAssign
>>= opShrAssign
>>>= opUShrAssign
+

The assignment expressions a op b are rewritten as a.opfunc(b) and then the best matching method is used. An assignment operator can for example be implemented like this:

+
+  obj@ opAssign(const obj &in other)
+  {
+    // Do the proper assignment
+    ...
    // Return a handle to self, so that multiple assignments can be chained
+    return this;
+  }
+

All script classes have a default assignment operator that does a bitwise copy of the content of the class, so if that is all you want to do, then there is no need to implement this method.

+

+Binary operators

+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
opopfuncopfunc_r
+ opAdd opAdd_r
- opSub opSub_r
* opMul opMul_r
/ opDiv opDiv_r
% opMod opMod_r
** opPow opPow_r
& opAnd opAnd_r
| opOr opOr_r
^ opXor opXor_r
<< opShl opShl_r
>> opShr opShr_r
>>> opUShr opUShr_r
+

The expressions with binary operators a op b will be rewritten as a.opfunc(b) and b.opfunc_r(a) and then the best match will be used.

+

+Index operators

+ + + + + +
opopfunc
[] opIndex
+

When the expression a[i] is compiled, the compiler will rewrite it as a.opIndex(i) and compile that instead. Multiple arguments between the brackets is also supported.

+

The index operator can also be formed similarly to property accessors. The get accessor should then be named get_opIndex and have one parameter for the indexing. The set accessor should be named set_opIndex and have two parameters, the first is for the indexing, and the second for the new value.

+
+  class MyObj
+  {
+    float get_opIndex(int idx) const       { return 0; }
+    void set_opIndex(int idx, float value) { }
+  }
+

When the expression a[i] is used to retrieve the value, the compiler will rewrite it as a.get_opIndex(i). When the expression is used to set the value, the compiler will rewrite it as a.set_opIndex(i, expr).

+

+Functor operator

+ + + + + +
opopfunc
() opCall
+

When the expression expr(arglist) is compiled and expr evaluates to an object, the compiler will rewrite it as expr.opCall(arglist) and compile that instead.

+

+Type conversion operators

+ + + + + + + +
opopfunc
type(expr)constructor, opConv, opImplConv
cast<type>(expr)opCast, opImplCast
+

When the expression type(expr) is compiled and type doesn't have a constructor that take an argument with the type of the expression, the compiler will try to rewrite it as expr.opConv(). The compiler will then chose the opConv that returns the desired type.

+

For implicit conversions, the compiler will look for a constructor of the target type that take a matching argument, and isn't flagged as explicit. If it doesn't find one, it will try to call the opImplConv on the source type that returns the target type.

+
+  class MyObj
+  {
+    double myValue;
    // Allow MyObj to be implicitly created from double
+    MyObj(double v)            { myValue = v; }
    // Allow MyObj to be implicitly converted to double
+    double opImplConv() const  { return myValue; }
    // Allow MyObj to be created from int, but only explicitly
+    MyObj(int v) explicit      { myValue = v; }
    // Allow MyObj to be converted to int, but only explicitly
+    int opConv() const         { return int(myValue); }
+  }
+

This should only be used for value conversions and not reference casts. That is, the methods are expected to return a new instance of the value with the new type.

+

If a reference cast is desired, i.e. a different type of handle to the same object instance, then the opCast method should be implemented instead. The compiler will attempt to rewrite an expression cast<type>(expr) as expr.opCast(), and chose the opCast overload that returns a handle of the desired type. Here too the opImplCast can be implemented instead if the reference cast is allowed to be performed implicitly by the compiler.

+
+  class MyObjA
+  {
+    MyObjB @objB;
+    MyObjC @objC;
+    MyObjB @opCast() { return objB; }
+    MyObjC @opImplCast() { return objC; }
+    const MyObjB @opCast() const { return objB; }
+    const MyObjC @opImplCast() const { return objC; }
+  }
+

An example where the opCast/opImplCast operator overloads come in handy is when extending a type without directly inheriting from it.

+
See also
Type conversions, Inheriting from application registered class
+
+
+
+ + + + diff --git a/docs/manual/doc_script_class_private.html b/docs/manual/doc_script_class_private.html new file mode 100644 index 0000000..9b0ffb3 --- /dev/null +++ b/docs/manual/doc_script_class_private.html @@ -0,0 +1,151 @@ + + + + + + + +AngelScript: Protected and private class members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Protected and private class members
+
+
+

Class members can be declared as protected or private to control where they can be accessed from. Protected members cannot be accessed from outside the class. Private members additionally cannot be accessed by derived classes.

+

This can be useful in large programs where you wish to avoid programmer errors where properties or methods are inappropriately used.

+
+  // A class with private members
+  class MyBase
+  {
+    // The following are public members
+    void PublicFunc()
+    {
+      // The class can access its own protected and private members
+      ProtectedProp = 0; // OK
+      ProtectedFunc();   // OK
+      PrivateProp = 0;   // OK
+      PrivateFunc();     // OK
+    }
    int PublicProp;
    // The following are protected members
+    protected void ProtectedFunc() {}
+    protected int ProtectedProp;
    // The following are private members
+    private void PrivateFunc() {} 
+    private int PrivateProp;
+  }
  class MyDerived : MyBase
+  {
+    void Func()
+    {
+      // The derived class can access the protected members
+      // of the base class but not the private members
+      ProtectedProp = 1; // OK
+      ProtectedFunc();   // OK
+      PrivateProp = 1;   // Error
+      PrivateFunc();     // Error  
+    }
+  }
  void GlobalFunc()
+  {
+    MyBase obj;
    // Public members can be accessed normally
+    obj.PublicProp = 0;  // OK
+    obj.PublicFunc();    // OK
    // Accessing protected and private members will give a compiler error
+    obj.ProtectedProp = 0; // Error
+    obj.ProtectedFunc();   // Error
+    obj.PrivateProp = 0;   // Error
+    obj.PrivateFunc();     // Error
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_class_prop.html b/docs/manual/doc_script_class_prop.html new file mode 100644 index 0000000..0a128ad --- /dev/null +++ b/docs/manual/doc_script_class_prop.html @@ -0,0 +1,199 @@ + + + + + + + +AngelScript: Property accessors + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Property accessors
+
+
+
Note
The application can optionally turn off support for property accessors, so you need to verify your application's manual to determine if this is supported for your application or not.
+

Many times when working with properties it is necessary to make sure specific logic is followed when accessing them. An example would be to always send a notification when a property is modified, or computing the value of the property from other properties. By implementing property accessor methods for the properties this can be implemented by the class itself, making it easier for the one who accesses the properties.

+

In AngelScript property accessors are declared with the following syntax:

+
+  class MyObj
+  {
+    // A virtual property with accessors
+    int prop 
+    { 
+      get const 
+      { 
+        // The actual value of the property could be stored
+        // somewhere else, or even computed at access time.
+        return realProp; 
+      } 
+      set 
+      { 
+        // The new value is stored in a hidden parameter appropriately called 'value'.
+        realProp = value; 
+      }
+    }
    // The actual value can be stored in a member or elsewhere.
+    // It is actually possible to use the same name for the real property, if so is desired.
+    private int realProp;
+  }
+

Behind the scene the compiler transforms this into two methods with the name of the property and the prefixes get_ and set_, and with the function decorator 'property'. The following generates the equivalent code, and is perfectly valid too:

+
+  class MyObj
+  {
+    int get_prop() const property { return realProp; }
+    void set_prop(int value) property { realProp = value; }
+    private int realProp;
+  }
+

If you implement the property accessors by explicitly writing the two methods you must make sure the return type of the get accessor and the parameter type of the set accessor match, otherwise the compiler will not know which is the correct type to use.

+

For interfaces the first alternative is usually the preferred way of declaring the property accessors, as it gets quite short and easy to read.

+
+  interface IProp
+  {
+    int prop { get const; set; }
+  }
+

You can also leave out either the get or set accessor. If you leave out the set accessor, then the property will be read-only. If you leave out the get accessor, then the property will be write-only.

+

Property accessors can also be implemented for global properties, which follows the same rules, except the functions are global.

+

When the property accessors have been declared it is possible to access them like ordinary properties, and the compiler will automatically expand the expressions to the appropriate function calls, either set_ or get_ depending on how the property is used in the expression.

+
+  void Func()
+  {
+    MyObj obj;
    // Set the property value just like a normal property.
+    // The compiler will convert this to a call to set_prop(10000).
+    obj.prop = 10000;
    // Get the property value just a like a normal property.
+    // The compiler will convert this to a call to get_prop().
+    assert( obj.prop == 1000 );
+  }
+

Observe that as property accessors are actually a pair of methods rather than direct access to the value, some restrictions apply as to how they can be used in expressions that inspect and mutate in the same operation. Compound assignments can be used on property accessors if the owning object is a reference type, but not if the owning object is a value type. This is because the compiler must be able to guarantee that the object stays alive between the two calls to the get accessor and set accessor.

+

The increment and decrement operators are currently not supported.

+

In such cases the expression must be expanded so that the read and write operation are performed separately, e.g. the increment operator must be rewritten as follows:

+
+  a++;     // will not work if a is a virtual property
+  a += 1;  // this is OK, as long as the owner of the virtual 
+           // property is a reference type or the property is global
+

+Indexed property accessors

+

Property accessors can be used to emulate a single property or an array of properties accessed through the index operator. Property accessors for indexed access work the same way as ordinary property accessors, except that they take an index argument. The get accessor should take the index argument as the only argument, and the set accessor should take the index argument as the first argument, and the new value as the second argument.

+
+  string firstString;
+  string secondString;
  // A global indexed get accessor
+  string get_stringArray(int idx) property
+  {
+    switch( idx )
+    {
+    case 0: return firstString;
+    case 1: return secondString;
+    }
+    return "";
+  }
  // A global indexed set accessor
+  void set_stringArray(int idx, const string &in value) property
+  {
+    switch( idx )
+    {
+    case 0: firstString = value; break;
+    case 1: secondString = value; break;
+    }
+  }
  void main()
+  {
+    // Setting the value of the indexed properties
+    stringArray[0] = "Hello";
+    stringArray[1] = "World";
    // Reading the value of the indexed properties
+    print(StringArray[0] + " " + stringArray[1] + "\n");
+  }
+

Compound assignments currently doesn't work for indexed properties.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_func.html b/docs/manual/doc_script_func.html new file mode 100644 index 0000000..a7c3c49 --- /dev/null +++ b/docs/manual/doc_script_func.html @@ -0,0 +1,120 @@ + + + + + + + +AngelScript: Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Functions
+
+
+

Functions are declared globally, and consists of a signature where the types of the arguments and the return value is defined, and a body where the implementation is declared.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_script_func.js b/docs/manual/doc_script_func.js new file mode 100644 index 0000000..a41095f --- /dev/null +++ b/docs/manual/doc_script_func.js @@ -0,0 +1,15 @@ +var doc_script_func = +[ + [ "Function declaration", "doc_script_func_decl.html", null ], + [ "Parameter references", "doc_script_func_ref.html", null ], + [ "Return references", "doc_script_func_retref.html", [ + [ "References to global variables are allowed", "doc_script_func_retref.html#doc_script_retref_global", null ], + [ "References to class members are allowed", "doc_script_func_retref.html#doc_script_refref_member", null ], + [ "Can't return reference to local variables", "doc_script_func_retref.html#doc_script_retref_local", null ], + [ "Can't use expressions with deferred parameters", "doc_script_func_retref.html#doc_script_retref_deferred", null ], + [ "Can't use expressions that rely on local objects", "doc_script_func_retref.html#doc_script_refref_cleanup", null ] + ] ], + [ "Function overloading", "doc_script_func_overload.html", null ], + [ "Default arguments", "doc_script_func_defarg.html", null ], + [ "Anonymous functions", "doc_script_anonfunc.html", null ] +]; \ No newline at end of file diff --git a/docs/manual/doc_script_func_decl.html b/docs/manual/doc_script_func_decl.html new file mode 100644 index 0000000..ee3220a --- /dev/null +++ b/docs/manual/doc_script_func_decl.html @@ -0,0 +1,121 @@ + + + + + + + +AngelScript: Function declaration + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Function declaration
+
+
+

Global functions provide the mean to implement routines that should operate on some input and produce a result. The functions themselves do not keep any memory, though they can update global variables, or memory passed by reference.

+

The function is always declared together with the function body. There is no need to declare function prototypes, as the function is globally visible regardless where it has been declared.

+
+  // A simple function declaration
+  int AFunction(int a, int b)
+  {
+    // Implement the function logic here
+    return a + b;
+  }
+

The type of the return value should be specified before the name of the function. If the function doesn't return anything the type should be defined as 'void'. After the function name, the list of parameters is specified between parenthesis. Each parameter is defined by its type and name.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_func_defarg.html b/docs/manual/doc_script_func_defarg.html new file mode 100644 index 0000000..6b16d7d --- /dev/null +++ b/docs/manual/doc_script_func_defarg.html @@ -0,0 +1,138 @@ + + + + + + + +AngelScript: Default arguments + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Default arguments
+
+
+

Sometimes implementing different functions for each overload is unnecessary when the difference can be provided with a default value to a parameter. This is where default arguments come in handy.

+

By defining default arguments in the declaration of the function, the script doesn't have to provide these values specifically when calling the function as the compiler will automatically fill in the default arguments.

+
+  void Function(int a, int b = 1, string c = "")
+  {
+    // Inside the function the arguments work normally
+  }
  void main()
+  {
+    // Default arguments doesn't have to be informed
+    // The following three calls produce the exact same result
+    Function(0);
+    Function(0,1);
+    Function(0,1,"");
+  }
+

When defining a default argument to one of the parameters, all subsequent parameters must have a default argument too.

+

The default argument expression can include references to variables or call functions, but only if the variables or functions are visible in the global scope.

+
+  int myvar = 42;
+  void Function(int a, int b = myvar) {}
+  void main()
+  {
+    int myvar = 1;
+    Function(1);    // This will use the global myvar and not the local myvar
+  }
+

The special 'void' expression can be used as default argument to make an optional output parameter.

+
+  void func(int &out output = void) { output = 42; }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_func_overload.html b/docs/manual/doc_script_func_overload.html new file mode 100644 index 0000000..9d223d4 --- /dev/null +++ b/docs/manual/doc_script_func_overload.html @@ -0,0 +1,134 @@ + + + + + + + +AngelScript: Function overloading + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Function overloading
+
+
+

Function overloading happens when more than one function with the same name is declared with different parameters. This is a useful feature when an operation needs to be able to work with different types of input, yet produce similar result.

+

The compiler is able to resolve which function to call by matching the type of each argument expression to the function parameter, and eliminating the functions where there is no possible conversion available. The compiler will do this for each argument from first to last. When all arguments have been evaluated only one function should be the best match, otherwise the compiler will give an error about the impossibility to determine the correct function to call.

+

The type of conversion that needs to be performed on the argument to get to the type of the parameter determines how well a function matches. The following list gives the order of how one type of conversion compares to another.

+
    +
  • no conversion needed
  • +
  • conversion to const
  • +
  • size of primitive changes
  • +
  • integer type to float type and vice versa
  • +
  • reference cast
  • +
  • object to primitive conversion
  • +
  • conversion to object
  • +
  • variable argument type
  • +
+

Observe that it is not possible to create overloads where the only difference is the return type. This is because the return type is not part of the selection criteria that the compiler uses to determine which function to call, the return type is just the result of the called function.

+
+  void Function(int a, float b, string c) {}
+  void Function(string a, int b, float c) {}
+  void Function(float a, string b, int c) {}
  void main()
+  {
+    Function(1, 2.5f, 'a');  // Will call the first overload
+    Function('a', 1, 2.5f);  // Will call the second overload
+    Function(2.5f, 'a', 1);  // Will call the third overload
+  }  
+
+
+
+ + + + diff --git a/docs/manual/doc_script_func_ref.html b/docs/manual/doc_script_func_ref.html new file mode 100644 index 0000000..9f8cb7e --- /dev/null +++ b/docs/manual/doc_script_func_ref.html @@ -0,0 +1,124 @@ + + + + + + + +AngelScript: Parameter references + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Parameter references
+
+
+

The parameters and return value can be of any type that can also be used for variable declarations. In addition, it is also possible to make a function take a value by reference, i.e. rather than a copy of the original value, the parameter will refer to the value.

+

Parameter references are used mainly for two purposes; a means of providing additional output from the function, or as a more performatic way of passing values.

+

In AngelScript it is necessary to specify the intention of the parameter reference, i.e. if it is meant as input, output, or both. This is necessary in order for the compiler to prepare the reference in a way that it cannot be invalidated due to some action during the processing of the function.

+

Input references are written as &in. As the reference is meant as input only, the actual value it refers to normally is a copy of the original so the function doesn't accidentally modify the original value. These are not commonly used, as they provide little benefit over passing arguments by value. Only in some circumstances can the performance be improved, especially if the parameter is declared as const too.

+

Output references are written as &out. These references are meant to allow the function to return additional values. When going in to the function, the reference will point to an uninitialized value. After the function returns, the value assigned by the function will be copied to the destination determined by the caller.

+

When the reference is meant as both input and output, it is declared as &inout, or just &. In this case the reference will point to the actual value. Only reference types, i.e. that can have handles to them, are allowed to be passed as inout references. This is because in order to guarantee that the reference will stay valid during the entire execution of the function, the value must be located in the memory heap.

+
+  void Function(const int &in a, int &out b, Object &c)
+  {
+    // Assigning an output value to the output reference
+    b = a;
    // The object is an inout reference and refers to the real object
+    c.DoSomething();
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_func_retref.html b/docs/manual/doc_script_func_retref.html new file mode 100644 index 0000000..4cf005a --- /dev/null +++ b/docs/manual/doc_script_func_retref.html @@ -0,0 +1,141 @@ + + + + + + + +AngelScript: Return references + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Return references
+
+
+

A function can also return references, which will allow the caller to modify the value pointed to by the reference. To declare a function that return a reference include the & symbol between the return type and name of the function. Add const before the type if the reference should be read only, i.e. it shouldn't be possible to modify the value it points to.

+
+  int property;
+  int &Function()
+  {
+    // Return a reference to the property
+    return property;
+  }
  void main()
+  {
+    // Modify the value pointed to by the returned reference
+    Function() = 1;
+  }
+

Due to the need to guarantee that the reference is valid even after the function returns to the caller there exist certain restrictions. You don't need to try to remember these restrictions as the compiler will give an error if you they are violated, but if you do encounter a compile error when returning a reference it will be good to understand why it is happening so that you can determine how to avoid it.

+

+References to global variables are allowed

+

As a global variable is in the global scope, the lifetime of the variable is longer than the scope of the function. A function can thus return a reference to a global variable, or even member of an object reached through a global variable.

+

+References to class members are allowed

+

A class method can return a reference to a class property of the same object, because the caller is required to hold a reference to the object it is known that the member will exist even after the method returns.

+

The class method is also allowed to return reference to global variables, just like any other function.

+

+Can't return reference to local variables

+

Because local variables must be freed when the function exits, it is not allowed to return a reference to them. The same is also true for any parameters that the function received. The parameters are also cleaned up when the function exits, so they too cannot be returned by reference.

+

+Can't use expressions with deferred parameters

+

For some function calls with arguments, there may be a necessary processing of the arguments after the function call returned, e.g. to clean up the input object, or to assign the output parameters. If the function that was called is returning a reference, then that reference cannot in turn be returned again, as it may be invalidated by the deferred evaluation of the arguments.

+

+Can't use expressions that rely on local objects

+

All local objects must be cleaned up before a function exits. For functions that return references this clean-up happens before the return expression is evaluated, otherwise the cleanup of the local objects may accidentally invalidate the reference. For this reason it is not possible to use expressions that rely on local objects to evaluate the reference that should be returned.

+

Primitive values can be used though, as these do not require cleanup upon exit.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_global.html b/docs/manual/doc_script_global.html new file mode 100644 index 0000000..53d47c4 --- /dev/null +++ b/docs/manual/doc_script_global.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Global entities + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Global entities
+
+
+

All global declarations share the same namespace so their names may not conflict. This includes extended data types and built-in functions registered by the host application. Also, all declarations are visible to all, e.g. a function to be called does not have to be declared above the function that calls it.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_script_global.js b/docs/manual/doc_script_global.js new file mode 100644 index 0000000..a254787 --- /dev/null +++ b/docs/manual/doc_script_global.js @@ -0,0 +1,14 @@ +var doc_script_global = +[ + [ "Functions", "doc_global_func.html", null ], + [ "Variables", "doc_global_variable.html", null ], + [ "Virtual properties", "doc_global_virtprop.html", null ], + [ "Script classes", "doc_global_class.html", null ], + [ "Interfaces", "doc_global_interface.html", null ], + [ "Mixin class", "doc_script_mixin.html", null ], + [ "Enums", "doc_global_enums.html", null ], + [ "Funcdefs", "doc_global_funcdef.html", null ], + [ "Typedefs", "doc_global_typedef.html", null ], + [ "Namespaces", "doc_global_namespace.html", null ], + [ "Imports", "doc_global_import.html", null ] +]; \ No newline at end of file diff --git a/docs/manual/doc_script_handle.html b/docs/manual/doc_script_handle.html new file mode 100644 index 0000000..de3e8a6 --- /dev/null +++ b/docs/manual/doc_script_handle.html @@ -0,0 +1,194 @@ + + + + + + + +AngelScript: Object handles + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Object handles
+
+
+

An object handle is a type that can hold a reference to an object. With object handles it is possible to declare more than one variables that refer to the same physical object.

+

Not all types allow object handles to be used. None of the primitive data types, bool, int, float, etc, can have object handles. Object types registered by the application may or may not allow object handles, depending on how they have been registered.

+
See also
Object handles to the application
+

+General usage

+

An object handle is declared by appending the @ symbol to the data type.

+
+  object@ obj_h;
+

This code declares the object handle obj and initializes it to null, i.e. it doesn't hold a reference to any object.

+

In expressions variables declared as object handles are used the exact same way as normal objects. But you should be aware that object handles are not guaranteed to actually reference an object, and if you try to access the contents of an object in a handle that is null an exception will be raised.

+
+  object obj;
+  object@ obj_h;
+  obj.Method();
+  obj_h.Method();
+

Operators like = or any other operator registered for the object type work on the actual object that the handle references. These will also throw an exception if the handle is empty.

+
+  object obj;
+  object@ obj_h;
+  obj_h = obj;
+

When you need to make an operation on the actual handle, you should prepend the expression with the @ symbol. Setting the object handle to point to an object is for example done like this:

+
+  object obj;
+  object@ obj_h;
+  @obj_h = @obj;
+

Note that the compiler can often implicitly determine that it is the handle of the object that is needed rather than the actual object itself. In these cases it is not necessary to explicitly prepend the expression with @.

+

An object handle can be compared against another object handle (of the same type) to verify if they are pointing to the same object or not. It can also be compared against null, which is a special keyword that represents an empty handle. This is done using the identity operator, is.

+
+  object@ obj_a, obj_b;
+  if( obj_a is obj_b ) {}
+  if( obj_a !is null ) {}
+

Observe, the == and != operators will do a value comparison on the objects referred to by the handles using the opEquals or opCmp operator overloads. Though, if the expressions are prepended with @ the operators will have the same function as is and !is.

+

+Object life times

+

An object's life time is normally for the duration of the scope the variable was declared in. But if a handle outside the scope is set to reference the object, the object will live on until all object handles are released.

+
+  object@ obj_h;
+  {
+    object obj;
+    @obj_h = @obj;
    // The object would normally die when the block ends,
+    // but the handle is still holding a reference to it
+  }
  // The object still lives on in obj_h ...
+  obj_h.Method();
  // ... until the reference is explicitly released
+  // or the object handle goes out of scope
+  @obj_h = null;
+

+Object relations and polymorphing

+

Object handles can be used to write common code for related types, by means of inheritance or interfaces. This allows a handle to an interface to store references to all object types that implement that interface, similarly a handle to a base class can store references to all object types that derive from that class.

+
+  interface I {}
+  class A : I {}
+  class B : I {}
  // Store reference in handle to interface 
+  I @i1 = A();  
+  I @i2 = B();
  void function(I @i)
+  { 
+    // Functions implemented by the interface can be  
+    // called directly on the interface handle. But if
+    // special treatment is need for a specific type, a 
+    // cast can be used to get a handle to the true type.
+    A @a = cast<A>(i);
+    if( a !is null )
+    {
+      // Access A's members directly
+      ...
+    }
+    else
+    { 
+      // The object referenced by i is not of type A
+      ...
+    }
+  }
+

+Const handles

+

Sometimes it is necessary to hold handles to objects that shouldn't be allowed to be modified. This is done by prefixing the type with 'const', e.g.

+
+  obj @a;                      // handle to modifiable object
+  const obj @b;                // handle to non-modifiable object
+

A handle to a non-modifiable object can refer to both modifiable objects and non-modifiable objects, but the script will not allow the object to be modified through that handle, nor allow the handle to be passed to another handle that would allow modifications.

+

This syntax is not to be confused with handles that are themselves read-only, i.e. the handle cannot be re-assigned to refer to a different object. Read-only handles like this are declared by adding the 'const' keyword as a suffix after the '@' symbol.

+
+  obj @ const c = obj();       // read-only handle to a modifiable object
+  const obj @ const d = obj(); // read-only handle to a non-modifiable object
+

A read-only handle can only be initialized when declared.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_mixin.html b/docs/manual/doc_script_mixin.html new file mode 100644 index 0000000..a4202dd --- /dev/null +++ b/docs/manual/doc_script_mixin.html @@ -0,0 +1,174 @@ + + + + + + + +AngelScript: Mixin class + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Mixin class
+
+
+

As multiple inheritance is not available, it may sometimes be necessary to implement identical code in multiple classes. When this is necessary it is recommended to use mixin classes to avoid writing the identical code in multiple places.

+

Mixin classes allows a script to declare a partial class structure that will be included into multiple different class declarations. The mixin classes themselves are not real types and cannot be instanciated.

+

When a mixin class is included into a class declaration, the properties and methods that were declared in the mixin class will be automatically replicated into the class.

+
+  // Declare a mixin class
+  mixin class MyMixin
+  {
+    void SomeMethod() { property++; }
+    int property;
+  }
  // Include the mixin class into the class to receive the methods and properties
+  class MyClass : MyMixin
+  {
+    int OtherMethod()
+    {  
+      SomeMethod();
+      return property;
+    }
+  }
+

Properties and methods that have already been explicitly declared in the class will not be included again. This way the mixin class can provide a default implementation that can be overridden by the class that includes the mixin.

+

The class methods included from a mixin class will be compiled in the context of the class that included it, so it is possible for a mixin class method to refer to properties and other methods that are not declared in the mixin class if the class that includes the mixin class provides those.

+
+  mixin class MyMixin
+  {
+    void MethodA() { print("Default behaviour"); } 
+    void MethodB() { property++; }
+  }
  class MyClass : MyMixin
+  {
+    // Override the default behaviour in MethodA
+    void MethodA() { print("Overridden behaviour"); }
    // Declare the property that will be used by MethodB
+    int property;
+  }
+

Mixin class methods override inherited methods from base classes, just as if the included method had been implemented in the derived class directly. Mixin class properties on the other hand are not included if the property is already inherited from a base class.

+
+  class MyBase
+  {
+    void MethodA() { print("Base behaviour"); }
+    int property;
+  }
  mixin class MyMixin
+  {
+    void MethodA() { print("Mixin behaviour"); }
+    float property;
+  }
  // Inheriting from base class and including mixin.
+  // MyClass ends up with the property from the base 
+  // class and the method from the mixin class.
+  class MyClass : MyBase, MyMixin
+  {
+  }
+

A mixin class can inform a list of interfaces that has to be implemented by the script class that includes the mixin class. In this case the methods for the interfaces can optionally be provided by the mixin class itself, or left out to be implemented by the script class directly.

+

A mixin class cannot inherit from other classes.

+
+  interface I 
+  {
+    void a();
+    void b();   
+  }
  mixin class M : I
+  {
+        // provide default implementation of a()
+    void a() { print("hello from a");
    // leave the implementation of b() to the script class
+  }
  class C : M
+  {
+    // a() is implemented by mixin class
        // b() has to be explicitly implemented by script class
+        void b() { print("hello from b");
+  }
+
+
+
+ + + + diff --git a/docs/manual/doc_script_shared.html b/docs/manual/doc_script_shared.html new file mode 100644 index 0000000..c5522d2 --- /dev/null +++ b/docs/manual/doc_script_shared.html @@ -0,0 +1,137 @@ + + + + + + + +AngelScript: Shared script entities + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Shared script entities
+
+
+

If the application uses multiple script modules to control different parts of the application it may sometimes be beneficial to allow parts of the scripts to be shared between the script modules. The main benefits of shared entities is the reduced memory consumption, and the fact that the type of the shared entity is the same for the modules thus simplifying the information exchange between modules where this is used.

+

Shared entities have a restriction in that they cannot access non-shared entities because the non-shared entities are exclusive to the script module in which they were compiled.

+

+How to declare shared entities

+

To declare a shared entity simply put the keyword 'shared' before the ordinary declaration, e.g.

+
+  shared class Foo
+  {
+    void MethodInFoo(int b) { bar = b; }
+    int bar;
+  }
  shared void GlobalFunc() {}
+

If the script tries to access any non-shared entity from within the shared entity then the compiler will give an error message.

+

Obviously, in order to work the scripts in all modules that share the entity must implement the entity the same way. If this is not done, the compiler will give an error in the scripts that are compiled after the first script that implemented the shared entity.

+

The easiest way to guarantee that the implementation is the same is by using the same source file, but this is not a requirement.

+

+External shared entities

+

An alternative to declaring the full shared entity in each module is to declared the shared entity that is known to have been compiled before as external. This can shorten the script, both reducing the size of the source code and the time to compile it.

+

To declare a shared entity as external, simply add the keyword 'external' before the declaration and end the statement with ';' after the signature that uniquely identifies the entity.

+
+  external shared class Foo;
+  external shared void GlobalFunc();
+

When compiling a shared entity declared as external and the shared entity hasn't been compiled in any other module before it, the compiler will give an error message.

+

+What can be shared

+

Currently only the class, interface, function, enum, and funcdefs entities can be shared.

+

Future versions may allow global variables to be shared too.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_statements.html b/docs/manual/doc_script_statements.html new file mode 100644 index 0000000..9151307 --- /dev/null +++ b/docs/manual/doc_script_statements.html @@ -0,0 +1,247 @@ + + + + + + + +AngelScript: Statements + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Statements
+
+
+
+

+Variable declarations

+
+  int var = 0, var2 = 10;
+  object@ handle, handle2;
+  const float pi = 3.141592f;
+

Variables must be declared before they are used within the statement block, or any sub blocks. When the code exits the statement block where the variable was declared the variable is no longer valid.

+

A variable can be declared with or without an initial expression. If it is declared with an initial expression it, the expression must have the evaluate to a type compatible with the variable type.

+

Any number of variables can be declared on the same line separated with commas, where all variables then get the same type.

+

Variables can be declared as const. In these cases the value of the variable cannot be changed after initialization.

+

Variables of primitive types that are declared without an initial value, will have a random value. Variables of complex types, such as handles and object are initialized with a default value. For handles this is null, for objects this is what is defined by the object's default constructor.

+

+Expression statement

+
+  a = b;  // a variable assignment
+  func(); // a function call
+

Any expression may be placed alone on a line as a statement. This will normally be used for variable assignments or function calls that don't return any value of importance.

+

All expression statements must end with a ;.

+

+Conditions: if / if-else / switch-case

+
+  if( condition ) 
+  {
+    // Do something if condition is true
+  }
  if( value < 10 ) 
+  {
+    // Do something if value is less than 10
+  }
+  else
+  {
+    // Do something else if value is greater than or equal to 10
+  }
+

If statements are used to decide whether to execute a part of the logic or not depending on a certain condition. The conditional expression must always evaluate to true or false.

+

It's possible to chain several if-else statements, in which case each condition will be evaluated sequencially until one is found to be true.

+
+  switch( value )
+  {
+  case 0:
+    // Do something if value equals 0, then leave
+    break;
  case 2:
+  case constant_value:
+    // This will be executed if value equals 2 or the constant_value
+    break;
  default:
+    // This will be executed if value doesn't equal any of the cases
+  }
+

If you have an integer (signed or unsigned) expression that have many different outcomes that should lead to different code, a switch case is often the best choice for implementing the condition. It is much faster than a series of ifs, especially if all of the case values are close in numbers.

+

Each case should be terminated with a break statement unless you want the code to continue with the next case.

+

The case value can be a constant variable that was initialized with a constant expression. If the constant variable was initialized with an expression that cannot be determined at compile time it cannot be used in the case values.

+

+Loops: while / do-while / for

+
+  // Loop, where the condition is checked before the logic is executed
+  int i = 0;
+  while( i < 10 )
+  {
+    // Do something
+    i++;
+  }
  // Loop, where the logic is executed before the condition is checked
+  int j = 0;
+  do 
+  {
+    // Do something
+    j++;
+  } while( j < 10 );
+

For both while and do-while the expression that determines if the loop should continue must evaluate to either true or false. If it evaluates to true, the loop continues, otherwise it stops and the code will continue with the next statement immediately following the loop.

+
+  // More compact loop, where condition is checked before the logic is executed
+  for( int n = 0; n < 10; n++ ) 
+  {
+    // Do something
+  }
+

The for loop is a more compact form of a while loop. The first part of the statement (until the first ;) is executed only once, before the loop starts. Here it is possible to declare a variable that will be visible only within the loop statement. The second part is the condition that must be satisfied for the loop to be executed. A blank expression here will always evaluate to true. The last part is executed after the logic within the loop, e.g. used to increment an iteration variable.

+

Multiple variables can be declared in the for loop, separated by ,. Likewise, multiple increment expressions can be used in the last part by separating them with ,.

+

+Loop control: break / continue

+
+  for(;;) // endless loop
+  {
+    // Do something
    // End the loop when condition is true
+    if( condition )
+      break;
+  }
+

break terminates the smallest enclosing loop statement or switch statement.

+
+  for(int n = 0; n < 10; n++ )
+  {
+    if( n == 5 )
+      continue;
    // Do something for all values from 0 to 9, except for the value 5
+  }
+

continue jumps to the next iteration of the smallest enclosing loop statement.

+

+Return statement

+
+  float valueOfPI()
+  {
+    return 3.141592f; // return a value 
+  }
+

Any function with a return type other than void must be finished with a return statement where expression evaluates to the same data type as the function return type. Functions declared as void can have return statements without any expression to terminate early.

+

+Statement blocks

+
+  {
+    int a; 
+    float b;
    {
+      float a; // Override the declaration of the outer variable
+               // but only within the scope of this block.
      // variables from outer blocks are still visible
+      b = a;
+    }
    // a now refers to the integer variable again
+  }
+

A statement block is a collection of statements. Each statement block has its own scope of visibility, so variables declared within a statement block are not visible outside the block.

+

+Try-catch blocks

+
+ {
+   try
+   {
+     DoSomethingThatMightThrowException();
     // This is not executed if an exception was thrown
+   }
+   catch
+   {
+     // This is executed if an exception was thrown
+   }
+  }
+

A try-catch block can be used if you're executing some code that might throw an exception and you want to catch that exception and continue with the exception rather than just abort the script.

+

Exceptions can occur for various reasons, some examples include, accessing null pointers in uninitialized handles, division by zero, or exceptions raised from application registered functions. In some cases exceptions are intentionally raised by the script to interrupt some execution.

+
See also
Exception handling
+
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib.html b/docs/manual/doc_script_stdlib.html new file mode 100644 index 0000000..89711f6 --- /dev/null +++ b/docs/manual/doc_script_stdlib.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Standard library + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Standard library
+
+
+

This pages describes the standard library provided by the AngelScript SDK. The applications that use AngelScript may or may not expose the standard library to the scripts. Always consult the application's manual for information on the API it exposes.

+ +
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib.js b/docs/manual/doc_script_stdlib.js new file mode 100644 index 0000000..83a47ea --- /dev/null +++ b/docs/manual/doc_script_stdlib.js @@ -0,0 +1,64 @@ +var doc_script_stdlib = +[ + [ "Exception handling", "doc_script_stdlib_exception.html", [ + [ "Functions", "doc_script_stdlib_exception.html#try_func", null ] + ] ], + [ "string", "doc_script_stdlib_string.html", [ + [ "Supporting string object and functions", "doc_script_stdlib_string.html#doc_datatypes_strings_addon", [ + [ "Operators", "doc_script_stdlib_string.html#doc_datatypes_strings_addon_ops", null ], + [ "Methods", "doc_script_stdlib_string.html#doc_datatypes_strings_addon_mthd", null ], + [ "Functions", "doc_script_stdlib_string.html#doc_datatypes_strings_addon_funcs", null ] + ] ] + ] ], + [ "array", "doc_datatypes_arrays.html", [ + [ "Supporting array object", "doc_datatypes_arrays.html#doc_datatypes_arrays_addon", [ + [ "Operators", "doc_datatypes_arrays.html#doc_datatypes_array_addon_ops", null ], + [ "Methods", "doc_datatypes_arrays.html#doc_datatypes_array_addon_mthd", null ], + [ "Script example", "doc_datatypes_arrays.html#doc_datatypes_array_addon_example", null ] + ] ] + ] ], + [ "dictionary", "doc_datatypes_dictionary.html", [ + [ "Supporting dictionary object", "doc_datatypes_dictionary.html#doc_datatypes_dictionary_addon", [ + [ "Operators", "doc_datatypes_dictionary.html#doc_datatypes_dictionary_addon_ops", null ], + [ "Methods", "doc_datatypes_dictionary.html#doc_datatypes_dictionary_addon_mthd", null ] + ] ], + [ "Supporting dictionaryValue object", "doc_datatypes_dictionary.html#doc_datatypes_dictionaryValue_addon", [ + [ "Operators", "doc_datatypes_dictionary.html#doc_datatypes_dictionaryValue_addon_ops", null ] + ] ] + ] ], + [ "ref", "doc_datatypes_ref.html", [ + [ "Supporting ref object", "doc_datatypes_ref.html#doc_datatypes_ref_addon", [ + [ "Operators", "doc_datatypes_ref.html#doc_datatypes_ref_addon_ops", null ] + ] ] + ] ], + [ "weakref", "doc_datatypes_weakref.html", [ + [ "Supporting weakref object", "doc_datatypes_weakref.html#doc_datatypes_weakref_addon", [ + [ "Operators", "doc_datatypes_weakref.html#doc_datatypes_weakref_addon_ops", null ], + [ "Methods", "doc_datatypes_weakref.html#doc_datatypes_weakref_addon_mthd", null ] + ] ] + ] ], + [ "datetime", "doc_script_stdlib_datetime.html", [ + [ "Supporting datetime object", "doc_script_stdlib_datetime.html#doc_datatype_datetime_addon", [ + [ "Constructors", "doc_script_stdlib_datetime.html#doc_addon_datetime_2_construct", null ], + [ "Methods", "doc_script_stdlib_datetime.html#doc_addon_datetime_2_methods", null ], + [ "Operators", "doc_script_stdlib_datetime.html#doc_addon_datetime_2_ops", null ] + ] ] + ] ], + [ "Co-routines", "doc_script_stdlib_coroutine.html", [ + [ "Functions", "doc_script_stdlib_coroutine.html#doc_script_stdlib_coroutine_1", null ] + ] ], + [ "file", "doc_script_stdlib_file.html", [ + [ "Supporting file object", "doc_script_stdlib_file.html#doc_script_stdlib_file_1", [ + [ "Methods", "doc_script_stdlib_file.html#doc_script_stdlib_file_1_1", null ], + [ "Properties", "doc_script_stdlib_file.html#doc_script_stdlib_file_1_2", null ] + ] ] + ] ], + [ "filesystem", "doc_script_stdlib_filesystem.html", [ + [ "Supporting filesystem object", "doc_script_stdlib_filesystem.html#doc_script_stdlib_filesystem_1", [ + [ "Methods", "doc_script_stdlib_filesystem.html#doc_script_stdlib_filesystem_1_1", null ] + ] ] + ] ], + [ "System functions", "doc_script_stdlib_system.html", [ + [ "Functions", "doc_script_stdlib_system.html#doc_script_stdlib_system_1", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_script_stdlib_coroutine.html b/docs/manual/doc_script_stdlib_coroutine.html new file mode 100644 index 0000000..0f8a616 --- /dev/null +++ b/docs/manual/doc_script_stdlib_coroutine.html @@ -0,0 +1,121 @@ + + + + + + + +AngelScript: Co-routines + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Co-routines
+
+
+
Note
Support for co-routines is only available in the scripts if the application registers support for it.
+

+Functions

+

funcdef void coroutine(dictionary@)
+ void createCoRoutine(coroutine @, dictionary @)

+

This function is used to create a co-routine. The co-routine will initiate in a yielded state, i.e. it will only begin execution once the control is given to it by the current thread.

+

Multiple co-routines can be created, and they will each take turn to execute in round-robin fashion.

+

void yield()

+

Yields control of the execution for the next co-routine in the queue.

+

When a co-routine receives control it will resume execution from the last call to yield, or the entry point if this is the first time the co-routine is allowed to execute.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib_datetime.html b/docs/manual/doc_script_stdlib_datetime.html new file mode 100644 index 0000000..d810ac1 --- /dev/null +++ b/docs/manual/doc_script_stdlib_datetime.html @@ -0,0 +1,156 @@ + + + + + + + +AngelScript: datetime + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
datetime
+
+
+
Note
datetime is only available in the scripts if the application registers support for it.
+

The datetime type represents a calendar date and time. It can be used to do math operations with dates, such as comparing two dates, determining the difference between dates, and addition/substraction on dates to form new dates.

+

It can also be used to get the current system time and thus allow measuring time for tasks, albeit with a rather low precision of seconds only.

+

+Supporting datetime object

+

+Constructors

+

datetime()
+ datetime(const datetime &in other)
+ datetime(uint y, uint m, uint d, uint h = 0, uint mi = 0, uint s = 0)
+

+

The default constructor initializes the object with the current system time in the universal time zone (UTC). If you need to consider a specific timezone with or without daylight savings then remember to adjust the time accordingly by adding the number of seconds for the difference.

+

The copy constructor copíes the content of the other object.

+

The set constructor initializes the object with the given date and time.

+

+Methods

+

uint get_year() const property

+

Returns the year of the date stored in the object.

+

uint get_month() const property

+

Returns the month of the date stored in the object. The range is 1 to 12, i.e. 1 is January, 12 is December, and so on.

+

uint get_day() const property

+

Returns the day of the month of the date stored in the object.

+

uint get_hour() const property

+

Returns the hour of the time stored in the object. The range is 0 to 23.

+

uint get_minute() const property

+

Returns the minute of the time stored in the object. The range is 0 to 59.

+

uint get_second() const property

+

Returns the second of the time stored in the object. The range is 0 to 59.

+

bool setDate(uint year, uint month, uint day)
+ bool setTime(uint hour, uint minute, uint second)

+

Sets the date or time. Returns true if the specified date or time is valid. Does not modify the object if not valid.

+

+Operators

+

= assignment

+

The assignment operator copies the content of the other object.

+

- difference

+

When subtracting one datetime object from another the result is the number of seconds between them.

+

+ add
+ - subtract
+ += add assign
+ -= subtract assign

+

The datetime object can be added or subtracted with seconds to form a new datetime object.

+

==, != equality
+ <, <=, >=, > comparison

+

The datetime object can be compared for equality or relativity.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib_exception.html b/docs/manual/doc_script_stdlib_exception.html new file mode 100644 index 0000000..5369837 --- /dev/null +++ b/docs/manual/doc_script_stdlib_exception.html @@ -0,0 +1,118 @@ + + + + + + + +AngelScript: Exception handling + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Exception handling
+
+
+
Note
The standard throw and getExceptionInfo are only provided if the application registers them.
+

+Functions

+

void throw(const string &in exception)

+

Explicitly throw an exception. The string should identify the type of exception, for logging or treating.

+

string getExceptionInfo()

+

Get the exception string for the last exception thrown.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib_file.html b/docs/manual/doc_script_stdlib_file.html new file mode 100644 index 0000000..5919a5c --- /dev/null +++ b/docs/manual/doc_script_stdlib_file.html @@ -0,0 +1,193 @@ + + + + + + + +AngelScript: file + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
file
+
+
+
Note
file is only available in the scripts if the application registers support for it.
+

Script example:

+
+  file f;
+  // Open the file in 'read' mode
+  if( f.open("file.txt", "r") >= 0 ) 
+  {
+      // Read the whole file into the string buffer
+      string str = f.readString(f.getSize()); 
+      f.close();
+  }
+

+Supporting file object

+

+Methods

+

int open(const string &in filename, const string &in mode)
+

+

Opens a file. The mode can be "r" for reading, "w" for writing, or "a" for appending.

+

If the file couldn't be opened, a negative value is returned.

+

int close()
+

+

Closes the file.

+

If no file is open, a negative value is returned.

+

int getSize() const
+

+

Returns the size of the file, or a negative value if no file is open.

+

bool isEndOfFile() const
+

+

Returns true if the current position is at the end of the file.

+

string readString(uint length)
+

+

Reads length bytes into a string and returns it.

+

string readLine()
+

+

Reads until a new line character, e.g. '\n', or end-of-file and returns the string. The new line character is also returned in the string.

+

int64 readInt(uint bytes)
+

+

Reads bytes as a signed integer number.

+

uint64 readUInt(uint bytes)
+

+

Reads bytes as an unsigned integer number.

+

float readFloat()
+

+

Reads 4 bytes as a float number.

+

double readDouble()
+

+

Reads 8 bytes as a double number.

+

int writeString(const string &in str)
+

+

Writes the bytes of the string into the file.

+

Returns the number of bytes written, or a negative value on error.

+

int writeInt(int64 value, uint bytes)
+

+

Writes bytes as a signed integer value.

+

Returns the number of bytes written, or a negative value on error.

+

int writeUInt(uint64 value, uint bytes)
+

+

Writes bytes as an unsigned integer value.

+

Returns the number of bytes written, or a negative value on error.

+

int writeFloat(float value)
+

+

Writes 4 bytes as a float value.

+

Returns the number of bytes written, or a negative value on error.

+

int writeDouble(double value)
+

+

Writes 8 bytes as a double value.

+

Returns the number of bytes written, or a negative value on error.

+

int getPos() const
+

+

Returns the current position in the file, or a negative value on error.

+

int setPos(int pos)
+

+

Sets the current position in the file. Returns the previous position or a negative value on error.

+

int movePos(int delta)
+

+

Moves the position delta bytes relative to the current position. Returns the previous position or a negative value on error.

+

+Properties

+

bool mostSignificantByteFirst
+

+

This property should be set to true if the most significant bit should be read or written first in the methods that reads/writes numbers.

+

It is set to false by default, which is the standard on most platforms.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib_filesystem.html b/docs/manual/doc_script_stdlib_filesystem.html new file mode 100644 index 0000000..6132884 --- /dev/null +++ b/docs/manual/doc_script_stdlib_filesystem.html @@ -0,0 +1,148 @@ + + + + + + + +AngelScript: filesystem + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
filesystem
+
+
+
Note
filesystem is only available in the scripts if the application registers support for it.
+

+Supporting filesystem object

+

+Methods

+

bool changeCurrentPath(const string &in path)

+

This changes the current directory used by the filesystem object. It will return true if the given path is valid.

+

It doesn't change the application' working directory.

+

string getCurrentPath() const

+

Returns the current path used by the filesystem object.

+

array<string> @getDirs()

+

Returns a list with the names of all directories in the current path.

+

array<string> @getFiles()

+

Returns a list with the names of all files in the current path.

+

bool isDir(const string &in path)

+

Returns true if the given path is a directory.

+

bool isLink(const string &in path)

+

Returns true if the given path is a link.

+

int64 getSize(const string &in) const

+

Returns the size of a file.

+

Returns -1 if the file doesn't exist or cannot be accessed.

+

int makeDir(const string &in)

+

Creates a new directory. Returns 0 on success.

+

int removeDir(const string &in)

+

Removes a directory. Will only remove the directory if it is empty. Returns 0 on success.

+

int deleteFile(const string &in)

+

Deletes a file. Returns 0 on success.

+

int copyFile(const string &in, const string &in)

+

Copies a file. Returns 0 on success.

+

int move(const string &in, const string &in)

+

Moves or renames a file or directory. Returns 0 on success.

+

datetime getCreateDateTime(const string &in)

+

Returns the date and time of the file creation in UTC.

+

Raises an exception if the file doesn't exist or cannot be accessed.

+

datetime getModifyDateTime(const string &in)

+

Returns the date and time of the last modification of the file in UTC.

+

Raises an exception if the file doesn't exist or cannot be accessed.

+
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib_string.html b/docs/manual/doc_script_stdlib_string.html new file mode 100644 index 0000000..e7f64d1 --- /dev/null +++ b/docs/manual/doc_script_stdlib_string.html @@ -0,0 +1,205 @@ + + + + + + + +AngelScript: string + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
string
+
+
+
Note
Strings are only available in the scripts if the application registers the support for them. The syntax for using strings may differ for the application you're working with so consult the application's manual for more details.
+
See also
Strings for information on syntax for string literals
+

+Supporting string object and functions

+

The string object supports a number of operators, and has several class methods and supporting global functions to facilitate the manipulation of strings.

+

+Operators

+

= assignment
+

+

The assignment operator copies the content of the right hand string into the left hand string.

+

Assignment of primitive types is allowed, which will do a default transformation of the primitive to a string.

+

+, += concatenation
+

+

The concatenation operator appends the content of the right hand string to the end of the left hand string.

+

Concatenation of primitives types is allowed, which will do a default transformation of the primitive to a string.

+

==, != equality
+

+

Compares the content of the two strings.

+

<, >, <=, >= comparison
+

+

Compares the content of the two strings. The comparison is done on the byte values in the strings, which may not correspond to alphabetical comparisons for some languages.

+

[] index operator
+

+

The index operator gives access to a single byte in the string.

+

+Methods

+

uint length() const
+

+

Returns the length of the string.

+

void resize(uint)
+

+

Sets the length of the string.

+

bool isEmpty() const
+

+

Returns true if the string is empty, i.e. the length is zero.

+

string substr(uint start = 0, int count = -1) const
+

+

Returns a string with the content starting at start and the number of bytes given by count. The default arguments will return the whole string as the new string.

+

void insert(uint pos, const string &in other)
+

+

Inserts another string other at position pos in the original string.

+

void erase(uint pos, int count = -1)
+

+

Erases a range of characters from the string, starting at position pos and counting count characters.

+

int findFirst(const string &in str, uint start = 0) const
+

+

Find the first occurrence of the value str in the string, starting at start. If no occurrence is found a negative value will be returned.

+

int findLast(const string &in str, int start = -1) const
+

+

Find the last occurrence of the value str in the string. If start is informed the search will begin at that position, i.e. any potential occurrence after that position will not be searched. If no occurrence is found a negative value will be returned.

+

int findFirstOf(const string &in chars, int start = 0) const
+ int findFirstNotOf(const string &in chars, int start = 0) const
+ int findLastOf(const string &in chars, int start = -1) const
+ int findLastNotOf(const string &in chars, int start = -1) const
+

+

The first variant finds the first character in the string that matches on of the characters in chars, starting at start. If no occurrence is found a negative value will be returned.

+

The second variant finds the first character that doesn't match any of those in chars. The third and last variant are the same except they start the search from the end of the string.

+
Note
These functions work on the individual bytes in the strings. They do not attempt to understand encoded characters, e.g. UTF-8 encoded characters that can take up to 4 bytes.
+

array<string>@ split(const string &in delimiter) const
+

+

Splits the string in smaller strings where the delimiter is found.

+

+Functions

+

string join(const array<string> &in arr, const string &in delimiter)
+

+

Concatenates the strings in the array into a large string, separated by the delimiter.

+

int64 parseInt(const string &in str, uint base = 10, uint &out byteCount = 0)
+ uint64 parseUInt(const string &in str, uint base = 10, uint &out byteCount = 0)
+

+

Parses the string for an integer value. The base can be 10 or 16 to support decimal numbers or hexadecimal numbers. If byteCount is provided it will be set to the number of bytes that were considered as part of the integer value.

+

double parseFloat(const string &in, uint &out byteCount = 0)
+

+

Parses the string for a floating point value. If byteCount is provided it will be set to the number of bytes that were considered as part of the value.

+

string formatInt(int64 val, const string &in options = '', uint width = 0)
+ string formatUInt(uint64 val, const string &in options = '', uint width = 0)
+ string formatFloat(double val, const string &in options = '', uint width = 0, uint precision = 0)
+

+

The format functions takes a string that defines how the number should be formatted. The string is a combination of the following characters:

+
    +
  • l = left justify
  • +
  • 0 = pad with zeroes
  • +
  • + = always include the sign, even if positive
  • +
  • space = add a space in case of positive number
  • +
  • h = hexadecimal integer small letters (not valid for formatFloat)
  • +
  • H = hexadecimal integer capital letters (not valid for formatFloat)
  • +
  • e = exponent character with small e (only valid for formatFloat)
  • +
  • E = exponent character with capital E (only valid for formatFloat)
  • +
+

Examples:

+
+  // Left justify number in string with 10 characters
+  string justified = formatInt(number, 'l', 10);
  // Create hexadecimal representation with capital letters, right justified
+  string hex = formatInt(number, 'H', 10);
  // Right justified, padded with zeroes and two digits after decimal separator
+  string num = formatFloat(number, '0', 8, 2);
+
+
+
+ + + + diff --git a/docs/manual/doc_script_stdlib_system.html b/docs/manual/doc_script_stdlib_system.html new file mode 100644 index 0000000..84cff9e --- /dev/null +++ b/docs/manual/doc_script_stdlib_system.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: System functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
System functions
+
+
+
Note
The system functions are only available in the scripts if the application registers support for it.
+

+Functions

+

void print(const string &in line)

+

Prints a line to the standard output.

+

string getInput()

+

Gets a line from the standard input.

+

array<string> @getCommandLineArgs()

+

Gets the command line arguments as an array.

+

int exec(const string &in cmd)
+ int exec(const string &in cmd, string &out output)

+

Executes a system command.

+

Returns -1 on error or raises an exception. On success returns the exit code from the system commmand.

+

The second alternative allows to capture the stdout into a string, to be further processed.

+
+
+
+ + + + diff --git a/docs/manual/doc_start.html b/docs/manual/doc_start.html new file mode 100644 index 0000000..695fb55 --- /dev/null +++ b/docs/manual/doc_start.html @@ -0,0 +1,117 @@ + + + + + + + +AngelScript: Getting started + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Getting started
+
+ +
+
+ + + + diff --git a/docs/manual/doc_start.js b/docs/manual/doc_start.js new file mode 100644 index 0000000..018898c --- /dev/null +++ b/docs/manual/doc_start.js @@ -0,0 +1,29 @@ +var doc_start = +[ + [ "Overview", "doc_overview.html", null ], + [ "Compile the library", "doc_compile_lib.html", [ + [ "Set compile time options", "doc_compile_lib.html#doc_compile_lib_1", null ], + [ "Linking with the library", "doc_compile_lib.html#doc_compile_lib_2", [ + [ "1. Include library source files in project", "doc_compile_lib.html#doc_compile_lib_2_1", null ], + [ "2. Compile a static library and link into project", "doc_compile_lib.html#doc_compile_lib_2_2", null ], + [ "3. Compile a dynamically loaded library with an import library", "doc_compile_lib.html#doc_compile_lib_2_3", null ], + [ "4. Load the dynamically loaded library manually", "doc_compile_lib.html#doc_compile_lib_2_4", null ] + ] ], + [ "Considerations for specific platforms", "doc_compile_lib.html#doc_compile_platforms", [ + [ "Windows 64bit", "doc_compile_lib.html#doc_compile_win64", null ], + [ "Microsoft Visual C++", "doc_compile_lib.html#doc_compile_msvc_sdk", null ], + [ "GNUC based compilers", "doc_compile_lib.html#doc_compile_gnuc", null ], + [ "Pocket PC with ARM CPU", "doc_compile_lib.html#doc_compile_pocketpc", null ], + [ "Marmalade", "doc_compile_lib.html#doc_compile_marmalade", null ] + ] ], + [ "Size of the library", "doc_compile_lib.html#doc_compile_size", null ] + ] ], + [ "Your first script", "doc_hello_world.html", [ + [ "Helper functions", "doc_hello_world.html#doc_hello_world_1", null ] + ] ], + [ "Good practices", "doc_good_practice.html", [ + [ "Always check return values for registrations", "doc_good_practice.html#doc_checkretval", null ], + [ "Use the message callback to receive detailed error messages", "doc_good_practice.html#doc_usemsgcallbck", null ], + [ "Always verify return value after executing script function", "doc_good_practice.html#doc_checkexceptions", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_strings.html b/docs/manual/doc_strings.html new file mode 100644 index 0000000..3ef6e9d --- /dev/null +++ b/docs/manual/doc_strings.html @@ -0,0 +1,148 @@ + + + + + + + +AngelScript: Custom string type + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Custom string type
+
+
+

Almost all applications have some need to manipulate text strings in one way or another. However most applications have very different needs, and also different ways of representing their string types. For that reason, AngelScript doesn't come with its own built-in string type that the application would be forced to adapt to, instead AngelScript allows the application to register its own string type.

+

This article presents the options for customizing the script language to the application's needs with regards to strings. If you do not want, or do not need to have AngelScript use your own string type, then I suggest you use the standard add-on for std::string registration.

+

+Registering the custom string type

+

To make the script language support strings, the string type must first be registered as type with the engine. The application is free to use any valid type name, not necessarily 'string', though it is probably the most commonly used name. The custom string type can also be either value type or a reference type at the preference of the application developer.

+

Once the string type is registered, the application must also provide a string factory to allow the scripts to use literal string constants. The string factory must implement the asIStringFactory interface, and be registered with the asIScriptEngine::RegisterStringFactory method.

+

The string factory must implement all 3 methods of the asIStringFactory interface. The GetStringConstant method receives the raw string data by the compiler and should return a pointer to the custom string object that represents that string. The ReleaseStringConstant is called when the engine no longer needs the string constant, e.g. when discarding a module. The GetRawStringData is called by the engine when the raw string data is needed, e.g. when saving bytecode or when requesting a copy of a string constant.

+

Although not necessary, the application should preferably implement caching of the string constants, so that if two calls to GetStringConstant with the same raw string data is received the string factory returns the address of the same string instance in both calls. This will reduce the amount of memory needed to store the string constants, especially when scripts use the same string constants in many places. Remember, when using caching, the ReleaseStringConstant must only free the string object when the last call for that same object is done.

+
See also
The standard string add-on
+

+Unicode vs ASCII

+

Is your application using Unicode or plain ASCII for the text? If you use Unicode, then you'll want to encode the scripts in UTF-8, which the AngelScript compiler supports natively. By default AngelScript expects the scripts to have been encoded in UTF-8, but should you prefer ASCII you can turn this off by setting the engine property asEP_SCRIPT_SCANNER to 0 right after creating the engine.

+
// Set engine to use ASCII scanner for script code
+ +

If you do use Unicode, then you'll also want to choose the desired encoding for the string literals, either UTF-8 or UTF-16. By default the string literals in AngelScript are encoded with UTF-8, but if your application is better prepared for UTF-16 then you'll want to change this by setting the engine property asEP_STRING_ENCODING to 1 before compiling your scripts.

+
// Set engine to use UTF-16 encoding for string literals
+ +

Observe that the string factory called by the engine to create new strings gives the size of the string data in bytes even for UTF-16 encoded strings, so you'll need to divide the size by two to get the number of characters in the string.

+

+Multiline string literals

+

There is also a couple of options that affect the script language itself a bit. If you like the convenience of allowing string literals to span multiple lines of code, then you can turn this on by setting the engine property asEP_ALLOW_MULTILINE_STRINGS to true. Without this the compiler will give an error if it encounters a line break before the end of the string.

+
// Set engine to allow string literals with line breaks
+ +

Observe that the line ending encoding of the source file will not be modified by the script compiler, so depending on how the file has been saved, you may get strings using different line endings.

+

The heredoc strings are not affected by this setting, as they are designed to support multiline text sections.

+

+Character literals

+

By default AngelScript doesn't have character literals as C and C++ does. A string literal can be written with double quotes or single quotes and still have the same meaning. This makes it convenient to embed scripts in XML files or C/C++ source files where double quotes would otherwise end the script code.

+

If you want to have single quoted literals mean a single character literal instead of a string, then you can do so by setting the engine property asEP_USE_CHARACTER_LITERALS to true. The compiler will then convert single quoted literals to an integer number representing the first character.

+
// Set engine to use character literals
+ +

Observe that the asEP_SCRIPT_SCANNER property has great importance in this case, as an ASCII character can only represent values between 0 and 255, whereas a Unicode character can represent values between 0 and 1,114,111.

+
+
+
+
@ asEP_STRING_ENCODING
Select string encoding for literals: 0 - UTF8/ASCII, 1 - UTF16. Default: 0 (UTF8)
Definition: angelscript.h:180
+
@ asEP_USE_CHARACTER_LITERALS
Interpret single quoted strings as character literals. Default: false.
Definition: angelscript.h:164
+
@ asEP_ALLOW_MULTILINE_STRINGS
Allow linebreaks in string constants. Default: false.
Definition: angelscript.h:166
+
virtual int SetEngineProperty(asEEngineProp property, asPWORD value)=0
Dynamically change some engine properties.
+
@ asEP_SCRIPT_SCANNER
Select scanning method: 0 - ASCII, 1 - UTF8. Default: 1 (UTF8).
Definition: angelscript.h:176
+ + + + diff --git a/docs/manual/doc_understanding_as.html b/docs/manual/doc_understanding_as.html new file mode 100644 index 0000000..77f4068 --- /dev/null +++ b/docs/manual/doc_understanding_as.html @@ -0,0 +1,121 @@ + + + + + + + +AngelScript: Understanding AngelScript + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Understanding AngelScript
+
+
+

In order to successfully use AngelScript it is important to understand some differences between AngelScript and C++. While the library has been written so that it can be embedded within the application with as little change to the application functions and classes as possible, there are some care that must be taken when passing objects between AngelScript and C++.

+ +
Todo:
Add article on the calling conventions used by AngelScript
+
Todo:
Add article on sandboxing
+
+
+
+ + + + diff --git a/docs/manual/doc_understanding_as.js b/docs/manual/doc_understanding_as.js new file mode 100644 index 0000000..1bd76d3 --- /dev/null +++ b/docs/manual/doc_understanding_as.js @@ -0,0 +1,44 @@ +var doc_understanding_as = +[ + [ "Versions", "doc_versions.html", [ + [ "History", "doc_versions.html#doc_versions_milestones", [ + [ "2003 - Birth and first public release", "doc_versions.html#doc_versions_2003", null ], + [ "2005 - Version 2, sand box, object handles, script classes, and garbage collection", "doc_versions.html#doc_versions_2005", null ], + [ "2006 - Script interface", "doc_versions.html#doc_versions_2006", null ], + [ "2009 - Inheritance, template types, operator overloads, and JIT compilation", "doc_versions.html#doc_versions_2009", null ], + [ "2010 - Function pointers", "doc_versions.html#doc_versions_2010", null ], + [ "2011 - Automatic garbage collection and debugging", "doc_versions.html#doc_versions_2011", null ], + [ "2012 - Namespaces and mixins", "doc_versions.html#doc_versions_2012", null ], + [ "2013 - Improved template types, delegates, weak references, and initialization lists", "doc_versions.html#doc_versions_2013", null ], + [ "2014 - Named arguments and auto", "doc_versions.html#doc_versions_2014", null ], + [ "2015 - Anonymous functions", "doc_versions.html#doc_versions_2015", null ], + [ "2016 - Child funcdefs", "doc_versions.html#doc_versions_2016", null ], + [ "2017 - external keyword and anonymous initialization lists", "doc_versions.html#doc_versions_2017", null ], + [ "2018 - Try-catch statements and explicit constructors", "doc_versions.html#doc_versions_2018", null ], + [ "2019 - Explicit property keyword", "doc_versions.html#doc_versions_2019", null ] + ] ] + ] ], + [ "Script modules", "doc_module.html", [ + [ "Single module versus multiple modules", "doc_module.html#doc_module_single_vs_multi", null ], + [ "Exchanging information between modules", "doc_module.html#doc_module_exchange", null ] + ] ], + [ "Datatypes in AngelScript and C++", "doc_as_vs_cpp_types.html", [ + [ "Primitives", "doc_as_vs_cpp_types.html#doc_as_vs_cpp_types_1", null ], + [ "Strings", "doc_as_vs_cpp_types.html#doc_as_vs_cpp_types_5", null ], + [ "Arrays", "doc_as_vs_cpp_types.html#doc_as_vs_cpp_types_2", null ], + [ "Object handles", "doc_as_vs_cpp_types.html#doc_as_vs_cpp_types_3", null ], + [ "Script classes and interfaces", "doc_as_vs_cpp_types.html#doc_as_vc_cpp_types_5", null ], + [ "Function pointers", "doc_as_vs_cpp_types.html#doc_as_vc_cpp_types_6", null ], + [ "Parameter references", "doc_as_vs_cpp_types.html#doc_as_vs_cpp_types_4", null ] + ] ], + [ "Object handles to the application", "doc_obj_handle.html", [ + [ "Managing the reference counter in functions", "doc_obj_handle.html#doc_obj_handle_3", null ], + [ "Auto handles can make it easier", "doc_obj_handle.html#doc_obj_handle_4", null ] + ] ], + [ "Memory management", "doc_memory.html", [ + [ "Overview of the memory management", "doc_memory.html#doc_memory_1", null ], + [ "Reference counting algorithm", "doc_memory.html#doc_memory_2", null ], + [ "Garbage collector algorithm", "doc_memory.html#doc_memory_3", null ], + [ "Memory heap", "doc_memory.html#doc_memory_4", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/doc_use_script_class.html b/docs/manual/doc_use_script_class.html new file mode 100644 index 0000000..d29510f --- /dev/null +++ b/docs/manual/doc_use_script_class.html @@ -0,0 +1,224 @@ + + + + + + + +AngelScript: Using script classes + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Using script classes
+
+
+

When there are multiple objects controlled by the same script implementation it may be favourable to use script classes, rather than global script functions. Using script classes each instance can have it's own set of variables within the class, contrary to the global functions that needs to rely on global variables to store persistent information.

+

Of course, it would be possible to duplicate the script modules, so that there is one module for each object instance, but that would be impose a rather big overhead for the application. Script classes don't have that overhead, as all instances share the same module, and thus the same bytecode and function ids, etc.

+

+Instantiating the script class

+

Before instantiating the script class you need to know which class to instantiate. Exactly how this is done depends on the application, but here are some suggestions.

+

If the application knows the name of the class, either hardcoded or from some configuration, the class type can easily be obtained by calling the module's GetTypeIdByDecl with the name of the class. The application can also choose to identify the class through some properties of the class, e.g. if the class implements a predefined interface. Then the application can enumerate the class types implemented in the script with GetObjectTypeByIndex and then examine the type through the asITypeInfo interface.

+

A third option, if you're using the script builder add-on, is to use the metadata to identify the class. If you choose this option, use the asIScriptModule to enumerate the declared types and then query the CScriptBuilder for their metadata.

+

Once the object type is known you create the instance by calling the class' factory function, passing it the necessary arguments, e.g. a pointer to the application object which the script class should be bound to. The factory function id is found by querying the asITypeInfo.

+
// Get the object type
+
asIScriptModule *module = engine->GetModule("MyModule");
+
asITypeInfo *type = module->GetTypeInfoByDecl("MyClass");
+
+
// Get the factory function from the object type
+
asIScriptFunction *factory = type->GetFactoryByDecl("MyClass @MyClass()");
+
+
// Prepare the context to call the factory function
+
ctx->Prepare(factory);
+
+
// Execute the call
+
ctx->Execute();
+
+
// Get the object that was created
+ +
+
// If you're going to store the object you must increase the reference,
+
// otherwise it will be destroyed when the context is reused or destroyed.
+
obj->AddRef();
+

The factory function is called as a regular global function and returns a handle to the newly instanciated class.

+

+Calling a method on the script class

+

Calling the methods of the script classes are similar to calling global functions except that you obtain the function id from the asITypeInfo, and you must set the object pointer along with the rest of the function arguments.

+
// Obtain the function object that represents the class method
+
asIScriptFunction *func = type->GetMethodByDecl("void method()");
+
+
// Prepare the context for calling the method
+
ctx->Prepare(func);
+
+
// Set the object pointer
+
ctx->SetObject(obj);
+
+
// Execute the call
+
ctx->Execute();
+

+Receiving script classes

+

In order for the application to register a function that receives a script class it must first know the type. Of course, since the class is declared in the script it isn't possible to know the type before the script is compiled. Instead the application can register an interface with the engine. The function can then be registered to receive a handle to that interface.

+
// Register an interface
+
engine->RegisterInterface("IMyObj");
+
+
// You can also register methods with the interface if you wish to force the script class to implement them
+
engine->RegisterInterfaceMethod("IMyObj", "void RequiredMethod()");
+
+
// Register a function that receives a handle to the interface
+
engine->RegisterGlobalFunction("void ReceiveMyObj(IMyObj @obj)", asFUNCTION(ReceiveMyObj), asCALL_CDECL);
+

The function that receives the interface should be implemented to take a pointer to an asIScriptObject.

+
asIScriptObject *gObj = 0;
+
void ReceiveMyObj(asIScriptObject *obj)
+
{
+
// Do something with the object
+
if( obj )
+
{
+
if( doStore )
+
{
+
// If the object is stored, we shouldn't release the handle
+
gObj = obj;
+
}
+
else
+
{
+
// If the object is not stored, we must release the handle before returning
+
obj->Release();
+
}
+
}
+
}
+

If you don't want to use interfaces like this, then you may want to look into the variable argument type or the generic script handle add-on, which are ways that can be used to receive values and objects of which the type is not known beforehand.

+

+Returning script classes

+

Returning a script class from a registered function involves much of the same as receiving them. In order to register the function either an interface needs to be used, or the generic script handle add-on can be used.

+
// The global variable is initialized elsewhere
+ +
+
asIScriptObject *ReturnMyObj()
+
{
+
if( gObj == 0 )
+
return 0;
+
+
// Increase the refcount to account for the returned handle
+
gObj->AddRef();
+
return gObj;
+
}
+

This function can be registered as following:

+
// Register an interface
+
engine->RegisterInterface("IMyObj");
+
+
// Register a function that returns a handle to the interface
+
engine->RegisterGlobalFunction("IMyObj @ReturnMyObj()", asFUNCTION(ReturnMyObj), asCALL_CDECL);
+
+
+
+
virtual int RegisterInterface(const char *name)=0
Registers a script interface.
+
virtual asIScriptModule * GetModule(const char *module, asEGMFlags flag=asGM_ONLY_IF_EXISTS)=0
Return an interface pointer to the module.
+
virtual void * GetAddressOfReturnValue()=0
Returns the address of the returned value.
+
virtual int Execute()=0
Executes the prepared function.
+
virtual int RegisterInterfaceMethod(const char *intf, const char *declaration)=0
Registers a script interface method.
+
virtual asIScriptFunction * GetMethodByDecl(const char *decl, bool getVirtual=true) const =0
Returns the method by declaration.
+
virtual int SetObject(void *obj)=0
Sets the object for a class method call.
+
virtual int RegisterGlobalFunction(const char *declaration, const asSFuncPtr &funcPointer, asDWORD callConv, void *auxiliary=0)=0
Registers a global function.
+
virtual int AddRef() const =0
Increase reference counter.
+
#define asFUNCTION(f)
Returns an asSFuncPtr representing the function specified by the name.
Definition: angelscript.h:675
+
virtual asIScriptFunction * GetFactoryByDecl(const char *decl) const =0
Returns the factory function by the declaration.
+
The interface for describing types This interface is used to describe the types in the script engine.
Definition: angelscript.h:3527
+
The interface for a script function description.
Definition: angelscript.h:3823
+
The interface to the script modules.
Definition: angelscript.h:2218
+
The interface for an instance of a script object.
Definition: angelscript.h:3413
+
@ asCALL_CDECL
A cdecl function.
Definition: angelscript.h:226
+
virtual int Prepare(asIScriptFunction *func)=0
Prepares the context for execution of the function.
+
virtual int Release() const =0
Decrease reference counter.
+
virtual asITypeInfo * GetTypeInfoByDecl(const char *decl) const =0
Returns a type by declaration.
+ + + + diff --git a/docs/manual/doc_versions.html b/docs/manual/doc_versions.html new file mode 100644 index 0000000..dab2e6f --- /dev/null +++ b/docs/manual/doc_versions.html @@ -0,0 +1,178 @@ + + + + + + + +AngelScript: Versions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Versions
+
+
+

The library's version number is composed of 3 numbers, and sometimes an additional letter. Examples:

+
    +
  • 1.10.1d
  • +
  • 2.8.0a
  • +
  • 2.30.2
  • +
+

The first number is the major version. This is updated whenever there is a major redesign, or a major milestone happens. When this number is changed backwards compatibility is not necessarily maintained by the library.

+

The second number is the application interface version. This is updated whenever there is a change in the interface, e.g. a new method is added or an existing method has its signature modified. Usually the change is incremental so that there is no need to modify the application code unless the new functions are wanted, but a recompilation is still necessary. Sometimes parts of the interface are deprecated, but whenever possible the deprecated parts can be turned back on through a compile time flag.

+

The third number is the minor version. This is updated when the back-end logic in the library is modified, e.g. adding or modifying a script language feature, but no interface change is done. No change in the application code should be required during an upgrade when only the minor version has changed.

+

The additional letter is used when the change is purely bug fixes. In this case the binary application interface should be untouched, so an application that loads the library as a shared object (dll) should be able to upgrade the library without recompiling the application.

+

+History

+

The following is a bit of history for the library that shows how it has evolved since the beginning to the current date. The complete change list can be found on the AngelScript site and in the SDK.

+

+2003 - Birth and first public release

+

The library was first conceived in early 2003, with the first working (internal) version available in March, 2003.

+

At the end of June, 2003 the library's first public release with version 1.0 was made.

+

+2005 - Version 2, sand box, object handles, script classes, and garbage collection

+

In the beginning of 2005 I made the difficult decision to do a major change of direction. Version 1 had several flaws that I couldn't solve without a major redesign. The worst was that the script language wasn't properly sand-boxed, i.e. the script writer had to be careful when writing scripts in order to crash the application or cause worse problems. The script compiler didn't make any attempts to guarantee that a value passed by reference to a function actually stayed alive during the call, and the script was allowed to use and manipulate pointers to access memory directly.

+

Version 2.0 included the concept of object handles, @, and parameter references with direction keywords, i.e. in & out. Object handles are basically smart pointers that the compiler uses to guarantee the proper life time of objects, and the direction keywords for parameter references are used to tell the compiler what the reference will be used for. This in turn allows the compiler to take necessary actions to guarantee the lifetime of the value, e.g. to create a temporary object that will receive the output value, which will only be assigned to the final destination after the called function returns to the caller.

+

With the release of 2.2.0 in mid-2005 the script language got its first version of script classes, at the time called struct. Before this the script language didn't support defining any new types, and scripts could only implement global functions for interacting the built-in types as well as application registered types.

+

With the introduction of classes the need for the incremental garbage collector was also born, as the scripts could now create objects with circular relationships that the simple reference counting memory model couldn't handle by itself.

+

+2006 - Script interface

+

In 2006, with the release of 2.7.0, the concept of interfaces was introduced in the script language. Allowing the application to register a script interface that the script class could implement made for an easier interaction between application and script.

+

+2009 - Inheritance, template types, operator overloads, and JIT compilation

+

Only in 2009, with version 2.15.2, was class inheritance implemented, though only single inheritance, to avoid complicating both the library and script language. Multiple interfaces are still allowed to support polymorphism.

+

Still in 2009, with version 2.16.1, the the library added support for registering templated types, to allow the application to create its own custom container types. The built-in array type would eventually be completely replaced by this and a default array add-on is provided.

+

With version 2.16.3 the script classes were enhanced to allow implementing operator overloads, thus making the language even more flexible and powerful.

+

Version 2.17.0, released in August 2009, introduced an interface to support external JIT compilers. While the AngelScript library doesn't provide its own JIT compiler, a third party JIT compiler was soon created with quick adoption by the community.

+

+2010 - Function pointers

+

Support for function pointers in the script language was added in 2010 with version 2.18.2. Now the application can allow scripts to setup its own callbacks.

+

+2011 - Automatic garbage collection and debugging

+

With the release of version 2.21.0 in 2011 the script engine gained support for automatic garbage collection to simplify this task for the application developer. Of course, the application developers that prefer to have full control can still do it manually by turning off the automatic collection.

+

This release also saw the implementation of a first standard debugger add-on that can be used by applications to add support for stepping through the scripts and inspecting variables for proper run-time debugging.

+

+2012 - Namespaces and mixins

+

Namespaces were added to the script language in 2012 with version 2.22.2.

+

Mixin classes were introduced with version 2.25.0 to provide better support for code re-use even without multiple inheritance.

+

+2013 - Improved template types, delegates, weak references, and initialization lists

+

The template types that were first introduced in 2009 were enhanced with version 2.26.1 to support multiple subtypes in order to give greater flexibility for the application.

+

Support for delegates was added with version 2.26.3.

+

Version 2.27.0 included support for weak references, so that is possible to have greater control over which handles keep objects alive or not.

+

Support for registrable factory functions that takes initialization lists was added in 2.28.0. This allows the application to define the specific pattern that should be used for different types using a simple syntax.

+

+2014 - Named arguments and auto

+

In version 2.29.0 the script language gained support for named arguments, and auto for automatically determining the type of variables based on the initialization expression.

+

+2015 - Anonymous functions

+

Anonymous functions were first implemented in version 2.30.2.

+

+2016 - Child funcdefs

+

Funcdefs can be declared as members of classes as of version 2.31.0.

+

+2017 - external keyword and anonymous initialization lists

+

The external keyword was introduced in version 2.32.0 to explicitly include shared entities from a previously compiled module. This version also introduced anonymouus initialization lists for more compact scripts.

+

+2018 - Try-catch statements and explicit constructors

+

In version 2.33.0 the language was improved to support try-catch statements, and for flagging constructors as explicit for better control over what type conversions can happen implicitly.

+

+2019 - Explicit property keyword

+

With version 2.34.0 virtual property access must be explicitly flagged with the property keyword so that functions starting with get_ or set_ won't automatically be interpreted as virtual properties.

+
+
+
+ + + + diff --git a/docs/manual/doxygen.css b/docs/manual/doxygen.css new file mode 100644 index 0000000..5e35db3 --- /dev/null +++ b/docs/manual/doxygen.css @@ -0,0 +1,1730 @@ +/* The standard CSS for doxygen 1.8.18 */ + +body, table, div, p, dl { + font: 400 14px/22px Roboto,sans-serif; +} + +p.reference, p.definition { + font: 400 14px/22px Roboto,sans-serif; +} + +/* @group Heading Levels */ + +h1.groupheader { + font-size: 150%; +} + +.title { + font: 400 14px/28px Roboto,sans-serif; + font-size: 150%; + font-weight: bold; + margin: 10px 2px; +} + +h2.groupheader { + border-bottom: 1px solid #879ECB; + color: #354C7B; + font-size: 150%; + font-weight: normal; + margin-top: 1.75em; + padding-top: 8px; + padding-bottom: 4px; + width: 100%; +} + +h3.groupheader { + font-size: 100%; +} + +h1, h2, h3, h4, h5, h6 { + -webkit-transition: text-shadow 0.5s linear; + -moz-transition: text-shadow 0.5s linear; + -ms-transition: text-shadow 0.5s linear; + -o-transition: text-shadow 0.5s linear; + transition: text-shadow 0.5s linear; + margin-right: 15px; +} + +h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { + text-shadow: 0 0 15px cyan; +} + +dt { + font-weight: bold; +} + +ul.multicol { + -moz-column-gap: 1em; + -webkit-column-gap: 1em; + column-gap: 1em; + -moz-column-count: 3; + -webkit-column-count: 3; + column-count: 3; +} + +p.startli, p.startdd { + margin-top: 2px; +} + +th p.starttd, p.intertd, p.endtd { + font-size: 100%; + font-weight: 700; +} + +p.starttd { + margin-top: 0px; +} + +p.endli { + margin-bottom: 0px; +} + +p.enddd { + margin-bottom: 4px; +} + +p.endtd { + margin-bottom: 2px; +} + +p.interli { +} + +p.interdd { +} + +p.intertd { +} + +/* @end */ + +caption { + font-weight: bold; +} + +span.legend { + font-size: 70%; + text-align: center; +} + +h3.version { + font-size: 90%; + text-align: center; +} + +div.qindex, div.navtab{ + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; +} + +div.qindex, div.navpath { + width: 100%; + line-height: 140%; +} + +div.navtab { + margin-right: 15px; +} + +/* @group Link Styling */ + +a { + color: #3D578C; + font-weight: normal; + text-decoration: none; +} + +.contents a:visited { + color: #4665A2; +} + +a:hover { + text-decoration: underline; +} + +a.qindex { + font-weight: bold; +} + +a.qindexHL { + font-weight: bold; + background-color: #9CAFD4; + color: #FFFFFF; + border: 1px double #869DCA; +} + +.contents a.qindexHL:visited { + color: #FFFFFF; +} + +a.el { + font-weight: bold; +} + +a.elRef { +} + +a.code, a.code:visited, a.line, a.line:visited { + color: #4665A2; +} + +a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited { + color: #4665A2; +} + +/* @end */ + +dl.el { + margin-left: -1cm; +} + +ul { + overflow: hidden; /*Fixed: list item bullets overlap floating elements*/ +} + +#side-nav ul { + overflow: visible; /* reset ul rule for scroll bar in GENERATE_TREEVIEW window */ +} + +#main-nav ul { + overflow: visible; /* reset ul rule for the navigation bar drop down lists */ +} + +.fragment { + text-align: left; + direction: ltr; + overflow-x: auto; /*Fixed: fragment lines overlap floating elements*/ + overflow-y: hidden; +} + +pre.fragment { + border: 1px solid #C4CFE5; + background-color: #FBFCFD; + padding: 4px 6px; + margin: 4px 8px 4px 2px; + overflow: auto; + word-wrap: break-word; + font-size: 9pt; + line-height: 125%; + font-family: monospace, fixed; + font-size: 105%; +} + +div.fragment { + padding: 0 0 1px 0; /*Fixed: last line underline overlap border*/ + margin: 4px 8px 4px 2px; + background-color: #FBFCFD; + border: 1px solid #C4CFE5; +} + +div.line { + font-family: monospace, fixed; + font-size: 13px; + min-height: 13px; + line-height: 1.0; + text-wrap: unrestricted; + white-space: -moz-pre-wrap; /* Moz */ + white-space: -pre-wrap; /* Opera 4-6 */ + white-space: -o-pre-wrap; /* Opera 7 */ + white-space: pre-wrap; /* CSS3 */ + word-wrap: break-word; /* IE 5.5+ */ + text-indent: -53px; + padding-left: 53px; + padding-bottom: 0px; + margin: 0px; + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +div.line:after { + content:"\000A"; + white-space: pre; +} + +div.line.glow { + background-color: cyan; + box-shadow: 0 0 10px cyan; +} + + +span.lineno { + padding-right: 4px; + text-align: right; + border-right: 2px solid #0F0; + background-color: #E8E8E8; + white-space: pre; +} +span.lineno a { + background-color: #D8D8D8; +} + +span.lineno a:hover { + background-color: #C8C8C8; +} + +.lineno { + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +div.ah, span.ah { + background-color: black; + font-weight: bold; + color: #FFFFFF; + margin-bottom: 3px; + margin-top: 3px; + padding: 0.2em; + border: solid thin #333; + border-radius: 0.5em; + -webkit-border-radius: .5em; + -moz-border-radius: .5em; + box-shadow: 2px 2px 3px #999; + -webkit-box-shadow: 2px 2px 3px #999; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444)); + background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000 110%); +} + +div.classindex ul { + list-style: none; + padding-left: 0; +} + +div.classindex span.ai { + display: inline-block; +} + +div.groupHeader { + margin-left: 16px; + margin-top: 12px; + font-weight: bold; +} + +div.groupText { + margin-left: 16px; + font-style: italic; +} + +body { + background-color: white; + color: black; + margin: 0; +} + +div.contents { + margin-top: 10px; + margin-left: 12px; + margin-right: 8px; +} + +td.indexkey { + background-color: #EBEFF6; + font-weight: bold; + border: 1px solid #C4CFE5; + margin: 2px 0px 2px 0; + padding: 2px 10px; + white-space: nowrap; + vertical-align: top; +} + +td.indexvalue { + background-color: #EBEFF6; + border: 1px solid #C4CFE5; + padding: 2px 10px; + margin: 2px 0px; +} + +tr.memlist { + background-color: #EEF1F7; +} + +p.formulaDsp { + text-align: center; +} + +img.formulaDsp { + +} + +img.formulaInl, img.inline { + vertical-align: middle; +} + +div.center { + text-align: center; + margin-top: 0px; + margin-bottom: 0px; + padding: 0px; +} + +div.center img { + border: 0px; +} + +address.footer { + text-align: right; + padding-right: 12px; +} + +img.footer { + border: 0px; + vertical-align: middle; +} + +/* @group Code Colorization */ + +span.keyword { + color: #008000 +} + +span.keywordtype { + color: #604020 +} + +span.keywordflow { + color: #e08000 +} + +span.comment { + color: #800000 +} + +span.preprocessor { + color: #806020 +} + +span.stringliteral { + color: #002080 +} + +span.charliteral { + color: #008080 +} + +span.vhdldigit { + color: #ff00ff +} + +span.vhdlchar { + color: #000000 +} + +span.vhdlkeyword { + color: #700070 +} + +span.vhdllogic { + color: #ff0000 +} + +blockquote { + background-color: #F7F8FB; + border-left: 2px solid #9CAFD4; + margin: 0 24px 0 4px; + padding: 0 12px 0 16px; +} + +blockquote.DocNodeRTL { + border-left: 0; + border-right: 2px solid #9CAFD4; + margin: 0 4px 0 24px; + padding: 0 16px 0 12px; +} + +/* @end */ + +/* +.search { + color: #003399; + font-weight: bold; +} + +form.search { + margin-bottom: 0px; + margin-top: 0px; +} + +input.search { + font-size: 75%; + color: #000080; + font-weight: normal; + background-color: #e8eef2; +} +*/ + +td.tiny { + font-size: 75%; +} + +.dirtab { + padding: 4px; + border-collapse: collapse; + border: 1px solid #A3B4D7; +} + +th.dirtab { + background: #EBEFF6; + font-weight: bold; +} + +hr { + height: 0px; + border: none; + border-top: 1px solid #4A6AAA; +} + +hr.footer { + height: 1px; +} + +/* @group Member Descriptions */ + +table.memberdecls { + border-spacing: 0px; + padding: 0px; +} + +.memberdecls td, .fieldtable tr { + -webkit-transition-property: background-color, box-shadow; + -webkit-transition-duration: 0.5s; + -moz-transition-property: background-color, box-shadow; + -moz-transition-duration: 0.5s; + -ms-transition-property: background-color, box-shadow; + -ms-transition-duration: 0.5s; + -o-transition-property: background-color, box-shadow; + -o-transition-duration: 0.5s; + transition-property: background-color, box-shadow; + transition-duration: 0.5s; +} + +.memberdecls td.glow, .fieldtable tr.glow { + background-color: cyan; + box-shadow: 0 0 15px cyan; +} + +.mdescLeft, .mdescRight, +.memItemLeft, .memItemRight, +.memTemplItemLeft, .memTemplItemRight, .memTemplParams { + background-color: #F9FAFC; + border: none; + margin: 4px; + padding: 1px 0 0 8px; +} + +.mdescLeft, .mdescRight { + padding: 0px 8px 4px 8px; + color: #555; +} + +.memSeparator { + border-bottom: 1px solid #DEE4F0; + line-height: 1px; + margin: 0px; + padding: 0px; +} + +.memItemLeft, .memTemplItemLeft { + white-space: nowrap; +} + +.memItemRight, .memTemplItemRight { + width: 100%; +} + +.memTemplParams { + color: #4665A2; + white-space: nowrap; + font-size: 80%; +} + +/* @end */ + +/* @group Member Details */ + +/* Styles for detailed member documentation */ + +.memtitle { + padding: 8px; + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + border-top-right-radius: 4px; + border-top-left-radius: 4px; + margin-bottom: -1px; + background-image: url('nav_f.png'); + background-repeat: repeat-x; + background-color: #E2E8F2; + line-height: 1.25; + font-weight: 300; + float:left; +} + +.permalink +{ + font-size: 65%; + display: inline-block; + vertical-align: middle; +} + +.memtemplate { + font-size: 80%; + color: #4665A2; + font-weight: normal; + margin-left: 9px; +} + +.memnav { + background-color: #EBEFF6; + border: 1px solid #A3B4D7; + text-align: center; + margin: 2px; + margin-right: 15px; + padding: 2px; +} + +.mempage { + width: 100%; +} + +.memitem { + padding: 0; + margin-bottom: 10px; + margin-right: 5px; + -webkit-transition: box-shadow 0.5s linear; + -moz-transition: box-shadow 0.5s linear; + -ms-transition: box-shadow 0.5s linear; + -o-transition: box-shadow 0.5s linear; + transition: box-shadow 0.5s linear; + display: table !important; + width: 100%; +} + +.memitem.glow { + box-shadow: 0 0 15px cyan; +} + +.memname { + font-weight: 400; + margin-left: 6px; +} + +.memname td { + vertical-align: bottom; +} + +.memproto, dl.reflist dt { + border-top: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 0px 6px 0px; + color: #253555; + font-weight: bold; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + background-color: #DFE5F1; + /* opera specific markup */ + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + border-top-right-radius: 4px; + /* firefox specific markup */ + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + -moz-border-radius-topright: 4px; + /* webkit specific markup */ + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + -webkit-border-top-right-radius: 4px; + +} + +.overload { + font-family: "courier new",courier,monospace; + font-size: 65%; +} + +.memdoc, dl.reflist dd { + border-bottom: 1px solid #A8B8D9; + border-left: 1px solid #A8B8D9; + border-right: 1px solid #A8B8D9; + padding: 6px 10px 2px 10px; + background-color: #FBFCFD; + border-top-width: 0; + background-image:url('nav_g.png'); + background-repeat:repeat-x; + background-color: #FFFFFF; + /* opera specific markup */ + border-bottom-left-radius: 4px; + border-bottom-right-radius: 4px; + box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); + /* firefox specific markup */ + -moz-border-radius-bottomleft: 4px; + -moz-border-radius-bottomright: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px; + /* webkit specific markup */ + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +dl.reflist dt { + padding: 5px; +} + +dl.reflist dd { + margin: 0px 0px 10px 0px; + padding: 5px; +} + +.paramkey { + text-align: right; +} + +.paramtype { + white-space: nowrap; +} + +.paramname { + color: #602020; + white-space: nowrap; +} +.paramname em { + font-style: normal; +} +.paramname code { + line-height: 14px; +} + +.params, .retval, .exception, .tparams { + margin-left: 0px; + padding-left: 0px; +} + +.params .paramname, .retval .paramname, .tparams .paramname, .exception .paramname { + font-weight: bold; + vertical-align: top; +} + +.params .paramtype, .tparams .paramtype { + font-style: italic; + vertical-align: top; +} + +.params .paramdir, .tparams .paramdir { + font-family: "courier new",courier,monospace; + vertical-align: top; +} + +table.mlabels { + border-spacing: 0px; +} + +td.mlabels-left { + width: 100%; + padding: 0px; +} + +td.mlabels-right { + vertical-align: bottom; + padding: 0px; + white-space: nowrap; +} + +span.mlabels { + margin-left: 8px; +} + +span.mlabel { + background-color: #728DC1; + border-top:1px solid #5373B4; + border-left:1px solid #5373B4; + border-right:1px solid #C4CFE5; + border-bottom:1px solid #C4CFE5; + text-shadow: none; + color: white; + margin-right: 4px; + padding: 2px 3px; + border-radius: 3px; + font-size: 7pt; + white-space: nowrap; + vertical-align: middle; +} + + + +/* @end */ + +/* these are for tree view inside a (index) page */ + +div.directory { + margin: 10px 0px; + border-top: 1px solid #9CAFD4; + border-bottom: 1px solid #9CAFD4; + width: 100%; +} + +.directory table { + border-collapse:collapse; +} + +.directory td { + margin: 0px; + padding: 0px; + vertical-align: top; +} + +.directory td.entry { + white-space: nowrap; + padding-right: 6px; + padding-top: 3px; +} + +.directory td.entry a { + outline:none; +} + +.directory td.entry a img { + border: none; +} + +.directory td.desc { + width: 100%; + padding-left: 6px; + padding-right: 6px; + padding-top: 3px; + border-left: 1px solid rgba(0,0,0,0.05); +} + +.directory tr.even { + padding-left: 6px; + background-color: #F7F8FB; +} + +.directory img { + vertical-align: -30%; +} + +.directory .levels { + white-space: nowrap; + width: 100%; + text-align: right; + font-size: 9pt; +} + +.directory .levels span { + cursor: pointer; + padding-left: 2px; + padding-right: 2px; + color: #3D578C; +} + +.arrow { + color: #9CAFD4; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + cursor: pointer; + font-size: 80%; + display: inline-block; + width: 16px; + height: 22px; +} + +.icon { + font-family: Arial, Helvetica; + font-weight: bold; + font-size: 12px; + height: 14px; + width: 16px; + display: inline-block; + background-color: #728DC1; + color: white; + text-align: center; + border-radius: 4px; + margin-left: 2px; + margin-right: 2px; +} + +.icona { + width: 24px; + height: 22px; + display: inline-block; +} + +.iconfopen { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderopen.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.iconfclosed { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('folderclosed.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +.icondoc { + width: 24px; + height: 18px; + margin-bottom: 4px; + background-image:url('doc.png'); + background-position: 0px -4px; + background-repeat: repeat-y; + vertical-align:top; + display: inline-block; +} + +table.directory { + font: 400 14px Roboto,sans-serif; +} + +/* @end */ + +div.dynheader { + margin-top: 8px; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +address { + font-style: normal; + color: #2A3D61; +} + +table.doxtable caption { + caption-side: top; +} + +table.doxtable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.doxtable td, table.doxtable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.doxtable th { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +table.fieldtable { + /*width: 100%;*/ + margin-bottom: 10px; + border: 1px solid #A8B8D9; + border-spacing: 0px; + -moz-border-radius: 4px; + -webkit-border-radius: 4px; + border-radius: 4px; + -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px; + -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); + box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15); +} + +.fieldtable td, .fieldtable th { + padding: 3px 7px 2px; +} + +.fieldtable td.fieldtype, .fieldtable td.fieldname { + white-space: nowrap; + border-right: 1px solid #A8B8D9; + border-bottom: 1px solid #A8B8D9; + vertical-align: top; +} + +.fieldtable td.fieldname { + padding-top: 3px; +} + +.fieldtable td.fielddoc { + border-bottom: 1px solid #A8B8D9; + /*width: 100%;*/ +} + +.fieldtable td.fielddoc p:first-child { + margin-top: 0px; +} + +.fieldtable td.fielddoc p:last-child { + margin-bottom: 2px; +} + +.fieldtable tr:last-child td { + border-bottom: none; +} + +.fieldtable th { + background-image:url('nav_f.png'); + background-repeat:repeat-x; + background-color: #E2E8F2; + font-size: 90%; + color: #253555; + padding-bottom: 4px; + padding-top: 5px; + text-align:left; + font-weight: 400; + -moz-border-radius-topleft: 4px; + -moz-border-radius-topright: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + border-top-left-radius: 4px; + border-top-right-radius: 4px; + border-bottom: 1px solid #A8B8D9; +} + + +.tabsearch { + top: 0px; + left: 10px; + height: 36px; + background-image: url('tab_b.png'); + z-index: 101; + overflow: hidden; + font-size: 13px; +} + +.navpath ul +{ + font-size: 11px; + background-image:url('tab_b.png'); + background-repeat:repeat-x; + background-position: 0 -5px; + height:30px; + line-height:30px; + color:#8AA0CC; + border:solid 1px #C2CDE4; + overflow:hidden; + margin:0px; + padding:0px; +} + +.navpath li +{ + list-style-type:none; + float:left; + padding-left:10px; + padding-right:15px; + background-image:url('bc_s.png'); + background-repeat:no-repeat; + background-position:right; + color:#364D7C; +} + +.navpath li.navelem a +{ + height:32px; + display:block; + text-decoration: none; + outline: none; + color: #283A5D; + font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; + text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9); + text-decoration: none; +} + +.navpath li.navelem a:hover +{ + color:#6884BD; +} + +.navpath li.footer +{ + list-style-type:none; + float:right; + padding-left:10px; + padding-right:15px; + background-image:none; + background-repeat:no-repeat; + background-position:right; + color:#364D7C; + font-size: 8pt; +} + + +div.summary +{ + float: right; + font-size: 8pt; + padding-right: 5px; + width: 50%; + text-align: right; +} + +div.summary a +{ + white-space: nowrap; +} + +table.classindex +{ + margin: 10px; + white-space: nowrap; + margin-left: 3%; + margin-right: 3%; + width: 94%; + border: 0; + border-spacing: 0; + padding: 0; +} + +div.ingroups +{ + font-size: 8pt; + width: 50%; + text-align: left; +} + +div.ingroups a +{ + white-space: nowrap; +} + +div.header +{ + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + margin: 0px; + border-bottom: 1px solid #C4CFE5; +} + +div.headertitle +{ + padding: 5px 5px 5px 10px; +} + +.PageDocRTL-title div.headertitle { + text-align: right; + direction: rtl; +} + +dl { + padding: 0 0 0 0; +} + +/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug, dl.examples */ +dl.section { + margin-left: 0px; + padding-left: 0px; +} + +dl.section.DocNodeRTL { + margin-right: 0px; + padding-right: 0px; +} + +dl.note { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #D0C000; +} + +dl.note.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #D0C000; +} + +dl.warning, dl.attention { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #FF0000; +} + +dl.warning.DocNodeRTL, dl.attention.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #FF0000; +} + +dl.pre, dl.post, dl.invariant { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00D000; +} + +dl.pre.DocNodeRTL, dl.post.DocNodeRTL, dl.invariant.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00D000; +} + +dl.deprecated { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #505050; +} + +dl.deprecated.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #505050; +} + +dl.todo { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #00C0E0; +} + +dl.todo.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #00C0E0; +} + +dl.test { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #3030E0; +} + +dl.test.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #3030E0; +} + +dl.bug { + margin-left: -7px; + padding-left: 3px; + border-left: 4px solid; + border-color: #C08050; +} + +dl.bug.DocNodeRTL { + margin-left: 0; + padding-left: 0; + border-left: 0; + margin-right: -7px; + padding-right: 3px; + border-right: 4px solid; + border-color: #C08050; +} + +dl.section dd { + margin-bottom: 6px; +} + + +#projectlogo +{ + text-align: center; + vertical-align: bottom; + border-collapse: separate; +} + +#projectlogo img +{ + border: 0px none; +} + +#projectalign +{ + vertical-align: middle; +} + +#projectname +{ + font: 300% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 2px 0px; +} + +#projectbrief +{ + font: 120% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#projectnumber +{ + font: 50% Tahoma, Arial,sans-serif; + margin: 0px; + padding: 0px; +} + +#titlearea +{ + padding: 0px; + margin: 0px; + width: 100%; + border-bottom: 1px solid #5373B4; +} + +.image +{ + text-align: center; +} + +.dotgraph +{ + text-align: center; +} + +.mscgraph +{ + text-align: center; +} + +.plantumlgraph +{ + text-align: center; +} + +.diagraph +{ + text-align: center; +} + +.caption +{ + font-weight: bold; +} + +div.zoom +{ + border: 1px solid #90A5CE; +} + +dl.citelist { + margin-bottom:50px; +} + +dl.citelist dt { + color:#334975; + float:left; + font-weight:bold; + margin-right:10px; + padding:5px; +} + +dl.citelist dd { + margin:2px 0; + padding:5px 0; +} + +div.toc { + padding: 14px 25px; + background-color: #F4F6FA; + border: 1px solid #D8DFEE; + border-radius: 7px 7px 7px 7px; + float: right; + height: auto; + margin: 0 8px 10px 10px; + width: 200px; +} + +.PageDocRTL-title div.toc { + float: left !important; + text-align: right; +} + +div.toc li { + background: url("bdwn.png") no-repeat scroll 0 5px transparent; + font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif; + margin-top: 5px; + padding-left: 10px; + padding-top: 2px; +} + +.PageDocRTL-title div.toc li { + background-position-x: right !important; + padding-left: 0 !important; + padding-right: 10px; +} + +div.toc h3 { + font: bold 12px/1.2 Arial,FreeSans,sans-serif; + color: #4665A2; + border-bottom: 0 none; + margin: 0; +} + +div.toc ul { + list-style: none outside none; + border: medium none; + padding: 0px; +} + +div.toc li.level1 { + margin-left: 0px; +} + +div.toc li.level2 { + margin-left: 15px; +} + +div.toc li.level3 { + margin-left: 30px; +} + +div.toc li.level4 { + margin-left: 45px; +} + +.PageDocRTL-title div.toc li.level1 { + margin-left: 0 !important; + margin-right: 0; +} + +.PageDocRTL-title div.toc li.level2 { + margin-left: 0 !important; + margin-right: 15px; +} + +.PageDocRTL-title div.toc li.level3 { + margin-left: 0 !important; + margin-right: 30px; +} + +.PageDocRTL-title div.toc li.level4 { + margin-left: 0 !important; + margin-right: 45px; +} + +.inherit_header { + font-weight: bold; + color: gray; + cursor: pointer; + -webkit-touch-callout: none; + -webkit-user-select: none; + -khtml-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; +} + +.inherit_header td { + padding: 6px 0px 2px 5px; +} + +.inherit { + display: none; +} + +tr.heading h2 { + margin-top: 12px; + margin-bottom: 4px; +} + +/* tooltip related style info */ + +.ttc { + position: absolute; + display: none; +} + +#powerTip { + cursor: default; + white-space: nowrap; + background-color: white; + border: 1px solid gray; + border-radius: 4px 4px 4px 4px; + box-shadow: 1px 1px 7px gray; + display: none; + font-size: smaller; + max-width: 80%; + opacity: 0.9; + padding: 1ex 1em 1em; + position: absolute; + z-index: 2147483647; +} + +#powerTip div.ttdoc { + color: grey; + font-style: italic; +} + +#powerTip div.ttname a { + font-weight: bold; +} + +#powerTip div.ttname { + font-weight: bold; +} + +#powerTip div.ttdeci { + color: #006318; +} + +#powerTip div { + margin: 0px; + padding: 0px; + font: 12px/16px Roboto,sans-serif; +} + +#powerTip:before, #powerTip:after { + content: ""; + position: absolute; + margin: 0px; +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.s:after, #powerTip.s:before, +#powerTip.w:after, #powerTip.w:before, +#powerTip.e:after, #powerTip.e:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.nw:after, #powerTip.nw:before, +#powerTip.sw:after, #powerTip.sw:before { + border: solid transparent; + content: " "; + height: 0; + width: 0; + position: absolute; +} + +#powerTip.n:after, #powerTip.s:after, +#powerTip.w:after, #powerTip.e:after, +#powerTip.nw:after, #powerTip.ne:after, +#powerTip.sw:after, #powerTip.se:after { + border-color: rgba(255, 255, 255, 0); +} + +#powerTip.n:before, #powerTip.s:before, +#powerTip.w:before, #powerTip.e:before, +#powerTip.nw:before, #powerTip.ne:before, +#powerTip.sw:before, #powerTip.se:before { + border-color: rgba(128, 128, 128, 0); +} + +#powerTip.n:after, #powerTip.n:before, +#powerTip.ne:after, #powerTip.ne:before, +#powerTip.nw:after, #powerTip.nw:before { + top: 100%; +} + +#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after { + border-top-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} +#powerTip.n:before { + border-top-color: #808080; + border-width: 11px; + margin: 0px -11px; +} +#powerTip.n:after, #powerTip.n:before { + left: 50%; +} + +#powerTip.nw:after, #powerTip.nw:before { + right: 14px; +} + +#powerTip.ne:after, #powerTip.ne:before { + left: 14px; +} + +#powerTip.s:after, #powerTip.s:before, +#powerTip.se:after, #powerTip.se:before, +#powerTip.sw:after, #powerTip.sw:before { + bottom: 100%; +} + +#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after { + border-bottom-color: #FFFFFF; + border-width: 10px; + margin: 0px -10px; +} + +#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before { + border-bottom-color: #808080; + border-width: 11px; + margin: 0px -11px; +} + +#powerTip.s:after, #powerTip.s:before { + left: 50%; +} + +#powerTip.sw:after, #powerTip.sw:before { + right: 14px; +} + +#powerTip.se:after, #powerTip.se:before { + left: 14px; +} + +#powerTip.e:after, #powerTip.e:before { + left: 100%; +} +#powerTip.e:after { + border-left-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.e:before { + border-left-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +#powerTip.w:after, #powerTip.w:before { + right: 100%; +} +#powerTip.w:after { + border-right-color: #FFFFFF; + border-width: 10px; + top: 50%; + margin-top: -10px; +} +#powerTip.w:before { + border-right-color: #808080; + border-width: 11px; + top: 50%; + margin-top: -11px; +} + +@media print +{ + #top { display: none; } + #side-nav { display: none; } + #nav-path { display: none; } + body { overflow:visible; } + h1, h2, h3, h4, h5, h6 { page-break-after: avoid; } + .summary { display: none; } + .memitem { page-break-inside: avoid; } + #doc-content + { + margin-left:0 !important; + height:auto !important; + width:auto !important; + overflow:inherit; + display:inline; + } +} + +/* @group Markdown */ + +table.markdownTable { + border-collapse:collapse; + margin-top: 4px; + margin-bottom: 4px; +} + +table.markdownTable td, table.markdownTable th { + border: 1px solid #2D4068; + padding: 3px 7px 2px; +} + +table.markdownTable tr { +} + +th.markdownTableHeadLeft, th.markdownTableHeadRight, th.markdownTableHeadCenter, th.markdownTableHeadNone { + background-color: #374F7F; + color: #FFFFFF; + font-size: 110%; + padding-bottom: 4px; + padding-top: 5px; +} + +th.markdownTableHeadLeft, td.markdownTableBodyLeft { + text-align: left +} + +th.markdownTableHeadRight, td.markdownTableBodyRight { + text-align: right +} + +th.markdownTableHeadCenter, td.markdownTableBodyCenter { + text-align: center +} + +.DocNodeRTL { + text-align: right; + direction: rtl; +} + +.DocNodeLTR { + text-align: left; + direction: ltr; +} + +table.DocNodeRTL { + width: auto; + margin-right: 0; + margin-left: auto; +} + +table.DocNodeLTR { + width: auto; + margin-right: auto; + margin-left: 0; +} + +tt, code, kbd, samp +{ + display: inline-block; + direction:ltr; +} +/* @end */ + +u { + text-decoration: underline; +} + diff --git a/docs/manual/doxygen.png b/docs/manual/doxygen.png new file mode 100644 index 0000000..3ff17d8 Binary files /dev/null and b/docs/manual/doxygen.png differ diff --git a/docs/manual/dynsections.js b/docs/manual/dynsections.js new file mode 100644 index 0000000..3174bd7 --- /dev/null +++ b/docs/manual/dynsections.js @@ -0,0 +1,121 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ +function toggleVisibility(linkObj) +{ + var base = $(linkObj).attr('id'); + var summary = $('#'+base+'-summary'); + var content = $('#'+base+'-content'); + var trigger = $('#'+base+'-trigger'); + var src=$(trigger).attr('src'); + if (content.is(':visible')===true) { + content.hide(); + summary.show(); + $(linkObj).addClass('closed').removeClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-8)+'closed.png'); + } else { + content.show(); + summary.hide(); + $(linkObj).removeClass('closed').addClass('opened'); + $(trigger).attr('src',src.substring(0,src.length-10)+'open.png'); + } + return false; +} + +function updateStripes() +{ + $('table.directory tr'). + removeClass('even').filter(':visible:even').addClass('even'); +} + +function toggleLevel(level) +{ + $('table.directory tr').each(function() { + var l = this.id.split('_').length-1; + var i = $('#img'+this.id.substring(3)); + var a = $('#arr'+this.id.substring(3)); + if (l + + + + + + +AngelScript: File List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
File List
+
+
+
Here is a list of all documented files with brief descriptions:
+ + +
 angelscript.hThe API definition for AngelScript
+
+
+
+ + + + diff --git a/docs/manual/folderclosed.png b/docs/manual/folderclosed.png new file mode 100644 index 0000000..bb8ab35 Binary files /dev/null and b/docs/manual/folderclosed.png differ diff --git a/docs/manual/folderopen.png b/docs/manual/folderopen.png new file mode 100644 index 0000000..d6c7f67 Binary files /dev/null and b/docs/manual/folderopen.png differ diff --git a/docs/manual/functions.html b/docs/manual/functions.html new file mode 100644 index 0000000..4d2b279 --- /dev/null +++ b/docs/manual/functions.html @@ -0,0 +1,130 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- a -

+
+
+ + + + diff --git a/docs/manual/functions_b.html b/docs/manual/functions_b.html new file mode 100644 index 0000000..b20ebf3 --- /dev/null +++ b/docs/manual/functions_b.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- b -

+
+
+ + + + diff --git a/docs/manual/functions_c.html b/docs/manual/functions_c.html new file mode 100644 index 0000000..bd756ba --- /dev/null +++ b/docs/manual/functions_c.html @@ -0,0 +1,150 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- c -

+
+
+ + + + diff --git a/docs/manual/functions_d.html b/docs/manual/functions_d.html new file mode 100644 index 0000000..8eab4bf --- /dev/null +++ b/docs/manual/functions_d.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- d -

+
+
+ + + + diff --git a/docs/manual/functions_e.html b/docs/manual/functions_e.html new file mode 100644 index 0000000..94cb01a --- /dev/null +++ b/docs/manual/functions_e.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- e -

+
+
+ + + + diff --git a/docs/manual/functions_f.html b/docs/manual/functions_f.html new file mode 100644 index 0000000..db4a00d --- /dev/null +++ b/docs/manual/functions_f.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- f -

+
+
+ + + + diff --git a/docs/manual/functions_func.html b/docs/manual/functions_func.html new file mode 100644 index 0000000..ea868e4 --- /dev/null +++ b/docs/manual/functions_func.html @@ -0,0 +1,130 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- a -

+
+
+ + + + diff --git a/docs/manual/functions_func_b.html b/docs/manual/functions_func_b.html new file mode 100644 index 0000000..92a6ead --- /dev/null +++ b/docs/manual/functions_func_b.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- b -

+
+
+ + + + diff --git a/docs/manual/functions_func_c.html b/docs/manual/functions_func_c.html new file mode 100644 index 0000000..50ca6cd --- /dev/null +++ b/docs/manual/functions_func_c.html @@ -0,0 +1,144 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- c -

+
+
+ + + + diff --git a/docs/manual/functions_func_d.html b/docs/manual/functions_func_d.html new file mode 100644 index 0000000..3dcb2c9 --- /dev/null +++ b/docs/manual/functions_func_d.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- d -

+
+
+ + + + diff --git a/docs/manual/functions_func_e.html b/docs/manual/functions_func_e.html new file mode 100644 index 0000000..8c6fd3f --- /dev/null +++ b/docs/manual/functions_func_e.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- e -

+
+
+ + + + diff --git a/docs/manual/functions_func_f.html b/docs/manual/functions_func_f.html new file mode 100644 index 0000000..e15106b --- /dev/null +++ b/docs/manual/functions_func_f.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- f -

+
+
+ + + + diff --git a/docs/manual/functions_func_g.html b/docs/manual/functions_func_g.html new file mode 100644 index 0000000..09965b6 --- /dev/null +++ b/docs/manual/functions_func_g.html @@ -0,0 +1,581 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- g -

+
+
+ + + + diff --git a/docs/manual/functions_func_i.html b/docs/manual/functions_func_i.html new file mode 100644 index 0000000..fc2a824 --- /dev/null +++ b/docs/manual/functions_func_i.html @@ -0,0 +1,146 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- i -

+
+
+ + + + diff --git a/docs/manual/functions_func_l.html b/docs/manual/functions_func_l.html new file mode 100644 index 0000000..c664ed6 --- /dev/null +++ b/docs/manual/functions_func_l.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- l -

+
+
+ + + + diff --git a/docs/manual/functions_func_n.html b/docs/manual/functions_func_n.html new file mode 100644 index 0000000..ef1f258 --- /dev/null +++ b/docs/manual/functions_func_n.html @@ -0,0 +1,113 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- n -

+
+
+ + + + diff --git a/docs/manual/functions_func_p.html b/docs/manual/functions_func_p.html new file mode 100644 index 0000000..d84d778 --- /dev/null +++ b/docs/manual/functions_func_p.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- p -

+
+
+ + + + diff --git a/docs/manual/functions_func_r.html b/docs/manual/functions_func_r.html new file mode 100644 index 0000000..7ec9b13 --- /dev/null +++ b/docs/manual/functions_func_r.html @@ -0,0 +1,193 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- r -

+
+
+ + + + diff --git a/docs/manual/functions_func_s.html b/docs/manual/functions_func_s.html new file mode 100644 index 0000000..294f9df --- /dev/null +++ b/docs/manual/functions_func_s.html @@ -0,0 +1,242 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- s -

+
+
+ + + + diff --git a/docs/manual/functions_func_u.html b/docs/manual/functions_func_u.html new file mode 100644 index 0000000..23f58ea --- /dev/null +++ b/docs/manual/functions_func_u.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- u -

+
+
+ + + + diff --git a/docs/manual/functions_func_w.html b/docs/manual/functions_func_w.html new file mode 100644 index 0000000..2ab998b --- /dev/null +++ b/docs/manual/functions_func_w.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Class Members - Functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- w -

+
+
+ + + + diff --git a/docs/manual/functions_g.html b/docs/manual/functions_g.html new file mode 100644 index 0000000..ce4f81a --- /dev/null +++ b/docs/manual/functions_g.html @@ -0,0 +1,581 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- g -

+
+
+ + + + diff --git a/docs/manual/functions_i.html b/docs/manual/functions_i.html new file mode 100644 index 0000000..4ccca38 --- /dev/null +++ b/docs/manual/functions_i.html @@ -0,0 +1,146 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- i -

+
+
+ + + + diff --git a/docs/manual/functions_l.html b/docs/manual/functions_l.html new file mode 100644 index 0000000..9af9f5d --- /dev/null +++ b/docs/manual/functions_l.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- l -

+
+
+ + + + diff --git a/docs/manual/functions_m.html b/docs/manual/functions_m.html new file mode 100644 index 0000000..a825768 --- /dev/null +++ b/docs/manual/functions_m.html @@ -0,0 +1,113 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- m -

+
+
+ + + + diff --git a/docs/manual/functions_n.html b/docs/manual/functions_n.html new file mode 100644 index 0000000..9e17885 --- /dev/null +++ b/docs/manual/functions_n.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- n -

+
+
+ + + + diff --git a/docs/manual/functions_o.html b/docs/manual/functions_o.html new file mode 100644 index 0000000..7294848 --- /dev/null +++ b/docs/manual/functions_o.html @@ -0,0 +1,116 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- o -

+
+
+ + + + diff --git a/docs/manual/functions_p.html b/docs/manual/functions_p.html new file mode 100644 index 0000000..0fbce0e --- /dev/null +++ b/docs/manual/functions_p.html @@ -0,0 +1,125 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- p -

+
+
+ + + + diff --git a/docs/manual/functions_r.html b/docs/manual/functions_r.html new file mode 100644 index 0000000..7127df6 --- /dev/null +++ b/docs/manual/functions_r.html @@ -0,0 +1,196 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- r -

+
+
+ + + + diff --git a/docs/manual/functions_s.html b/docs/manual/functions_s.html new file mode 100644 index 0000000..29ded91 --- /dev/null +++ b/docs/manual/functions_s.html @@ -0,0 +1,254 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- s -

+
+
+ + + + diff --git a/docs/manual/functions_t.html b/docs/manual/functions_t.html new file mode 100644 index 0000000..d018bcf --- /dev/null +++ b/docs/manual/functions_t.html @@ -0,0 +1,114 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- t -

+
+
+ + + + diff --git a/docs/manual/functions_u.html b/docs/manual/functions_u.html new file mode 100644 index 0000000..8d195ac --- /dev/null +++ b/docs/manual/functions_u.html @@ -0,0 +1,122 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- u -

+
+
+ + + + diff --git a/docs/manual/functions_v.html b/docs/manual/functions_v.html new file mode 100644 index 0000000..6a937de --- /dev/null +++ b/docs/manual/functions_v.html @@ -0,0 +1,113 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- v -

+
+
+ + + + diff --git a/docs/manual/functions_vars.html b/docs/manual/functions_vars.html new file mode 100644 index 0000000..c358ea8 --- /dev/null +++ b/docs/manual/functions_vars.html @@ -0,0 +1,157 @@ + + + + + + + +AngelScript: Class Members - Variables + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/manual/functions_w.html b/docs/manual/functions_w.html new file mode 100644 index 0000000..2035f71 --- /dev/null +++ b/docs/manual/functions_w.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: Class Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented class members with links to the class documentation for each member:
+ +

- w -

+
+
+ + + + diff --git a/docs/manual/globals.html b/docs/manual/globals.html new file mode 100644 index 0000000..9f2bf64 --- /dev/null +++ b/docs/manual/globals.html @@ -0,0 +1,1565 @@ + + + + + + + +AngelScript: File Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
Here is a list of all documented file members with links to the documentation:
+ +

- a -

+
+
+ + + + diff --git a/docs/manual/globals_defs.html b/docs/manual/globals_defs.html new file mode 100644 index 0000000..e5d13fb --- /dev/null +++ b/docs/manual/globals_defs.html @@ -0,0 +1,162 @@ + + + + + + + +AngelScript: File Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/manual/globals_enum.html b/docs/manual/globals_enum.html new file mode 100644 index 0000000..8f34014 --- /dev/null +++ b/docs/manual/globals_enum.html @@ -0,0 +1,156 @@ + + + + + + + +AngelScript: File Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/manual/globals_eval.html b/docs/manual/globals_eval.html new file mode 100644 index 0000000..f4abf99 --- /dev/null +++ b/docs/manual/globals_eval.html @@ -0,0 +1,1334 @@ + + + + + + + +AngelScript: File Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+  + +

- a -

+
+
+ + + + diff --git a/docs/manual/globals_func.html b/docs/manual/globals_func.html new file mode 100644 index 0000000..dfd31ed --- /dev/null +++ b/docs/manual/globals_func.html @@ -0,0 +1,168 @@ + + + + + + + +AngelScript: File Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/manual/globals_type.html b/docs/manual/globals_type.html new file mode 100644 index 0000000..9170da4 --- /dev/null +++ b/docs/manual/globals_type.html @@ -0,0 +1,171 @@ + + + + + + + +AngelScript: File Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/manual/globals_vars.html b/docs/manual/globals_vars.html new file mode 100644 index 0000000..6d26bcd --- /dev/null +++ b/docs/manual/globals_vars.html @@ -0,0 +1,114 @@ + + + + + + + +AngelScript: File Members + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
+ + + + diff --git a/docs/manual/group__api__auxiliary__functions.html b/docs/manual/group__api__auxiliary__functions.html new file mode 100644 index 0000000..a09eaa0 --- /dev/null +++ b/docs/manual/group__api__auxiliary__functions.html @@ -0,0 +1,169 @@ + + + + + + + +AngelScript: Auxiliary functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Auxiliary functions
+
+
+ + + + + +

+Classes

class  asIThreadManager
 The interface for the thread manager. More...
 
+ + + + + + + +

+Functions

AS_API const char * asGetLibraryVersion ()
 Returns the version of the compiled library. More...
 
AS_API const char * asGetLibraryOptions ()
 Returns the options used to compile the library. More...
 
+

Detailed Description

+

Function Documentation

+ +

◆ asGetLibraryOptions()

+ +
+
+ + + + + + + +
AS_API const char* asGetLibraryOptions ()
+
+
Returns
A null terminated string with indicators that identify the options used to compile the script library.
+

This can be used to identify at run-time different ways to configure the engine. For example, if the returned string contain the identifier AS_MAX_PORTABILITY then functions and methods must be registered with the asCALL_GENERIC calling convention.

+ +
+
+ +

◆ asGetLibraryVersion()

+ +
+
+ + + + + + + +
AS_API const char* asGetLibraryVersion ()
+
+
Returns
A null terminated string with the library version.
+

The returned string can be used for presenting the library version in a log file, or in the GUI.

+ +
+
+
+
+ + + + diff --git a/docs/manual/group__api__auxiliary__functions.js b/docs/manual/group__api__auxiliary__functions.js new file mode 100644 index 0000000..86376c9 --- /dev/null +++ b/docs/manual/group__api__auxiliary__functions.js @@ -0,0 +1,6 @@ +var group__api__auxiliary__functions = +[ + [ "asIThreadManager", "classas_i_thread_manager.html", null ], + [ "asGetLibraryOptions", "group__api__auxiliary__functions.html#gaba86cba765a7148e2a306b4305ba48f9", null ], + [ "asGetLibraryVersion", "group__api__auxiliary__functions.html#ga79cbcfe1a47e436da6f2f28ff0314f75", null ] +]; \ No newline at end of file diff --git a/docs/manual/group__api__auxiliary__interfaces.html b/docs/manual/group__api__auxiliary__interfaces.html new file mode 100644 index 0000000..d97c85e --- /dev/null +++ b/docs/manual/group__api__auxiliary__interfaces.html @@ -0,0 +1,126 @@ + + + + + + + +AngelScript: Auxiliary interfaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Auxiliary interfaces
+
+
+ + + + + + + + + + + +

+Classes

class  asIBinaryStream
 A binary stream interface. More...
 
class  asILockableSharedBool
 A lockable shared boolean. More...
 
class  asIJITCompiler
 The interface that AS use to interact with the JIT compiler. More...
 
+

Detailed Description

+
+
+ + + + diff --git a/docs/manual/group__api__auxiliary__interfaces.js b/docs/manual/group__api__auxiliary__interfaces.js new file mode 100644 index 0000000..b5df97c --- /dev/null +++ b/docs/manual/group__api__auxiliary__interfaces.js @@ -0,0 +1,19 @@ +var group__api__auxiliary__interfaces = +[ + [ "asIBinaryStream", "classas_i_binary_stream.html", [ + [ "Read", "classas_i_binary_stream.html#a8bbd68cea1f96b42c723f9732ac19140", null ], + [ "Write", "classas_i_binary_stream.html#a57724f9cd63a625a843bf97e7704d9a7", null ] + ] ], + [ "asILockableSharedBool", "classas_i_lockable_shared_bool.html", [ + [ "AddRef", "classas_i_lockable_shared_bool.html#a1183742552ce6b952cc3742bd456d787", null ], + [ "Get", "classas_i_lockable_shared_bool.html#abab39fc60f00ae8941423258ffc2c3c6", null ], + [ "Lock", "classas_i_lockable_shared_bool.html#aef12cc309395d682aa138da5eea9d82b", null ], + [ "Release", "classas_i_lockable_shared_bool.html#a1dae71f6f1141b5b16520232a9ea5fb2", null ], + [ "Set", "classas_i_lockable_shared_bool.html#aa29488ac2f1c38788d5e79545fdfc8c7", null ], + [ "Unlock", "classas_i_lockable_shared_bool.html#a863984c1b271df84f71fb5ba978ce2b8", null ] + ] ], + [ "asIJITCompiler", "classas_i_j_i_t_compiler.html", [ + [ "CompileFunction", "classas_i_j_i_t_compiler.html#aa6270727e61d8708d651a0f5faada695", null ], + [ "ReleaseJITFunction", "classas_i_j_i_t_compiler.html#afbf9390868269c9224df85d49aabd451", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/group__api__memory__functions.html b/docs/manual/group__api__memory__functions.html new file mode 100644 index 0000000..03703b3 --- /dev/null +++ b/docs/manual/group__api__memory__functions.html @@ -0,0 +1,236 @@ + + + + + + + +AngelScript: Memory functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Memory functions
+
+
+ + + + + + + + + + + + + + +

+Functions

AS_API int asSetGlobalMemoryFunctions (asALLOCFUNC_t allocFunc, asFREEFUNC_t freeFunc)
 Set the memory management functions that AngelScript should use. More...
 
AS_API int asResetGlobalMemoryFunctions ()
 Remove previously registered memory management functions. More...
 
AS_API void * asAllocMem (size_t size)
 Allocate memory using the memory function registered with AngelScript. More...
 
AS_API void asFreeMem (void *mem)
 Deallocates memory using the memory function registered with AngelScript. More...
 
+

Detailed Description

+

Function Documentation

+ +

◆ asAllocMem()

+ +
+
+ + + + + + + + +
AS_API void* asAllocMem (size_t size)
+
+
Parameters
+ + +
[in]sizeThe size of the buffer to allocate
+
+
+
Returns
A pointer to the allocated buffer, or null on error.
+ +
+
+ +

◆ asFreeMem()

+ +
+
+ + + + + + + + +
AS_API void asFreeMem (void * mem)
+
+
Parameters
+ + +
[in]memA pointer to the buffer to deallocate
+
+
+ +
+
+ +

◆ asResetGlobalMemoryFunctions()

+ +
+
+ + + + + + + +
AS_API int asResetGlobalMemoryFunctions ()
+
+
Returns
A negative value on error.
+

Call this method to restore the default memory management functions.

+ +
+
+ +

◆ asSetGlobalMemoryFunctions()

+ +
+
+ + + + + + + + + + + + + + + + + + +
AS_API int asSetGlobalMemoryFunctions (asALLOCFUNC_t allocFunc,
asFREEFUNC_t freeFunc 
)
+
+
Parameters
+ + + +
[in]allocFuncThe function that will be used to allocate memory.
[in]freeFuncThe function that will be used to free the memory.
+
+
+
Returns
A negative value on error.
+

Call this method to register the global memory allocation and deallocation functions that AngelScript should use for memory management. This function should be called before asCreateScriptEngine.

+

If not called, AngelScript will use the malloc and free functions from the standard C library.

+ +
+
+
+
+ + + + diff --git a/docs/manual/group__api__memory__functions.js b/docs/manual/group__api__memory__functions.js new file mode 100644 index 0000000..2a77964 --- /dev/null +++ b/docs/manual/group__api__memory__functions.js @@ -0,0 +1,7 @@ +var group__api__memory__functions = +[ + [ "asAllocMem", "group__api__memory__functions.html#ga54a201f99d19e648526abf30ae31e466", null ], + [ "asFreeMem", "group__api__memory__functions.html#ga9da61275bbfd5f7bd55ed411d05fe103", null ], + [ "asResetGlobalMemoryFunctions", "group__api__memory__functions.html#ga9267c4ad35aceaf7cc0961cd42147ee7", null ], + [ "asSetGlobalMemoryFunctions", "group__api__memory__functions.html#ga527ab125defc58aa40cc151a25582a31", null ] +]; \ No newline at end of file diff --git a/docs/manual/group__api__multithread__functions.html b/docs/manual/group__api__multithread__functions.html new file mode 100644 index 0000000..816b7c8 --- /dev/null +++ b/docs/manual/group__api__multithread__functions.html @@ -0,0 +1,391 @@ + + + + + + + +AngelScript: Multi-thread support functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Multi-thread support functions
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+Functions

AS_API int asPrepareMultithread (asIThreadManager *externalMgr=0)
 Sets up the internally shared resources for multithreading. More...
 
AS_API void asUnprepareMultithread ()
 Frees resources prepared for multithreading. More...
 
AS_API asIThreadManagerasGetThreadManager ()
 Get the thread manager used by the application. More...
 
AS_API void asAcquireExclusiveLock ()
 Acquire an exclusive lock. More...
 
AS_API void asReleaseExclusiveLock ()
 Release an exclusive lock. More...
 
AS_API void asAcquireSharedLock ()
 Acquire a shared lock. More...
 
AS_API void asReleaseSharedLock ()
 Release a shared lock. More...
 
AS_API int asAtomicInc (int &value)
 Increments the value by one and returns the result as a single atomic instruction. More...
 
AS_API int asAtomicDec (int &value)
 Decrements the value by one and returns the result as a single atomic instruction. More...
 
AS_API int asThreadCleanup ()
 Cleans up memory allocated for the current thread. More...
 
AS_API asILockableSharedBoolasCreateLockableSharedBool ()
 Create a lockable shared boolean. More...
 
+

Detailed Description

+

Function Documentation

+ +

◆ asAcquireExclusiveLock()

+ +
+
+ + + + + + + +
AS_API void asAcquireExclusiveLock ()
+
+

This function will block the calling thread until there are no other threads that hold shared or exclusive locks.

+ +
+
+ +

◆ asAcquireSharedLock()

+ +
+
+ + + + + + + +
AS_API void asAcquireSharedLock ()
+
+

This function will block the calling thread until there are no other threads that hold exclusive locks. Other threads may hold shared locks.

+ +
+
+ +

◆ asAtomicDec()

+ +
+
+ + + + + + + + +
AS_API int asAtomicDec (int & value)
+
+
Parameters
+ + +
[in]valueA reference to the value that should be decremented
+
+
+
Returns
The decremented value
+

This function is especially useful for implementing thread safe reference counters.

+ +
+
+ +

◆ asAtomicInc()

+ +
+
+ + + + + + + + +
AS_API int asAtomicInc (int & value)
+
+
Parameters
+ + +
[in]valueA reference to the value that should be incremented
+
+
+
Returns
The incremented value
+

This function is especially useful for implementing thread safe reference counters.

+ +
+
+ +

◆ asCreateLockableSharedBool()

+ +
+
+ + + + + + + +
AS_API asILockableSharedBool* asCreateLockableSharedBool ()
+
+
Returns
A new lockable shared boolean.
+

The lockable shared boolean will be created with an initial reference count of 1, and the boolean value false.

+

The object can be used for weak reference flags.

+ +
+
+ +

◆ asGetThreadManager()

+ +
+
+ + + + + + + +
AS_API asIThreadManager* asGetThreadManager ()
+
+
Returns
The thread manager prepared with asPrepareMultithread()
+ +
+
+ +

◆ asPrepareMultithread()

+ +
+
+ + + + + + + + +
AS_API int asPrepareMultithread (asIThreadManagerexternalMgr = 0)
+
+
Parameters
+ + +
[in]externalMgrPre-existent thread manager (optional)
+
+
+
Returns
A negative value on error
+
Return values
+ + +
asINVALID_ARGexternalMgr informed even though local manager already exists
+
+
+

Call this function from the main thread to set up shared resources for multithreading if engines are to be created in multiple threads.

+

If multiple modules (dlls) are used it may be necessary to call this with the thread manager retrieved from asGetThreadManager() in the main module in order for all modules to share the same thread manager.

+
See also
Multithreading
+ +
+
+ +

◆ asReleaseExclusiveLock()

+ +
+
+ + + + + + + +
AS_API void asReleaseExclusiveLock ()
+
+

Releases the previously acquired exclusive lock.

+ +
+
+ +

◆ asReleaseSharedLock()

+ +
+
+ + + + + + + +
AS_API void asReleaseSharedLock ()
+
+

Releases the previously acquired shared lock.

+ +
+
+ +

◆ asThreadCleanup()

+ +
+
+ + + + + + + +
AS_API int asThreadCleanup ()
+
+
Returns
A negative value on error.
+
Return values
+ + +
asCONTEXT_ACTIVEA context is still active.
+
+
+

Call this function before terminating a thread that has accessed the engine to clean up memory allocated for that thread.

+

It's not necessary to call this if only a single thread accesses the engine.

+ +
+
+ +

◆ asUnprepareMultithread()

+ +
+
+ + + + + + + +
AS_API void asUnprepareMultithread ()
+
+

If asPrepareMultithread() has been called, then this function should be called after the last engine has been released to free the resources prepared for multithreading.

+ +
+
+
+
+ + + + diff --git a/docs/manual/group__api__multithread__functions.js b/docs/manual/group__api__multithread__functions.js new file mode 100644 index 0000000..288c634 --- /dev/null +++ b/docs/manual/group__api__multithread__functions.js @@ -0,0 +1,14 @@ +var group__api__multithread__functions = +[ + [ "asAcquireExclusiveLock", "group__api__multithread__functions.html#ga016dbf716a1c761b3f903b92eb8bb580", null ], + [ "asAcquireSharedLock", "group__api__multithread__functions.html#gaa45545a038adcc8c73348cfe9488f32d", null ], + [ "asAtomicDec", "group__api__multithread__functions.html#ga0565bcb53be170dd85ae27a5b6f2b828", null ], + [ "asAtomicInc", "group__api__multithread__functions.html#gaf0074d581ac2edd06e63e56e4be52c8e", null ], + [ "asCreateLockableSharedBool", "group__api__multithread__functions.html#gaa0ffb789dab56b5617e2f961f9c79fdb", null ], + [ "asGetThreadManager", "group__api__multithread__functions.html#ga948def50c98db90596b706ca4b58041e", null ], + [ "asPrepareMultithread", "group__api__multithread__functions.html#gaa5bea65c3f2a224bb1c677515e3bb0e2", null ], + [ "asReleaseExclusiveLock", "group__api__multithread__functions.html#ga8a0617637eea3d76e33a52758b2cd49f", null ], + [ "asReleaseSharedLock", "group__api__multithread__functions.html#ga44f7327c5601e8dbf74768a2f3cc0dc3", null ], + [ "asThreadCleanup", "group__api__multithread__functions.html#ga51079811680d5217046aad2a2b695dc7", null ], + [ "asUnprepareMultithread", "group__api__multithread__functions.html#ga011355a8978d438cec77b4e1f041cba7", null ] +]; \ No newline at end of file diff --git a/docs/manual/group__api__principal__functions.html b/docs/manual/group__api__principal__functions.html new file mode 100644 index 0000000..36f737a --- /dev/null +++ b/docs/manual/group__api__principal__functions.html @@ -0,0 +1,206 @@ + + + + + + + +AngelScript: Principal functions + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Principal functions
+
+
+ + + + + + + + + + + + +

+Functions

AS_API asIScriptEngineasCreateScriptEngine (asDWORD version=ANGELSCRIPT_VERSION)
 Creates the script engine. More...
 
AS_API asIScriptContextasGetActiveContext ()
 Returns the currently active context. More...
 
template<typename T >
asUINT asGetTypeTraits ()
 Returns the appropriate flags for use with RegisterObjectType. More...
 
+

Detailed Description

+

Function Documentation

+ +

◆ asCreateScriptEngine()

+ +
+
+ + + + + + + + +
AS_API asIScriptEngine* asCreateScriptEngine (asDWORD version = ANGELSCRIPT_VERSION)
+
+
Parameters
+ + +
[in]versionThe library version. Should always be ANGELSCRIPT_VERSION.
+
+
+
Returns
A pointer to the script engine interface, or null on error.
+

Call this function to create a new script engine. When you're done with the script engine, i.e. after you've executed all your scripts, you should call ShutDownAndRelease on the pointer to cleanup any objects that may still be alive and free the engine object.

+

The version argument is there to allow AngelScript to validate that the application has been compiled with the correct interface. This is especially important when linking dynamically against the library. If the version is incorrect a null pointer is returned.

+ +
+
+ +

◆ asGetActiveContext()

+ +
+
+ + + + + + + +
AS_API asIScriptContext* asGetActiveContext ()
+
+
Returns
A pointer to the currently executing context, or null if no context is executing.
+

This function is most useful for registered functions, as it will allow them to obtain a pointer to the context that is calling the function, and through that get the engine, or custom user data.

+

If the script library is compiled with multithread support, this function will return the context that is currently active in the thread that is being executed. It will thus work even if there are multiple threads executing scripts at the same time.

+

This function does not increase the reference count of the context.

+ +
+
+ +

◆ asGetTypeTraits()

+ +
+
+
+template<typename T >
+ + + + + + + +
asUINT asGetTypeTraits ()
+
+
Template Parameters
+ + +
TThe type for which the flags should be determined
+
+
+
Returns
The flags necessary to register this type as a value type
+
Note
This function is only availabe if the compiler supports C++11 feature set. Check existance with #if AS_CAN_USE_CPP11.
+

This template function uses C++11 STL template functions to determine the appropriate flags to use when registering the desired type as a value type with asIScriptEngine::RegisterObjectType.

+

It is capable to determine all the asOBJ_APP_xxx flags, except for asOBJ_APP_CLASS_ALLINTS, asOBJ_APP_CLASS_ALLFLOATS, and asOBJ_APP_CLASS_ALIGN8. These flags must still be informed manually when needed.

+
See also
Value types and native calling conventions
+ +
+
+
+
+ + + + diff --git a/docs/manual/group__api__principal__functions.js b/docs/manual/group__api__principal__functions.js new file mode 100644 index 0000000..5f4d70c --- /dev/null +++ b/docs/manual/group__api__principal__functions.js @@ -0,0 +1,6 @@ +var group__api__principal__functions = +[ + [ "asCreateScriptEngine", "group__api__principal__functions.html#gacb6a62345d9cca6c9b5a3dac67d80d0b", null ], + [ "asGetActiveContext", "group__api__principal__functions.html#gad3a20dc58093b92a5a44c7b6ada34a10", null ], + [ "asGetTypeTraits", "group__api__principal__functions.html#ga863f2a1e60e6c19eea9c6b34690dcc00", null ] +]; \ No newline at end of file diff --git a/docs/manual/group__api__principal__interfaces.html b/docs/manual/group__api__principal__interfaces.html new file mode 100644 index 0000000..f8acc9d --- /dev/null +++ b/docs/manual/group__api__principal__interfaces.html @@ -0,0 +1,126 @@ + + + + + + + +AngelScript: Principal interfaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Principal interfaces
+
+
+ + + + + + + + + + + +

+Classes

class  asIScriptEngine
 The engine interface. More...
 
class  asIScriptModule
 The interface to the script modules. More...
 
class  asIScriptContext
 The interface to the virtual machine. More...
 
+

Detailed Description

+
+
+ + + + diff --git a/docs/manual/group__api__principal__interfaces.js b/docs/manual/group__api__principal__interfaces.js new file mode 100644 index 0000000..184d62c --- /dev/null +++ b/docs/manual/group__api__principal__interfaces.js @@ -0,0 +1,198 @@ +var group__api__principal__interfaces = +[ + [ "asIScriptEngine", "classas_i_script_engine.html", [ + [ "AddRef", "classas_i_script_engine.html#aa95a5d9b5d9e7e6a230fedf056eaf8ce", null ], + [ "AddRefScriptObject", "classas_i_script_engine.html#ade1d309876c876c733d437a53e708c28", null ], + [ "AssignScriptObject", "classas_i_script_engine.html#a9180da5fd475f52916be6b39e522fabb", null ], + [ "BeginConfigGroup", "classas_i_script_engine.html#ac81014e50dd7efc1920adcb3fd2d1e5d", null ], + [ "ClearMessageCallback", "classas_i_script_engine.html#ada64567fc9621e5e98160c7f03efa064", null ], + [ "CreateContext", "classas_i_script_engine.html#a2630e1cd03ffab0fee9b820bf0afe42a", null ], + [ "CreateDelegate", "classas_i_script_engine.html#ab4a4cea1cfeea361b8a44d80f3d928e3", null ], + [ "CreateScriptObject", "classas_i_script_engine.html#a3101479b4340bc16bb9acb8e8d554266", null ], + [ "CreateScriptObjectCopy", "classas_i_script_engine.html#ab2b1543ea6d24b912aebeb77e6764269", null ], + [ "CreateUninitializedScriptObject", "classas_i_script_engine.html#a9de3c5e4465f699ad698740d6037e1a6", null ], + [ "DiscardModule", "classas_i_script_engine.html#afb0ce55e5846eb18afdcf906aeb67cf7", null ], + [ "EndConfigGroup", "classas_i_script_engine.html#a4cc5ed7ea71811655f7910d298bb5a02", null ], + [ "ForwardGCEnumReferences", "classas_i_script_engine.html#abe95ce0e45d914fec478fa112a7bb8dd", null ], + [ "ForwardGCReleaseReferences", "classas_i_script_engine.html#a60cdec608a18f6ebc0aebe29a143183f", null ], + [ "GarbageCollect", "classas_i_script_engine.html#a17511a1de72ecdb836b974768f2ec422", null ], + [ "GCEnumCallback", "classas_i_script_engine.html#a58ceeafd780dea3543e0ede4106199fd", null ], + [ "GetDefaultArrayTypeId", "classas_i_script_engine.html#ae86e5444979b0abd92777be83c53fc80", null ], + [ "GetDefaultNamespace", "classas_i_script_engine.html#a257a25e285faa25e8cf08e455528def7", null ], + [ "GetEngineProperty", "classas_i_script_engine.html#a5531bf5310a0c933aa698725a6828e5f", null ], + [ "GetEnumByIndex", "classas_i_script_engine.html#adedc8b2ad11a84ec12aef4f98e27a4c4", null ], + [ "GetEnumCount", "classas_i_script_engine.html#a4b4307dab64061be43db84ffb97e3782", null ], + [ "GetFuncdefByIndex", "classas_i_script_engine.html#ad4228220347347384c0aa0e0dd8308c6", null ], + [ "GetFuncdefCount", "classas_i_script_engine.html#a48aceb1556f88ce3bec3e0f84abe127f", null ], + [ "GetFunctionById", "classas_i_script_engine.html#aaf67dc0b1f26be437ccbcc0ac5f330c9", null ], + [ "GetGCStatistics", "classas_i_script_engine.html#a166e6cdd0cb35bcfd942824d8e882783", null ], + [ "GetGlobalFunctionByDecl", "classas_i_script_engine.html#a42edd02e95731c795e13706400e8665a", null ], + [ "GetGlobalFunctionByIndex", "classas_i_script_engine.html#aaf2b79cef75adb4099a24e3412e4ea79", null ], + [ "GetGlobalFunctionCount", "classas_i_script_engine.html#a72aa1a3a5ac88a5a1dba4fa3655141d6", null ], + [ "GetGlobalPropertyByIndex", "classas_i_script_engine.html#a93bd686853a48647d2136792e27380fb", null ], + [ "GetGlobalPropertyCount", "classas_i_script_engine.html#aa69f6b37f9c7bdf9b52b9c1692daf048", null ], + [ "GetGlobalPropertyIndexByDecl", "classas_i_script_engine.html#a91a4cc8af51ca439ca82b9b6630439b3", null ], + [ "GetGlobalPropertyIndexByName", "classas_i_script_engine.html#a07e85878869e4d0597c1177d767dc717", null ], + [ "GetJITCompiler", "classas_i_script_engine.html#a2fb6db9085df3c7d487c0d58de76bb83", null ], + [ "GetModule", "classas_i_script_engine.html#a9f7cdc52b59034e6e55eb8a56b427aa4", null ], + [ "GetModuleByIndex", "classas_i_script_engine.html#a31b95df21e6f1990cf84b3b286067675", null ], + [ "GetModuleCount", "classas_i_script_engine.html#a457cf6202cc64ce8ee242dcc97d3422f", null ], + [ "GetObjectInGC", "classas_i_script_engine.html#a39a5f221baa01d43e7471c0e9f5378e4", null ], + [ "GetObjectTypeByIndex", "classas_i_script_engine.html#afac08d4f81e587031c7863574c6783ba", null ], + [ "GetObjectTypeCount", "classas_i_script_engine.html#ac2667fbe30dd00ed14bc14e6ef7fc725", null ], + [ "GetSizeOfPrimitiveType", "classas_i_script_engine.html#a39b7207a6c4c55a5cbf10eab2ccfb8e6", null ], + [ "GetStringFactoryReturnTypeId", "classas_i_script_engine.html#afb3935d85494231e2f02af5816ba9830", null ], + [ "GetTypeDeclaration", "classas_i_script_engine.html#a3ae23fcde6af0d816ff97097cd443281", null ], + [ "GetTypedefByIndex", "classas_i_script_engine.html#a635cd008ea123b510c66fbddcea735f5", null ], + [ "GetTypedefCount", "classas_i_script_engine.html#a0ebbbb86ea0e314cc2695f6276ebe507", null ], + [ "GetTypeIdByDecl", "classas_i_script_engine.html#ad1f6fecb0f53fd7966736b01f65c3dcb", null ], + [ "GetTypeInfoByDecl", "classas_i_script_engine.html#ab00808f9b762c4badf508ed511789d1b", null ], + [ "GetTypeInfoById", "classas_i_script_engine.html#a55cc2d9592651538efcf79eb8106a867", null ], + [ "GetTypeInfoByName", "classas_i_script_engine.html#aea2583b8aa724779b7c37df8b7fa437b", null ], + [ "GetUserData", "classas_i_script_engine.html#a701aa6a7ddf51a22c62281f3dec9a772", null ], + [ "GetWeakRefFlagOfScriptObject", "classas_i_script_engine.html#ab31103bef62096445fe03632de691827", null ], + [ "NotifyGarbageCollectorOfNewObject", "classas_i_script_engine.html#a52a7644b48cbc771e33db5070814f6df", null ], + [ "ParseToken", "classas_i_script_engine.html#a57ecbd86ae9370684877c755e83cef0d", null ], + [ "RefCastObject", "classas_i_script_engine.html#a32c9d9aac77a67eeb046fc67d7473fa2", null ], + [ "RegisterDefaultArrayType", "classas_i_script_engine.html#ac9451feece1297eba8d1649036039e82", null ], + [ "RegisterEnum", "classas_i_script_engine.html#abed6e77f2a532c8a4f528650fa137d37", null ], + [ "RegisterEnumValue", "classas_i_script_engine.html#a4d331153596dd39838f3bed2a861af18", null ], + [ "RegisterFuncdef", "classas_i_script_engine.html#a03c1a2cc23ae4b742c927f3472a1a4f7", null ], + [ "RegisterGlobalFunction", "classas_i_script_engine.html#a2f84b9b51733f22c68b8448b02c2f1c7", null ], + [ "RegisterGlobalProperty", "classas_i_script_engine.html#aacd32f32b2922b8ffaed204812013169", null ], + [ "RegisterInterface", "classas_i_script_engine.html#ae2d89b82561b7f9843f35693c664589f", null ], + [ "RegisterInterfaceMethod", "classas_i_script_engine.html#a43bd2c12c94a55c22be76d209de93f1a", null ], + [ "RegisterObjectBehaviour", "classas_i_script_engine.html#a9f122dd87394f3a83ac766ea19f37317", null ], + [ "RegisterObjectMethod", "classas_i_script_engine.html#ad74043be9cc30f105c62f482ca720574", null ], + [ "RegisterObjectProperty", "classas_i_script_engine.html#a0aa35bf824180fe6aed685b40f0e8c34", null ], + [ "RegisterObjectType", "classas_i_script_engine.html#a29c6c087c8c5b5cdb6271cfd161cc5a6", null ], + [ "RegisterStringFactory", "classas_i_script_engine.html#ac6598c07c36652b0270b4c2d61db1f01", null ], + [ "RegisterTypedef", "classas_i_script_engine.html#addb24466769dc52be96c7e37d5305245", null ], + [ "Release", "classas_i_script_engine.html#aae91a45da75af9234b87e825b5c08b81", null ], + [ "ReleaseScriptObject", "classas_i_script_engine.html#a82873d3769ded547894a7c3d52c220fd", null ], + [ "RemoveConfigGroup", "classas_i_script_engine.html#ab607be7fe727cdcce502d2beedbf4c0a", null ], + [ "RequestContext", "classas_i_script_engine.html#a32391ee83e58083b406ba068ab2ee049", null ], + [ "ReturnContext", "classas_i_script_engine.html#a22e42bf32902cbd6885731a6beeaca20", null ], + [ "SetCircularRefDetectedCallback", "classas_i_script_engine.html#aac3d5b7c9920b4f98405a19e515ceb26", null ], + [ "SetContextCallbacks", "classas_i_script_engine.html#ae5ba9fe99b72c60392cdaeef164f2c65", null ], + [ "SetContextUserDataCleanupCallback", "classas_i_script_engine.html#acaced7eb9ebe013ede23f7593daf58e3", null ], + [ "SetDefaultAccessMask", "classas_i_script_engine.html#a570df3e676f2d9e03e87d97b8cede1c7", null ], + [ "SetDefaultNamespace", "classas_i_script_engine.html#a605f114814f1f64804c04391816d948b", null ], + [ "SetEngineProperty", "classas_i_script_engine.html#a1bce4e5f573a2ca0ff55163e28f761dd", null ], + [ "SetEngineUserDataCleanupCallback", "classas_i_script_engine.html#a8fa4fc9aacb99db6d4be0a5542b85e35", null ], + [ "SetFunctionUserDataCleanupCallback", "classas_i_script_engine.html#ae75ee087fe6608cf0af1c24794ca73c7", null ], + [ "SetJITCompiler", "classas_i_script_engine.html#aee4f910163604203a27db1ffea3b1c9c", null ], + [ "SetMessageCallback", "classas_i_script_engine.html#a74192fe950808eb72a64e3e371f0ea02", null ], + [ "SetModuleUserDataCleanupCallback", "classas_i_script_engine.html#a7523853b9a9bf7dab603fa6a06393d51", null ], + [ "SetScriptObjectUserDataCleanupCallback", "classas_i_script_engine.html#a4654e2cae0690c50e19b177f1ec54592", null ], + [ "SetTranslateAppExceptionCallback", "classas_i_script_engine.html#addce6a202934a4918f7776b2f77c43fd", null ], + [ "SetTypeInfoUserDataCleanupCallback", "classas_i_script_engine.html#afa31e7c28c63a2c876d8e08305cf5d75", null ], + [ "SetUserData", "classas_i_script_engine.html#aabee8d6ef426c434adee85ec6d57f940", null ], + [ "ShutDownAndRelease", "classas_i_script_engine.html#a28c3800620d4aeaca75d084391eb758e", null ], + [ "WriteMessage", "classas_i_script_engine.html#a936ce6566af958bb75ba1c0945d8b03a", null ] + ] ], + [ "asIScriptModule", "classas_i_script_module.html", [ + [ "AddScriptSection", "classas_i_script_module.html#a330835919b565c76c25e9425536f50b7", null ], + [ "BindAllImportedFunctions", "classas_i_script_module.html#a3f0c215576adefd922c2cc95d16b55d8", null ], + [ "BindImportedFunction", "classas_i_script_module.html#ab24a8b95ce887c3f731eb906e3b518e5", null ], + [ "Build", "classas_i_script_module.html#a8acf107194c5f079d7f7507309ebe613", null ], + [ "CompileFunction", "classas_i_script_module.html#a1258d7cfeed965f36ba312beeb49e81c", null ], + [ "CompileGlobalVar", "classas_i_script_module.html#a34850e152dcdcb58c53a2b6929cebf77", null ], + [ "Discard", "classas_i_script_module.html#a0e6a69be59f16c8b51d1e21d3905d95c", null ], + [ "GetAddressOfGlobalVar", "classas_i_script_module.html#a0998d375ca1de02bc72f4544806da58c", null ], + [ "GetDefaultNamespace", "classas_i_script_module.html#aa1aa775a81fc2bbf84ff2b07fd9561e3", null ], + [ "GetEngine", "classas_i_script_module.html#aef861826f4d09fd411aee7792854bfb8", null ], + [ "GetEnumByIndex", "classas_i_script_module.html#a0ec42bef3874f0fc0e6b929068ae927c", null ], + [ "GetEnumCount", "classas_i_script_module.html#a1a241b3dfd47f7ab5bb475c757e38df9", null ], + [ "GetFunctionByDecl", "classas_i_script_module.html#ab4754d55d8667aefbed135b4794d461b", null ], + [ "GetFunctionByIndex", "classas_i_script_module.html#afd4d9951ee006caa8ec1bab3d3d206fc", null ], + [ "GetFunctionByName", "classas_i_script_module.html#a81d727c9677b683942b6087df4ce95ad", null ], + [ "GetFunctionCount", "classas_i_script_module.html#a373d102f109ae0fa20584f243ead4035", null ], + [ "GetGlobalVar", "classas_i_script_module.html#a939e6caf004c6fdae78fe89bb244d962", null ], + [ "GetGlobalVarCount", "classas_i_script_module.html#a87e29773f7e6f2980d75288faaa74d02", null ], + [ "GetGlobalVarDeclaration", "classas_i_script_module.html#aebe27735e0ce4c06bf79b2b4282192cd", null ], + [ "GetGlobalVarIndexByDecl", "classas_i_script_module.html#ac3d5dafe8ca92bf618f438dc79ef2906", null ], + [ "GetGlobalVarIndexByName", "classas_i_script_module.html#a00cff95b43c256cc6b9062e135a473a2", null ], + [ "GetImportedFunctionCount", "classas_i_script_module.html#a12273a6a6dd9bd39ca9675bcd84b0cc7", null ], + [ "GetImportedFunctionDeclaration", "classas_i_script_module.html#a20e46ad7ea467f98bbf35ee052b86868", null ], + [ "GetImportedFunctionIndexByDecl", "classas_i_script_module.html#a6de1053c8317e7134e7e59e4527339f6", null ], + [ "GetImportedFunctionSourceModule", "classas_i_script_module.html#adc01b24a82ad14356f2edc082af4c146", null ], + [ "GetName", "classas_i_script_module.html#a4967db3ed89836ac2f3b529c499d473d", null ], + [ "GetObjectTypeByIndex", "classas_i_script_module.html#a49ebfdd345f18d88e489edebd4888af7", null ], + [ "GetObjectTypeCount", "classas_i_script_module.html#a931d0c00cba2df1b4e368e59bac1a207", null ], + [ "GetTypedefByIndex", "classas_i_script_module.html#a6a31f0767b01cc4203212fd531576de4", null ], + [ "GetTypedefCount", "classas_i_script_module.html#ad30b22539655df3135f29ce28b89c820", null ], + [ "GetTypeIdByDecl", "classas_i_script_module.html#a7fbc2bd888b248d2c2ee2d953b49eefc", null ], + [ "GetTypeInfoByDecl", "classas_i_script_module.html#a3c61bf81a0a88c0017a0e33aecc417ba", null ], + [ "GetTypeInfoByName", "classas_i_script_module.html#ae8460fa05f441072e14f984ccf507396", null ], + [ "GetUserData", "classas_i_script_module.html#af292f99799d8358277298f749efedaaa", null ], + [ "LoadByteCode", "classas_i_script_module.html#a8b4a222e5309c6b367f136b6d2f664ba", null ], + [ "RemoveFunction", "classas_i_script_module.html#a54b6f8e09787ad20880f73bc97a8ef10", null ], + [ "RemoveGlobalVar", "classas_i_script_module.html#aac10878c3d16f18ace4db881f7a1bb11", null ], + [ "ResetGlobalVars", "classas_i_script_module.html#a7b084b6693a05616097d7059e54d983b", null ], + [ "SaveByteCode", "classas_i_script_module.html#ac6cd95dd97cc6abf28ab4d82257f5aeb", null ], + [ "SetAccessMask", "classas_i_script_module.html#a76733de5a86875c4a0f021f7f92a6d12", null ], + [ "SetDefaultNamespace", "classas_i_script_module.html#ab8629af79cee8212d0d244314d36f42a", null ], + [ "SetName", "classas_i_script_module.html#a1a7534bace9eefdc3175a1999f9cbf4a", null ], + [ "SetUserData", "classas_i_script_module.html#a06582e57e7101df4157ee36c81867c13", null ], + [ "UnbindAllImportedFunctions", "classas_i_script_module.html#ab7b4c4b94190779028776fd1057a658f", null ], + [ "UnbindImportedFunction", "classas_i_script_module.html#a4d59b4e833bf139f6b7256d6b6bd40b6", null ] + ] ], + [ "asIScriptContext", "classas_i_script_context.html", [ + [ "Abort", "classas_i_script_context.html#a374befd21b8c14de81ef0ed9d2dea334", null ], + [ "AddRef", "classas_i_script_context.html#a5e24f4cb5773f732a1d46b818d963a1d", null ], + [ "ClearExceptionCallback", "classas_i_script_context.html#acb5cfe5703031fd76672a57d8afae547", null ], + [ "ClearLineCallback", "classas_i_script_context.html#a3771cf314de339fa5d70edfbfcd88370", null ], + [ "Execute", "classas_i_script_context.html#a8e52894432737acac2e1a422e496bf84", null ], + [ "GetAddressOfArg", "classas_i_script_context.html#a0fbab94982862b30cd55996d4a24949c", null ], + [ "GetAddressOfReturnValue", "classas_i_script_context.html#a889bf11123beba669637849c8e9b2b86", null ], + [ "GetAddressOfVar", "classas_i_script_context.html#acc916505d79de321a2ab2b46b1c61fb7", null ], + [ "GetCallstackSize", "classas_i_script_context.html#aab359abc4563a8439338bfd655824bd7", null ], + [ "GetEngine", "classas_i_script_context.html#a07f12016c5435aec5b63449abb6e4d8d", null ], + [ "GetExceptionFunction", "classas_i_script_context.html#a8e59aceec42080d29e08b44460ceb8b3", null ], + [ "GetExceptionLineNumber", "classas_i_script_context.html#a22e3c351fe6b13ba0a62010dfc305080", null ], + [ "GetExceptionString", "classas_i_script_context.html#a46e2411bc84e99f57e7d9fe2374bb479", null ], + [ "GetFunction", "classas_i_script_context.html#a1c101300447f2909e5d188409a7180f6", null ], + [ "GetLineNumber", "classas_i_script_context.html#adf82981def59c6ec5dd9f74f034be2af", null ], + [ "GetReturnAddress", "classas_i_script_context.html#a2438a7fcf46faa2267bdb94057cd1f2e", null ], + [ "GetReturnByte", "classas_i_script_context.html#a4c92259c03f1394310d3ea7d0774b3cb", null ], + [ "GetReturnDouble", "classas_i_script_context.html#a7e1ce03637cd5dd48ea652fdf7913bd7", null ], + [ "GetReturnDWord", "classas_i_script_context.html#a43cd2fb72685aef96e8ddc622c9621bf", null ], + [ "GetReturnFloat", "classas_i_script_context.html#a4ad325995e43fe6a929bcbd8fa592500", null ], + [ "GetReturnObject", "classas_i_script_context.html#a6d5739fac9c90bcd0fea55d01841d43a", null ], + [ "GetReturnQWord", "classas_i_script_context.html#a22bdd3b67dee3b1dbcb3f9f9a1f21fa4", null ], + [ "GetReturnWord", "classas_i_script_context.html#a5a3e054d35a6a361af67448d0a4930f9", null ], + [ "GetState", "classas_i_script_context.html#a17024a9e1648f66711a3182b21676aa7", null ], + [ "GetSystemFunction", "classas_i_script_context.html#a214cc16c4dd889072c1c24c089223a6a", null ], + [ "GetThisPointer", "classas_i_script_context.html#a4f6761a7a0c872dda681d8e180830ff9", null ], + [ "GetThisTypeId", "classas_i_script_context.html#a404681f8950c1ebd9382d30ef1ed3b89", null ], + [ "GetUserData", "classas_i_script_context.html#a0f8503675abfd473915d66a92c6e6df7", null ], + [ "GetVarCount", "classas_i_script_context.html#a3d735c6c7c5a166302cc4ba8ea38e3e8", null ], + [ "GetVarDeclaration", "classas_i_script_context.html#ae3419d239a51d702870b1ab8ee1b7140", null ], + [ "GetVarName", "classas_i_script_context.html#aac398eb23d9f17fcbeaa3f3809f8923d", null ], + [ "GetVarTypeId", "classas_i_script_context.html#a8684e1931e54dbfe53da763fc334413d", null ], + [ "IsNested", "classas_i_script_context.html#a378f3bbfa04ef7b806300c5d4f1a0d65", null ], + [ "IsVarInScope", "classas_i_script_context.html#a45fcf7d8d711d5ec5cb9927e7839387a", null ], + [ "PopState", "classas_i_script_context.html#a5d963974625e582799b5d911d182d9be", null ], + [ "Prepare", "classas_i_script_context.html#a43976f42dfc6c1af23e132d36265173a", null ], + [ "PushState", "classas_i_script_context.html#ad8f7637a23d67e227d07f65621b6cdd6", null ], + [ "Release", "classas_i_script_context.html#a1b13a5f3e58627e9ff4300c0c6f0f3cf", null ], + [ "SetArgAddress", "classas_i_script_context.html#aa8de8f21dfbb2cdf0becbabaa3e883ed", null ], + [ "SetArgByte", "classas_i_script_context.html#ac5ac8ce5bb209f43d4da620db5d271da", null ], + [ "SetArgDouble", "classas_i_script_context.html#acbdddda3b80c37b70b8fd35c8e7383b9", null ], + [ "SetArgDWord", "classas_i_script_context.html#a14cac831c1b419f552ca62a239dfcf45", null ], + [ "SetArgFloat", "classas_i_script_context.html#a702a40cfe539e4e655a84e15161f8db8", null ], + [ "SetArgObject", "classas_i_script_context.html#a09044a12dfb2d44d19bd8a4025cb814d", null ], + [ "SetArgQWord", "classas_i_script_context.html#a742c870360588e99528f09bae6156482", null ], + [ "SetArgVarType", "classas_i_script_context.html#a626d97ec564c92120e2abaf69f6e3698", null ], + [ "SetArgWord", "classas_i_script_context.html#ac882e19b922c681052a0a88d69289a47", null ], + [ "SetException", "classas_i_script_context.html#a6f0f071215e0f7effc0b765043f01275", null ], + [ "SetExceptionCallback", "classas_i_script_context.html#a4d1f481473df3f7aefccc5bb6904e405", null ], + [ "SetLineCallback", "classas_i_script_context.html#ae2747f643bf9a07364f922c460ef57dd", null ], + [ "SetObject", "classas_i_script_context.html#a10d3c152b25d07584999f4d9fe5ce8b1", null ], + [ "SetUserData", "classas_i_script_context.html#a263dc70abb2a8c77adcea7c9ede0a479", null ], + [ "Suspend", "classas_i_script_context.html#ad4ac8be3586c46069b5870e40c86544a", null ], + [ "Unprepare", "classas_i_script_context.html#ae3c18a2cc66c56f840e6ee4310287f65", null ], + [ "WillExceptionBeCaught", "classas_i_script_context.html#a57cfcc729b214fdaacb1358e03daf610", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/group__api__secondary__interfaces.html b/docs/manual/group__api__secondary__interfaces.html new file mode 100644 index 0000000..088084b --- /dev/null +++ b/docs/manual/group__api__secondary__interfaces.html @@ -0,0 +1,132 @@ + + + + + + + +AngelScript: Secondary interfaces + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
Secondary interfaces
+
+
+ + + + + + + + + + + + + + + + + +

+Classes

class  asIStringFactory
 The interface for the string factory. More...
 
class  asIScriptGeneric
 The interface for the generic calling convention. More...
 
class  asIScriptObject
 The interface for an instance of a script object. More...
 
class  asITypeInfo
 The interface for describing types This interface is used to describe the types in the script engine. More...
 
class  asIScriptFunction
 The interface for a script function description. More...
 
+

Detailed Description

+
+
+ + + + diff --git a/docs/manual/group__api__secondary__interfaces.js b/docs/manual/group__api__secondary__interfaces.js new file mode 100644 index 0000000..0135fae --- /dev/null +++ b/docs/manual/group__api__secondary__interfaces.js @@ -0,0 +1,134 @@ +var group__api__secondary__interfaces = +[ + [ "asIStringFactory", "classas_i_string_factory.html", [ + [ "GetRawStringData", "classas_i_string_factory.html#ae798179f4d90b30371416f8c5c522333", null ], + [ "GetStringConstant", "classas_i_string_factory.html#a59d5d4d13a21105791e34bef5cb57e6b", null ], + [ "ReleaseStringConstant", "classas_i_string_factory.html#ae4ca9e666eb711671a765dba8debe8b1", null ] + ] ], + [ "asIScriptGeneric", "classas_i_script_generic.html", [ + [ "GetAddressOfArg", "classas_i_script_generic.html#a08f922bc97867e1e97e923a5bdee4dbc", null ], + [ "GetAddressOfReturnLocation", "classas_i_script_generic.html#a103a91f081ec894a116cd3db06b0d8d1", null ], + [ "GetArgAddress", "classas_i_script_generic.html#ac5c73473ccefe029582c5e3793d1a41b", null ], + [ "GetArgByte", "classas_i_script_generic.html#a20f30e6ed55ed952bcb5c70096eb83dd", null ], + [ "GetArgCount", "classas_i_script_generic.html#aafdaf0ed1ff5023b2aaf4ae1adfa3714", null ], + [ "GetArgDouble", "classas_i_script_generic.html#ad0bb07a940b7ba08abc3ce114dca99fc", null ], + [ "GetArgDWord", "classas_i_script_generic.html#aab74bcbe4be32fc423b21b75a3f4d57a", null ], + [ "GetArgFloat", "classas_i_script_generic.html#a487a68e409d79e61fcc624337c4ac991", null ], + [ "GetArgObject", "classas_i_script_generic.html#a6732b01132cd58e81cd0354ac274039a", null ], + [ "GetArgQWord", "classas_i_script_generic.html#a0fbd6ce45aebc29e29a64dac4affc111", null ], + [ "GetArgTypeId", "classas_i_script_generic.html#a2bdce6872b371355665e932a962548cb", null ], + [ "GetArgWord", "classas_i_script_generic.html#afdb602c3c2e285c5f34bc477ebbd1534", null ], + [ "GetAuxiliary", "classas_i_script_generic.html#adf0ec41b9df5c93d72a950c78f6fea8e", null ], + [ "GetEngine", "classas_i_script_generic.html#a3f3b0838588e3afa7172f9bbb87f5445", null ], + [ "GetFunction", "classas_i_script_generic.html#acf00e806a36e0b42686c0f8df25b0898", null ], + [ "GetObject", "classas_i_script_generic.html#ab9e6627ec3920b1e1576d82586cac84d", null ], + [ "GetObjectTypeId", "classas_i_script_generic.html#a3de95071fa358d554137cae88a5229ea", null ], + [ "GetReturnTypeId", "classas_i_script_generic.html#a9da6f7f81392cd25733ebc6c803a397a", null ], + [ "SetReturnAddress", "classas_i_script_generic.html#afd8ead96f17d6e77f3a26c70c3a1d80c", null ], + [ "SetReturnByte", "classas_i_script_generic.html#a81c42965dfccfd242e955f50b02a641c", null ], + [ "SetReturnDouble", "classas_i_script_generic.html#a8a720ef33859981dd941c616b2c83cad", null ], + [ "SetReturnDWord", "classas_i_script_generic.html#a3260e1f3b76791713bced9af0b81bdbc", null ], + [ "SetReturnFloat", "classas_i_script_generic.html#acc2fddd4175ad35854cec8f5c38a6495", null ], + [ "SetReturnObject", "classas_i_script_generic.html#a94c9ca32722cb44b09211e51fa906e6e", null ], + [ "SetReturnQWord", "classas_i_script_generic.html#a25f5ec30c666ffbb51edeedfd4c89546", null ], + [ "SetReturnWord", "classas_i_script_generic.html#a9c51e3ff3f4fb37f6b4c82a050319955", null ] + ] ], + [ "asIScriptObject", "classas_i_script_object.html", [ + [ "AddRef", "classas_i_script_object.html#a3e08890e31163e4d33c0f27dc9072662", null ], + [ "CopyFrom", "classas_i_script_object.html#ab83919a23c02ec07c66d9aedcbecf261", null ], + [ "GetAddressOfProperty", "classas_i_script_object.html#a6a8a3c7d1e103e43923614b719e3cb3a", null ], + [ "GetEngine", "classas_i_script_object.html#a5dda2d380ae1580e15ddf9d95893c57a", null ], + [ "GetObjectType", "classas_i_script_object.html#aec79a2608f633a63169365d1ba79f611", null ], + [ "GetPropertyCount", "classas_i_script_object.html#a902a8e3f3b4d6d2e56b6e258febf6259", null ], + [ "GetPropertyName", "classas_i_script_object.html#af777076ab0d87e4995e1a343511f8a61", null ], + [ "GetPropertyTypeId", "classas_i_script_object.html#a0b39e0e07b126b43d12ad1ec944a333e", null ], + [ "GetTypeId", "classas_i_script_object.html#a19c5ab9d8adb0f921bf0b6474d97f468", null ], + [ "GetUserData", "classas_i_script_object.html#a63e8ab74fd7552d057e23e0ce550a157", null ], + [ "GetWeakRefFlag", "classas_i_script_object.html#a9ccca7fe3453219377fc9bd190bf7903", null ], + [ "Release", "classas_i_script_object.html#a4bed3c3ac9f16294985835747aa122d3", null ], + [ "SetUserData", "classas_i_script_object.html#ac85cea9bca5dd3868e027285e44dd6d0", null ] + ] ], + [ "asITypeInfo", "classas_i_type_info.html", [ + [ "AddRef", "classas_i_type_info.html#a532069932de1f584ab52e4c2afacf95e", null ], + [ "DerivesFrom", "classas_i_type_info.html#a4ce24b7a0ecd27bb7e34f1fa58c08d29", null ], + [ "GetAccessMask", "classas_i_type_info.html#a849e5890b225717b243c73e3d4f38204", null ], + [ "GetBaseType", "classas_i_type_info.html#a8722ecc6b7e47491cdb6e442a3bf1ba2", null ], + [ "GetBehaviourByIndex", "classas_i_type_info.html#ae91a1b2080e76a0dcad8106436728314", null ], + [ "GetBehaviourCount", "classas_i_type_info.html#ad7c3c757cc99df4d40c6b3b44896cb96", null ], + [ "GetChildFuncdef", "classas_i_type_info.html#a01fe2f0b68614246a63e52cada374b69", null ], + [ "GetChildFuncdefCount", "classas_i_type_info.html#aa9b5a0281ff01d448e55cb10e42ba340", null ], + [ "GetConfigGroup", "classas_i_type_info.html#aa181c094c192e86299b394ebcfa68760", null ], + [ "GetEngine", "classas_i_type_info.html#abafbb3a12cbd94f56a4f3c1739fd6ada", null ], + [ "GetEnumValueByIndex", "classas_i_type_info.html#aaece7c2106dbced04436b52515f1f7ac", null ], + [ "GetEnumValueCount", "classas_i_type_info.html#abe22697bab6560c30c9b613187d6b4d7", null ], + [ "GetFactoryByDecl", "classas_i_type_info.html#aca1e08cd395231d30ad78a7ca3fea142", null ], + [ "GetFactoryByIndex", "classas_i_type_info.html#a6a8b52fefd309102142ba74621d35714", null ], + [ "GetFactoryCount", "classas_i_type_info.html#a22cb802db08d6f464f6ee12337390d12", null ], + [ "GetFlags", "classas_i_type_info.html#a068900ec359ff7fc2ee59a938ffe20ab", null ], + [ "GetFuncdefSignature", "classas_i_type_info.html#abf4e686097f0c485e6dcd330fe47f91e", null ], + [ "GetInterface", "classas_i_type_info.html#a320141f6c331a9e49334de2576c725f7", null ], + [ "GetInterfaceCount", "classas_i_type_info.html#a47a4bdc2462b38a5659c3cb96e61c649", null ], + [ "GetMethodByDecl", "classas_i_type_info.html#a80c61bb4d018647561ce3af24fedf65b", null ], + [ "GetMethodByIndex", "classas_i_type_info.html#a235262cb0bacaf1f160e5ac5156db4e8", null ], + [ "GetMethodByName", "classas_i_type_info.html#af3febbb10e7e85425f0960aad892f9b8", null ], + [ "GetMethodCount", "classas_i_type_info.html#a50877d3602e460e784df4f611ae6f360", null ], + [ "GetModule", "classas_i_type_info.html#a3e08d6c6ee1957c421bb297f94a81d54", null ], + [ "GetName", "classas_i_type_info.html#a49f83d3a9158331029324bfbe9ae46a8", null ], + [ "GetNamespace", "classas_i_type_info.html#a90b16019d2569d6c721130f3049786a2", null ], + [ "GetParentType", "classas_i_type_info.html#aa2836268d01f3a4424263190b57d9b04", null ], + [ "GetProperty", "classas_i_type_info.html#a48f468bd5b6b0e22c852b40639a7a2b5", null ], + [ "GetPropertyCount", "classas_i_type_info.html#a01d086e1bb97aa56a7b128c00c174ac6", null ], + [ "GetPropertyDeclaration", "classas_i_type_info.html#a9e6916f51f09970d268378aef9601349", null ], + [ "GetSize", "classas_i_type_info.html#ad965398e393144e87c0436ef865b9b6d", null ], + [ "GetSubType", "classas_i_type_info.html#a8e947504f268c7f0e1c26973dd7d3837", null ], + [ "GetSubTypeCount", "classas_i_type_info.html#a1657d5094afa550c93d8cc74c216c3c6", null ], + [ "GetSubTypeId", "classas_i_type_info.html#aa1a56809ce5c340364ecd8beac508eb4", null ], + [ "GetTypedefTypeId", "classas_i_type_info.html#aca9edb046026db68d255e226dd419b3a", null ], + [ "GetTypeId", "classas_i_type_info.html#a06698aa9dcc6dc315ec2651fc70dbe19", null ], + [ "GetUserData", "classas_i_type_info.html#a80b01b2ceadfaf91cc34988033a1598c", null ], + [ "Implements", "classas_i_type_info.html#a19bacd881681ee398de95a076f427726", null ], + [ "Release", "classas_i_type_info.html#a73b9059dc335b6fde8c7bbf4b1b95914", null ], + [ "SetUserData", "classas_i_type_info.html#a5e8ea071f1c1f3b7c6dfc1950bec73f4", null ] + ] ], + [ "asIScriptFunction", "classas_i_script_function.html", [ + [ "AddRef", "classas_i_script_function.html#a0a00f9581e7ece5f2a536d0e22c10d0c", null ], + [ "FindNextLineWithCode", "classas_i_script_function.html#a30dc23991856a13f59e682b3b1498e2f", null ], + [ "GetAccessMask", "classas_i_script_function.html#a5c49841eb92a0993a16eb855577b590c", null ], + [ "GetAuxiliary", "classas_i_script_function.html#acbdd97f1c3658cb4f82a154591e100f6", null ], + [ "GetByteCode", "classas_i_script_function.html#afb38e9ba77ce8b49378e43dadd83ef94", null ], + [ "GetConfigGroup", "classas_i_script_function.html#afea841f0923573cea81467ac90b71996", null ], + [ "GetDeclaration", "classas_i_script_function.html#a2fb021b09ae0e7e87f8fa4fdfd39df83", null ], + [ "GetDelegateFunction", "classas_i_script_function.html#aa28f4e68da8abb770d7f725375bcd2bb", null ], + [ "GetDelegateObject", "classas_i_script_function.html#ae1786c3f4341dc3bfcaacc3cb8900a57", null ], + [ "GetDelegateObjectType", "classas_i_script_function.html#ad79461f80fcffd513b43564d75cc5360", null ], + [ "GetEngine", "classas_i_script_function.html#a7a0ef04f035d1809fb8b7702134afd06", null ], + [ "GetFuncType", "classas_i_script_function.html#aa4d06c7d590e7eb4df280a8224f4499c", null ], + [ "GetId", "classas_i_script_function.html#a7aca255486dd77b8846f545495128cac", null ], + [ "GetModule", "classas_i_script_function.html#a5c3477dd6b634e6b6ca3d5b97f6d5b30", null ], + [ "GetModuleName", "classas_i_script_function.html#af03c30e4764f81c01400d7f77a8d0832", null ], + [ "GetName", "classas_i_script_function.html#a96cf134f1369f312aa182de5006f8b71", null ], + [ "GetNamespace", "classas_i_script_function.html#ab692c00b9a7111778acb4fbca1c63df7", null ], + [ "GetObjectName", "classas_i_script_function.html#a69e30464d13867fb72e66ce3365fdec8", null ], + [ "GetObjectType", "classas_i_script_function.html#af930b362c37e5c4c117485d0bd4a34fb", null ], + [ "GetParam", "classas_i_script_function.html#a2b3000b9fc5d3f2cfeea490d8c0c062a", null ], + [ "GetParamCount", "classas_i_script_function.html#a8ca059886317b944c52933b7bbe85cfa", null ], + [ "GetReturnTypeId", "classas_i_script_function.html#a18968d49065c6af9833ee589b6d1e864", null ], + [ "GetScriptSectionName", "classas_i_script_function.html#a62a77c029782162135d98d6e2b383eca", null ], + [ "GetTypeId", "classas_i_script_function.html#a4a5e24c464e423a2a6724cb849babd21", null ], + [ "GetUserData", "classas_i_script_function.html#a0d0d4671e524fcd868a34bee33ee9fde", null ], + [ "GetVar", "classas_i_script_function.html#aaf11dde60bec710bcd729127bfe12dd4", null ], + [ "GetVarCount", "classas_i_script_function.html#a92e14168997c0f67a975e7ed042d8328", null ], + [ "GetVarDecl", "classas_i_script_function.html#acef067f00f2a6a997d6955f5cf3c6d13", null ], + [ "IsCompatibleWithTypeId", "classas_i_script_function.html#a76715df2843cb37cc010fc3a5d999e84", null ], + [ "IsExplicit", "classas_i_script_function.html#aea24c6ba2ab0fcc5c42a734f72856814", null ], + [ "IsFinal", "classas_i_script_function.html#aa071c702946372020a1245f901502d52", null ], + [ "IsOverride", "classas_i_script_function.html#a5aec17ae5639fb9cad403c835d429f6e", null ], + [ "IsPrivate", "classas_i_script_function.html#a7ef1f42ff812a03e2a323046835159fb", null ], + [ "IsProperty", "classas_i_script_function.html#ad6ecdae3667ebef1fc867e884504078c", null ], + [ "IsProtected", "classas_i_script_function.html#a2e17b763527ba3a9b0d05c4cd35b5742", null ], + [ "IsReadOnly", "classas_i_script_function.html#a99bbe26ae0ec3f0cc09070bf89aff2f9", null ], + [ "IsShared", "classas_i_script_function.html#a805ae8064598ad12f44bb583118b6cc5", null ], + [ "Release", "classas_i_script_function.html#a0a98f1f7f91574a11d7d8c5062bdcdee", null ], + [ "SetUserData", "classas_i_script_function.html#a9dd036ce8e91d335eb5a3ad8851f1a41", null ] + ] ] +]; \ No newline at end of file diff --git a/docs/manual/index.html b/docs/manual/index.html new file mode 100644 index 0000000..d405cce --- /dev/null +++ b/docs/manual/index.html @@ -0,0 +1,117 @@ + + + + + + + +AngelScript: Introduction + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Introduction
+
+
+
+ +
+
Version 2.35.0

AngelScript is a free, open source, flexible, and cross-platform scripting library meant to be embedded in applications. The purpose is to provide an easy to use library that is powerful, but that isn't weighed down by a large amount of rarely used features.

+

Development of AngelScript begun in February, 2003, with the first public release on March 28th, 2003, with only the most basic of functionality. Ever since that day the world has seen frequent releases with new features and improvements. The author is still dedicated to the continued improvement and growth of this library.

+

The official site for the library is http://www.angelcode.com/angelscript.

+
+
+
+ + + + diff --git a/docs/manual/jquery.js b/docs/manual/jquery.js new file mode 100644 index 0000000..103c32d --- /dev/null +++ b/docs/manual/jquery.js @@ -0,0 +1,35 @@ +/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?k.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;nx",y.noCloneChecked=!!me.cloneNode(!0).lastChild.defaultValue;var Te=/^key/,Ce=/^(?:mouse|pointer|contextmenu|drag|drop)|click/,Ee=/^([^.]*)(?:\.(.+)|)/;function ke(){return!0}function Se(){return!1}function Ne(e,t){return e===function(){try{return E.activeElement}catch(e){}}()==("focus"===t)}function Ae(e,t,n,r,i,o){var a,s;if("object"==typeof t){for(s in"string"!=typeof n&&(r=r||n,n=void 0),t)Ae(e,s,n,r,t[s],o);return e}if(null==r&&null==i?(i=n,r=n=void 0):null==i&&("string"==typeof n?(i=r,r=void 0):(i=r,r=n,n=void 0)),!1===i)i=Se;else if(!i)return e;return 1===o&&(a=i,(i=function(e){return k().off(e),a.apply(this,arguments)}).guid=a.guid||(a.guid=k.guid++)),e.each(function(){k.event.add(this,t,i,r,n)})}function De(e,i,o){o?(Q.set(e,i,!1),k.event.add(e,i,{namespace:!1,handler:function(e){var t,n,r=Q.get(this,i);if(1&e.isTrigger&&this[i]){if(r.length)(k.event.special[i]||{}).delegateType&&e.stopPropagation();else if(r=s.call(arguments),Q.set(this,i,r),t=o(this,i),this[i](),r!==(n=Q.get(this,i))||t?Q.set(this,i,!1):n={},r!==n)return e.stopImmediatePropagation(),e.preventDefault(),n.value}else r.length&&(Q.set(this,i,{value:k.event.trigger(k.extend(r[0],k.Event.prototype),r.slice(1),this)}),e.stopImmediatePropagation())}})):void 0===Q.get(e,i)&&k.event.add(e,i,ke)}k.event={global:{},add:function(t,e,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.get(t);if(v){n.handler&&(n=(o=n).handler,i=o.selector),i&&k.find.matchesSelector(ie,i),n.guid||(n.guid=k.guid++),(u=v.events)||(u=v.events={}),(a=v.handle)||(a=v.handle=function(e){return"undefined"!=typeof k&&k.event.triggered!==e.type?k.event.dispatch.apply(t,arguments):void 0}),l=(e=(e||"").match(R)||[""]).length;while(l--)d=g=(s=Ee.exec(e[l])||[])[1],h=(s[2]||"").split(".").sort(),d&&(f=k.event.special[d]||{},d=(i?f.delegateType:f.bindType)||d,f=k.event.special[d]||{},c=k.extend({type:d,origType:g,data:r,handler:n,guid:n.guid,selector:i,needsContext:i&&k.expr.match.needsContext.test(i),namespace:h.join(".")},o),(p=u[d])||((p=u[d]=[]).delegateCount=0,f.setup&&!1!==f.setup.call(t,r,h,a)||t.addEventListener&&t.addEventListener(d,a)),f.add&&(f.add.call(t,c),c.handler.guid||(c.handler.guid=n.guid)),i?p.splice(p.delegateCount++,0,c):p.push(c),k.event.global[d]=!0)}},remove:function(e,t,n,r,i){var o,a,s,u,l,c,f,p,d,h,g,v=Q.hasData(e)&&Q.get(e);if(v&&(u=v.events)){l=(t=(t||"").match(R)||[""]).length;while(l--)if(d=g=(s=Ee.exec(t[l])||[])[1],h=(s[2]||"").split(".").sort(),d){f=k.event.special[d]||{},p=u[d=(r?f.delegateType:f.bindType)||d]||[],s=s[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),a=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||s&&!s.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));a&&!p.length&&(f.teardown&&!1!==f.teardown.call(e,h,v.handle)||k.removeEvent(e,d,v.handle),delete u[d])}else for(d in u)k.event.remove(e,d+t[l],n,r,!0);k.isEmptyObject(u)&&Q.remove(e,"handle events")}},dispatch:function(e){var t,n,r,i,o,a,s=k.event.fix(e),u=new Array(arguments.length),l=(Q.get(this,"events")||{})[s.type]||[],c=k.event.special[s.type]||{};for(u[0]=s,t=1;t\x20\t\r\n\f]*)[^>]*)\/>/gi,qe=/\s*$/g;function Oe(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&k(e).children("tbody")[0]||e}function Pe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Re(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Me(e,t){var n,r,i,o,a,s,u,l;if(1===t.nodeType){if(Q.hasData(e)&&(o=Q.access(e),a=Q.set(t,o),l=o.events))for(i in delete a.handle,a.events={},l)for(n=0,r=l[i].length;n")},clone:function(e,t,n){var r,i,o,a,s,u,l,c=e.cloneNode(!0),f=oe(e);if(!(y.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||k.isXMLDoc(e)))for(a=ve(c),r=0,i=(o=ve(e)).length;r").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var Vt,Gt=[],Yt=/(=)\?(?=&|$)|\?\?/;k.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=Gt.pop()||k.expando+"_"+kt++;return this[e]=!0,e}}),k.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Yt.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Yt.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Yt,"$1"+r):!1!==e.jsonp&&(e.url+=(St.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||k.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?k(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,Gt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((Vt=E.implementation.createHTMLDocument("").body).innerHTML="
",2===Vt.childNodes.length),k.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=D.exec(e))?[t.createElement(i[1])]:(i=we([e],t,o),o&&o.length&&k(o).remove(),k.merge([],i.childNodes)));var r,i,o},k.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(k.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},k.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){k.fn[t]=function(e){return this.on(t,e)}}),k.expr.pseudos.animated=function(t){return k.grep(k.timers,function(e){return t===e.elem}).length},k.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=k.css(e,"position"),c=k(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=k.css(e,"top"),u=k.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,k.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},k.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){k.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===k.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===k.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=k(e).offset()).top+=k.css(e,"borderTopWidth",!0),i.left+=k.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-k.css(r,"marginTop",!0),left:t.left-i.left-k.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===k.css(e,"position"))e=e.offsetParent;return e||ie})}}),k.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;k.fn[t]=function(e){return _(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),k.each(["top","left"],function(e,n){k.cssHooks[n]=ze(y.pixelPosition,function(e,t){if(t)return t=_e(e,n),$e.test(t)?k(e).position()[n]+"px":t})}),k.each({Height:"height",Width:"width"},function(a,s){k.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){k.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return _(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?k.css(e,t,i):k.style(e,t,n,i)},s,n?e:void 0,n)}})}),k.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){k.fn[n]=function(e,t){return 0a;a++)for(i in o[a])n=o[a][i],o[a].hasOwnProperty(i)&&void 0!==n&&(e[i]=t.isPlainObject(n)?t.isPlainObject(e[i])?t.widget.extend({},e[i],n):t.widget.extend({},n):n);return e},t.widget.bridge=function(e,i){var n=i.prototype.widgetFullName||e;t.fn[e]=function(o){var a="string"==typeof o,r=s.call(arguments,1),h=this;return a?this.length||"instance"!==o?this.each(function(){var i,s=t.data(this,n);return"instance"===o?(h=s,!1):s?t.isFunction(s[o])&&"_"!==o.charAt(0)?(i=s[o].apply(s,r),i!==s&&void 0!==i?(h=i&&i.jquery?h.pushStack(i.get()):i,!1):void 0):t.error("no such method '"+o+"' for "+e+" widget instance"):t.error("cannot call methods on "+e+" prior to initialization; "+"attempted to call method '"+o+"'")}):h=void 0:(r.length&&(o=t.widget.extend.apply(null,[o].concat(r))),this.each(function(){var e=t.data(this,n);e?(e.option(o||{}),e._init&&e._init()):t.data(this,n,new i(o,this))})),h}},t.Widget=function(){},t.Widget._childConstructors=[],t.Widget.prototype={widgetName:"widget",widgetEventPrefix:"",defaultElement:"
",options:{classes:{},disabled:!1,create:null},_createWidget:function(e,s){s=t(s||this.defaultElement||this)[0],this.element=t(s),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=t(),this.hoverable=t(),this.focusable=t(),this.classesElementLookup={},s!==this&&(t.data(s,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===s&&this.destroy()}}),this.document=t(s.style?s.ownerDocument:s.document||s),this.window=t(this.document[0].defaultView||this.document[0].parentWindow)),this.options=t.widget.extend({},this.options,this._getCreateOptions(),e),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:t.noop,_create:t.noop,_init:t.noop,destroy:function(){var e=this;this._destroy(),t.each(this.classesElementLookup,function(t,i){e._removeClass(i,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:t.noop,widget:function(){return this.element},option:function(e,i){var s,n,o,a=e;if(0===arguments.length)return t.widget.extend({},this.options);if("string"==typeof e)if(a={},s=e.split("."),e=s.shift(),s.length){for(n=a[e]=t.widget.extend({},this.options[e]),o=0;s.length-1>o;o++)n[s[o]]=n[s[o]]||{},n=n[s[o]];if(e=s.pop(),1===arguments.length)return void 0===n[e]?null:n[e];n[e]=i}else{if(1===arguments.length)return void 0===this.options[e]?null:this.options[e];a[e]=i}return this._setOptions(a),this},_setOptions:function(t){var e;for(e in t)this._setOption(e,t[e]);return this},_setOption:function(t,e){return"classes"===t&&this._setOptionClasses(e),this.options[t]=e,"disabled"===t&&this._setOptionDisabled(e),this},_setOptionClasses:function(e){var i,s,n;for(i in e)n=this.classesElementLookup[i],e[i]!==this.options.classes[i]&&n&&n.length&&(s=t(n.get()),this._removeClass(n,i),s.addClass(this._classes({element:s,keys:i,classes:e,add:!0})))},_setOptionDisabled:function(t){this._toggleClass(this.widget(),this.widgetFullName+"-disabled",null,!!t),t&&(this._removeClass(this.hoverable,null,"ui-state-hover"),this._removeClass(this.focusable,null,"ui-state-focus"))},enable:function(){return this._setOptions({disabled:!1})},disable:function(){return this._setOptions({disabled:!0})},_classes:function(e){function i(i,o){var a,r;for(r=0;i.length>r;r++)a=n.classesElementLookup[i[r]]||t(),a=e.add?t(t.unique(a.get().concat(e.element.get()))):t(a.not(e.element).get()),n.classesElementLookup[i[r]]=a,s.push(i[r]),o&&e.classes[i[r]]&&s.push(e.classes[i[r]])}var s=[],n=this;return e=t.extend({element:this.element,classes:this.options.classes||{}},e),this._on(e.element,{remove:"_untrackClassesElement"}),e.keys&&i(e.keys.match(/\S+/g)||[],!0),e.extra&&i(e.extra.match(/\S+/g)||[]),s.join(" ")},_untrackClassesElement:function(e){var i=this;t.each(i.classesElementLookup,function(s,n){-1!==t.inArray(e.target,n)&&(i.classesElementLookup[s]=t(n.not(e.target).get()))})},_removeClass:function(t,e,i){return this._toggleClass(t,e,i,!1)},_addClass:function(t,e,i){return this._toggleClass(t,e,i,!0)},_toggleClass:function(t,e,i,s){s="boolean"==typeof s?s:i;var n="string"==typeof t||null===t,o={extra:n?e:i,keys:n?t:e,element:n?this.element:t,add:s};return o.element.toggleClass(this._classes(o),s),this},_on:function(e,i,s){var n,o=this;"boolean"!=typeof e&&(s=i,i=e,e=!1),s?(i=n=t(i),this.bindings=this.bindings.add(i)):(s=i,i=this.element,n=this.widget()),t.each(s,function(s,a){function r(){return e||o.options.disabled!==!0&&!t(this).hasClass("ui-state-disabled")?("string"==typeof a?o[a]:a).apply(o,arguments):void 0}"string"!=typeof a&&(r.guid=a.guid=a.guid||r.guid||t.guid++);var h=s.match(/^([\w:-]*)\s*(.*)$/),l=h[1]+o.eventNamespace,c=h[2];c?n.on(l,c,r):i.on(l,r)})},_off:function(e,i){i=(i||"").split(" ").join(this.eventNamespace+" ")+this.eventNamespace,e.off(i).off(i),this.bindings=t(this.bindings.not(e).get()),this.focusable=t(this.focusable.not(e).get()),this.hoverable=t(this.hoverable.not(e).get())},_delay:function(t,e){function i(){return("string"==typeof t?s[t]:t).apply(s,arguments)}var s=this;return setTimeout(i,e||0)},_hoverable:function(e){this.hoverable=this.hoverable.add(e),this._on(e,{mouseenter:function(e){this._addClass(t(e.currentTarget),null,"ui-state-hover")},mouseleave:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-hover")}})},_focusable:function(e){this.focusable=this.focusable.add(e),this._on(e,{focusin:function(e){this._addClass(t(e.currentTarget),null,"ui-state-focus")},focusout:function(e){this._removeClass(t(e.currentTarget),null,"ui-state-focus")}})},_trigger:function(e,i,s){var n,o,a=this.options[e];if(s=s||{},i=t.Event(i),i.type=(e===this.widgetEventPrefix?e:this.widgetEventPrefix+e).toLowerCase(),i.target=this.element[0],o=i.originalEvent)for(n in o)n in i||(i[n]=o[n]);return this.element.trigger(i,s),!(t.isFunction(a)&&a.apply(this.element[0],[i].concat(s))===!1||i.isDefaultPrevented())}},t.each({show:"fadeIn",hide:"fadeOut"},function(e,i){t.Widget.prototype["_"+e]=function(s,n,o){"string"==typeof n&&(n={effect:n});var a,r=n?n===!0||"number"==typeof n?i:n.effect||i:e;n=n||{},"number"==typeof n&&(n={duration:n}),a=!t.isEmptyObject(n),n.complete=o,n.delay&&s.delay(n.delay),a&&t.effects&&t.effects.effect[r]?s[e](n):r!==e&&s[r]?s[r](n.duration,n.easing,o):s.queue(function(i){t(this)[e](),o&&o.call(s[0]),i()})}}),t.widget,function(){function e(t,e,i){return[parseFloat(t[0])*(u.test(t[0])?e/100:1),parseFloat(t[1])*(u.test(t[1])?i/100:1)]}function i(e,i){return parseInt(t.css(e,i),10)||0}function s(e){var i=e[0];return 9===i.nodeType?{width:e.width(),height:e.height(),offset:{top:0,left:0}}:t.isWindow(i)?{width:e.width(),height:e.height(),offset:{top:e.scrollTop(),left:e.scrollLeft()}}:i.preventDefault?{width:0,height:0,offset:{top:i.pageY,left:i.pageX}}:{width:e.outerWidth(),height:e.outerHeight(),offset:e.offset()}}var n,o=Math.max,a=Math.abs,r=/left|center|right/,h=/top|center|bottom/,l=/[\+\-]\d+(\.[\d]+)?%?/,c=/^\w+/,u=/%$/,d=t.fn.position;t.position={scrollbarWidth:function(){if(void 0!==n)return n;var e,i,s=t("
"),o=s.children()[0];return t("body").append(s),e=o.offsetWidth,s.css("overflow","scroll"),i=o.offsetWidth,e===i&&(i=s[0].clientWidth),s.remove(),n=e-i},getScrollInfo:function(e){var i=e.isWindow||e.isDocument?"":e.element.css("overflow-x"),s=e.isWindow||e.isDocument?"":e.element.css("overflow-y"),n="scroll"===i||"auto"===i&&e.widthi?"left":e>0?"right":"center",vertical:0>r?"top":s>0?"bottom":"middle"};l>p&&p>a(e+i)&&(u.horizontal="center"),c>f&&f>a(s+r)&&(u.vertical="middle"),u.important=o(a(e),a(i))>o(a(s),a(r))?"horizontal":"vertical",n.using.call(this,t,u)}),h.offset(t.extend(D,{using:r}))})},t.ui.position={fit:{left:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollLeft:s.offset.left,a=s.width,r=t.left-e.collisionPosition.marginLeft,h=n-r,l=r+e.collisionWidth-a-n;e.collisionWidth>a?h>0&&0>=l?(i=t.left+h+e.collisionWidth-a-n,t.left+=h-i):t.left=l>0&&0>=h?n:h>l?n+a-e.collisionWidth:n:h>0?t.left+=h:l>0?t.left-=l:t.left=o(t.left-r,t.left)},top:function(t,e){var i,s=e.within,n=s.isWindow?s.scrollTop:s.offset.top,a=e.within.height,r=t.top-e.collisionPosition.marginTop,h=n-r,l=r+e.collisionHeight-a-n;e.collisionHeight>a?h>0&&0>=l?(i=t.top+h+e.collisionHeight-a-n,t.top+=h-i):t.top=l>0&&0>=h?n:h>l?n+a-e.collisionHeight:n:h>0?t.top+=h:l>0?t.top-=l:t.top=o(t.top-r,t.top)}},flip:{left:function(t,e){var i,s,n=e.within,o=n.offset.left+n.scrollLeft,r=n.width,h=n.isWindow?n.scrollLeft:n.offset.left,l=t.left-e.collisionPosition.marginLeft,c=l-h,u=l+e.collisionWidth-r-h,d="left"===e.my[0]?-e.elemWidth:"right"===e.my[0]?e.elemWidth:0,p="left"===e.at[0]?e.targetWidth:"right"===e.at[0]?-e.targetWidth:0,f=-2*e.offset[0];0>c?(i=t.left+d+p+f+e.collisionWidth-r-o,(0>i||a(c)>i)&&(t.left+=d+p+f)):u>0&&(s=t.left-e.collisionPosition.marginLeft+d+p+f-h,(s>0||u>a(s))&&(t.left+=d+p+f))},top:function(t,e){var i,s,n=e.within,o=n.offset.top+n.scrollTop,r=n.height,h=n.isWindow?n.scrollTop:n.offset.top,l=t.top-e.collisionPosition.marginTop,c=l-h,u=l+e.collisionHeight-r-h,d="top"===e.my[1],p=d?-e.elemHeight:"bottom"===e.my[1]?e.elemHeight:0,f="top"===e.at[1]?e.targetHeight:"bottom"===e.at[1]?-e.targetHeight:0,m=-2*e.offset[1];0>c?(s=t.top+p+f+m+e.collisionHeight-r-o,(0>s||a(c)>s)&&(t.top+=p+f+m)):u>0&&(i=t.top-e.collisionPosition.marginTop+p+f+m-h,(i>0||u>a(i))&&(t.top+=p+f+m))}},flipfit:{left:function(){t.ui.position.flip.left.apply(this,arguments),t.ui.position.fit.left.apply(this,arguments)},top:function(){t.ui.position.flip.top.apply(this,arguments),t.ui.position.fit.top.apply(this,arguments)}}}}(),t.ui.position,t.extend(t.expr[":"],{data:t.expr.createPseudo?t.expr.createPseudo(function(e){return function(i){return!!t.data(i,e)}}):function(e,i,s){return!!t.data(e,s[3])}}),t.fn.extend({disableSelection:function(){var t="onselectstart"in document.createElement("div")?"selectstart":"mousedown";return function(){return this.on(t+".ui-disableSelection",function(t){t.preventDefault()})}}(),enableSelection:function(){return this.off(".ui-disableSelection")}}),t.ui.focusable=function(i,s){var n,o,a,r,h,l=i.nodeName.toLowerCase();return"area"===l?(n=i.parentNode,o=n.name,i.href&&o&&"map"===n.nodeName.toLowerCase()?(a=t("img[usemap='#"+o+"']"),a.length>0&&a.is(":visible")):!1):(/^(input|select|textarea|button|object)$/.test(l)?(r=!i.disabled,r&&(h=t(i).closest("fieldset")[0],h&&(r=!h.disabled))):r="a"===l?i.href||s:s,r&&t(i).is(":visible")&&e(t(i)))},t.extend(t.expr[":"],{focusable:function(e){return t.ui.focusable(e,null!=t.attr(e,"tabindex"))}}),t.ui.focusable,t.fn.form=function(){return"string"==typeof this[0].form?this.closest("form"):t(this[0].form)},t.ui.formResetMixin={_formResetHandler:function(){var e=t(this);setTimeout(function(){var i=e.data("ui-form-reset-instances");t.each(i,function(){this.refresh()})})},_bindFormResetHandler:function(){if(this.form=this.element.form(),this.form.length){var t=this.form.data("ui-form-reset-instances")||[];t.length||this.form.on("reset.ui-form-reset",this._formResetHandler),t.push(this),this.form.data("ui-form-reset-instances",t)}},_unbindFormResetHandler:function(){if(this.form.length){var e=this.form.data("ui-form-reset-instances");e.splice(t.inArray(this,e),1),e.length?this.form.data("ui-form-reset-instances",e):this.form.removeData("ui-form-reset-instances").off("reset.ui-form-reset")}}},"1.7"===t.fn.jquery.substring(0,3)&&(t.each(["Width","Height"],function(e,i){function s(e,i,s,o){return t.each(n,function(){i-=parseFloat(t.css(e,"padding"+this))||0,s&&(i-=parseFloat(t.css(e,"border"+this+"Width"))||0),o&&(i-=parseFloat(t.css(e,"margin"+this))||0)}),i}var n="Width"===i?["Left","Right"]:["Top","Bottom"],o=i.toLowerCase(),a={innerWidth:t.fn.innerWidth,innerHeight:t.fn.innerHeight,outerWidth:t.fn.outerWidth,outerHeight:t.fn.outerHeight};t.fn["inner"+i]=function(e){return void 0===e?a["inner"+i].call(this):this.each(function(){t(this).css(o,s(this,e)+"px")})},t.fn["outer"+i]=function(e,n){return"number"!=typeof e?a["outer"+i].call(this,e):this.each(function(){t(this).css(o,s(this,e,!0,n)+"px")})}}),t.fn.addBack=function(t){return this.add(null==t?this.prevObject:this.prevObject.filter(t))}),t.ui.keyCode={BACKSPACE:8,COMMA:188,DELETE:46,DOWN:40,END:35,ENTER:13,ESCAPE:27,HOME:36,LEFT:37,PAGE_DOWN:34,PAGE_UP:33,PERIOD:190,RIGHT:39,SPACE:32,TAB:9,UP:38},t.ui.escapeSelector=function(){var t=/([!"#$%&'()*+,./:;<=>?@[\]^`{|}~])/g;return function(e){return e.replace(t,"\\$1")}}(),t.fn.labels=function(){var e,i,s,n,o;return this[0].labels&&this[0].labels.length?this.pushStack(this[0].labels):(n=this.eq(0).parents("label"),s=this.attr("id"),s&&(e=this.eq(0).parents().last(),o=e.add(e.length?e.siblings():this.siblings()),i="label[for='"+t.ui.escapeSelector(s)+"']",n=n.add(o.find(i).addBack(i))),this.pushStack(n))},t.fn.scrollParent=function(e){var i=this.css("position"),s="absolute"===i,n=e?/(auto|scroll|hidden)/:/(auto|scroll)/,o=this.parents().filter(function(){var e=t(this);return s&&"static"===e.css("position")?!1:n.test(e.css("overflow")+e.css("overflow-y")+e.css("overflow-x"))}).eq(0);return"fixed"!==i&&o.length?o:t(this[0].ownerDocument||document)},t.extend(t.expr[":"],{tabbable:function(e){var i=t.attr(e,"tabindex"),s=null!=i;return(!s||i>=0)&&t.ui.focusable(e,s)}}),t.fn.extend({uniqueId:function(){var t=0;return function(){return this.each(function(){this.id||(this.id="ui-id-"+ ++t)})}}(),removeUniqueId:function(){return this.each(function(){/^ui-id-\d+$/.test(this.id)&&t(this).removeAttr("id")})}}),t.ui.ie=!!/msie [\w.]+/.exec(navigator.userAgent.toLowerCase());var n=!1;t(document).on("mouseup",function(){n=!1}),t.widget("ui.mouse",{version:"1.12.1",options:{cancel:"input, textarea, button, select, option",distance:1,delay:0},_mouseInit:function(){var e=this;this.element.on("mousedown."+this.widgetName,function(t){return e._mouseDown(t)}).on("click."+this.widgetName,function(i){return!0===t.data(i.target,e.widgetName+".preventClickEvent")?(t.removeData(i.target,e.widgetName+".preventClickEvent"),i.stopImmediatePropagation(),!1):void 0}),this.started=!1},_mouseDestroy:function(){this.element.off("."+this.widgetName),this._mouseMoveDelegate&&this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate)},_mouseDown:function(e){if(!n){this._mouseMoved=!1,this._mouseStarted&&this._mouseUp(e),this._mouseDownEvent=e;var i=this,s=1===e.which,o="string"==typeof this.options.cancel&&e.target.nodeName?t(e.target).closest(this.options.cancel).length:!1;return s&&!o&&this._mouseCapture(e)?(this.mouseDelayMet=!this.options.delay,this.mouseDelayMet||(this._mouseDelayTimer=setTimeout(function(){i.mouseDelayMet=!0},this.options.delay)),this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(e)!==!1,!this._mouseStarted)?(e.preventDefault(),!0):(!0===t.data(e.target,this.widgetName+".preventClickEvent")&&t.removeData(e.target,this.widgetName+".preventClickEvent"),this._mouseMoveDelegate=function(t){return i._mouseMove(t)},this._mouseUpDelegate=function(t){return i._mouseUp(t)},this.document.on("mousemove."+this.widgetName,this._mouseMoveDelegate).on("mouseup."+this.widgetName,this._mouseUpDelegate),e.preventDefault(),n=!0,!0)):!0}},_mouseMove:function(e){if(this._mouseMoved){if(t.ui.ie&&(!document.documentMode||9>document.documentMode)&&!e.button)return this._mouseUp(e);if(!e.which)if(e.originalEvent.altKey||e.originalEvent.ctrlKey||e.originalEvent.metaKey||e.originalEvent.shiftKey)this.ignoreMissingWhich=!0;else if(!this.ignoreMissingWhich)return this._mouseUp(e)}return(e.which||e.button)&&(this._mouseMoved=!0),this._mouseStarted?(this._mouseDrag(e),e.preventDefault()):(this._mouseDistanceMet(e)&&this._mouseDelayMet(e)&&(this._mouseStarted=this._mouseStart(this._mouseDownEvent,e)!==!1,this._mouseStarted?this._mouseDrag(e):this._mouseUp(e)),!this._mouseStarted)},_mouseUp:function(e){this.document.off("mousemove."+this.widgetName,this._mouseMoveDelegate).off("mouseup."+this.widgetName,this._mouseUpDelegate),this._mouseStarted&&(this._mouseStarted=!1,e.target===this._mouseDownEvent.target&&t.data(e.target,this.widgetName+".preventClickEvent",!0),this._mouseStop(e)),this._mouseDelayTimer&&(clearTimeout(this._mouseDelayTimer),delete this._mouseDelayTimer),this.ignoreMissingWhich=!1,n=!1,e.preventDefault()},_mouseDistanceMet:function(t){return Math.max(Math.abs(this._mouseDownEvent.pageX-t.pageX),Math.abs(this._mouseDownEvent.pageY-t.pageY))>=this.options.distance},_mouseDelayMet:function(){return this.mouseDelayMet},_mouseStart:function(){},_mouseDrag:function(){},_mouseStop:function(){},_mouseCapture:function(){return!0}}),t.ui.plugin={add:function(e,i,s){var n,o=t.ui[e].prototype;for(n in s)o.plugins[n]=o.plugins[n]||[],o.plugins[n].push([i,s[n]])},call:function(t,e,i,s){var n,o=t.plugins[e];if(o&&(s||t.element[0].parentNode&&11!==t.element[0].parentNode.nodeType))for(n=0;o.length>n;n++)t.options[o[n][0]]&&o[n][1].apply(t.element,i)}},t.widget("ui.resizable",t.ui.mouse,{version:"1.12.1",widgetEventPrefix:"resize",options:{alsoResize:!1,animate:!1,animateDuration:"slow",animateEasing:"swing",aspectRatio:!1,autoHide:!1,classes:{"ui-resizable-se":"ui-icon ui-icon-gripsmall-diagonal-se"},containment:!1,ghost:!1,grid:!1,handles:"e,s,se",helper:!1,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:90,resize:null,start:null,stop:null},_num:function(t){return parseFloat(t)||0},_isNumber:function(t){return!isNaN(parseFloat(t))},_hasScroll:function(e,i){if("hidden"===t(e).css("overflow"))return!1;var s=i&&"left"===i?"scrollLeft":"scrollTop",n=!1;return e[s]>0?!0:(e[s]=1,n=e[s]>0,e[s]=0,n)},_create:function(){var e,i=this.options,s=this;this._addClass("ui-resizable"),t.extend(this,{_aspectRatio:!!i.aspectRatio,aspectRatio:i.aspectRatio,originalElement:this.element,_proportionallyResizeElements:[],_helper:i.helper||i.ghost||i.animate?i.helper||"ui-resizable-helper":null}),this.element[0].nodeName.match(/^(canvas|textarea|input|select|button|img)$/i)&&(this.element.wrap(t("
").css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),top:this.element.css("top"),left:this.element.css("left")})),this.element=this.element.parent().data("ui-resizable",this.element.resizable("instance")),this.elementIsWrapper=!0,e={marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom"),marginLeft:this.originalElement.css("marginLeft")},this.element.css(e),this.originalElement.css("margin",0),this.originalResizeStyle=this.originalElement.css("resize"),this.originalElement.css("resize","none"),this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"})),this.originalElement.css(e),this._proportionallyResize()),this._setupHandles(),i.autoHide&&t(this.element).on("mouseenter",function(){i.disabled||(s._removeClass("ui-resizable-autohide"),s._handles.show())}).on("mouseleave",function(){i.disabled||s.resizing||(s._addClass("ui-resizable-autohide"),s._handles.hide())}),this._mouseInit()},_destroy:function(){this._mouseDestroy();var e,i=function(e){t(e).removeData("resizable").removeData("ui-resizable").off(".resizable").find(".ui-resizable-handle").remove()};return this.elementIsWrapper&&(i(this.element),e=this.element,this.originalElement.css({position:e.css("position"),width:e.outerWidth(),height:e.outerHeight(),top:e.css("top"),left:e.css("left")}).insertAfter(e),e.remove()),this.originalElement.css("resize",this.originalResizeStyle),i(this.originalElement),this},_setOption:function(t,e){switch(this._super(t,e),t){case"handles":this._removeHandles(),this._setupHandles();break;default:}},_setupHandles:function(){var e,i,s,n,o,a=this.options,r=this;if(this.handles=a.handles||(t(".ui-resizable-handle",this.element).length?{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",nw:".ui-resizable-nw"}:"e,s,se"),this._handles=t(),this.handles.constructor===String)for("all"===this.handles&&(this.handles="n,e,s,w,se,sw,ne,nw"),s=this.handles.split(","),this.handles={},i=0;s.length>i;i++)e=t.trim(s[i]),n="ui-resizable-"+e,o=t("
"),this._addClass(o,"ui-resizable-handle "+n),o.css({zIndex:a.zIndex}),this.handles[e]=".ui-resizable-"+e,this.element.append(o);this._renderAxis=function(e){var i,s,n,o;e=e||this.element;for(i in this.handles)this.handles[i].constructor===String?this.handles[i]=this.element.children(this.handles[i]).first().show():(this.handles[i].jquery||this.handles[i].nodeType)&&(this.handles[i]=t(this.handles[i]),this._on(this.handles[i],{mousedown:r._mouseDown})),this.elementIsWrapper&&this.originalElement[0].nodeName.match(/^(textarea|input|select|button)$/i)&&(s=t(this.handles[i],this.element),o=/sw|ne|nw|se|n|s/.test(i)?s.outerHeight():s.outerWidth(),n=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join(""),e.css(n,o),this._proportionallyResize()),this._handles=this._handles.add(this.handles[i])},this._renderAxis(this.element),this._handles=this._handles.add(this.element.find(".ui-resizable-handle")),this._handles.disableSelection(),this._handles.on("mouseover",function(){r.resizing||(this.className&&(o=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i)),r.axis=o&&o[1]?o[1]:"se")}),a.autoHide&&(this._handles.hide(),this._addClass("ui-resizable-autohide"))},_removeHandles:function(){this._handles.remove()},_mouseCapture:function(e){var i,s,n=!1;for(i in this.handles)s=t(this.handles[i])[0],(s===e.target||t.contains(s,e.target))&&(n=!0);return!this.options.disabled&&n},_mouseStart:function(e){var i,s,n,o=this.options,a=this.element;return this.resizing=!0,this._renderProxy(),i=this._num(this.helper.css("left")),s=this._num(this.helper.css("top")),o.containment&&(i+=t(o.containment).scrollLeft()||0,s+=t(o.containment).scrollTop()||0),this.offset=this.helper.offset(),this.position={left:i,top:s},this.size=this._helper?{width:this.helper.width(),height:this.helper.height()}:{width:a.width(),height:a.height()},this.originalSize=this._helper?{width:a.outerWidth(),height:a.outerHeight()}:{width:a.width(),height:a.height()},this.sizeDiff={width:a.outerWidth()-a.width(),height:a.outerHeight()-a.height()},this.originalPosition={left:i,top:s},this.originalMousePosition={left:e.pageX,top:e.pageY},this.aspectRatio="number"==typeof o.aspectRatio?o.aspectRatio:this.originalSize.width/this.originalSize.height||1,n=t(".ui-resizable-"+this.axis).css("cursor"),t("body").css("cursor","auto"===n?this.axis+"-resize":n),this._addClass("ui-resizable-resizing"),this._propagate("start",e),!0},_mouseDrag:function(e){var i,s,n=this.originalMousePosition,o=this.axis,a=e.pageX-n.left||0,r=e.pageY-n.top||0,h=this._change[o];return this._updatePrevProperties(),h?(i=h.apply(this,[e,a,r]),this._updateVirtualBoundaries(e.shiftKey),(this._aspectRatio||e.shiftKey)&&(i=this._updateRatio(i,e)),i=this._respectSize(i,e),this._updateCache(i),this._propagate("resize",e),s=this._applyChanges(),!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize(),t.isEmptyObject(s)||(this._updatePrevProperties(),this._trigger("resize",e,this.ui()),this._applyChanges()),!1):!1},_mouseStop:function(e){this.resizing=!1;var i,s,n,o,a,r,h,l=this.options,c=this;return this._helper&&(i=this._proportionallyResizeElements,s=i.length&&/textarea/i.test(i[0].nodeName),n=s&&this._hasScroll(i[0],"left")?0:c.sizeDiff.height,o=s?0:c.sizeDiff.width,a={width:c.helper.width()-o,height:c.helper.height()-n},r=parseFloat(c.element.css("left"))+(c.position.left-c.originalPosition.left)||null,h=parseFloat(c.element.css("top"))+(c.position.top-c.originalPosition.top)||null,l.animate||this.element.css(t.extend(a,{top:h,left:r})),c.helper.height(c.size.height),c.helper.width(c.size.width),this._helper&&!l.animate&&this._proportionallyResize()),t("body").css("cursor","auto"),this._removeClass("ui-resizable-resizing"),this._propagate("stop",e),this._helper&&this.helper.remove(),!1},_updatePrevProperties:function(){this.prevPosition={top:this.position.top,left:this.position.left},this.prevSize={width:this.size.width,height:this.size.height}},_applyChanges:function(){var t={};return this.position.top!==this.prevPosition.top&&(t.top=this.position.top+"px"),this.position.left!==this.prevPosition.left&&(t.left=this.position.left+"px"),this.size.width!==this.prevSize.width&&(t.width=this.size.width+"px"),this.size.height!==this.prevSize.height&&(t.height=this.size.height+"px"),this.helper.css(t),t},_updateVirtualBoundaries:function(t){var e,i,s,n,o,a=this.options;o={minWidth:this._isNumber(a.minWidth)?a.minWidth:0,maxWidth:this._isNumber(a.maxWidth)?a.maxWidth:1/0,minHeight:this._isNumber(a.minHeight)?a.minHeight:0,maxHeight:this._isNumber(a.maxHeight)?a.maxHeight:1/0},(this._aspectRatio||t)&&(e=o.minHeight*this.aspectRatio,s=o.minWidth/this.aspectRatio,i=o.maxHeight*this.aspectRatio,n=o.maxWidth/this.aspectRatio,e>o.minWidth&&(o.minWidth=e),s>o.minHeight&&(o.minHeight=s),o.maxWidth>i&&(o.maxWidth=i),o.maxHeight>n&&(o.maxHeight=n)),this._vBoundaries=o},_updateCache:function(t){this.offset=this.helper.offset(),this._isNumber(t.left)&&(this.position.left=t.left),this._isNumber(t.top)&&(this.position.top=t.top),this._isNumber(t.height)&&(this.size.height=t.height),this._isNumber(t.width)&&(this.size.width=t.width)},_updateRatio:function(t){var e=this.position,i=this.size,s=this.axis;return this._isNumber(t.height)?t.width=t.height*this.aspectRatio:this._isNumber(t.width)&&(t.height=t.width/this.aspectRatio),"sw"===s&&(t.left=e.left+(i.width-t.width),t.top=null),"nw"===s&&(t.top=e.top+(i.height-t.height),t.left=e.left+(i.width-t.width)),t},_respectSize:function(t){var e=this._vBoundaries,i=this.axis,s=this._isNumber(t.width)&&e.maxWidth&&e.maxWidtht.width,a=this._isNumber(t.height)&&e.minHeight&&e.minHeight>t.height,r=this.originalPosition.left+this.originalSize.width,h=this.originalPosition.top+this.originalSize.height,l=/sw|nw|w/.test(i),c=/nw|ne|n/.test(i);return o&&(t.width=e.minWidth),a&&(t.height=e.minHeight),s&&(t.width=e.maxWidth),n&&(t.height=e.maxHeight),o&&l&&(t.left=r-e.minWidth),s&&l&&(t.left=r-e.maxWidth),a&&c&&(t.top=h-e.minHeight),n&&c&&(t.top=h-e.maxHeight),t.width||t.height||t.left||!t.top?t.width||t.height||t.top||!t.left||(t.left=null):t.top=null,t},_getPaddingPlusBorderDimensions:function(t){for(var e=0,i=[],s=[t.css("borderTopWidth"),t.css("borderRightWidth"),t.css("borderBottomWidth"),t.css("borderLeftWidth")],n=[t.css("paddingTop"),t.css("paddingRight"),t.css("paddingBottom"),t.css("paddingLeft")];4>e;e++)i[e]=parseFloat(s[e])||0,i[e]+=parseFloat(n[e])||0;return{height:i[0]+i[2],width:i[1]+i[3]}},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var t,e=0,i=this.helper||this.element;this._proportionallyResizeElements.length>e;e++)t=this._proportionallyResizeElements[e],this.outerDimensions||(this.outerDimensions=this._getPaddingPlusBorderDimensions(t)),t.css({height:i.height()-this.outerDimensions.height||0,width:i.width()-this.outerDimensions.width||0})},_renderProxy:function(){var e=this.element,i=this.options;this.elementOffset=e.offset(),this._helper?(this.helper=this.helper||t("
"),this._addClass(this.helper,this._helper),this.helper.css({width:this.element.outerWidth(),height:this.element.outerHeight(),position:"absolute",left:this.elementOffset.left+"px",top:this.elementOffset.top+"px",zIndex:++i.zIndex}),this.helper.appendTo("body").disableSelection()):this.helper=this.element +},_change:{e:function(t,e){return{width:this.originalSize.width+e}},w:function(t,e){var i=this.originalSize,s=this.originalPosition;return{left:s.left+e,width:i.width-e}},n:function(t,e,i){var s=this.originalSize,n=this.originalPosition;return{top:n.top+i,height:s.height-i}},s:function(t,e,i){return{height:this.originalSize.height+i}},se:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},sw:function(e,i,s){return t.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[e,i,s]))},ne:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.e.apply(this,[e,i,s]))},nw:function(e,i,s){return t.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[e,i,s]))}},_propagate:function(e,i){t.ui.plugin.call(this,e,[i,this.ui()]),"resize"!==e&&this._trigger(e,i,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}}),t.ui.plugin.add("resizable","animate",{stop:function(e){var i=t(this).resizable("instance"),s=i.options,n=i._proportionallyResizeElements,o=n.length&&/textarea/i.test(n[0].nodeName),a=o&&i._hasScroll(n[0],"left")?0:i.sizeDiff.height,r=o?0:i.sizeDiff.width,h={width:i.size.width-r,height:i.size.height-a},l=parseFloat(i.element.css("left"))+(i.position.left-i.originalPosition.left)||null,c=parseFloat(i.element.css("top"))+(i.position.top-i.originalPosition.top)||null;i.element.animate(t.extend(h,c&&l?{top:c,left:l}:{}),{duration:s.animateDuration,easing:s.animateEasing,step:function(){var s={width:parseFloat(i.element.css("width")),height:parseFloat(i.element.css("height")),top:parseFloat(i.element.css("top")),left:parseFloat(i.element.css("left"))};n&&n.length&&t(n[0]).css({width:s.width,height:s.height}),i._updateCache(s),i._propagate("resize",e)}})}}),t.ui.plugin.add("resizable","containment",{start:function(){var e,i,s,n,o,a,r,h=t(this).resizable("instance"),l=h.options,c=h.element,u=l.containment,d=u instanceof t?u.get(0):/parent/.test(u)?c.parent().get(0):u;d&&(h.containerElement=t(d),/document/.test(u)||u===document?(h.containerOffset={left:0,top:0},h.containerPosition={left:0,top:0},h.parentData={element:t(document),left:0,top:0,width:t(document).width(),height:t(document).height()||document.body.parentNode.scrollHeight}):(e=t(d),i=[],t(["Top","Right","Left","Bottom"]).each(function(t,s){i[t]=h._num(e.css("padding"+s))}),h.containerOffset=e.offset(),h.containerPosition=e.position(),h.containerSize={height:e.innerHeight()-i[3],width:e.innerWidth()-i[1]},s=h.containerOffset,n=h.containerSize.height,o=h.containerSize.width,a=h._hasScroll(d,"left")?d.scrollWidth:o,r=h._hasScroll(d)?d.scrollHeight:n,h.parentData={element:d,left:s.left,top:s.top,width:a,height:r}))},resize:function(e){var i,s,n,o,a=t(this).resizable("instance"),r=a.options,h=a.containerOffset,l=a.position,c=a._aspectRatio||e.shiftKey,u={top:0,left:0},d=a.containerElement,p=!0;d[0]!==document&&/static/.test(d.css("position"))&&(u=h),l.left<(a._helper?h.left:0)&&(a.size.width=a.size.width+(a._helper?a.position.left-h.left:a.position.left-u.left),c&&(a.size.height=a.size.width/a.aspectRatio,p=!1),a.position.left=r.helper?h.left:0),l.top<(a._helper?h.top:0)&&(a.size.height=a.size.height+(a._helper?a.position.top-h.top:a.position.top),c&&(a.size.width=a.size.height*a.aspectRatio,p=!1),a.position.top=a._helper?h.top:0),n=a.containerElement.get(0)===a.element.parent().get(0),o=/relative|absolute/.test(a.containerElement.css("position")),n&&o?(a.offset.left=a.parentData.left+a.position.left,a.offset.top=a.parentData.top+a.position.top):(a.offset.left=a.element.offset().left,a.offset.top=a.element.offset().top),i=Math.abs(a.sizeDiff.width+(a._helper?a.offset.left-u.left:a.offset.left-h.left)),s=Math.abs(a.sizeDiff.height+(a._helper?a.offset.top-u.top:a.offset.top-h.top)),i+a.size.width>=a.parentData.width&&(a.size.width=a.parentData.width-i,c&&(a.size.height=a.size.width/a.aspectRatio,p=!1)),s+a.size.height>=a.parentData.height&&(a.size.height=a.parentData.height-s,c&&(a.size.width=a.size.height*a.aspectRatio,p=!1)),p||(a.position.left=a.prevPosition.left,a.position.top=a.prevPosition.top,a.size.width=a.prevSize.width,a.size.height=a.prevSize.height)},stop:function(){var e=t(this).resizable("instance"),i=e.options,s=e.containerOffset,n=e.containerPosition,o=e.containerElement,a=t(e.helper),r=a.offset(),h=a.outerWidth()-e.sizeDiff.width,l=a.outerHeight()-e.sizeDiff.height;e._helper&&!i.animate&&/relative/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l}),e._helper&&!i.animate&&/static/.test(o.css("position"))&&t(this).css({left:r.left-n.left-s.left,width:h,height:l})}}),t.ui.plugin.add("resizable","alsoResize",{start:function(){var e=t(this).resizable("instance"),i=e.options;t(i.alsoResize).each(function(){var e=t(this);e.data("ui-resizable-alsoresize",{width:parseFloat(e.width()),height:parseFloat(e.height()),left:parseFloat(e.css("left")),top:parseFloat(e.css("top"))})})},resize:function(e,i){var s=t(this).resizable("instance"),n=s.options,o=s.originalSize,a=s.originalPosition,r={height:s.size.height-o.height||0,width:s.size.width-o.width||0,top:s.position.top-a.top||0,left:s.position.left-a.left||0};t(n.alsoResize).each(function(){var e=t(this),s=t(this).data("ui-resizable-alsoresize"),n={},o=e.parents(i.originalElement[0]).length?["width","height"]:["width","height","top","left"];t.each(o,function(t,e){var i=(s[e]||0)+(r[e]||0);i&&i>=0&&(n[e]=i||null)}),e.css(n)})},stop:function(){t(this).removeData("ui-resizable-alsoresize")}}),t.ui.plugin.add("resizable","ghost",{start:function(){var e=t(this).resizable("instance"),i=e.size;e.ghost=e.originalElement.clone(),e.ghost.css({opacity:.25,display:"block",position:"relative",height:i.height,width:i.width,margin:0,left:0,top:0}),e._addClass(e.ghost,"ui-resizable-ghost"),t.uiBackCompat!==!1&&"string"==typeof e.options.ghost&&e.ghost.addClass(this.options.ghost),e.ghost.appendTo(e.helper)},resize:function(){var e=t(this).resizable("instance");e.ghost&&e.ghost.css({position:"relative",height:e.size.height,width:e.size.width})},stop:function(){var e=t(this).resizable("instance");e.ghost&&e.helper&&e.helper.get(0).removeChild(e.ghost.get(0))}}),t.ui.plugin.add("resizable","grid",{resize:function(){var e,i=t(this).resizable("instance"),s=i.options,n=i.size,o=i.originalSize,a=i.originalPosition,r=i.axis,h="number"==typeof s.grid?[s.grid,s.grid]:s.grid,l=h[0]||1,c=h[1]||1,u=Math.round((n.width-o.width)/l)*l,d=Math.round((n.height-o.height)/c)*c,p=o.width+u,f=o.height+d,m=s.maxWidth&&p>s.maxWidth,g=s.maxHeight&&f>s.maxHeight,_=s.minWidth&&s.minWidth>p,v=s.minHeight&&s.minHeight>f;s.grid=h,_&&(p+=l),v&&(f+=c),m&&(p-=l),g&&(f-=c),/^(se|s|e)$/.test(r)?(i.size.width=p,i.size.height=f):/^(ne)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.top=a.top-d):/^(sw)$/.test(r)?(i.size.width=p,i.size.height=f,i.position.left=a.left-u):((0>=f-c||0>=p-l)&&(e=i._getPaddingPlusBorderDimensions(this)),f-c>0?(i.size.height=f,i.position.top=a.top-d):(f=c-e.height,i.size.height=f,i.position.top=a.top+o.height-f),p-l>0?(i.size.width=p,i.position.left=a.left-u):(p=l-e.width,i.size.width=p,i.position.left=a.left+o.width-p))}}),t.ui.resizable});/** + * Copyright (c) 2007 Ariel Flesler - aflesler ○ gmail • com | https://github.com/flesler + * Licensed under MIT + * @author Ariel Flesler + * @version 2.1.2 + */ +;(function(f){"use strict";"function"===typeof define&&define.amd?define(["jquery"],f):"undefined"!==typeof module&&module.exports?module.exports=f(require("jquery")):f(jQuery)})(function($){"use strict";function n(a){return!a.nodeName||-1!==$.inArray(a.nodeName.toLowerCase(),["iframe","#document","html","body"])}function h(a){return $.isFunction(a)||$.isPlainObject(a)?a:{top:a,left:a}}var p=$.scrollTo=function(a,d,b){return $(window).scrollTo(a,d,b)};p.defaults={axis:"xy",duration:0,limit:!0};$.fn.scrollTo=function(a,d,b){"object"=== typeof d&&(b=d,d=0);"function"===typeof b&&(b={onAfter:b});"max"===a&&(a=9E9);b=$.extend({},p.defaults,b);d=d||b.duration;var u=b.queue&&1=f[g]?0:Math.min(f[g],n));!a&&1-1){targetElements.on(evt+EVENT_NAMESPACE,function elementToggle(event){$.powerTip.toggle(this,event)})}else{targetElements.on(evt+EVENT_NAMESPACE,function elementOpen(event){$.powerTip.show(this,event)})}});$.each(options.closeEvents,function(idx,evt){if($.inArray(evt,options.openEvents)<0){targetElements.on(evt+EVENT_NAMESPACE,function elementClose(event){$.powerTip.hide(this,!isMouseEvent(event))})}});targetElements.on("keydown"+EVENT_NAMESPACE,function elementKeyDown(event){if(event.keyCode===27){$.powerTip.hide(this,true)}})}return targetElements};$.fn.powerTip.defaults={fadeInTime:200,fadeOutTime:100,followMouse:false,popupId:"powerTip",popupClass:null,intentSensitivity:7,intentPollInterval:100,closeDelay:100,placement:"n",smartPlacement:false,offset:10,mouseOnToPopup:false,manual:false,openEvents:["mouseenter","focus"],closeEvents:["mouseleave","blur"]};$.fn.powerTip.smartPlacementLists={n:["n","ne","nw","s"],e:["e","ne","se","w","nw","sw","n","s","e"],s:["s","se","sw","n"],w:["w","nw","sw","e","ne","se","n","s","w"],nw:["nw","w","sw","n","s","se","nw"],ne:["ne","e","se","n","s","sw","ne"],sw:["sw","w","nw","s","n","ne","sw"],se:["se","e","ne","s","n","nw","se"],"nw-alt":["nw-alt","n","ne-alt","sw-alt","s","se-alt","w","e"],"ne-alt":["ne-alt","n","nw-alt","se-alt","s","sw-alt","e","w"],"sw-alt":["sw-alt","s","se-alt","nw-alt","n","ne-alt","w","e"],"se-alt":["se-alt","s","sw-alt","ne-alt","n","nw-alt","e","w"]};$.powerTip={show:function apiShowTip(element,event){if(isMouseEvent(event)){trackMouse(event);session.previousX=event.pageX;session.previousY=event.pageY;$(element).data(DATA_DISPLAYCONTROLLER).show()}else{$(element).first().data(DATA_DISPLAYCONTROLLER).show(true,true)}return element},reposition:function apiResetPosition(element){$(element).first().data(DATA_DISPLAYCONTROLLER).resetPosition();return element},hide:function apiCloseTip(element,immediate){var displayController;immediate=element?immediate:true;if(element){displayController=$(element).first().data(DATA_DISPLAYCONTROLLER)}else if(session.activeHover){displayController=session.activeHover.data(DATA_DISPLAYCONTROLLER)}if(displayController){displayController.hide(immediate)}return element},toggle:function apiToggle(element,event){if(session.activeHover&&session.activeHover.is(element)){$.powerTip.hide(element,!isMouseEvent(event))}else{$.powerTip.show(element,event)}return element}};$.powerTip.showTip=$.powerTip.show;$.powerTip.closeTip=$.powerTip.hide;function CSSCoordinates(){var me=this;me.top="auto";me.left="auto";me.right="auto";me.bottom="auto";me.set=function(property,value){if($.isNumeric(value)){me[property]=Math.round(value)}}}function DisplayController(element,options,tipController){var hoverTimer=null,myCloseDelay=null;function openTooltip(immediate,forceOpen){cancelTimer();if(!element.data(DATA_HASACTIVEHOVER)){if(!immediate){session.tipOpenImminent=true;hoverTimer=setTimeout(function intentDelay(){hoverTimer=null;checkForIntent()},options.intentPollInterval)}else{if(forceOpen){element.data(DATA_FORCEDOPEN,true)}closeAnyDelayed();tipController.showTip(element)}}else{cancelClose()}}function closeTooltip(disableDelay){if(myCloseDelay){myCloseDelay=session.closeDelayTimeout=clearTimeout(myCloseDelay);session.delayInProgress=false}cancelTimer();session.tipOpenImminent=false;if(element.data(DATA_HASACTIVEHOVER)){element.data(DATA_FORCEDOPEN,false);if(!disableDelay){session.delayInProgress=true;session.closeDelayTimeout=setTimeout(function closeDelay(){session.closeDelayTimeout=null;tipController.hideTip(element);session.delayInProgress=false;myCloseDelay=null},options.closeDelay);myCloseDelay=session.closeDelayTimeout}else{tipController.hideTip(element)}}}function checkForIntent(){var xDifference=Math.abs(session.previousX-session.currentX),yDifference=Math.abs(session.previousY-session.currentY),totalDifference=xDifference+yDifference;if(totalDifference",{id:options.popupId});if($body.length===0){$body=$("body")}$body.append(tipElement);session.tooltips=session.tooltips?session.tooltips.add(tipElement):tipElement}if(options.followMouse){if(!tipElement.data(DATA_HASMOUSEMOVE)){$document.on("mousemove"+EVENT_NAMESPACE,positionTipOnCursor);$window.on("scroll"+EVENT_NAMESPACE,positionTipOnCursor);tipElement.data(DATA_HASMOUSEMOVE,true)}}function beginShowTip(element){element.data(DATA_HASACTIVEHOVER,true);tipElement.queue(function queueTipInit(next){showTip(element);next()})}function showTip(element){var tipContent;if(!element.data(DATA_HASACTIVEHOVER)){return}if(session.isTipOpen){if(!session.isClosing){hideTip(session.activeHover)}tipElement.delay(100).queue(function queueTipAgain(next){showTip(element);next()});return}element.trigger("powerTipPreRender");tipContent=getTooltipContent(element);if(tipContent){tipElement.empty().append(tipContent)}else{return}element.trigger("powerTipRender");session.activeHover=element;session.isTipOpen=true;tipElement.data(DATA_MOUSEONTOTIP,options.mouseOnToPopup);tipElement.addClass(options.popupClass);if(!options.followMouse||element.data(DATA_FORCEDOPEN)){positionTipOnElement(element);session.isFixedTipOpen=true}else{positionTipOnCursor()}if(!element.data(DATA_FORCEDOPEN)&&!options.followMouse){$document.on("click"+EVENT_NAMESPACE,function documentClick(event){var target=event.target;if(target!==element[0]){if(options.mouseOnToPopup){if(target!==tipElement[0]&&!$.contains(tipElement[0],target)){$.powerTip.hide()}}else{$.powerTip.hide()}}})}if(options.mouseOnToPopup&&!options.manual){tipElement.on("mouseenter"+EVENT_NAMESPACE,function tipMouseEnter(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).cancel()}});tipElement.on("mouseleave"+EVENT_NAMESPACE,function tipMouseLeave(){if(session.activeHover){session.activeHover.data(DATA_DISPLAYCONTROLLER).hide()}})}tipElement.fadeIn(options.fadeInTime,function fadeInCallback(){if(!session.desyncTimeout){session.desyncTimeout=setInterval(closeDesyncedTip,500)}element.trigger("powerTipOpen")})}function hideTip(element){session.isClosing=true;session.isTipOpen=false;session.desyncTimeout=clearInterval(session.desyncTimeout);element.data(DATA_HASACTIVEHOVER,false);element.data(DATA_FORCEDOPEN,false);$document.off("click"+EVENT_NAMESPACE);tipElement.off(EVENT_NAMESPACE);tipElement.fadeOut(options.fadeOutTime,function fadeOutCallback(){var coords=new CSSCoordinates;session.activeHover=null;session.isClosing=false;session.isFixedTipOpen=false;tipElement.removeClass();coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);tipElement.css(coords);element.trigger("powerTipClose")})}function positionTipOnCursor(){var tipWidth,tipHeight,coords,collisions,collisionCount;if(!session.isFixedTipOpen&&(session.isTipOpen||session.tipOpenImminent&&tipElement.data(DATA_HASMOUSEMOVE))){tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=new CSSCoordinates;coords.set("top",session.currentY+options.offset);coords.set("left",session.currentX+options.offset);collisions=getViewportCollisions(coords,tipWidth,tipHeight);if(collisions!==Collision.none){collisionCount=countFlags(collisions);if(collisionCount===1){if(collisions===Collision.right){coords.set("left",session.scrollLeft+session.windowWidth-tipWidth)}else if(collisions===Collision.bottom){coords.set("top",session.scrollTop+session.windowHeight-tipHeight)}}else{coords.set("left",session.currentX-tipWidth-options.offset);coords.set("top",session.currentY-tipHeight-options.offset)}}tipElement.css(coords)}}function positionTipOnElement(element){var priorityList,finalPlacement;if(options.smartPlacement||options.followMouse&&element.data(DATA_FORCEDOPEN)){priorityList=$.fn.powerTip.smartPlacementLists[options.placement];$.each(priorityList,function(idx,pos){var collisions=getViewportCollisions(placeTooltip(element,pos),tipElement.outerWidth(),tipElement.outerHeight());finalPlacement=pos;return collisions!==Collision.none})}else{placeTooltip(element,options.placement);finalPlacement=options.placement}tipElement.removeClass("w nw sw e ne se n s w se-alt sw-alt ne-alt nw-alt");tipElement.addClass(finalPlacement)}function placeTooltip(element,placement){var iterationCount=0,tipWidth,tipHeight,coords=new CSSCoordinates;coords.set("top",0);coords.set("left",0);tipElement.css(coords);do{tipWidth=tipElement.outerWidth();tipHeight=tipElement.outerHeight();coords=placementCalculator.compute(element,placement,tipWidth,tipHeight,options.offset);tipElement.css(coords)}while(++iterationCount<=5&&(tipWidth!==tipElement.outerWidth()||tipHeight!==tipElement.outerHeight()));return coords}function closeDesyncedTip(){var isDesynced=false,hasDesyncableCloseEvent=$.grep(["mouseleave","mouseout","blur","focusout"],function(eventType){return $.inArray(eventType,options.closeEvents)!==-1}).length>0;if(session.isTipOpen&&!session.isClosing&&!session.delayInProgress&&hasDesyncableCloseEvent){if(session.activeHover.data(DATA_HASACTIVEHOVER)===false||session.activeHover.is(":disabled")){isDesynced=true}else if(!isMouseOver(session.activeHover)&&!session.activeHover.is(":focus")&&!session.activeHover.data(DATA_FORCEDOPEN)){if(tipElement.data(DATA_MOUSEONTOTIP)){if(!isMouseOver(tipElement)){isDesynced=true}}else{isDesynced=true}}if(isDesynced){hideTip(session.activeHover)}}}this.showTip=beginShowTip;this.hideTip=hideTip;this.resetPosition=positionTipOnElement}function isSvgElement(element){return Boolean(window.SVGElement&&element[0]instanceof SVGElement)}function isMouseEvent(event){return Boolean(event&&$.inArray(event.type,MOUSE_EVENTS)>-1&&typeof event.pageX==="number")}function initTracking(){if(!session.mouseTrackingActive){session.mouseTrackingActive=true;getViewportDimensions();$(getViewportDimensions);$document.on("mousemove"+EVENT_NAMESPACE,trackMouse);$window.on("resize"+EVENT_NAMESPACE,trackResize);$window.on("scroll"+EVENT_NAMESPACE,trackScroll)}}function getViewportDimensions(){session.scrollLeft=$window.scrollLeft();session.scrollTop=$window.scrollTop();session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackResize(){session.windowWidth=$window.width();session.windowHeight=$window.height()}function trackScroll(){var x=$window.scrollLeft(),y=$window.scrollTop();if(x!==session.scrollLeft){session.currentX+=x-session.scrollLeft;session.scrollLeft=x}if(y!==session.scrollTop){session.currentY+=y-session.scrollTop;session.scrollTop=y}}function trackMouse(event){session.currentX=event.pageX;session.currentY=event.pageY}function isMouseOver(element){var elementPosition=element.offset(),elementBox=element[0].getBoundingClientRect(),elementWidth=elementBox.right-elementBox.left,elementHeight=elementBox.bottom-elementBox.top;return session.currentX>=elementPosition.left&&session.currentX<=elementPosition.left+elementWidth&&session.currentY>=elementPosition.top&&session.currentY<=elementPosition.top+elementHeight}function getTooltipContent(element){var tipText=element.data(DATA_POWERTIP),tipObject=element.data(DATA_POWERTIPJQ),tipTarget=element.data(DATA_POWERTIPTARGET),targetElement,content;if(tipText){if($.isFunction(tipText)){tipText=tipText.call(element[0])}content=tipText}else if(tipObject){if($.isFunction(tipObject)){tipObject=tipObject.call(element[0])}if(tipObject.length>0){content=tipObject.clone(true,true)}}else if(tipTarget){targetElement=$("#"+tipTarget);if(targetElement.length>0){content=targetElement.html()}}return content}function getViewportCollisions(coords,elementWidth,elementHeight){var viewportTop=session.scrollTop,viewportLeft=session.scrollLeft,viewportBottom=viewportTop+session.windowHeight,viewportRight=viewportLeft+session.windowWidth,collisions=Collision.none;if(coords.topviewportBottom||Math.abs(coords.bottom-session.windowHeight)>viewportBottom){collisions|=Collision.bottom}if(coords.leftviewportRight){collisions|=Collision.left}if(coords.left+elementWidth>viewportRight||coords.right1)){a.preventDefault();var c=a.originalEvent.changedTouches[0],d=document.createEvent("MouseEvents");d.initMouseEvent(b,!0,!0,window,1,c.screenX,c.screenY,c.clientX,c.clientY,!1,!1,!1,!1,0,null),a.target.dispatchEvent(d)}}if(a.support.touch="ontouchend"in document,a.support.touch){var e,b=a.ui.mouse.prototype,c=b._mouseInit,d=b._mouseDestroy;b._touchStart=function(a){var b=this;!e&&b._mouseCapture(a.originalEvent.changedTouches[0])&&(e=!0,b._touchMoved=!1,f(a,"mouseover"),f(a,"mousemove"),f(a,"mousedown"))},b._touchMove=function(a){e&&(this._touchMoved=!0,f(a,"mousemove"))},b._touchEnd=function(a){e&&(f(a,"mouseup"),f(a,"mouseout"),this._touchMoved||f(a,"click"),e=!1)},b._mouseInit=function(){var b=this;b.element.bind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),c.call(b)},b._mouseDestroy=function(){var b=this;b.element.unbind({touchstart:a.proxy(b,"_touchStart"),touchmove:a.proxy(b,"_touchMove"),touchend:a.proxy(b,"_touchEnd")}),d.call(b)}}}(jQuery);/*! SmartMenus jQuery Plugin - v1.1.0 - September 17, 2017 + * http://www.smartmenus.org/ + * Copyright Vasil Dinkov, Vadikom Web Ltd. http://vadikom.com; Licensed MIT */(function(t){"function"==typeof define&&define.amd?define(["jquery"],t):"object"==typeof module&&"object"==typeof module.exports?module.exports=t(require("jquery")):t(jQuery)})(function($){function initMouseDetection(t){var e=".smartmenus_mouse";if(mouseDetectionEnabled||t)mouseDetectionEnabled&&t&&($(document).off(e),mouseDetectionEnabled=!1);else{var i=!0,s=null,o={mousemove:function(t){var e={x:t.pageX,y:t.pageY,timeStamp:(new Date).getTime()};if(s){var o=Math.abs(s.x-e.x),a=Math.abs(s.y-e.y);if((o>0||a>0)&&2>=o&&2>=a&&300>=e.timeStamp-s.timeStamp&&(mouse=!0,i)){var n=$(t.target).closest("a");n.is("a")&&$.each(menuTrees,function(){return $.contains(this.$root[0],n[0])?(this.itemEnter({currentTarget:n[0]}),!1):void 0}),i=!1}}s=e}};o[touchEvents?"touchstart":"pointerover pointermove pointerout MSPointerOver MSPointerMove MSPointerOut"]=function(t){isTouchEvent(t.originalEvent)&&(mouse=!1)},$(document).on(getEventsNS(o,e)),mouseDetectionEnabled=!0}}function isTouchEvent(t){return!/^(4|mouse)$/.test(t.pointerType)}function getEventsNS(t,e){e||(e="");var i={};for(var s in t)i[s.split(" ").join(e+" ")+e]=t[s];return i}var menuTrees=[],mouse=!1,touchEvents="ontouchstart"in window,mouseDetectionEnabled=!1,requestAnimationFrame=window.requestAnimationFrame||function(t){return setTimeout(t,1e3/60)},cancelAnimationFrame=window.cancelAnimationFrame||function(t){clearTimeout(t)},canAnimate=!!$.fn.animate;return $.SmartMenus=function(t,e){this.$root=$(t),this.opts=e,this.rootId="",this.accessIdPrefix="",this.$subArrow=null,this.activatedItems=[],this.visibleSubMenus=[],this.showTimeout=0,this.hideTimeout=0,this.scrollTimeout=0,this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.idInc=0,this.$firstLink=null,this.$firstSub=null,this.disabled=!1,this.$disableOverlay=null,this.$touchScrollingSub=null,this.cssTransforms3d="perspective"in t.style||"webkitPerspective"in t.style,this.wasCollapsible=!1,this.init()},$.extend($.SmartMenus,{hideAll:function(){$.each(menuTrees,function(){this.menuHideAll()})},destroy:function(){for(;menuTrees.length;)menuTrees[0].destroy();initMouseDetection(!0)},prototype:{init:function(t){var e=this;if(!t){menuTrees.push(this),this.rootId=((new Date).getTime()+Math.random()+"").replace(/\D/g,""),this.accessIdPrefix="sm-"+this.rootId+"-",this.$root.hasClass("sm-rtl")&&(this.opts.rightToLeftSubMenus=!0);var i=".smartmenus";this.$root.data("smartmenus",this).attr("data-smartmenus-id",this.rootId).dataSM("level",1).on(getEventsNS({"mouseover focusin":$.proxy(this.rootOver,this),"mouseout focusout":$.proxy(this.rootOut,this),keydown:$.proxy(this.rootKeyDown,this)},i)).on(getEventsNS({mouseenter:$.proxy(this.itemEnter,this),mouseleave:$.proxy(this.itemLeave,this),mousedown:$.proxy(this.itemDown,this),focus:$.proxy(this.itemFocus,this),blur:$.proxy(this.itemBlur,this),click:$.proxy(this.itemClick,this)},i),"a"),i+=this.rootId,this.opts.hideOnClick&&$(document).on(getEventsNS({touchstart:$.proxy(this.docTouchStart,this),touchmove:$.proxy(this.docTouchMove,this),touchend:$.proxy(this.docTouchEnd,this),click:$.proxy(this.docClick,this)},i)),$(window).on(getEventsNS({"resize orientationchange":$.proxy(this.winResize,this)},i)),this.opts.subIndicators&&(this.$subArrow=$("").addClass("sub-arrow"),this.opts.subIndicatorsText&&this.$subArrow.html(this.opts.subIndicatorsText)),initMouseDetection()}if(this.$firstSub=this.$root.find("ul").each(function(){e.menuInit($(this))}).eq(0),this.$firstLink=this.$root.find("a").eq(0),this.opts.markCurrentItem){var s=/(index|default)\.[^#\?\/]*/i,o=/#.*/,a=window.location.href.replace(s,""),n=a.replace(o,"");this.$root.find("a").each(function(){var t=this.href.replace(s,""),i=$(this);(t==a||t==n)&&(i.addClass("current"),e.opts.markCurrentTree&&i.parentsUntil("[data-smartmenus-id]","ul").each(function(){$(this).dataSM("parent-a").addClass("current")}))})}this.wasCollapsible=this.isCollapsible()},destroy:function(t){if(!t){var e=".smartmenus";this.$root.removeData("smartmenus").removeAttr("data-smartmenus-id").removeDataSM("level").off(e),e+=this.rootId,$(document).off(e),$(window).off(e),this.opts.subIndicators&&(this.$subArrow=null)}this.menuHideAll();var i=this;this.$root.find("ul").each(function(){var t=$(this);t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.dataSM("shown-before")&&((i.opts.subMenusMinWidth||i.opts.subMenusMaxWidth)&&t.css({width:"",minWidth:"",maxWidth:""}).removeClass("sm-nowrap"),t.dataSM("scroll-arrows")&&t.dataSM("scroll-arrows").remove(),t.css({zIndex:"",top:"",left:"",marginLeft:"",marginTop:"",display:""})),0==(t.attr("id")||"").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeDataSM("in-mega").removeDataSM("shown-before").removeDataSM("scroll-arrows").removeDataSM("parent-a").removeDataSM("level").removeDataSM("beforefirstshowfired").removeAttr("role").removeAttr("aria-hidden").removeAttr("aria-labelledby").removeAttr("aria-expanded"),this.$root.find("a.has-submenu").each(function(){var t=$(this);0==t.attr("id").indexOf(i.accessIdPrefix)&&t.removeAttr("id")}).removeClass("has-submenu").removeDataSM("sub").removeAttr("aria-haspopup").removeAttr("aria-controls").removeAttr("aria-expanded").closest("li").removeDataSM("sub"),this.opts.subIndicators&&this.$root.find("span.sub-arrow").remove(),this.opts.markCurrentItem&&this.$root.find("a.current").removeClass("current"),t||(this.$root=null,this.$firstLink=null,this.$firstSub=null,this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),menuTrees.splice($.inArray(this,menuTrees),1))},disable:function(t){if(!this.disabled){if(this.menuHideAll(),!t&&!this.opts.isPopup&&this.$root.is(":visible")){var e=this.$root.offset();this.$disableOverlay=$('
').css({position:"absolute",top:e.top,left:e.left,width:this.$root.outerWidth(),height:this.$root.outerHeight(),zIndex:this.getStartZIndex(!0),opacity:0}).appendTo(document.body)}this.disabled=!0}},docClick:function(t){return this.$touchScrollingSub?(this.$touchScrollingSub=null,void 0):((this.visibleSubMenus.length&&!$.contains(this.$root[0],t.target)||$(t.target).closest("a").length)&&this.menuHideAll(),void 0)},docTouchEnd:function(){if(this.lastTouch){if(!(!this.visibleSubMenus.length||void 0!==this.lastTouch.x2&&this.lastTouch.x1!=this.lastTouch.x2||void 0!==this.lastTouch.y2&&this.lastTouch.y1!=this.lastTouch.y2||this.lastTouch.target&&$.contains(this.$root[0],this.lastTouch.target))){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var t=this;this.hideTimeout=setTimeout(function(){t.menuHideAll()},350)}this.lastTouch=null}},docTouchMove:function(t){if(this.lastTouch){var e=t.originalEvent.touches[0];this.lastTouch.x2=e.pageX,this.lastTouch.y2=e.pageY}},docTouchStart:function(t){var e=t.originalEvent.touches[0];this.lastTouch={x1:e.pageX,y1:e.pageY,target:e.target}},enable:function(){this.disabled&&(this.$disableOverlay&&(this.$disableOverlay.remove(),this.$disableOverlay=null),this.disabled=!1)},getClosestMenu:function(t){for(var e=$(t).closest("ul");e.dataSM("in-mega");)e=e.parent().closest("ul");return e[0]||null},getHeight:function(t){return this.getOffset(t,!0)},getOffset:function(t,e){var i;"none"==t.css("display")&&(i={position:t[0].style.position,visibility:t[0].style.visibility},t.css({position:"absolute",visibility:"hidden"}).show());var s=t[0].getBoundingClientRect&&t[0].getBoundingClientRect(),o=s&&(e?s.height||s.bottom-s.top:s.width||s.right-s.left);return o||0===o||(o=e?t[0].offsetHeight:t[0].offsetWidth),i&&t.hide().css(i),o},getStartZIndex:function(t){var e=parseInt(this[t?"$root":"$firstSub"].css("z-index"));return!t&&isNaN(e)&&(e=parseInt(this.$root.css("z-index"))),isNaN(e)?1:e},getTouchPoint:function(t){return t.touches&&t.touches[0]||t.changedTouches&&t.changedTouches[0]||t},getViewport:function(t){var e=t?"Height":"Width",i=document.documentElement["client"+e],s=window["inner"+e];return s&&(i=Math.min(i,s)),i},getViewportHeight:function(){return this.getViewport(!0)},getViewportWidth:function(){return this.getViewport()},getWidth:function(t){return this.getOffset(t)},handleEvents:function(){return!this.disabled&&this.isCSSOn()},handleItemEvents:function(t){return this.handleEvents()&&!this.isLinkInMegaMenu(t)},isCollapsible:function(){return"static"==this.$firstSub.css("position")},isCSSOn:function(){return"inline"!=this.$firstLink.css("display")},isFixed:function(){var t="fixed"==this.$root.css("position");return t||this.$root.parentsUntil("body").each(function(){return"fixed"==$(this).css("position")?(t=!0,!1):void 0}),t},isLinkInMegaMenu:function(t){return $(this.getClosestMenu(t[0])).hasClass("mega-menu")},isTouchMode:function(){return!mouse||this.opts.noMouseOver||this.isCollapsible()},itemActivate:function(t,e){var i=t.closest("ul"),s=i.dataSM("level");if(s>1&&(!this.activatedItems[s-2]||this.activatedItems[s-2][0]!=i.dataSM("parent-a")[0])){var o=this;$(i.parentsUntil("[data-smartmenus-id]","ul").get().reverse()).add(i).each(function(){o.itemActivate($(this).dataSM("parent-a"))})}if((!this.isCollapsible()||e)&&this.menuHideSubMenus(this.activatedItems[s-1]&&this.activatedItems[s-1][0]==t[0]?s:s-1),this.activatedItems[s-1]=t,this.$root.triggerHandler("activate.smapi",t[0])!==!1){var a=t.dataSM("sub");a&&(this.isTouchMode()||!this.opts.showOnClick||this.clickActivated)&&this.menuShow(a)}},itemBlur:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&this.$root.triggerHandler("blur.smapi",e[0])},itemClick:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(this.$touchScrollingSub&&this.$touchScrollingSub[0]==e.closest("ul")[0])return this.$touchScrollingSub=null,t.stopPropagation(),!1;if(this.$root.triggerHandler("click.smapi",e[0])===!1)return!1;var i=$(t.target).is(".sub-arrow"),s=e.dataSM("sub"),o=s?2==s.dataSM("level"):!1,a=this.isCollapsible(),n=/toggle$/.test(this.opts.collapsibleBehavior),r=/link$/.test(this.opts.collapsibleBehavior),h=/^accordion/.test(this.opts.collapsibleBehavior);if(s&&!s.is(":visible")){if((!r||!a||i)&&(this.opts.showOnClick&&o&&(this.clickActivated=!0),this.itemActivate(e,h),s.is(":visible")))return this.focusActivated=!0,!1}else if(a&&(n||i))return this.itemActivate(e,h),this.menuHide(s),n&&(this.focusActivated=!1),!1;return this.opts.showOnClick&&o||e.hasClass("disabled")||this.$root.triggerHandler("select.smapi",e[0])===!1?!1:void 0}},itemDown:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&e.dataSM("mousedown",!0)},itemEnter:function(t){var e=$(t.currentTarget);if(this.handleItemEvents(e)){if(!this.isTouchMode()){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);var i=this;this.showTimeout=setTimeout(function(){i.itemActivate(e)},this.opts.showOnClick&&1==e.closest("ul").dataSM("level")?1:this.opts.showTimeout)}this.$root.triggerHandler("mouseenter.smapi",e[0])}},itemFocus:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(!this.focusActivated||this.isTouchMode()&&e.dataSM("mousedown")||this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0]==e[0]||this.itemActivate(e,!0),this.$root.triggerHandler("focus.smapi",e[0]))},itemLeave:function(t){var e=$(t.currentTarget);this.handleItemEvents(e)&&(this.isTouchMode()||(e[0].blur(),this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0)),e.removeDataSM("mousedown"),this.$root.triggerHandler("mouseleave.smapi",e[0]))},menuHide:function(t){if(this.$root.triggerHandler("beforehide.smapi",t[0])!==!1&&(canAnimate&&t.stop(!0,!0),"none"!=t.css("display"))){var e=function(){t.css("z-index","")};this.isCollapsible()?canAnimate&&this.opts.collapsibleHideFunction?this.opts.collapsibleHideFunction.call(this,t,e):t.hide(this.opts.collapsibleHideDuration,e):canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,t,e):t.hide(this.opts.hideDuration,e),t.dataSM("scroll")&&(this.menuScrollStop(t),t.css({"touch-action":"","-ms-touch-action":"","-webkit-transform":"",transform:""}).off(".smartmenus_scroll").removeDataSM("scroll").dataSM("scroll-arrows").hide()),t.dataSM("parent-a").removeClass("highlighted").attr("aria-expanded","false"),t.attr({"aria-expanded":"false","aria-hidden":"true"});var i=t.dataSM("level");this.activatedItems.splice(i-1,1),this.visibleSubMenus.splice($.inArray(t,this.visibleSubMenus),1),this.$root.triggerHandler("hide.smapi",t[0])}},menuHideAll:function(){this.showTimeout&&(clearTimeout(this.showTimeout),this.showTimeout=0);for(var t=this.opts.isPopup?1:0,e=this.visibleSubMenus.length-1;e>=t;e--)this.menuHide(this.visibleSubMenus[e]);this.opts.isPopup&&(canAnimate&&this.$root.stop(!0,!0),this.$root.is(":visible")&&(canAnimate&&this.opts.hideFunction?this.opts.hideFunction.call(this,this.$root):this.$root.hide(this.opts.hideDuration))),this.activatedItems=[],this.visibleSubMenus=[],this.clickActivated=!1,this.focusActivated=!1,this.zIndexInc=0,this.$root.triggerHandler("hideAll.smapi")},menuHideSubMenus:function(t){for(var e=this.activatedItems.length-1;e>=t;e--){var i=this.activatedItems[e].dataSM("sub");i&&this.menuHide(i)}},menuInit:function(t){if(!t.dataSM("in-mega")){t.hasClass("mega-menu")&&t.find("ul").dataSM("in-mega",!0);for(var e=2,i=t[0];(i=i.parentNode.parentNode)!=this.$root[0];)e++;var s=t.prevAll("a").eq(-1);s.length||(s=t.prevAll().find("a").eq(-1)),s.addClass("has-submenu").dataSM("sub",t),t.dataSM("parent-a",s).dataSM("level",e).parent().dataSM("sub",t);var o=s.attr("id")||this.accessIdPrefix+ ++this.idInc,a=t.attr("id")||this.accessIdPrefix+ ++this.idInc;s.attr({id:o,"aria-haspopup":"true","aria-controls":a,"aria-expanded":"false"}),t.attr({id:a,role:"group","aria-hidden":"true","aria-labelledby":o,"aria-expanded":"false"}),this.opts.subIndicators&&s[this.opts.subIndicatorsPos](this.$subArrow.clone())}},menuPosition:function(t){var e,i,s=t.dataSM("parent-a"),o=s.closest("li"),a=o.parent(),n=t.dataSM("level"),r=this.getWidth(t),h=this.getHeight(t),u=s.offset(),l=u.left,c=u.top,d=this.getWidth(s),m=this.getHeight(s),p=$(window),f=p.scrollLeft(),v=p.scrollTop(),b=this.getViewportWidth(),S=this.getViewportHeight(),g=a.parent().is("[data-sm-horizontal-sub]")||2==n&&!a.hasClass("sm-vertical"),M=this.opts.rightToLeftSubMenus&&!o.is("[data-sm-reverse]")||!this.opts.rightToLeftSubMenus&&o.is("[data-sm-reverse]"),w=2==n?this.opts.mainMenuSubOffsetX:this.opts.subMenusSubOffsetX,T=2==n?this.opts.mainMenuSubOffsetY:this.opts.subMenusSubOffsetY;if(g?(e=M?d-r-w:w,i=this.opts.bottomToTopSubMenus?-h-T:m+T):(e=M?w-r:d-w,i=this.opts.bottomToTopSubMenus?m-T-h:T),this.opts.keepInViewport){var y=l+e,I=c+i;if(M&&f>y?e=g?f-y+e:d-w:!M&&y+r>f+b&&(e=g?f+b-r-y+e:w-r),g||(S>h&&I+h>v+S?i+=v+S-h-I:(h>=S||v>I)&&(i+=v-I)),g&&(I+h>v+S+.49||v>I)||!g&&h>S+.49){var x=this;t.dataSM("scroll-arrows")||t.dataSM("scroll-arrows",$([$('')[0],$('')[0]]).on({mouseenter:function(){t.dataSM("scroll").up=$(this).hasClass("scroll-up"),x.menuScroll(t)},mouseleave:function(e){x.menuScrollStop(t),x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(t){t.preventDefault()}}).insertAfter(t));var A=".smartmenus_scroll";if(t.dataSM("scroll",{y:this.cssTransforms3d?0:i-m,step:1,itemH:m,subH:h,arrowDownH:this.getHeight(t.dataSM("scroll-arrows").eq(1))}).on(getEventsNS({mouseover:function(e){x.menuScrollOver(t,e)},mouseout:function(e){x.menuScrollOut(t,e)},"mousewheel DOMMouseScroll":function(e){x.menuScrollMousewheel(t,e)}},A)).dataSM("scroll-arrows").css({top:"auto",left:"0",marginLeft:e+(parseInt(t.css("border-left-width"))||0),width:r-(parseInt(t.css("border-left-width"))||0)-(parseInt(t.css("border-right-width"))||0),zIndex:t.css("z-index")}).eq(g&&this.opts.bottomToTopSubMenus?0:1).show(),this.isFixed()){var C={};C[touchEvents?"touchstart touchmove touchend":"pointerdown pointermove pointerup MSPointerDown MSPointerMove MSPointerUp"]=function(e){x.menuScrollTouch(t,e)},t.css({"touch-action":"none","-ms-touch-action":"none"}).on(getEventsNS(C,A))}}}t.css({top:"auto",left:"0",marginLeft:e,marginTop:i-m})},menuScroll:function(t,e,i){var s,o=t.dataSM("scroll"),a=t.dataSM("scroll-arrows"),n=o.up?o.upEnd:o.downEnd;if(!e&&o.momentum){if(o.momentum*=.92,s=o.momentum,.5>s)return this.menuScrollStop(t),void 0}else s=i||(e||!this.opts.scrollAccelerate?this.opts.scrollStep:Math.floor(o.step));var r=t.dataSM("level");if(this.activatedItems[r-1]&&this.activatedItems[r-1].dataSM("sub")&&this.activatedItems[r-1].dataSM("sub").is(":visible")&&this.menuHideSubMenus(r-1),o.y=o.up&&o.y>=n||!o.up&&n>=o.y?o.y:Math.abs(n-o.y)>s?o.y+(o.up?s:-s):n,t.css(this.cssTransforms3d?{"-webkit-transform":"translate3d(0, "+o.y+"px, 0)",transform:"translate3d(0, "+o.y+"px, 0)"}:{marginTop:o.y}),mouse&&(o.up&&o.y>o.downEnd||!o.up&&o.y0;t.dataSM("scroll-arrows").eq(i?0:1).is(":visible")&&(t.dataSM("scroll").up=i,this.menuScroll(t,!0))}e.preventDefault()},menuScrollOut:function(t,e){mouse&&(/^scroll-(up|down)/.test((e.relatedTarget||"").className)||(t[0]==e.relatedTarget||$.contains(t[0],e.relatedTarget))&&this.getClosestMenu(e.relatedTarget)==t[0]||t.dataSM("scroll-arrows").css("visibility","hidden"))},menuScrollOver:function(t,e){if(mouse&&!/^scroll-(up|down)/.test(e.target.className)&&this.getClosestMenu(e.target)==t[0]){this.menuScrollRefreshData(t);var i=t.dataSM("scroll"),s=$(window).scrollTop()-t.dataSM("parent-a").offset().top-i.itemH;t.dataSM("scroll-arrows").eq(0).css("margin-top",s).end().eq(1).css("margin-top",s+this.getViewportHeight()-i.arrowDownH).end().css("visibility","visible")}},menuScrollRefreshData:function(t){var e=t.dataSM("scroll"),i=$(window).scrollTop()-t.dataSM("parent-a").offset().top-e.itemH;this.cssTransforms3d&&(i=-(parseFloat(t.css("margin-top"))-i)),$.extend(e,{upEnd:i,downEnd:i+this.getViewportHeight()-e.subH})},menuScrollStop:function(t){return this.scrollTimeout?(cancelAnimationFrame(this.scrollTimeout),this.scrollTimeout=0,t.dataSM("scroll").step=1,!0):void 0},menuScrollTouch:function(t,e){if(e=e.originalEvent,isTouchEvent(e)){var i=this.getTouchPoint(e);if(this.getClosestMenu(i.target)==t[0]){var s=t.dataSM("scroll");if(/(start|down)$/i.test(e.type))this.menuScrollStop(t)?(e.preventDefault(),this.$touchScrollingSub=t):this.$touchScrollingSub=null,this.menuScrollRefreshData(t),$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp});else if(/move$/i.test(e.type)){var o=void 0!==s.touchY?s.touchY:s.touchStartY;if(void 0!==o&&o!=i.pageY){this.$touchScrollingSub=t;var a=i.pageY>o;void 0!==s.up&&s.up!=a&&$.extend(s,{touchStartY:i.pageY,touchStartTime:e.timeStamp}),$.extend(s,{up:a,touchY:i.pageY}),this.menuScroll(t,!0,Math.abs(i.pageY-o))}e.preventDefault()}else void 0!==s.touchY&&((s.momentum=15*Math.pow(Math.abs(i.pageY-s.touchStartY)/(e.timeStamp-s.touchStartTime),2))&&(this.menuScrollStop(t),this.menuScroll(t),e.preventDefault()),delete s.touchY)}}},menuShow:function(t){if((t.dataSM("beforefirstshowfired")||(t.dataSM("beforefirstshowfired",!0),this.$root.triggerHandler("beforefirstshow.smapi",t[0])!==!1))&&this.$root.triggerHandler("beforeshow.smapi",t[0])!==!1&&(t.dataSM("shown-before",!0),canAnimate&&t.stop(!0,!0),!t.is(":visible"))){var e=t.dataSM("parent-a"),i=this.isCollapsible();if((this.opts.keepHighlighted||i)&&e.addClass("highlighted"),i)t.removeClass("sm-nowrap").css({zIndex:"",width:"auto",minWidth:"",maxWidth:"",top:"",left:"",marginLeft:"",marginTop:""});else{if(t.css("z-index",this.zIndexInc=(this.zIndexInc||this.getStartZIndex())+1),(this.opts.subMenusMinWidth||this.opts.subMenusMaxWidth)&&(t.css({width:"auto",minWidth:"",maxWidth:""}).addClass("sm-nowrap"),this.opts.subMenusMinWidth&&t.css("min-width",this.opts.subMenusMinWidth),this.opts.subMenusMaxWidth)){var s=this.getWidth(t);t.css("max-width",this.opts.subMenusMaxWidth),s>this.getWidth(t)&&t.removeClass("sm-nowrap").css("width",this.opts.subMenusMaxWidth)}this.menuPosition(t)}var o=function(){t.css("overflow","")};i?canAnimate&&this.opts.collapsibleShowFunction?this.opts.collapsibleShowFunction.call(this,t,o):t.show(this.opts.collapsibleShowDuration,o):canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,t,o):t.show(this.opts.showDuration,o),e.attr("aria-expanded","true"),t.attr({"aria-expanded":"true","aria-hidden":"false"}),this.visibleSubMenus.push(t),this.$root.triggerHandler("show.smapi",t[0])}},popupHide:function(t){this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0);var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},t?1:this.opts.hideTimeout)},popupShow:function(t,e){if(!this.opts.isPopup)return alert('SmartMenus jQuery Error:\n\nIf you want to show this menu via the "popupShow" method, set the isPopup:true option.'),void 0;if(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),this.$root.dataSM("shown-before",!0),canAnimate&&this.$root.stop(!0,!0),!this.$root.is(":visible")){this.$root.css({left:t,top:e});var i=this,s=function(){i.$root.css("overflow","")};canAnimate&&this.opts.showFunction?this.opts.showFunction.call(this,this.$root,s):this.$root.show(this.opts.showDuration,s),this.visibleSubMenus[0]=this.$root}},refresh:function(){this.destroy(!0),this.init(!0)},rootKeyDown:function(t){if(this.handleEvents())switch(t.keyCode){case 27:var e=this.activatedItems[0];if(e){this.menuHideAll(),e[0].focus();var i=e.dataSM("sub");i&&this.menuHide(i)}break;case 32:var s=$(t.target);if(s.is("a")&&this.handleItemEvents(s)){var i=s.dataSM("sub");i&&!i.is(":visible")&&(this.itemClick({currentTarget:t.target}),t.preventDefault())}}},rootOut:function(t){if(this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&(this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0),!this.opts.showOnClick||!this.opts.hideOnClick)){var e=this;this.hideTimeout=setTimeout(function(){e.menuHideAll()},this.opts.hideTimeout)}},rootOver:function(t){this.handleEvents()&&!this.isTouchMode()&&t.target!=this.$root[0]&&this.hideTimeout&&(clearTimeout(this.hideTimeout),this.hideTimeout=0)},winResize:function(t){if(this.handleEvents()){if(!("onorientationchange"in window)||"orientationchange"==t.type){var e=this.isCollapsible();this.wasCollapsible&&e||(this.activatedItems.length&&this.activatedItems[this.activatedItems.length-1][0].blur(),this.menuHideAll()),this.wasCollapsible=e}}else if(this.$disableOverlay){var i=this.$root.offset();this.$disableOverlay.css({top:i.top,left:i.left,width:this.$root.outerWidth(),height:this.$root.outerHeight()})}}}}),$.fn.dataSM=function(t,e){return e?this.data(t+"_smartmenus",e):this.data(t+"_smartmenus")},$.fn.removeDataSM=function(t){return this.removeData(t+"_smartmenus")},$.fn.smartmenus=function(options){if("string"==typeof options){var args=arguments,method=options;return Array.prototype.shift.call(args),this.each(function(){var t=$(this).data("smartmenus");t&&t[method]&&t[method].apply(t,args)})}return this.each(function(){var dataOpts=$(this).data("sm-options")||null;if(dataOpts)try{dataOpts=eval("("+dataOpts+")")}catch(e){dataOpts=null,alert('ERROR\n\nSmartMenus jQuery init:\nInvalid "data-sm-options" attribute value syntax.')}new $.SmartMenus(this,$.extend({},$.fn.smartmenus.defaults,options,dataOpts))})},$.fn.smartmenus.defaults={isPopup:!1,mainMenuSubOffsetX:0,mainMenuSubOffsetY:0,subMenusSubOffsetX:0,subMenusSubOffsetY:0,subMenusMinWidth:"10em",subMenusMaxWidth:"20em",subIndicators:!0,subIndicatorsPos:"append",subIndicatorsText:"",scrollStep:30,scrollAccelerate:!0,showTimeout:250,hideTimeout:500,showDuration:0,showFunction:null,hideDuration:0,hideFunction:function(t,e){t.fadeOut(200,e)},collapsibleShowDuration:0,collapsibleShowFunction:function(t,e){t.slideDown(200,e)},collapsibleHideDuration:0,collapsibleHideFunction:function(t,e){t.slideUp(200,e)},showOnClick:!1,hideOnClick:!0,noMouseOver:!1,keepInViewport:!0,keepHighlighted:!0,markCurrentItem:!1,markCurrentTree:!0,rightToLeftSubMenus:!1,bottomToTopSubMenus:!1,collapsibleBehavior:"default"},$}); \ No newline at end of file diff --git a/docs/manual/main_topics.html b/docs/manual/main_topics.html new file mode 100644 index 0000000..6031023 --- /dev/null +++ b/docs/manual/main_topics.html @@ -0,0 +1,124 @@ + + + + + + + +AngelScript: Developer manual + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ + + + + + diff --git a/docs/manual/main_topics.js b/docs/manual/main_topics.js new file mode 100644 index 0000000..471a8ba --- /dev/null +++ b/docs/manual/main_topics.js @@ -0,0 +1,32 @@ +var main_topics = +[ + [ "License", "doc_license.html", [ + [ "AngelCode Scripting Library", "doc_license.html#doc_lic_1", null ] + ] ], + [ "Getting started", "doc_start.html", "doc_start" ], + [ "Understanding AngelScript", "doc_understanding_as.html", "doc_understanding_as" ], + [ "Registering the application interface", "doc_register_api_topic.html", "doc_register_api_topic" ], + [ "Compiling scripts", "doc_compile_script.html", [ + [ "Message callback", "doc_compile_script.html#doc_compile_script_msg", null ], + [ "Loading and compiling scripts", "doc_compile_script.html#doc_compile_script_load", null ] + ] ], + [ "Calling a script function", "doc_call_script_func.html", [ + [ "Preparing context and executing the function", "doc_call_script_func.html#doc_call_script_1", null ], + [ "Passing and returning primitives", "doc_call_script_func.html#doc_call_script_2", null ], + [ "Passing and returning objects", "doc_call_script_func.html#doc_call_script_3", null ], + [ "Exception handling", "doc_call_script_func.html#doc_call_script_4", null ] + ] ], + [ "Using script classes", "doc_use_script_class.html", [ + [ "Instantiating the script class", "doc_use_script_class.html#doc_use_script_class_1", null ], + [ "Calling a method on the script class", "doc_use_script_class.html#doc_use_script_class_2", null ], + [ "Receiving script classes", "doc_use_script_class.html#doc_use_script_class_3", null ], + [ "Returning script classes", "doc_use_script_class.html#doc_use_script_class_4", null ] + ] ], + [ "Funcdefs and script callback functions", "doc_callbacks.html", [ + [ "An example", "doc_callbacks.html#doc_callbacks_example", null ], + [ "Delegates", "doc_callbacks.html#doc_callbacks_delegate", null ] + ] ], + [ "Advanced topics", "doc_advanced.html", "doc_advanced" ], + [ "Samples", "doc_samples.html", "doc_samples" ], + [ "Add-ons", "doc_addon.html", "doc_addon" ] +]; \ No newline at end of file diff --git a/docs/manual/modules.html b/docs/manual/modules.html new file mode 100644 index 0000000..ccea113 --- /dev/null +++ b/docs/manual/modules.html @@ -0,0 +1,121 @@ + + + + + + + +AngelScript: The API reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
The API reference
+
+ +
+ + + + diff --git a/docs/manual/modules.js b/docs/manual/modules.js new file mode 100644 index 0000000..95f40e1 --- /dev/null +++ b/docs/manual/modules.js @@ -0,0 +1,10 @@ +var modules = +[ + [ "Principal interfaces", "group__api__principal__interfaces.html", "group__api__principal__interfaces" ], + [ "Secondary interfaces", "group__api__secondary__interfaces.html", "group__api__secondary__interfaces" ], + [ "Auxiliary interfaces", "group__api__auxiliary__interfaces.html", "group__api__auxiliary__interfaces" ], + [ "Principal functions", "group__api__principal__functions.html", "group__api__principal__functions" ], + [ "Memory functions", "group__api__memory__functions.html", "group__api__memory__functions" ], + [ "Multi-thread support functions", "group__api__multithread__functions.html", "group__api__multithread__functions" ], + [ "Auxiliary functions", "group__api__auxiliary__functions.html", "group__api__auxiliary__functions" ] +]; \ No newline at end of file diff --git a/docs/manual/nav_f.png b/docs/manual/nav_f.png new file mode 100644 index 0000000..72a58a5 Binary files /dev/null and b/docs/manual/nav_f.png differ diff --git a/docs/manual/nav_g.png b/docs/manual/nav_g.png new file mode 100644 index 0000000..2093a23 Binary files /dev/null and b/docs/manual/nav_g.png differ diff --git a/docs/manual/nav_h.png b/docs/manual/nav_h.png new file mode 100644 index 0000000..33389b1 Binary files /dev/null and b/docs/manual/nav_h.png differ diff --git a/docs/manual/navtree.css b/docs/manual/navtree.css new file mode 100644 index 0000000..33341a6 --- /dev/null +++ b/docs/manual/navtree.css @@ -0,0 +1,146 @@ +#nav-tree .children_ul { + margin:0; + padding:4px; +} + +#nav-tree ul { + list-style:none outside none; + margin:0px; + padding:0px; +} + +#nav-tree li { + white-space:nowrap; + margin:0px; + padding:0px; +} + +#nav-tree .plus { + margin:0px; +} + +#nav-tree .selected { + background-image: url('tab_a.png'); + background-repeat:repeat-x; + color: #fff; + text-shadow: 0px 1px 1px rgba(0, 0, 0, 1.0); +} + +#nav-tree img { + margin:0px; + padding:0px; + border:0px; + vertical-align: middle; +} + +#nav-tree a { + text-decoration:none; + padding:0px; + margin:0px; + outline:none; +} + +#nav-tree .label { + margin:0px; + padding:0px; + font: 12px 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif; +} + +#nav-tree .label a { + padding:2px; +} + +#nav-tree .selected a { + text-decoration:none; + color:#fff; +} + +#nav-tree .children_ul { + margin:0px; + padding:0px; +} + +#nav-tree .item { + margin:0px; + padding:0px; +} + +#nav-tree { + padding: 0px 0px; + background-color: #FAFAFF; + font-size:14px; + overflow:auto; +} + +#doc-content { + overflow:auto; + display:block; + padding:0px; + margin:0px; + -webkit-overflow-scrolling : touch; /* iOS 5+ */ +} + +#side-nav { + padding:0 6px 0 0; + margin: 0px; + display:block; + position: absolute; + left: 0px; + width: 250px; +} + +.ui-resizable .ui-resizable-handle { + display:block; +} + +.ui-resizable-e { + background-image:url("splitbar.png"); + background-size:100%; + background-repeat:repeat-y; + background-attachment: scroll; + cursor:ew-resize; + height:100%; + right:0; + top:0; + width:6px; +} + +.ui-resizable-handle { + display:none; + font-size:0.1px; + position:absolute; + z-index:1; +} + +#nav-tree-contents { + margin: 6px 0px 0px 0px; +} + +#nav-tree { + background-image:url('nav_h.png'); + background-repeat:repeat-x; + background-color: #F9FAFC; + -webkit-overflow-scrolling : touch; /* iOS 5+ */ +} + +#nav-sync { + position:absolute; + top:5px; + right:24px; + z-index:0; +} + +#nav-sync img { + opacity:0.3; +} + +#nav-sync img:hover { + opacity:0.9; +} + +@media print +{ + #nav-tree { display: none; } + div.ui-resizable-handle { display: none; position: relative; } +} + diff --git a/docs/manual/navtree.js b/docs/manual/navtree.js new file mode 100644 index 0000000..1e272d3 --- /dev/null +++ b/docs/manual/navtree.js @@ -0,0 +1,546 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ +var navTreeSubIndices = new Array(); +var arrowDown = '▼'; +var arrowRight = '►'; + +function getData(varName) +{ + var i = varName.lastIndexOf('/'); + var n = i>=0 ? varName.substring(i+1) : varName; + return eval(n.replace(/\-/g,'_')); +} + +function stripPath(uri) +{ + return uri.substring(uri.lastIndexOf('/')+1); +} + +function stripPath2(uri) +{ + var i = uri.lastIndexOf('/'); + var s = uri.substring(i+1); + var m = uri.substring(0,i+1).match(/\/d\w\/d\w\w\/$/); + return m ? uri.substring(i-6) : s; +} + +function hashValue() +{ + return $(location).attr('hash').substring(1).replace(/[^\w\-]/g,''); +} + +function hashUrl() +{ + return '#'+hashValue(); +} + +function pathName() +{ + return $(location).attr('pathname').replace(/[^-A-Za-z0-9+&@#/%?=~_|!:,.;\(\)]/g, ''); +} + +function localStorageSupported() +{ + try { + return 'localStorage' in window && window['localStorage'] !== null && window.localStorage.getItem; + } + catch(e) { + return false; + } +} + +function storeLink(link) +{ + if (!$("#nav-sync").hasClass('sync') && localStorageSupported()) { + window.localStorage.setItem('navpath',link); + } +} + +function deleteLink() +{ + if (localStorageSupported()) { + window.localStorage.setItem('navpath',''); + } +} + +function cachedLink() +{ + if (localStorageSupported()) { + return window.localStorage.getItem('navpath'); + } else { + return ''; + } +} + +function getScript(scriptName,func,show) +{ + var head = document.getElementsByTagName("head")[0]; + var script = document.createElement('script'); + script.id = scriptName; + script.type = 'text/javascript'; + script.onload = func; + script.src = scriptName+'.js'; + head.appendChild(script); +} + +function createIndent(o,domNode,node,level) +{ + var level=-1; + var n = node; + while (n.parentNode) { level++; n=n.parentNode; } + if (node.childrenData) { + var imgNode = document.createElement("span"); + imgNode.className = 'arrow'; + imgNode.style.paddingLeft=(16*level).toString()+'px'; + imgNode.innerHTML=arrowRight; + node.plus_img = imgNode; + node.expandToggle = document.createElement("a"); + node.expandToggle.href = "javascript:void(0)"; + node.expandToggle.onclick = function() { + if (node.expanded) { + $(node.getChildrenUL()).slideUp("fast"); + node.plus_img.innerHTML=arrowRight; + node.expanded = false; + } else { + expandNode(o, node, false, false); + } + } + node.expandToggle.appendChild(imgNode); + domNode.appendChild(node.expandToggle); + } else { + var span = document.createElement("span"); + span.className = 'arrow'; + span.style.width = 16*(level+1)+'px'; + span.innerHTML = ' '; + domNode.appendChild(span); + } +} + +var animationInProgress = false; + +function gotoAnchor(anchor,aname,updateLocation) +{ + var pos, docContent = $('#doc-content'); + var ancParent = $(anchor.parent()); + if (ancParent.hasClass('memItemLeft') || + ancParent.hasClass('memtitle') || + ancParent.hasClass('fieldname') || + ancParent.hasClass('fieldtype') || + ancParent.is(':header')) + { + pos = ancParent.position().top; + } else if (anchor.position()) { + pos = anchor.position().top; + } + if (pos) { + var dist = Math.abs(Math.min( + pos-docContent.offset().top, + docContent[0].scrollHeight- + docContent.height()-docContent.scrollTop())); + animationInProgress=true; + docContent.animate({ + scrollTop: pos + docContent.scrollTop() - docContent.offset().top + },Math.max(50,Math.min(500,dist)),function(){ + if (updateLocation) window.location.href=aname; + animationInProgress=false; + }); + } +} + +function newNode(o, po, text, link, childrenData, lastNode) +{ + var node = new Object(); + node.children = Array(); + node.childrenData = childrenData; + node.depth = po.depth + 1; + node.relpath = po.relpath; + node.isLast = lastNode; + + node.li = document.createElement("li"); + po.getChildrenUL().appendChild(node.li); + node.parentNode = po; + + node.itemDiv = document.createElement("div"); + node.itemDiv.className = "item"; + + node.labelSpan = document.createElement("span"); + node.labelSpan.className = "label"; + + createIndent(o,node.itemDiv,node,0); + node.itemDiv.appendChild(node.labelSpan); + node.li.appendChild(node.itemDiv); + + var a = document.createElement("a"); + node.labelSpan.appendChild(a); + node.label = document.createTextNode(text); + node.expanded = false; + a.appendChild(node.label); + if (link) { + var url; + if (link.substring(0,1)=='^') { + url = link.substring(1); + link = url; + } else { + url = node.relpath+link; + } + a.className = stripPath(link.replace('#',':')); + if (link.indexOf('#')!=-1) { + var aname = '#'+link.split('#')[1]; + var srcPage = stripPath(pathName()); + var targetPage = stripPath(link.split('#')[0]); + a.href = srcPage!=targetPage ? url : "javascript:void(0)"; + a.onclick = function(){ + storeLink(link); + if (!$(a).parent().parent().hasClass('selected')) + { + $('.item').removeClass('selected'); + $('.item').removeAttr('id'); + $(a).parent().parent().addClass('selected'); + $(a).parent().parent().attr('id','selected'); + } + var anchor = $(aname); + gotoAnchor(anchor,aname,true); + }; + } else { + a.href = url; + a.onclick = function() { storeLink(link); } + } + } else { + if (childrenData != null) + { + a.className = "nolink"; + a.href = "javascript:void(0)"; + a.onclick = node.expandToggle.onclick; + } + } + + node.childrenUL = null; + node.getChildrenUL = function() { + if (!node.childrenUL) { + node.childrenUL = document.createElement("ul"); + node.childrenUL.className = "children_ul"; + node.childrenUL.style.display = "none"; + node.li.appendChild(node.childrenUL); + } + return node.childrenUL; + }; + + return node; +} + +function showRoot() +{ + var headerHeight = $("#top").height(); + var footerHeight = $("#nav-path").height(); + var windowHeight = $(window).height() - headerHeight - footerHeight; + (function (){ // retry until we can scroll to the selected item + try { + var navtree=$('#nav-tree'); + navtree.scrollTo('#selected',100,{offset:-windowHeight/2}); + } catch (err) { + setTimeout(arguments.callee, 0); + } + })(); +} + +function expandNode(o, node, imm, showRoot) +{ + if (node.childrenData && !node.expanded) { + if (typeof(node.childrenData)==='string') { + var varName = node.childrenData; + getScript(node.relpath+varName,function(){ + node.childrenData = getData(varName); + expandNode(o, node, imm, showRoot); + }, showRoot); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } + $(node.getChildrenUL()).slideDown("fast"); + node.plus_img.innerHTML = arrowDown; + node.expanded = true; + } + } +} + +function glowEffect(n,duration) +{ + n.addClass('glow').delay(duration).queue(function(next){ + $(this).removeClass('glow');next(); + }); +} + +function highlightAnchor() +{ + var aname = hashUrl(); + var anchor = $(aname); + if (anchor.parent().attr('class')=='memItemLeft'){ + var rows = $('.memberdecls tr[class$="'+hashValue()+'"]'); + glowEffect(rows.children(),300); // member without details + } else if (anchor.parent().attr('class')=='fieldname'){ + glowEffect(anchor.parent().parent(),1000); // enum value + } else if (anchor.parent().attr('class')=='fieldtype'){ + glowEffect(anchor.parent().parent(),1000); // struct field + } else if (anchor.parent().is(":header")) { + glowEffect(anchor.parent(),1000); // section header + } else { + glowEffect(anchor.next(),1000); // normal member + } +} + +function selectAndHighlight(hash,n) +{ + var a; + if (hash) { + var link=stripPath(pathName())+':'+hash.substring(1); + a=$('.item a[class$="'+link+'"]'); + } + if (a && a.length) { + a.parent().parent().addClass('selected'); + a.parent().parent().attr('id','selected'); + highlightAnchor(); + } else if (n) { + $(n.itemDiv).addClass('selected'); + $(n.itemDiv).attr('id','selected'); + } + if ($('#nav-tree-contents .item:first').hasClass('selected')) { + $('#nav-sync').css('top','30px'); + } else { + $('#nav-sync').css('top','5px'); + } + showRoot(); +} + +function showNode(o, node, index, hash) +{ + if (node && node.childrenData) { + if (typeof(node.childrenData)==='string') { + var varName = node.childrenData; + getScript(node.relpath+varName,function(){ + node.childrenData = getData(varName); + showNode(o,node,index,hash); + },true); + } else { + if (!node.childrenVisited) { + getNode(o, node); + } + $(node.getChildrenUL()).css({'display':'block'}); + node.plus_img.innerHTML = arrowDown; + node.expanded = true; + var n = node.children[o.breadcrumbs[index]]; + if (index+11) hash = '#'+parts[1].replace(/[^\w\-]/g,''); + else hash=''; + } + if (hash.match(/^#l\d+$/)) { + var anchor=$('a[name='+hash.substring(1)+']'); + glowEffect(anchor.parent(),1000); // line number + hash=''; // strip line number anchors + } + var url=root+hash; + var i=-1; + while (NAVTREEINDEX[i+1]<=url) i++; + if (i==-1) { i=0; root=NAVTREE[0][1]; } // fallback: show index + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath) + } else { + getScript(relpath+'navtreeindex'+i,function(){ + navTreeSubIndices[i] = eval('NAVTREEINDEX'+i); + if (navTreeSubIndices[i]) { + gotoNode(o,i,root,hash,relpath); + } + },true); + } +} + +function showSyncOff(n,relpath) +{ + n.html(''); +} + +function showSyncOn(n,relpath) +{ + n.html(''); +} + +function toggleSyncButton(relpath) +{ + var navSync = $('#nav-sync'); + if (navSync.hasClass('sync')) { + navSync.removeClass('sync'); + showSyncOff(navSync,relpath); + storeLink(stripPath2(pathName())+hashUrl()); + } else { + navSync.addClass('sync'); + showSyncOn(navSync,relpath); + deleteLink(); + } +} + +var loadTriggered = false; +var readyTriggered = false; +var loadObject,loadToRoot,loadUrl,loadRelPath; + +$(window).on('load',function(){ + if (readyTriggered) { // ready first + navTo(loadObject,loadToRoot,loadUrl,loadRelPath); + showRoot(); + } + loadTriggered=true; +}); + +function initNavTree(toroot,relpath) +{ + var o = new Object(); + o.toroot = toroot; + o.node = new Object(); + o.node.li = document.getElementById("nav-tree-contents"); + o.node.childrenData = NAVTREE; + o.node.children = new Array(); + o.node.childrenUL = document.createElement("ul"); + o.node.getChildrenUL = function() { return o.node.childrenUL; }; + o.node.li.appendChild(o.node.childrenUL); + o.node.depth = 0; + o.node.relpath = relpath; + o.node.expanded = false; + o.node.isLast = true; + o.node.plus_img = document.createElement("span"); + o.node.plus_img.className = 'arrow'; + o.node.plus_img.innerHTML = arrowRight; + + if (localStorageSupported()) { + var navSync = $('#nav-sync'); + if (cachedLink()) { + showSyncOff(navSync,relpath); + navSync.removeClass('sync'); + } else { + showSyncOn(navSync,relpath); + } + navSync.click(function(){ toggleSyncButton(relpath); }); + } + + if (loadTriggered) { // load before ready + navTo(o,toroot,hashUrl(),relpath); + showRoot(); + } else { // ready before load + loadObject = o; + loadToRoot = toroot; + loadUrl = hashUrl(); + loadRelPath = relpath; + readyTriggered=true; + } + + $(window).bind('hashchange', function(){ + if (window.location.hash && window.location.hash.length>1){ + var a; + if ($(location).attr('hash')){ + var clslink=stripPath(pathName())+':'+hashValue(); + a=$('.item a[class$="'+clslink.replace(/ + + + + + + +AngelScript: Related Pages + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Related Pages
+
+
+
Here is a list of all related documentation pages:
+
[detail level 1234]
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
 Developer manual
 License
 Getting started
 Understanding AngelScript
 Registering the application interface
 Compiling scripts
 Calling a script function
 Using script classes
 Funcdefs and script callback functions
 Advanced topics
 Samples
 Add-ons
 The script language
 Global entities
 Statements
 Expressions
 Data types
 Functions
 Script classes
 Object handles
 Shared script entities
 Operator precedence
 Reserved keywords and tokens
 Script language grammar
 Standard library
 Todo List
+
+
+
+ + + + diff --git a/docs/manual/resize.js b/docs/manual/resize.js new file mode 100644 index 0000000..e1ad0fe --- /dev/null +++ b/docs/manual/resize.js @@ -0,0 +1,140 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ +function initResizable() +{ + var cookie_namespace = 'doxygen'; + var sidenav,navtree,content,header,collapsed,collapsedWidth=0,barWidth=6,desktop_vp=768,titleHeight; + + function readCookie(cookie) + { + var myCookie = cookie_namespace+"_"+cookie+"="; + if (document.cookie) { + var index = document.cookie.indexOf(myCookie); + if (index != -1) { + var valStart = index + myCookie.length; + var valEnd = document.cookie.indexOf(";", valStart); + if (valEnd == -1) { + valEnd = document.cookie.length; + } + var val = document.cookie.substring(valStart, valEnd); + return val; + } + } + return 0; + } + + function writeCookie(cookie, val, expiration) + { + if (val==undefined) return; + if (expiration == null) { + var date = new Date(); + date.setTime(date.getTime()+(10*365*24*60*60*1000)); // default expiration is one week + expiration = date.toGMTString(); + } + document.cookie = cookie_namespace + "_" + cookie + "=" + val + "; expires=" + expiration+"; path=/"; + } + + function resizeWidth() + { + var windowWidth = $(window).width() + "px"; + var sidenavWidth = $(sidenav).outerWidth(); + content.css({marginLeft:parseInt(sidenavWidth)+"px"}); + writeCookie('width',sidenavWidth-barWidth, null); + } + + function restoreWidth(navWidth) + { + var windowWidth = $(window).width() + "px"; + content.css({marginLeft:parseInt(navWidth)+barWidth+"px"}); + sidenav.css({width:navWidth + "px"}); + } + + function resizeHeight() + { + var headerHeight = header.outerHeight(); + var footerHeight = footer.outerHeight(); + var windowHeight = $(window).height() - headerHeight - footerHeight; + content.css({height:windowHeight + "px"}); + navtree.css({height:windowHeight + "px"}); + sidenav.css({height:windowHeight + "px"}); + var width=$(window).width(); + if (width!=collapsedWidth) { + if (width=desktop_vp) { + if (!collapsed) { + collapseExpand(); + } + } else if (width>desktop_vp && collapsedWidth0) { + restoreWidth(0); + collapsed=true; + } + else { + var width = readCookie('width'); + if (width>200 && width<$(window).width()) { restoreWidth(width); } else { restoreWidth(200); } + collapsed=false; + } + } + + header = $("#top"); + sidenav = $("#side-nav"); + content = $("#doc-content"); + navtree = $("#nav-tree"); + footer = $("#nav-path"); + $(".side-nav-resizable").resizable({resize: function(e, ui) { resizeWidth(); } }); + $(sidenav).resizable({ minWidth: 0 }); + $(window).resize(function() { resizeHeight(); }); + var device = navigator.userAgent.toLowerCase(); + var touch_device = device.match(/(iphone|ipod|ipad|android)/); + if (touch_device) { /* wider split bar for touch only devices */ + $(sidenav).css({ paddingRight:'20px' }); + $('.ui-resizable-e').css({ width:'20px' }); + $('#nav-sync').css({ right:'34px' }); + barWidth=20; + } + var width = readCookie('width'); + if (width) { restoreWidth(width); } else { resizeWidth(); } + resizeHeight(); + var url = location.href; + var i=url.indexOf("#"); + if (i>=0) window.location.hash=url.substr(i); + var _preventDefault = function(evt) { evt.preventDefault(); }; + $("#splitbar").bind("dragstart", _preventDefault).bind("selectstart", _preventDefault); + $(".ui-resizable-handle").dblclick(collapseExpand); + $(window).on('load',resizeHeight); +} +/* @license-end */ diff --git a/docs/manual/search/all_0.html b/docs/manual/search/all_0.html new file mode 100644 index 0000000..ea50fff --- /dev/null +++ b/docs/manual/search/all_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_0.js b/docs/manual/search/all_0.js new file mode 100644 index 0000000..f23cb99 --- /dev/null +++ b/docs/manual/search/all_0.js @@ -0,0 +1,524 @@ +var searchData= +[ + ['abort_0',['Abort',['../classas_i_script_context.html#a374befd21b8c14de81ef0ed9d2dea334',1,'asIScriptContext']]], + ['addref_1',['AddRef',['../classas_i_script_engine.html#aa95a5d9b5d9e7e6a230fedf056eaf8ce',1,'asIScriptEngine::AddRef()'],['../classas_i_script_context.html#a5e24f4cb5773f732a1d46b818d963a1d',1,'asIScriptContext::AddRef()'],['../classas_i_script_object.html#a3e08890e31163e4d33c0f27dc9072662',1,'asIScriptObject::AddRef()'],['../classas_i_type_info.html#a532069932de1f584ab52e4c2afacf95e',1,'asITypeInfo::AddRef()'],['../classas_i_script_function.html#a0a00f9581e7ece5f2a536d0e22c10d0c',1,'asIScriptFunction::AddRef()'],['../classas_i_lockable_shared_bool.html#a1183742552ce6b952cc3742bd456d787',1,'asILockableSharedBool::AddRef()']]], + ['addrefscriptobject_2',['AddRefScriptObject',['../classas_i_script_engine.html#ade1d309876c876c733d437a53e708c28',1,'asIScriptEngine']]], + ['addscriptsection_3',['AddScriptSection',['../classas_i_script_module.html#a330835919b565c76c25e9425536f50b7',1,'asIScriptModule']]], + ['angelscript_2eh_4',['angelscript.h',['../angelscript_8h.html',1,'']]], + ['angelscript_5fversion_5',['ANGELSCRIPT_VERSION',['../angelscript_8h.html#a99c6b8b0882e45e5d0b2ed19f6f7a157',1,'angelscript.h']]], + ['auxiliary_20functions_6',['Auxiliary functions',['../group__api__auxiliary__functions.html',1,'']]], + ['auxiliary_20interfaces_7',['Auxiliary interfaces',['../group__api__auxiliary__interfaces.html',1,'']]], + ['as_5fapi_8',['AS_API',['../angelscript_8h.html#a6412a04ba6b2737922fdb2d8f822f51c',1,'angelscript.h']]], + ['as_5fcan_5fuse_5fcpp11_9',['AS_CAN_USE_CPP11',['../angelscript_8h.html#a9e0eb27a2013e875a33565dd3fe76f79',1,'angelscript.h']]], + ['asacquireexclusivelock_10',['asAcquireExclusiveLock',['../group__api__multithread__functions.html#ga016dbf716a1c761b3f903b92eb8bb580',1,'angelscript.h']]], + ['asacquiresharedlock_11',['asAcquireSharedLock',['../group__api__multithread__functions.html#gaa45545a038adcc8c73348cfe9488f32d',1,'angelscript.h']]], + ['asallocfunc_5ft_12',['asALLOCFUNC_t',['../angelscript_8h.html#ac69a827822c73771cd972bff270cefc7',1,'angelscript.h']]], + ['asallocmem_13',['asAllocMem',['../group__api__memory__functions.html#ga54a201f99d19e648526abf30ae31e466',1,'angelscript.h']]], + ['asalready_5fregistered_14',['asALREADY_REGISTERED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a8025c1eca773e41db5f3102ae3c41690',1,'angelscript.h']]], + ['asatomicdec_15',['asAtomicDec',['../group__api__multithread__functions.html#ga0565bcb53be170dd85ae27a5b6f2b828',1,'angelscript.h']]], + ['asatomicinc_16',['asAtomicInc',['../group__api__multithread__functions.html#gaf0074d581ac2edd06e63e56e4be52c8e',1,'angelscript.h']]], + ['asbc_5faddd_17',['asBC_ADDd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad2ff7a206ad788bd2b37b8ee92be7940',1,'angelscript.h']]], + ['asbc_5faddf_18',['asBC_ADDf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab1bffd05b8b41e4a9dd09618b82bba9d',1,'angelscript.h']]], + ['asbc_5faddi_19',['asBC_ADDi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a42520944f391260636e0eed5c9ab76a9',1,'angelscript.h']]], + ['asbc_5faddi64_20',['asBC_ADDi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab1afb9b4dbebb726108b46887175c57e',1,'angelscript.h']]], + ['asbc_5faddif_21',['asBC_ADDIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a15032e422f3346940aa37ec6dc6305d7',1,'angelscript.h']]], + ['asbc_5faddii_22',['asBC_ADDIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1194db3e433a943156d548b2bb34ef13',1,'angelscript.h']]], + ['asbc_5faddsi_23',['asBC_ADDSi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0219f343e6e7248e72d209ea22b63f4d',1,'angelscript.h']]], + ['asbc_5falloc_24',['asBC_ALLOC',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac215e24151dbbf8ca218ee90b77953d2',1,'angelscript.h']]], + ['asbc_5fallocmem_25',['asBC_AllocMem',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a60cb5c56bd8cd1dfd7bde88be588b19c',1,'angelscript.h']]], + ['asbc_5fband_26',['asBC_BAND',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a051857d502a904223293d1604765c0f5',1,'angelscript.h']]], + ['asbc_5fband64_27',['asBC_BAND64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af1dff3cce666a689e8b1d5ceb91f1b42',1,'angelscript.h']]], + ['asbc_5fbnot_28',['asBC_BNOT',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac9e8418aad908e23c4e2e9cbbc71f8fe',1,'angelscript.h']]], + ['asbc_5fbnot64_29',['asBC_BNOT64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a263c5cfa90baf8f63c5b4d110c3d9daa',1,'angelscript.h']]], + ['asbc_5fbor_30',['asBC_BOR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4265bc99ed27ff3e3cd55e7de3f6ee57',1,'angelscript.h']]], + ['asbc_5fbor64_31',['asBC_BOR64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a5d6d553690fa38dc7f2b6a7b9ee14345',1,'angelscript.h']]], + ['asbc_5fbsll_32',['asBC_BSLL',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a671220a8df608a65acb7c5be7d950134',1,'angelscript.h']]], + ['asbc_5fbsll64_33',['asBC_BSLL64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af18e856f167de0796acb84d3f5df09b2',1,'angelscript.h']]], + ['asbc_5fbsra_34',['asBC_BSRA',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae7f2672c3c3a6859f17ebc25df4d95a1',1,'angelscript.h']]], + ['asbc_5fbsra64_35',['asBC_BSRA64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4203e09b3bf5f15810f0e2076c0088a5',1,'angelscript.h']]], + ['asbc_5fbsrl_36',['asBC_BSRL',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a427239dea36c73be86be67963dbc1935',1,'angelscript.h']]], + ['asbc_5fbsrl64_37',['asBC_BSRL64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0abb511dcd15fb9875ba270d5b95fed24d',1,'angelscript.h']]], + ['asbc_5fbxor_38',['asBC_BXOR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a099bdbc768c58ad62d2662dd9727806a',1,'angelscript.h']]], + ['asbc_5fbxor64_39',['asBC_BXOR64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae4d7a6a1af23b2f14d5af7b6dfaa3f28',1,'angelscript.h']]], + ['asbc_5fcall_40',['asBC_CALL',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4055fd59f44ce3f31eac60377b0967c8',1,'angelscript.h']]], + ['asbc_5fcallbnd_41',['asBC_CALLBND',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a22f812924fa0048de540e0cca53a2718',1,'angelscript.h']]], + ['asbc_5fcallintf_42',['asBC_CALLINTF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aedb4e479a4988aac48f1facb6a0048d6',1,'angelscript.h']]], + ['asbc_5fcallptr_43',['asBC_CallPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a35c09c890b9f46160c193a3a07cdeedb',1,'angelscript.h']]], + ['asbc_5fcallsys_44',['asBC_CALLSYS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac21b3ff5a3ecb6d834bfe2bf7ff36669',1,'angelscript.h']]], + ['asbc_5fcast_45',['asBC_Cast',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4ef6c5e255ffe285bff104bacaed2ba9',1,'angelscript.h']]], + ['asbc_5fchknulls_46',['asBC_ChkNullS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af859e97239e00dd003a8f75fbf963ded',1,'angelscript.h']]], + ['asbc_5fchknullv_47',['asBC_ChkNullV',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a81142673f63ffd177e20b6296718d3aa',1,'angelscript.h']]], + ['asbc_5fchkref_48',['asBC_CHKREF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0ae4b5ff463c26aad9fbd975a144f2fa',1,'angelscript.h']]], + ['asbc_5fchkrefs_49',['asBC_ChkRefS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad0c18f6eab27072771563d4464d06a4a',1,'angelscript.h']]], + ['asbc_5fclrhi_50',['asBC_ClrHi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1293f6086ce51f270a7d756413cabb9c',1,'angelscript.h']]], + ['asbc_5fclrvptr_51',['asBC_ClrVPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8b5cd32b4b5bc6aaafb0456d931dc11e',1,'angelscript.h']]], + ['asbc_5fcmpd_52',['asBC_CMPd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad72b54941de6dccfbea9c6ccb5d915df',1,'angelscript.h']]], + ['asbc_5fcmpf_53',['asBC_CMPf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a158d7962cea577c9a18f639976c6c0ab',1,'angelscript.h']]], + ['asbc_5fcmpi_54',['asBC_CMPi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af81b0602117dd9ef104dea7d2d526cfa',1,'angelscript.h']]], + ['asbc_5fcmpi64_55',['asBC_CMPi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa2c75f0562b433b18406a939bcd62e95',1,'angelscript.h']]], + ['asbc_5fcmpif_56',['asBC_CMPIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2f5efa47419aa3a053f1e8916b46e303',1,'angelscript.h']]], + ['asbc_5fcmpii_57',['asBC_CMPIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a33a798d1fe04ec8e1794ddb0838039d9',1,'angelscript.h']]], + ['asbc_5fcmpiu_58',['asBC_CMPIu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad7195755387f9159b4a2c5de9e60a068',1,'angelscript.h']]], + ['asbc_5fcmpptr_59',['asBC_CmpPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a17c0368321613c9e38e438f96b80bdd7',1,'angelscript.h']]], + ['asbc_5fcmpu_60',['asBC_CMPu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2d473195aba3ddcc8d6419c047d0c741',1,'angelscript.h']]], + ['asbc_5fcmpu64_61',['asBC_CMPu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af521b982839cdc97e9b2413ac085b09f',1,'angelscript.h']]], + ['asbc_5fcopy_62',['asBC_COPY',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa06ef833e37285449bfc72e0c93479a9',1,'angelscript.h']]], + ['asbc_5fcpygtov4_63',['asBC_CpyGtoV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4ed62e4b84509466aef25d638026b883',1,'angelscript.h']]], + ['asbc_5fcpyrtov4_64',['asBC_CpyRtoV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a27458705bfaa7f4e5b27f848c0e59c7c',1,'angelscript.h']]], + ['asbc_5fcpyrtov8_65',['asBC_CpyRtoV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a399ae190caa78f468883f9736e8f9d40',1,'angelscript.h']]], + ['asbc_5fcpyvtog4_66',['asBC_CpyVtoG4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4e7398002dfd57870657a8df142259a1',1,'angelscript.h']]], + ['asbc_5fcpyvtor4_67',['asBC_CpyVtoR4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af77782bde1062e849fc6c02c8c4e0106',1,'angelscript.h']]], + ['asbc_5fcpyvtor8_68',['asBC_CpyVtoR8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a25f9b87968cb0fea646d003a90bbd0a6',1,'angelscript.h']]], + ['asbc_5fcpyvtov4_69',['asBC_CpyVtoV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac8e1a29718cf8958201d578d56cf74b4',1,'angelscript.h']]], + ['asbc_5fcpyvtov8_70',['asBC_CpyVtoV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af0a7f6b4a1c14352e7cd02e03c1e7595',1,'angelscript.h']]], + ['asbc_5fdecd_71',['asBC_DECd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a46ccee51c06462cd452c6a97a2854a22',1,'angelscript.h']]], + ['asbc_5fdecf_72',['asBC_DECf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0fedf5312b600d2cd8e991139ff237f1',1,'angelscript.h']]], + ['asbc_5fdeci_73',['asBC_DECi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad78d2aec3e51a9aaf3fb5f3c12afc420',1,'angelscript.h']]], + ['asbc_5fdeci16_74',['asBC_DECi16',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9ea8e03a8da22997477fca4f79d55830',1,'angelscript.h']]], + ['asbc_5fdeci64_75',['asBC_DECi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a27cdd04643b9331e2aedfb6c1af1c021',1,'angelscript.h']]], + ['asbc_5fdeci8_76',['asBC_DECi8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aeb53c8898d91276563cf360539b2c4ce',1,'angelscript.h']]], + ['asbc_5fdecvi_77',['asBC_DecVi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0f57e25fb34f2d086f35f60cfe51782e',1,'angelscript.h']]], + ['asbc_5fdivd_78',['asBC_DIVd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a016b86c3e0706775fc653d6f94048765',1,'angelscript.h']]], + ['asbc_5fdivf_79',['asBC_DIVf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0acf3448b40f2fc34b4007f27c4f8488a2',1,'angelscript.h']]], + ['asbc_5fdivi_80',['asBC_DIVi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a27123834824beb61355869faf5e23cf4',1,'angelscript.h']]], + ['asbc_5fdivi64_81',['asBC_DIVi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9f31be749c98afaa86f5b3a83218752b',1,'angelscript.h']]], + ['asbc_5fdivu_82',['asBC_DIVu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4e171bc08a91c52a5eae821ff3435892',1,'angelscript.h']]], + ['asbc_5fdivu64_83',['asBC_DIVu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8cc1a88aa5da6d91bbf7bccb7abc3327',1,'angelscript.h']]], + ['asbc_5fdtof_84',['asBC_dTOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a854599de98fcbd9334c9223e8e9058db',1,'angelscript.h']]], + ['asbc_5fdtoi_85',['asBC_dTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0afb5dbe4edea3e5cfa521fd3a5738ccf6',1,'angelscript.h']]], + ['asbc_5fdtoi64_86',['asBC_dTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a043e40662a884a7c39bbd982d3e2266f',1,'angelscript.h']]], + ['asbc_5fdtou_87',['asBC_dTOu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab316237649a76cf10a1b9bc68c2792c4',1,'angelscript.h']]], + ['asbc_5fdtou64_88',['asBC_dTOu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a062cb021be1b64d913527c22c7dba896',1,'angelscript.h']]], + ['asbc_5fdwordarg_89',['asBC_DWORDARG',['../angelscript_8h.html#a7b3dbfcc3928ddd853a4ee53cbc13b69',1,'angelscript.h']]], + ['asbc_5ffloatarg_90',['asBC_FLOATARG',['../angelscript_8h.html#a0183edd413564ff4897eb4a2473d01f6',1,'angelscript.h']]], + ['asbc_5ffree_91',['asBC_FREE',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1d13cb9820edf1d65e09e3c70f67d3b9',1,'angelscript.h']]], + ['asbc_5fftod_92',['asBC_fTOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8d1a589383ae9187b58a3f774cbe77cd',1,'angelscript.h']]], + ['asbc_5fftoi_93',['asBC_fTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a505d5d669a5d046b5fe5edbde407d12a',1,'angelscript.h']]], + ['asbc_5fftoi64_94',['asBC_fTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0acd75aec128802694c2674b122204e704',1,'angelscript.h']]], + ['asbc_5fftou_95',['asBC_fTOu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9e9e1d16d150ca95e5f8abee59aaed51',1,'angelscript.h']]], + ['asbc_5fftou64_96',['asBC_fTOu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae5bd9d9c6b756c2898f2776b0b08e793',1,'angelscript.h']]], + ['asbc_5ffuncptr_97',['asBC_FuncPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab4a58c4177502bd6d3a034f2d4244404',1,'angelscript.h']]], + ['asbc_5fgetobj_98',['asBC_GETOBJ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aaef456de01ad209271078728d304b803',1,'angelscript.h']]], + ['asbc_5fgetobjref_99',['asBC_GETOBJREF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6b9d0ef0c8e981a591c384792acf2c6d',1,'angelscript.h']]], + ['asbc_5fgetref_100',['asBC_GETREF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6ad13f895f055f69384efb4a67941369',1,'angelscript.h']]], + ['asbc_5fi64tod_101',['asBC_i64TOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7e110775dee3e08f9ef7e2215fb48b26',1,'angelscript.h']]], + ['asbc_5fi64tof_102',['asBC_i64TOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a22f2099b91cb1bde2df44760ea2efed7',1,'angelscript.h']]], + ['asbc_5fi64toi_103',['asBC_i64TOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae66d679b16934aeb2c7047ea1b1fae85',1,'angelscript.h']]], + ['asbc_5fincd_104',['asBC_INCd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a46b7c1d75685f454688e361e4da99994',1,'angelscript.h']]], + ['asbc_5fincf_105',['asBC_INCf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aef2f50c2ed4d67c3da6630616ad00a7b',1,'angelscript.h']]], + ['asbc_5finci_106',['asBC_INCi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a630408d0f3892bfa8ba01da409ca30e3',1,'angelscript.h']]], + ['asbc_5finci16_107',['asBC_INCi16',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4669b8c92a8b8d9c6e84d0ed1db14d33',1,'angelscript.h']]], + ['asbc_5finci64_108',['asBC_INCi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6216ec910e53970e52e518da4786a37b',1,'angelscript.h']]], + ['asbc_5finci8_109',['asBC_INCi8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a152dde2647cf17bf01f255cab7d7a398',1,'angelscript.h']]], + ['asbc_5fincvi_110',['asBC_IncVi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af9579b13bff9bcc81710fe7dba9c0957',1,'angelscript.h']]], + ['asbc_5fintarg_111',['asBC_INTARG',['../angelscript_8h.html#a290586f7a153d5e8717b01680262b667',1,'angelscript.h']]], + ['asbc_5fitob_112',['asBC_iTOb',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aea965df01399592f1e8c3950a35e837f',1,'angelscript.h']]], + ['asbc_5fitod_113',['asBC_iTOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad9a5f8875c44b01fa6e1501bb70bae00',1,'angelscript.h']]], + ['asbc_5fitof_114',['asBC_iTOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a92116eabda2e6b20e1ea2a13a316decd',1,'angelscript.h']]], + ['asbc_5fitoi64_115',['asBC_iTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa48a1b118c32dc9d5667b9039aa06bff',1,'angelscript.h']]], + ['asbc_5fitow_116',['asBC_iTOw',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0acdf698af6bd4a5e427922e9462244319',1,'angelscript.h']]], + ['asbc_5fjitentry_117',['asBC_JitEntry',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6705ee9692b45f118cfe0ea24581fae5',1,'angelscript.h']]], + ['asbc_5fjlownz_118',['asBC_JLowNZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a12e9c561f401be75a6db13a94a687d77',1,'angelscript.h']]], + ['asbc_5fjlowz_119',['asBC_JLowZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9da365af8ea85e3eb538567207d4a705',1,'angelscript.h']]], + ['asbc_5fjmp_120',['asBC_JMP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6742a11dd679468b98df9c45aabfb32b',1,'angelscript.h']]], + ['asbc_5fjmpp_121',['asBC_JMPP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a31eae477a85a0b1ee618df42deb0519c',1,'angelscript.h']]], + ['asbc_5fjnp_122',['asBC_JNP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae4f95a73cfe667f1928e7766ea09511e',1,'angelscript.h']]], + ['asbc_5fjns_123',['asBC_JNS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a736796cbac759ad4fc43bb09267f36ca',1,'angelscript.h']]], + ['asbc_5fjnz_124',['asBC_JNZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a262d3c0a50f45e6b6de3f1b77f4b4bf0',1,'angelscript.h']]], + ['asbc_5fjp_125',['asBC_JP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac2792270f8022801384ccd0ae3b00604',1,'angelscript.h']]], + ['asbc_5fjs_126',['asBC_JS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2357fddab027985d9af0398e304b0ec1',1,'angelscript.h']]], + ['asbc_5fjz_127',['asBC_JZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a497ae321f5a5889c9bee415b7cc38e9c',1,'angelscript.h']]], + ['asbc_5fldg_128',['asBC_LDG',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7eecc42f41efaa2a9e52a38b5b2e0761',1,'angelscript.h']]], + ['asbc_5fldgrdr4_129',['asBC_LdGRdR4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2d39346b29e025ea48c3d1f9ad5be43e',1,'angelscript.h']]], + ['asbc_5fldv_130',['asBC_LDV',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a506cf72989aae9c3f0613b3fdd788a96',1,'angelscript.h']]], + ['asbc_5floadobj_131',['asBC_LOADOBJ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a05fa84bd9f65d7e99871d9b78da54e16',1,'angelscript.h']]], + ['asbc_5floadrobjr_132',['asBC_LoadRObjR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a55e484687643f87565827249a81cf3a8',1,'angelscript.h']]], + ['asbc_5floadthisr_133',['asBC_LoadThisR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8950187a9c91330124df91bb27d7a1a3',1,'angelscript.h']]], + ['asbc_5floadvobjr_134',['asBC_LoadVObjR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2285121bf664f86d462560fde6dad0f7',1,'angelscript.h']]], + ['asbc_5fmodd_135',['asBC_MODd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac2137a8a8fe7af5070f37e796d863af2',1,'angelscript.h']]], + ['asbc_5fmodf_136',['asBC_MODf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae54338068d6b6e965c497c6b1d68c64e',1,'angelscript.h']]], + ['asbc_5fmodi_137',['asBC_MODi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae8e569143d23f682b3aecfa100bdfd4e',1,'angelscript.h']]], + ['asbc_5fmodi64_138',['asBC_MODi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a3bd852f5aa7c1a12da37a7ac91b1c83f',1,'angelscript.h']]], + ['asbc_5fmodu_139',['asBC_MODu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a22772f5830ff9c17b6427e70128711f8',1,'angelscript.h']]], + ['asbc_5fmodu64_140',['asBC_MODu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aaa0fe36a1a3467428d9d9bc06bf038fe',1,'angelscript.h']]], + ['asbc_5fmuld_141',['asBC_MULd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a411e71202157cfece504379e6171a464',1,'angelscript.h']]], + ['asbc_5fmulf_142',['asBC_MULf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab32f923ffcabab481a2e46f702b17f7a',1,'angelscript.h']]], + ['asbc_5fmuli_143',['asBC_MULi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a93c630d303bb6e91e044d6afea71b798',1,'angelscript.h']]], + ['asbc_5fmuli64_144',['asBC_MULi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a38931ac737104c4ccca730705bd7ec48',1,'angelscript.h']]], + ['asbc_5fmulif_145',['asBC_MULIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a29cb2ee51427268cf549f90e110b1e38',1,'angelscript.h']]], + ['asbc_5fmulii_146',['asBC_MULIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af29eb13449c228f4dead9ba6da590147',1,'angelscript.h']]], + ['asbc_5fnegd_147',['asBC_NEGd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a928187662dfd857cf8edb10a632651d4',1,'angelscript.h']]], + ['asbc_5fnegf_148',['asBC_NEGf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7de6d0118307feca68660e67c79ca7dc',1,'angelscript.h']]], + ['asbc_5fnegi_149',['asBC_NEGi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a01fe11f3f95464cb3e409c3181a02c1a',1,'angelscript.h']]], + ['asbc_5fnegi64_150',['asBC_NEGi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a3cf16372d571ec566ae93fd80e05b1ad',1,'angelscript.h']]], + ['asbc_5fnot_151',['asBC_NOT',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a13a6093971474018818db5a76f012f26',1,'angelscript.h']]], + ['asbc_5fobjtype_152',['asBC_OBJTYPE',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0dcad2ccee9332253501c3cef2200fad',1,'angelscript.h']]], + ['asbc_5fpga_153',['asBC_PGA',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0adc83ae72a402eb4c8d8248ef2ef75d9c',1,'angelscript.h']]], + ['asbc_5fpopptr_154',['asBC_PopPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a61f3044359836f88001928bcab382c1e',1,'angelscript.h']]], + ['asbc_5fpoprptr_155',['asBC_PopRPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a567f07266bd50926c205460b31d579f6',1,'angelscript.h']]], + ['asbc_5fpowd_156',['asBC_POWd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a17794eb37e2e24d3f92945e492fd8fdc',1,'angelscript.h']]], + ['asbc_5fpowdi_157',['asBC_POWdi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a550ee3e286be8a70a06194206c0ae1b9',1,'angelscript.h']]], + ['asbc_5fpowf_158',['asBC_POWf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aedc33b037796cfbb5879799a6bea3b0d',1,'angelscript.h']]], + ['asbc_5fpowi_159',['asBC_POWi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1b9ae2022b484a3c44820b6528c68ac0',1,'angelscript.h']]], + ['asbc_5fpowi64_160',['asBC_POWi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7546139b9cafeae5d71a345ec3b4424d',1,'angelscript.h']]], + ['asbc_5fpowu_161',['asBC_POWu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a45adae8be4e9dde1b77dc9346786cfef',1,'angelscript.h']]], + ['asbc_5fpowu64_162',['asBC_POWu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a23bbb267da86c108b4fe23f0443d5f1d',1,'angelscript.h']]], + ['asbc_5fpsf_163',['asBC_PSF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1c42ff5ba726e656b989e3408fe9648f',1,'angelscript.h']]], + ['asbc_5fpshc4_164',['asBC_PshC4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a53fa213a7d3fed6add6d37dfe073e1cb',1,'angelscript.h']]], + ['asbc_5fpshc8_165',['asBC_PshC8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac987a5f48ff66860142d01ed51670d91',1,'angelscript.h']]], + ['asbc_5fpshg4_166',['asBC_PshG4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a71be4bc7beb5407aac980f73cce33bd6',1,'angelscript.h']]], + ['asbc_5fpshgptr_167',['asBC_PshGPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0c1133692af5029feef4a1e5aec5c65b',1,'angelscript.h']]], + ['asbc_5fpshlistelmnt_168',['asBC_PshListElmnt',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a980fccdeeebe67503f9623722ed893a5',1,'angelscript.h']]], + ['asbc_5fpshnull_169',['asBC_PshNull',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9343148f733f970e3463f37fac57f998',1,'angelscript.h']]], + ['asbc_5fpshrptr_170',['asBC_PshRPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a3ecef93739a85d45002cd073b00da52c',1,'angelscript.h']]], + ['asbc_5fpshv4_171',['asBC_PshV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab858dd8ba0b9fed72638c549f40f60ba',1,'angelscript.h']]], + ['asbc_5fpshv8_172',['asBC_PshV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae2923dbf7fc9bb70c0c3cbbf8673467c',1,'angelscript.h']]], + ['asbc_5fpshvptr_173',['asBC_PshVPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a15f565f207bdaab4d5b72867cdd25007',1,'angelscript.h']]], + ['asbc_5fptrarg_174',['asBC_PTRARG',['../angelscript_8h.html#aac9eb586274fc44bb1b838d833963996',1,'angelscript.h']]], + ['asbc_5fqwordarg_175',['asBC_QWORDARG',['../angelscript_8h.html#a92e1437ea399e8c545e15bffd651f45f',1,'angelscript.h']]], + ['asbc_5frdr1_176',['asBC_RDR1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0375f41153eeaa6d250a6ee262ffa0ba',1,'angelscript.h']]], + ['asbc_5frdr2_177',['asBC_RDR2',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa470ed962fa3e1a86296998914cbcc12',1,'angelscript.h']]], + ['asbc_5frdr4_178',['asBC_RDR4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac66bc5d2959ef22b6c967313aa791b54',1,'angelscript.h']]], + ['asbc_5frdr8_179',['asBC_RDR8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a36dc7a09798a7055d8faece1321e241a',1,'angelscript.h']]], + ['asbc_5frdsptr_180',['asBC_RDSPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2628264804fd19af3ce94e0336b3eeeb',1,'angelscript.h']]], + ['asbc_5frefcpy_181',['asBC_REFCPY',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0509f97130860b6fe3477f66e9fb712d',1,'angelscript.h']]], + ['asbc_5frefcpyv_182',['asBC_RefCpyV',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8b1c7e7b7c8054b36a9d48c3452adf79',1,'angelscript.h']]], + ['asbc_5fret_183',['asBC_RET',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0adf0df27f972bc4edb9b2213fe6448f68',1,'angelscript.h']]], + ['asbc_5fsbtoi_184',['asBC_sbTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0afbfb6f5aaf4d6599e16b4bfe458ce01e',1,'angelscript.h']]], + ['asbc_5fsetg4_185',['asBC_SetG4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a880a2be05a247612df28ea4569a7a99b',1,'angelscript.h']]], + ['asbc_5fsetlistsize_186',['asBC_SetListSize',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8c8a41c980d7b8f2054780da0153ae64',1,'angelscript.h']]], + ['asbc_5fsetlisttype_187',['asBC_SetListType',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7abb1d21f26401e75305a2b4cf7a4733',1,'angelscript.h']]], + ['asbc_5fsetv1_188',['asBC_SetV1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af3909e9889d0994c0d0190a147eac3cb',1,'angelscript.h']]], + ['asbc_5fsetv2_189',['asBC_SetV2',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a709cec30c38c5dc89dfcd92341dafd61',1,'angelscript.h']]], + ['asbc_5fsetv4_190',['asBC_SetV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a95d9223bb76b2abcbc590318007aed93',1,'angelscript.h']]], + ['asbc_5fsetv8_191',['asBC_SetV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ade5e3b21c7d1b9348ac12fc4cd1cbf8a',1,'angelscript.h']]], + ['asbc_5fstoreobj_192',['asBC_STOREOBJ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aaa9dd5f07ce2b4b9d72750daa4b64294',1,'angelscript.h']]], + ['asbc_5fstr_193',['asBC_STR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa9541dbcbb58f820d5d8e81414367d5e',1,'angelscript.h']]], + ['asbc_5fsubd_194',['asBC_SUBd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a40632786e202cc6a617bbe63a8d4cc0f',1,'angelscript.h']]], + ['asbc_5fsubf_195',['asBC_SUBf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aca247b39114dc45ae993dd1cf80226aa',1,'angelscript.h']]], + ['asbc_5fsubi_196',['asBC_SUBi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af04edb64674c1c46b1769b4f31828441',1,'angelscript.h']]], + ['asbc_5fsubi64_197',['asBC_SUBi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a14984f047b26178d73ea024e97b3718c',1,'angelscript.h']]], + ['asbc_5fsubif_198',['asBC_SUBIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a83fc6f0a163316a6be6c280df57fcd13',1,'angelscript.h']]], + ['asbc_5fsubii_199',['asBC_SUBIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab77b30af827c52ee62a5ccab94d96003',1,'angelscript.h']]], + ['asbc_5fsuspend_200',['asBC_SUSPEND',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a175714567c483ff439c1d2c125ca9608',1,'angelscript.h']]], + ['asbc_5fswapptr_201',['asBC_SwapPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac23d851c5aaffca166d6494bec9bcf24',1,'angelscript.h']]], + ['asbc_5fswordarg0_202',['asBC_SWORDARG0',['../angelscript_8h.html#a2287157faea7f6d32b316c17e0858ddf',1,'angelscript.h']]], + ['asbc_5fswordarg1_203',['asBC_SWORDARG1',['../angelscript_8h.html#a92601565873cf5d29a6876c2638d7fec',1,'angelscript.h']]], + ['asbc_5fswordarg2_204',['asBC_SWORDARG2',['../angelscript_8h.html#a698449bbbe369b8a479fb0dd82c9b18e',1,'angelscript.h']]], + ['asbc_5fswtoi_205',['asBC_swTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aad0cc8bb8012f257fa99f01b8b7035bd',1,'angelscript.h']]], + ['asbc_5fthiscall1_206',['asBC_Thiscall1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a25fe35c5c31674255821ecc3c9a9d23c',1,'angelscript.h']]], + ['asbc_5ftnp_207',['asBC_TNP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa57f16a2b46be5e2ce7740389c8eb479',1,'angelscript.h']]], + ['asbc_5ftns_208',['asBC_TNS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6283325ca6354974eec243ce918e6902',1,'angelscript.h']]], + ['asbc_5ftnz_209',['asBC_TNZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac63ed68678f4e7490d67727fd3dc6a80',1,'angelscript.h']]], + ['asbc_5ftp_210',['asBC_TP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6dc225b22eecb133457b82700081cbcf',1,'angelscript.h']]], + ['asbc_5fts_211',['asBC_TS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0136c50e72d9f3e09f053768373f8fd2',1,'angelscript.h']]], + ['asbc_5ftypeid_212',['asBC_TYPEID',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8f1ffc19b950ebc7b6a4b9ac97f8dc4d',1,'angelscript.h']]], + ['asbc_5ftz_213',['asBC_TZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0afa0764106ecce859b73b84119cdbbb19',1,'angelscript.h']]], + ['asbc_5fu64tod_214',['asBC_u64TOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a61a9abe7f4b17874cc1f2eff761bc3b2',1,'angelscript.h']]], + ['asbc_5fu64tof_215',['asBC_u64TOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad293bf12c4a8de3c50794a9eaeac636d',1,'angelscript.h']]], + ['asbc_5fubtoi_216',['asBC_ubTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9c20fcde56da1d0386a10490fb13a7d6',1,'angelscript.h']]], + ['asbc_5futod_217',['asBC_uTOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0abb2e2f37012d6cb75b446fc992dba6c4',1,'angelscript.h']]], + ['asbc_5futof_218',['asBC_uTOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6f445f24f6501cf4c3711929a1d5e111',1,'angelscript.h']]], + ['asbc_5futoi64_219',['asBC_uTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af5f7cad82e5cd2dc4a3d690a2ab46bce',1,'angelscript.h']]], + ['asbc_5fuwtoi_220',['asBC_uwTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1d90e73c2b31b0e15282d092b46cf742',1,'angelscript.h']]], + ['asbc_5fvar_221',['asBC_VAR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0adb056673fe9802b5d8351835d0c4cea9',1,'angelscript.h']]], + ['asbc_5fwordarg0_222',['asBC_WORDARG0',['../angelscript_8h.html#a942798ec89a8ac96550523d80570c703',1,'angelscript.h']]], + ['asbc_5fwordarg1_223',['asBC_WORDARG1',['../angelscript_8h.html#a0a704bf4db31deda2a69d3216312618c',1,'angelscript.h']]], + ['asbc_5fwrtv1_224',['asBC_WRTV1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a94dbdd03bb807ceb48c3ced7b08cbaf3',1,'angelscript.h']]], + ['asbc_5fwrtv2_225',['asBC_WRTV2',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af50492589b9b48fb6cce810ea12b2313',1,'angelscript.h']]], + ['asbc_5fwrtv4_226',['asBC_WRTV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aecc937d822668f3d443c2cf7c2c9a91b',1,'angelscript.h']]], + ['asbc_5fwrtv8_227',['asBC_WRTV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac912670273a5cc5857967d6c4ee9fb71',1,'angelscript.h']]], + ['asbcinfo_228',['asBCInfo',['../angelscript_8h.html#ac58d23b688ddd6d6e788b034daf25df7',1,'angelscript.h']]], + ['asbctype_5fdw_5farg_229',['asBCTYPE_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcacda81b5a95de8ef351d80f7f007f3c1f',1,'angelscript.h']]], + ['asbctype_5fdw_5fdw_5farg_230',['asBCTYPE_DW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcac7dee47b6d43b90ec5d3f348d9adb29b',1,'angelscript.h']]], + ['asbctype_5fno_5farg_231',['asBCTYPE_NO_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca5d474089af62503917b5a9075ea884a0',1,'angelscript.h']]], + ['asbctype_5fqw_5farg_232',['asBCTYPE_QW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcab5ccbe43d9de8e5261c5d98c0235e680',1,'angelscript.h']]], + ['asbctype_5fqw_5fdw_5farg_233',['asBCTYPE_QW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca1923164123cd74d611b8ed4bf491a489',1,'angelscript.h']]], + ['asbctype_5frw_5farg_234',['asBCTYPE_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca8f31f45900a4e5a456c8423e6efa2435',1,'angelscript.h']]], + ['asbctype_5frw_5fdw_5farg_235',['asBCTYPE_rW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcab6ce6fd0303ba86f9933afba82af1da5',1,'angelscript.h']]], + ['asbctype_5frw_5fdw_5fdw_5farg_236',['asBCTYPE_rW_DW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcae203bd09b5f39c9c2b6f9da1cb125fc9',1,'angelscript.h']]], + ['asbctype_5frw_5fqw_5farg_237',['asBCTYPE_rW_QW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcac7dd4b17f956dd9f77154a969826c5b9',1,'angelscript.h']]], + ['asbctype_5frw_5frw_5farg_238',['asBCTYPE_rW_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca3bab72c18fc7528b191c07fa69ce8592',1,'angelscript.h']]], + ['asbctype_5frw_5fw_5fdw_5farg_239',['asBCTYPE_rW_W_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca21c4ffbfac771e092bf8b229d041bfa8',1,'angelscript.h']]], + ['asbctype_5fw_5farg_240',['asBCTYPE_W_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca2ed4017596353fbfd8284abb87693479',1,'angelscript.h']]], + ['asbctype_5fw_5fdw_5farg_241',['asBCTYPE_W_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca3363c16ca9a7dd52a6292e4006a97e25',1,'angelscript.h']]], + ['asbctype_5fww_5farg_242',['asBCTYPE_wW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca35b791ccee8b22494cf5c0d1cd7c1bf1',1,'angelscript.h']]], + ['asbctype_5fww_5fdw_5farg_243',['asBCTYPE_wW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcaca83b5ca2543f825bfb235a7c75bf861',1,'angelscript.h']]], + ['asbctype_5fww_5fqw_5farg_244',['asBCTYPE_wW_QW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcad0f58ec314c7ee6b346428f181406462',1,'angelscript.h']]], + ['asbctype_5fww_5frw_5farg_245',['asBCTYPE_wW_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca983e22175938d52ed285d05729082356',1,'angelscript.h']]], + ['asbctype_5fww_5frw_5fdw_5farg_246',['asBCTYPE_wW_rW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcabd1019654afbbc88a6d7ec145d187d43',1,'angelscript.h']]], + ['asbctype_5fww_5frw_5frw_5farg_247',['asBCTYPE_wW_rW_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca70e3f2b6c20b552f734afa1237ffbfa1',1,'angelscript.h']]], + ['asbctype_5fww_5fw_5farg_248',['asBCTYPE_wW_W_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca20eff83445fbfaeccf0099d04434ddff',1,'angelscript.h']]], + ['asbctypesize_249',['asBCTypeSize',['../angelscript_8h.html#a9f93754a6f4d43118cd0d2b3896875a5',1,'angelscript.h']]], + ['asbehave_5faddref_250',['asBEHAVE_ADDREF',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a1dfa5b72ad69a7bf70636d4fcb1b1d84',1,'angelscript.h']]], + ['asbehave_5fconstruct_251',['asBEHAVE_CONSTRUCT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5aa4cf235bfbf72ec03d0f651cea324101',1,'angelscript.h']]], + ['asbehave_5fdestruct_252',['asBEHAVE_DESTRUCT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a0748a0f3a559354761ce15c2d1de2e51',1,'angelscript.h']]], + ['asbehave_5fenumrefs_253',['asBEHAVE_ENUMREFS',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a08ccf78a37567b5dd192ff5d95c6667b',1,'angelscript.h']]], + ['asbehave_5ffactory_254',['asBEHAVE_FACTORY',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a0b3db16eea35213b6f41f8d19dc1bd4c',1,'angelscript.h']]], + ['asbehave_5fget_5fweakref_5fflag_255',['asBEHAVE_GET_WEAKREF_FLAG',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a7a5e435e88a5fc1dcdee13fce091b081',1,'angelscript.h']]], + ['asbehave_5fgetgcflag_256',['asBEHAVE_GETGCFLAG',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5abfce2539609e667f15b24bbc8551c7b7',1,'angelscript.h']]], + ['asbehave_5fgetrefcount_257',['asBEHAVE_GETREFCOUNT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5af998529f8ea1e54567997b8fb2867640',1,'angelscript.h']]], + ['asbehave_5flist_5fconstruct_258',['asBEHAVE_LIST_CONSTRUCT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a04c0b561986c6814e8a54ce3679178a2',1,'angelscript.h']]], + ['asbehave_5flist_5ffactory_259',['asBEHAVE_LIST_FACTORY',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5aea078bc3b877ce33a2335e78ddb4938d',1,'angelscript.h']]], + ['asbehave_5frelease_260',['asBEHAVE_RELEASE',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a7134ce13c81967191af401a1e5170a0c',1,'angelscript.h']]], + ['asbehave_5freleaserefs_261',['asBEHAVE_RELEASEREFS',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a4275ebe0b4852f2d4a10d4d9db333fe9',1,'angelscript.h']]], + ['asbehave_5fsetgcflag_262',['asBEHAVE_SETGCFLAG',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5aadbad474a338c3a0fe6e90df679bb2e6',1,'angelscript.h']]], + ['asbehave_5ftemplate_5fcallback_263',['asBEHAVE_TEMPLATE_CALLBACK',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a8c9afe12ff833cd09bd893e1408b9103',1,'angelscript.h']]], + ['asbuild_5fin_5fprogress_264',['asBUILD_IN_PROGRESS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54abbab3f809b0eeea2c331e5239be517c1',1,'angelscript.h']]], + ['asbyte_265',['asBYTE',['../angelscript_8h.html#a48b3da7121b3abb56bff63b3beb0df63',1,'angelscript.h']]], + ['ascall_5fcdecl_266',['asCALL_CDECL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a68ae43cc91cdfc3fa4590c9e6164e4f4',1,'angelscript.h']]], + ['ascall_5fcdecl_5fobjfirst_267',['asCALL_CDECL_OBJFIRST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a7c3e88628c2722d0a103b411d4aceaa0',1,'angelscript.h']]], + ['ascall_5fcdecl_5fobjlast_268',['asCALL_CDECL_OBJLAST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4ac08652c72f1cc0dc81c37812fab0e253',1,'angelscript.h']]], + ['ascall_5fgeneric_269',['asCALL_GENERIC',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a750c26b6a6e0c9ccbb93078f532ef8ce',1,'angelscript.h']]], + ['ascall_5fstdcall_270',['asCALL_STDCALL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a138a08e8363ebc695636dfe987674e2e',1,'angelscript.h']]], + ['ascall_5fthiscall_271',['asCALL_THISCALL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4aea516c8742acc1edff6a43dc1bb09e96',1,'angelscript.h']]], + ['ascall_5fthiscall_5fasglobal_272',['asCALL_THISCALL_ASGLOBAL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4aa241a0c1deedaa2d55eb99a83829efad',1,'angelscript.h']]], + ['ascall_5fthiscall_5fobjfirst_273',['asCALL_THISCALL_OBJFIRST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a613a388ed51315f6fce19f3824d6b17a',1,'angelscript.h']]], + ['ascall_5fthiscall_5fobjlast_274',['asCALL_THISCALL_OBJLAST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a491f0ab2b66032a7b5541364f7f225b1',1,'angelscript.h']]], + ['ascant_5fbind_5fall_5ffunctions_275',['asCANT_BIND_ALL_FUNCTIONS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a412d2352693e848f46ccdd93c8d047e4',1,'angelscript.h']]], + ['ascircularreffunc_5ft_276',['asCIRCULARREFFUNC_t',['../angelscript_8h.html#ad39eb868abeebf44bb67fd3965f8bc5f',1,'angelscript.h']]], + ['ascleancontextfunc_5ft_277',['asCLEANCONTEXTFUNC_t',['../angelscript_8h.html#a761b892984e5af51e0f6e37c27dfadb6',1,'angelscript.h']]], + ['ascleanenginefunc_5ft_278',['asCLEANENGINEFUNC_t',['../angelscript_8h.html#aa3dd561bcccb3d5e4966966d7eb2715c',1,'angelscript.h']]], + ['ascleanfunctionfunc_5ft_279',['asCLEANFUNCTIONFUNC_t',['../angelscript_8h.html#a6c0fcc7fee72733c9feb03c0bbf8f5d6',1,'angelscript.h']]], + ['ascleanmodulefunc_5ft_280',['asCLEANMODULEFUNC_t',['../angelscript_8h.html#a5a01d6871440c3b6261da54a8308c452',1,'angelscript.h']]], + ['ascleanscriptobjectfunc_5ft_281',['asCLEANSCRIPTOBJECTFUNC_t',['../angelscript_8h.html#ab89ff127aa05aef3793646b377e9c724',1,'angelscript.h']]], + ['ascleantypeinfofunc_5ft_282',['asCLEANTYPEINFOFUNC_t',['../angelscript_8h.html#aca9bfb1e5a93426df269bd10d88e5cb3',1,'angelscript.h']]], + ['ascomp_5fadd_5fto_5fmodule_283',['asCOMP_ADD_TO_MODULE',['../angelscript_8h.html#a2bf48c41455371788805269376ca5e41a85d0a4fa51dbcc4ad4150f406185b918',1,'angelscript.h']]], + ['asconfig_5fgroup_5fis_5fin_5fuse_284',['asCONFIG_GROUP_IS_IN_USE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ae38f8f5613a631df20d2cc105aafc612',1,'angelscript.h']]], + ['ascontext_5factive_285',['asCONTEXT_ACTIVE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aa818a5cf319a2b2da155554d33cc91b4',1,'angelscript.h']]], + ['ascontext_5fnot_5ffinished_286',['asCONTEXT_NOT_FINISHED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aaca0bfc695713c03655328bf0e2ff814',1,'angelscript.h']]], + ['ascontext_5fnot_5fprepared_287',['asCONTEXT_NOT_PREPARED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a82940f46469cd8cee7b00b346611658c',1,'angelscript.h']]], + ['ascreatelockablesharedbool_288',['asCreateLockableSharedBool',['../group__api__multithread__functions.html#gaa0ffb789dab56b5617e2f961f9c79fdb',1,'angelscript.h']]], + ['ascreatescriptengine_289',['asCreateScriptEngine',['../group__api__principal__functions.html#gacb6a62345d9cca6c9b5a3dac67d80d0b',1,'angelscript.h']]], + ['asdword_290',['asDWORD',['../angelscript_8h.html#a5428f0c940201e5f3bbb28304aeb81bc',1,'angelscript.h']]], + ['asebcinstr_291',['asEBCInstr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0',1,'angelscript.h']]], + ['asebctype_292',['asEBCType',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dc',1,'angelscript.h']]], + ['asebehaviours_293',['asEBehaviours',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5',1,'angelscript.h']]], + ['asecallconvtypes_294',['asECallConvTypes',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4',1,'angelscript.h']]], + ['asecompileflags_295',['asECompileFlags',['../angelscript_8h.html#a2bf48c41455371788805269376ca5e41',1,'angelscript.h']]], + ['asecontextstate_296',['asEContextState',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69',1,'angelscript.h']]], + ['aseengineprop_297',['asEEngineProp',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0f',1,'angelscript.h']]], + ['asefunctype_298',['asEFuncType',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648f',1,'angelscript.h']]], + ['asegcflags_299',['asEGCFlags',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9d',1,'angelscript.h']]], + ['asegmflags_300',['asEGMFlags',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0c',1,'angelscript.h']]], + ['asemsgtype_301',['asEMsgType',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5',1,'angelscript.h']]], + ['aseobjtypeflags_302',['asEObjTypeFlags',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7a',1,'angelscript.h']]], + ['asep_5fallow_5fimplicit_5fhandle_5ftypes_303',['asEP_ALLOW_IMPLICIT_HANDLE_TYPES',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa77c3747503489ca122aa61276dae3c1f',1,'angelscript.h']]], + ['asep_5fallow_5fmultiline_5fstrings_304',['asEP_ALLOW_MULTILINE_STRINGS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa218fdf7e181bf9ee0498112f5a87c415',1,'angelscript.h']]], + ['asep_5fallow_5funicode_5fidentifiers_305',['asEP_ALLOW_UNICODE_IDENTIFIERS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa651f1843c922a61ccee5c81fac58e4d1',1,'angelscript.h']]], + ['asep_5fallow_5funsafe_5freferences_306',['asEP_ALLOW_UNSAFE_REFERENCES',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa8facaf887921a6b26e5a1f06e01ec37a',1,'angelscript.h']]], + ['asep_5falter_5fsyntax_5fnamed_5fargs_307',['asEP_ALTER_SYNTAX_NAMED_ARGS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa9c876445c7d138ad096705fc18f311d1',1,'angelscript.h']]], + ['asep_5falways_5fimpl_5fdefault_5fconstruct_308',['asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6d80b60995ad046918b2376d7d79f2af',1,'angelscript.h']]], + ['asep_5fauto_5fgarbage_5fcollect_309',['asEP_AUTO_GARBAGE_COLLECT',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa9b5d1d8ff5143a6a77dfd18143d87c7d',1,'angelscript.h']]], + ['asep_5fbuild_5fwithout_5fline_5fcues_310',['asEP_BUILD_WITHOUT_LINE_CUES',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa73b396e4ea6376f0962d19add962bd91',1,'angelscript.h']]], + ['asep_5fcompiler_5fwarnings_311',['asEP_COMPILER_WARNINGS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fadd96da828860b5de2352de07c2456633',1,'angelscript.h']]], + ['asep_5fcopy_5fscript_5fsections_312',['asEP_COPY_SCRIPT_SECTIONS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fabf1577418b716c92f0a85be3e2617243',1,'angelscript.h']]], + ['asep_5fdisable_5finteger_5fdivision_313',['asEP_DISABLE_INTEGER_DIVISION',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fae6af9c6963372e11c6da873868f594cd',1,'angelscript.h']]], + ['asep_5fdisallow_5fempty_5flist_5felements_314',['asEP_DISALLOW_EMPTY_LIST_ELEMENTS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fabed7d49670612ec27227210021926692',1,'angelscript.h']]], + ['asep_5fdisallow_5fglobal_5fvars_315',['asEP_DISALLOW_GLOBAL_VARS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fab81c81f4fdeb616dd6487da48a0c3456',1,'angelscript.h']]], + ['asep_5fdisallow_5fvalue_5fassign_5ffor_5fref_5ftype_316',['asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa563bec877e91b0646c47197b2ae7ac0c',1,'angelscript.h']]], + ['asep_5fexpand_5fdef_5farray_5fto_5ftmpl_317',['asEP_EXPAND_DEF_ARRAY_TO_TMPL',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa530e8d9576f94a258446c5fb9b7bd7a5',1,'angelscript.h']]], + ['asep_5fgeneric_5fcall_5fmode_318',['asEP_GENERIC_CALL_MODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa58fa0f29330923b24ab795e7c6ada52e',1,'angelscript.h']]], + ['asep_5fheredoc_5ftrim_5fmode_319',['asEP_HEREDOC_TRIM_MODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa9658b61d2368cc84fe816c817444e0ba',1,'angelscript.h']]], + ['asep_5finclude_5fjit_5finstructions_320',['asEP_INCLUDE_JIT_INSTRUCTIONS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa7ff74f4afa490b55839daaf217cf898c',1,'angelscript.h']]], + ['asep_5finit_5fcall_5fstack_5fsize_321',['asEP_INIT_CALL_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0faabb0261a40d98af8a0f6d38c2150a4e8',1,'angelscript.h']]], + ['asep_5finit_5fglobal_5fvars_5fafter_5fbuild_322',['asEP_INIT_GLOBAL_VARS_AFTER_BUILD',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0facac241d97facce4eaf9e5b0ca40dfcf1',1,'angelscript.h']]], + ['asep_5finit_5fstack_5fsize_323',['asEP_INIT_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6d74b8325be718ace661484f1e8e7fb1',1,'angelscript.h']]], + ['asep_5fmax_5fcall_5fstack_5fsize_324',['asEP_MAX_CALL_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa4d8ec81a881162a1f0689b56ba864346',1,'angelscript.h']]], + ['asep_5fmax_5fnested_5fcalls_325',['asEP_MAX_NESTED_CALLS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fab441e1bdd7488bbe8f6dfa9c6b80e4fc',1,'angelscript.h']]], + ['asep_5fmax_5fstack_5fsize_326',['asEP_MAX_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa1ab4c8f8734f0d90bee4005afd810f83',1,'angelscript.h']]], + ['asep_5foptimize_5fbytecode_327',['asEP_OPTIMIZE_BYTECODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6159294272e4d20dd4b35359a25f3ac6',1,'angelscript.h']]], + ['asep_5fprivate_5fprop_5fas_5fprotected_328',['asEP_PRIVATE_PROP_AS_PROTECTED',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0faa6f88a81f5706542acb94f3c470ac3f3',1,'angelscript.h']]], + ['asep_5fproperty_5faccessor_5fmode_329',['asEP_PROPERTY_ACCESSOR_MODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0facc694c9d52274a113262ebf5984f20ad',1,'angelscript.h']]], + ['asep_5frequire_5fenum_5fscope_330',['asEP_REQUIRE_ENUM_SCOPE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa90adb1e54ce0217235545941daa2dccd',1,'angelscript.h']]], + ['asep_5fscript_5fscanner_331',['asEP_SCRIPT_SCANNER',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa02405d96a12b81aa816986b22bf752c2',1,'angelscript.h']]], + ['asep_5fstring_5fencoding_332',['asEP_STRING_ENCODING',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fab6daa2ae0c712da7f6f16d698305fba1',1,'angelscript.h']]], + ['asep_5fuse_5fcharacter_5fliterals_333',['asEP_USE_CHARACTER_LITERALS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6dc1c33f9227c66f18fc0f95a0c798b2',1,'angelscript.h']]], + ['aseretcodes_334',['asERetCodes',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54',1,'angelscript.h']]], + ['aserror_335',['asERROR',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ac265666b65474ec2848d93201a5bc8c8',1,'angelscript.h']]], + ['asetokenclass_336',['asETokenClass',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbca',1,'angelscript.h']]], + ['asetypeidflags_337',['asETypeIdFlags',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83a',1,'angelscript.h']]], + ['asetypemodifiers_338',['asETypeModifiers',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7',1,'angelscript.h']]], + ['asexecution_5faborted_339',['asEXECUTION_ABORTED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a6f384f00eac7033b4da1430ea7267bbf',1,'angelscript.h']]], + ['asexecution_5factive_340',['asEXECUTION_ACTIVE',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a690200ba7f2d821b0f330ac4220b299a',1,'angelscript.h']]], + ['asexecution_5ferror_341',['asEXECUTION_ERROR',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a9024318029d37f82b07b8c92a42b1bb2',1,'angelscript.h']]], + ['asexecution_5fexception_342',['asEXECUTION_EXCEPTION',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69aa3d548fa7d2278d848e50222b700c6c8',1,'angelscript.h']]], + ['asexecution_5ffinished_343',['asEXECUTION_FINISHED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a6d3730dd7a91aff81cafaaca4e93efaa',1,'angelscript.h']]], + ['asexecution_5fprepared_344',['asEXECUTION_PREPARED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69ab976b0bdaae9969d72a7c73db62e61e1',1,'angelscript.h']]], + ['asexecution_5fsuspended_345',['asEXECUTION_SUSPENDED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a7b5644be315c46f2fa44f032731242c7',1,'angelscript.h']]], + ['asexecution_5funinitialized_346',['asEXECUTION_UNINITIALIZED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a684a042709702ab93417d7db98ae7090',1,'angelscript.h']]], + ['asfreefunc_5ft_347',['asFREEFUNC_t',['../angelscript_8h.html#adeecc934971e695fc4441a47694860fb',1,'angelscript.h']]], + ['asfreemem_348',['asFreeMem',['../group__api__memory__functions.html#ga9da61275bbfd5f7bd55ed411d05fe103',1,'angelscript.h']]], + ['asfunc_5fdelegate_349',['asFUNC_DELEGATE',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa02773b148f9c6fb3ed5d945a940f302a',1,'angelscript.h']]], + ['asfunc_5ffuncdef_350',['asFUNC_FUNCDEF',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa73c9b6201770e89cb90212c793ca5173',1,'angelscript.h']]], + ['asfunc_5fimported_351',['asFUNC_IMPORTED',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa9c44f646079e0592316cf5892e33d0ec',1,'angelscript.h']]], + ['asfunc_5finterface_352',['asFUNC_INTERFACE',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fac245ebb3ca53d4037e28de80ae81991f',1,'angelscript.h']]], + ['asfunc_5fscript_353',['asFUNC_SCRIPT',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fac5431c6f2ee2e7cf530739c01c1343eb',1,'angelscript.h']]], + ['asfunc_5fsystem_354',['asFUNC_SYSTEM',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa9ea0b7b39362f427b7449b11d70f306b',1,'angelscript.h']]], + ['asfunc_5fvirtual_355',['asFUNC_VIRTUAL',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fac6a82b2b64cfee8e143a41b4b627083a',1,'angelscript.h']]], + ['asfunction_356',['asFUNCTION',['../angelscript_8h.html#a78f8f2c7f1c88b12e74a5ac47b4184ae',1,'angelscript.h']]], + ['asfunctionpr_357',['asFUNCTIONPR',['../angelscript_8h.html#a153aee5a6228913a469b6e6867e54efb',1,'angelscript.h']]], + ['asgc_5fdestroy_5fgarbage_358',['asGC_DESTROY_GARBAGE',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da61ab8361ad09823a287572d026efe7f1',1,'angelscript.h']]], + ['asgc_5fdetect_5fgarbage_359',['asGC_DETECT_GARBAGE',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da3ff3b60e4d1bbc94f6ad46604994526a',1,'angelscript.h']]], + ['asgc_5ffull_5fcycle_360',['asGC_FULL_CYCLE',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da31e476bfb875b0f4fb209a3ef2540709',1,'angelscript.h']]], + ['asgc_5fone_5fstep_361',['asGC_ONE_STEP',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da33a4cea43ee17e4f01bef742762e5af8',1,'angelscript.h']]], + ['asgetactivecontext_362',['asGetActiveContext',['../group__api__principal__functions.html#gad3a20dc58093b92a5a44c7b6ada34a10',1,'angelscript.h']]], + ['asgetlibraryoptions_363',['asGetLibraryOptions',['../group__api__auxiliary__functions.html#gaba86cba765a7148e2a306b4305ba48f9',1,'angelscript.h']]], + ['asgetlibraryversion_364',['asGetLibraryVersion',['../group__api__auxiliary__functions.html#ga79cbcfe1a47e436da6f2f28ff0314f75',1,'angelscript.h']]], + ['asgetthreadmanager_365',['asGetThreadManager',['../group__api__multithread__functions.html#ga948def50c98db90596b706ca4b58041e',1,'angelscript.h']]], + ['asgettypetraits_366',['asGetTypeTraits',['../group__api__principal__functions.html#ga863f2a1e60e6c19eea9c6b34690dcc00',1,'angelscript.h']]], + ['asgm_5falways_5fcreate_367',['asGM_ALWAYS_CREATE',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0ca0843ab784ed9a9ea6cb47d915825186f',1,'angelscript.h']]], + ['asgm_5fcreate_5fif_5fnot_5fexists_368',['asGM_CREATE_IF_NOT_EXISTS',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0cafaa7b80aa39b669fbe250c0822af63bb',1,'angelscript.h']]], + ['asgm_5fonly_5fif_5fexists_369',['asGM_ONLY_IF_EXISTS',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0ca2feb963eb04c221e251867bc3a93d79d',1,'angelscript.h']]], + ['asibinarystream_370',['asIBinaryStream',['../classas_i_binary_stream.html',1,'']]], + ['asijitcompiler_371',['asIJITCompiler',['../classas_i_j_i_t_compiler.html',1,'']]], + ['asillegal_5fbehaviour_5ffor_5ftype_372',['asILLEGAL_BEHAVIOUR_FOR_TYPE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a5cd00c005a05345d8967021ebaae51f8',1,'angelscript.h']]], + ['asilockablesharedbool_373',['asILockableSharedBool',['../classas_i_lockable_shared_bool.html',1,'']]], + ['asinit_5fglobal_5fvars_5ffailed_374',['asINIT_GLOBAL_VARS_FAILED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a539a1fcf3f48feaaf7c0776c88123430',1,'angelscript.h']]], + ['asint16_375',['asINT16',['../angelscript_8h.html#afd9f62d6b3a975d02b22432f7a923f83',1,'angelscript.h']]], + ['asint64_376',['asINT64',['../angelscript_8h.html#aa8044b56ee56e2350b06f1e7207b43df',1,'angelscript.h']]], + ['asint8_377',['asINT8',['../angelscript_8h.html#a2b6922ec0cb3785c6c2328afa7bd9a9b',1,'angelscript.h']]], + ['asinvalid_5farg_378',['asINVALID_ARG',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a04e0f0b1ea30eacff3b4a6dddf2060b8',1,'angelscript.h']]], + ['asinvalid_5fconfiguration_379',['asINVALID_CONFIGURATION',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a7416ebaf18f32e180595fb366a072754',1,'angelscript.h']]], + ['asinvalid_5fdeclaration_380',['asINVALID_DECLARATION',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ab25fab2dbf4379d7a95a800b765287e4',1,'angelscript.h']]], + ['asinvalid_5finterface_381',['asINVALID_INTERFACE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a87279b314ed35fc9a6bff9e7cb05eb73',1,'angelscript.h']]], + ['asinvalid_5fname_382',['asINVALID_NAME',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a85a932230d1622bcb5ec341d25db7775',1,'angelscript.h']]], + ['asinvalid_5fobject_383',['asINVALID_OBJECT',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aa9b05e66771b2af2e7d14d32701a6015',1,'angelscript.h']]], + ['asinvalid_5ftype_384',['asINVALID_TYPE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a4af648067b42f433f0b1d7141f6e487c',1,'angelscript.h']]], + ['asiscriptcontext_385',['asIScriptContext',['../classas_i_script_context.html',1,'']]], + ['asiscriptengine_386',['asIScriptEngine',['../classas_i_script_engine.html',1,'']]], + ['asiscriptfunction_387',['asIScriptFunction',['../classas_i_script_function.html',1,'']]], + ['asiscriptgeneric_388',['asIScriptGeneric',['../classas_i_script_generic.html',1,'']]], + ['asiscriptmodule_389',['asIScriptModule',['../classas_i_script_module.html',1,'']]], + ['asiscriptobject_390',['asIScriptObject',['../classas_i_script_object.html',1,'']]], + ['asistringfactory_391',['asIStringFactory',['../classas_i_string_factory.html',1,'']]], + ['asithreadmanager_392',['asIThreadManager',['../classas_i_thread_manager.html',1,'']]], + ['asitypeinfo_393',['asITypeInfo',['../classas_i_type_info.html',1,'']]], + ['asjitfunction_394',['asJITFunction',['../angelscript_8h.html#af9d3986a33c1bda5c4f82a7aaa0dfeeb',1,'angelscript.h']]], + ['aslower_5farray_5fdimension_5fnot_5fregistered_395',['asLOWER_ARRAY_DIMENSION_NOT_REGISTERED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ab11ea721572e02e63498b681105fe8cc',1,'angelscript.h']]], + ['asmethod_396',['asMETHOD',['../angelscript_8h.html#a7345e6b3afabec24efd0ff77886d49a6',1,'angelscript.h']]], + ['asmethodpr_397',['asMETHODPR',['../angelscript_8h.html#ac45ccb5854326cce38d721e2c00f1563',1,'angelscript.h']]], + ['asmodule_5fis_5fin_5fuse_398',['asMODULE_IS_IN_USE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54af1e13f62c802e525a94722429575a345',1,'angelscript.h']]], + ['asmsgtype_5ferror_399',['asMSGTYPE_ERROR',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5a2e3d48fd09f1ca865fc5b81b0dbeb7d4',1,'angelscript.h']]], + ['asmsgtype_5finformation_400',['asMSGTYPE_INFORMATION',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5ae29dba474231c07149dca09a9258f80d',1,'angelscript.h']]], + ['asmsgtype_5fwarning_401',['asMSGTYPE_WARNING',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5a210c2023d6971d688a0302096acf945d',1,'angelscript.h']]], + ['asmultiple_5ffunctions_402',['asMULTIPLE_FUNCTIONS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54acb8338c55edbf8c27e2eb0b2505a0773',1,'angelscript.h']]], + ['asname_5ftaken_403',['asNAME_TAKEN',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a0210997973bc0b74288a2041757f2763',1,'angelscript.h']]], + ['asno_5ffunction_404',['asNO_FUNCTION',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ad021afee96a6ef28423c2d37d3430eed',1,'angelscript.h']]], + ['asno_5fglobal_5fvar_405',['asNO_GLOBAL_VAR',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aa465751329c2a7315318f609b1c271d4',1,'angelscript.h']]], + ['asno_5fmodule_406',['asNO_MODULE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a4cf88b5ffb76ebe34cb57d4d983bae79',1,'angelscript.h']]], + ['asnot_5fsupported_407',['asNOT_SUPPORTED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a93ccbf6a4f741cb8c0c7ef3fae4c4084',1,'angelscript.h']]], + ['asobj_5fabstract_408',['asOBJ_ABSTRACT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa7c3d513b69c810647dbb80d48da77ee5',1,'angelscript.h']]], + ['asobj_5fapp_5falign16_409',['asOBJ_APP_ALIGN16',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aacb0a87a6461924a892502c0e7a861d24',1,'angelscript.h']]], + ['asobj_5fapp_5farray_410',['asOBJ_APP_ARRAY',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa84a949c5cc6d4d872054baac1a085419',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_411',['asOBJ_APP_CLASS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa103297ed88696a3c30ec12e533d902c3',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fa_412',['asOBJ_APP_CLASS_A',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaf7389e5dc914e6ab121580430be6d88b',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fak_413',['asOBJ_APP_CLASS_AK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa7b1ce7e4c79ba23fd26b01474d550173',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5falign8_414',['asOBJ_APP_CLASS_ALIGN8',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa244efb813b401b3a6d087c3add802818',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fallfloats_415',['asOBJ_APP_CLASS_ALLFLOATS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa12afb6a0fa4ac874ce89815d3611823d',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fallints_416',['asOBJ_APP_CLASS_ALLINTS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa5b8de58c5be3145aaa3e54008fb2edeb',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fassignment_417',['asOBJ_APP_CLASS_ASSIGNMENT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa6bf9b7bead31a40e7983538d8cecc3a4',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fc_418',['asOBJ_APP_CLASS_C',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa3eb67e27cc0fac7602934c1ff101aed5',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fca_419',['asOBJ_APP_CLASS_CA',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa90b85700943e8acb45316943f1951d04',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcak_420',['asOBJ_APP_CLASS_CAK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa97b022a4656cd9f351cd68c3903170b2',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcd_421',['asOBJ_APP_CLASS_CD',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaf15f3dd82be0e77e05ee0dbea096bb36',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcda_422',['asOBJ_APP_CLASS_CDA',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aae13159e3ea949d52803cb635538a77f2',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcdak_423',['asOBJ_APP_CLASS_CDAK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa12d358962300537f2b0da20106eb270c',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcdk_424',['asOBJ_APP_CLASS_CDK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa2aa6c871af75df3852f52658bf284765',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fck_425',['asOBJ_APP_CLASS_CK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa619d54158a026e44bc5cffbb30794497',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fconstructor_426',['asOBJ_APP_CLASS_CONSTRUCTOR',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aafd799c0705cee720a12ceb2838796024',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcopy_5fconstructor_427',['asOBJ_APP_CLASS_COPY_CONSTRUCTOR',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa925febfd30b150d97a84b7c6ee6a8677',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fd_428',['asOBJ_APP_CLASS_D',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa30a67a6e98721d20d41b70fe961ff778',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fda_429',['asOBJ_APP_CLASS_DA',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa38dd93911127894c5594474b4f06db1a',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fdak_430',['asOBJ_APP_CLASS_DAK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa4b7a67f596940218860dc36ad9a4c66c',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fdestructor_431',['asOBJ_APP_CLASS_DESTRUCTOR',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa18d80c6d92e4bc104955da393c966917',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fdk_432',['asOBJ_APP_CLASS_DK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aab59c583cdcee2acce632f35db39139ae',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fk_433',['asOBJ_APP_CLASS_K',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa54236f54163e1df076bef918a862bd82',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fmore_5fconstructors_434',['asOBJ_APP_CLASS_MORE_CONSTRUCTORS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa4d3329b6e6e223207da73c97f01533e7',1,'angelscript.h']]], + ['asobj_5fapp_5ffloat_435',['asOBJ_APP_FLOAT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa7f7690d53d9bfc580e09ac7bf5868175',1,'angelscript.h']]], + ['asobj_5fapp_5fprimitive_436',['asOBJ_APP_PRIMITIVE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa539ede421d313b03464c88cb15f08c75',1,'angelscript.h']]], + ['asobj_5fashandle_437',['asOBJ_ASHANDLE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aadf3d1f30658e593f48c5c5f542ac4845',1,'angelscript.h']]], + ['asobj_5fenum_438',['asOBJ_ENUM',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa018e73b8c343fe8f46fa7a7829643ff9',1,'angelscript.h']]], + ['asobj_5ffuncdef_439',['asOBJ_FUNCDEF',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa5b0f6287649893c8a04b43ed1f71a182',1,'angelscript.h']]], + ['asobj_5fgc_440',['asOBJ_GC',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aacc1d835f9c25043cef86026a4aa6a470',1,'angelscript.h']]], + ['asobj_5fimplicit_5fhandle_441',['asOBJ_IMPLICIT_HANDLE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaee8bfdbc6c2faac1938bba7e3a8b5ff2',1,'angelscript.h']]], + ['asobj_5flist_5fpattern_442',['asOBJ_LIST_PATTERN',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaa1094cbe2986e60ba82da9dea38bba05',1,'angelscript.h']]], + ['asobj_5fmask_5fvalid_5fflags_443',['asOBJ_MASK_VALID_FLAGS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa6570f63d7f13e7d945770228a82f1f12',1,'angelscript.h']]], + ['asobj_5fnocount_444',['asOBJ_NOCOUNT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aad8b12da6bf9cd48990d48c2ddf13584d',1,'angelscript.h']]], + ['asobj_5fnohandle_445',['asOBJ_NOHANDLE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aafa1830b02c4d51ddc25451e7ad1a7592',1,'angelscript.h']]], + ['asobj_5fnoinherit_446',['asOBJ_NOINHERIT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa770f4012f052a1190edbac8931140091',1,'angelscript.h']]], + ['asobj_5fpod_447',['asOBJ_POD',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa8ad017ddf25368870b28ee0fba96495a',1,'angelscript.h']]], + ['asobj_5fref_448',['asOBJ_REF',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa9450e038342b36c745858d2e5ae4b861',1,'angelscript.h']]], + ['asobj_5fscoped_449',['asOBJ_SCOPED',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaaae92b24e278976320f19d9dc75fe6db',1,'angelscript.h']]], + ['asobj_5fscript_5fobject_450',['asOBJ_SCRIPT_OBJECT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaa82f3ef517372e0db029f7dcfe7f88eb',1,'angelscript.h']]], + ['asobj_5fshared_451',['asOBJ_SHARED',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa92354ace56201eb543c818b6c0852baf',1,'angelscript.h']]], + ['asobj_5ftemplate_452',['asOBJ_TEMPLATE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aae8de459b4106475aa8766edb5b088aac',1,'angelscript.h']]], + ['asobj_5ftemplate_5fsubtype_453',['asOBJ_TEMPLATE_SUBTYPE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa8e4f2ff9cea9a561be32711c91bf71e6',1,'angelscript.h']]], + ['asobj_5ftypedef_454',['asOBJ_TYPEDEF',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aad9ec544ec0cca5ec329d19bceefadf0c',1,'angelscript.h']]], + ['asobj_5fvalue_455',['asOBJ_VALUE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa9fc16a8ac0f30f9ff9c6568e0b7be91d',1,'angelscript.h']]], + ['asoffset_456',['asOFFSET',['../angelscript_8h.html#a717eccea17214bc1eb64bb9789c4915a',1,'angelscript.h']]], + ['asout_5fof_5fmemory_457',['asOUT_OF_MEMORY',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a9a5232a5c1028cd729a744f592387059',1,'angelscript.h']]], + ['aspreparemultithread_458',['asPrepareMultithread',['../group__api__multithread__functions.html#gaa5bea65c3f2a224bb1c677515e3bb0e2',1,'angelscript.h']]], + ['aspword_459',['asPWORD',['../angelscript_8h.html#a76fc6994aba7ff6c685a62c273c057e3',1,'angelscript.h']]], + ['asqword_460',['asQWORD',['../angelscript_8h.html#a10aea5de212e440ffd6ec8fc0b17563d',1,'angelscript.h']]], + ['asreleaseexclusivelock_461',['asReleaseExclusiveLock',['../group__api__multithread__functions.html#ga8a0617637eea3d76e33a52758b2cd49f',1,'angelscript.h']]], + ['asreleasesharedlock_462',['asReleaseSharedLock',['../group__api__multithread__functions.html#ga44f7327c5601e8dbf74768a2f3cc0dc3',1,'angelscript.h']]], + ['asrequestcontextfunc_5ft_463',['asREQUESTCONTEXTFUNC_t',['../angelscript_8h.html#a2925360becae92319e68abb23a61fd56',1,'angelscript.h']]], + ['asresetglobalmemoryfunctions_464',['asResetGlobalMemoryFunctions',['../group__api__memory__functions.html#ga9267c4ad35aceaf7cc0961cd42147ee7',1,'angelscript.h']]], + ['asreturncontextfunc_5ft_465',['asRETURNCONTEXTFUNC_t',['../angelscript_8h.html#a3ffcfca5bd3be4f4c633408a6b209476',1,'angelscript.h']]], + ['assbcinfo_466',['asSBCInfo',['../structas_s_b_c_info.html',1,'']]], + ['assetglobalmemoryfunctions_467',['asSetGlobalMemoryFunctions',['../group__api__memory__functions.html#ga527ab125defc58aa40cc151a25582a31',1,'angelscript.h']]], + ['assfuncptr_468',['asSFuncPtr',['../structas_s_func_ptr.html',1,'']]], + ['assignscriptobject_469',['AssignScriptObject',['../classas_i_script_engine.html#a9180da5fd475f52916be6b39e522fabb',1,'asIScriptEngine']]], + ['assmessageinfo_470',['asSMessageInfo',['../structas_s_message_info.html',1,'']]], + ['assuccess_471',['asSUCCESS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a0bf59062f03c90599e66a87275f37854',1,'angelscript.h']]], + ['assvmregisters_472',['asSVMRegisters',['../structas_s_v_m_registers.html',1,'']]], + ['astc_5fcomment_473',['asTC_COMMENT',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaac738f8a91d1e0badd12d456206372224',1,'angelscript.h']]], + ['astc_5fidentifier_474',['asTC_IDENTIFIER',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaad31e06870d87e2eb0d37da0bdd06d87f',1,'angelscript.h']]], + ['astc_5fkeyword_475',['asTC_KEYWORD',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa96a4ebcca4fd7cade65c6163d4eb2bc0',1,'angelscript.h']]], + ['astc_5funknown_476',['asTC_UNKNOWN',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa2a6ba011564d30250b5664beee57f727',1,'angelscript.h']]], + ['astc_5fvalue_477',['asTC_VALUE',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa75fd6044f67010b490a65ff3718d93e2',1,'angelscript.h']]], + ['astc_5fwhitespace_478',['asTC_WHITESPACE',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa7ca0b961e4d799140f79c971d3596cf8',1,'angelscript.h']]], + ['asthreadcleanup_479',['asThreadCleanup',['../group__api__multithread__functions.html#ga51079811680d5217046aad2a2b695dc7',1,'angelscript.h']]], + ['astm_5fconst_480',['asTM_CONST',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7a75422a76c05f8b084895e73f90972e34',1,'angelscript.h']]], + ['astm_5finoutref_481',['asTM_INOUTREF',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7aaefa7d0cb8d421469fcfc4248d3ba5c5',1,'angelscript.h']]], + ['astm_5finref_482',['asTM_INREF',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7a8de0af7f268793bb251f0607b72cad19',1,'angelscript.h']]], + ['astm_5fnone_483',['asTM_NONE',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7aad24888f100d685b7eb4c330e8e09047',1,'angelscript.h']]], + ['astm_5foutref_484',['asTM_OUTREF',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7a8ebee94d0968a789e3953d0100a9d2ee',1,'angelscript.h']]], + ['astypeid_5fappobject_485',['asTYPEID_APPOBJECT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa3b1403bbf7d1c617f734c39a574c7aa1',1,'angelscript.h']]], + ['astypeid_5fbool_486',['asTYPEID_BOOL',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa502865ff428df06342ac9d94d69318ec',1,'angelscript.h']]], + ['astypeid_5fdouble_487',['asTYPEID_DOUBLE',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa8b069e24ecddd678b3811126832df49f',1,'angelscript.h']]], + ['astypeid_5ffloat_488',['asTYPEID_FLOAT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa43ec6e15e840ebf165070c2ebe9c954d',1,'angelscript.h']]], + ['astypeid_5fhandletoconst_489',['asTYPEID_HANDLETOCONST',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aaa4c35253b679ef667c30153f586ecbb5',1,'angelscript.h']]], + ['astypeid_5fint16_490',['asTYPEID_INT16',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa3d246e59038d67ba2945b9c89ed874c0',1,'angelscript.h']]], + ['astypeid_5fint32_491',['asTYPEID_INT32',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aabcc8e086d59505f6ba18ea85e72afc33',1,'angelscript.h']]], + ['astypeid_5fint64_492',['asTYPEID_INT64',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aaa73d32346b63cef156c6783703414a21',1,'angelscript.h']]], + ['astypeid_5fint8_493',['asTYPEID_INT8',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa7e647a9a1ce963f22d5c384673d0dc5f',1,'angelscript.h']]], + ['astypeid_5fmask_5fobject_494',['asTYPEID_MASK_OBJECT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa09eef59280d15a58c75e0c8983a3c3af',1,'angelscript.h']]], + ['astypeid_5fmask_5fseqnbr_495',['asTYPEID_MASK_SEQNBR',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa8a0789b5d397d79ba34a441116a6321b',1,'angelscript.h']]], + ['astypeid_5fobjhandle_496',['asTYPEID_OBJHANDLE',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa63249041dff18d01e362d71efca2b4ed',1,'angelscript.h']]], + ['astypeid_5fscriptobject_497',['asTYPEID_SCRIPTOBJECT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa29f9a7c07904452b512431b7b4b5b6e4',1,'angelscript.h']]], + ['astypeid_5ftemplate_498',['asTYPEID_TEMPLATE',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aab5fde5eaa0401712c8abd01fc366e9cc',1,'angelscript.h']]], + ['astypeid_5fuint16_499',['asTYPEID_UINT16',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aae72cf12a6d4a77c74b278972256d11f3',1,'angelscript.h']]], + ['astypeid_5fuint32_500',['asTYPEID_UINT32',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aac069cb7584e126ac4cf6faeb33fa87a3',1,'angelscript.h']]], + ['astypeid_5fuint64_501',['asTYPEID_UINT64',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aaf22925e9946a4493c2e1c238c6043844',1,'angelscript.h']]], + ['astypeid_5fuint8_502',['asTYPEID_UINT8',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa32fa8c495f1eed78592d3898d35e1a46',1,'angelscript.h']]], + ['astypeid_5fvoid_503',['asTYPEID_VOID',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aad924c0d48ab734431bbd7467a9bfa819',1,'angelscript.h']]], + ['asuint_504',['asUINT',['../angelscript_8h.html#ac8186f029686800b7ce36bde4a55c815',1,'angelscript.h']]], + ['asunpreparemultithread_505',['asUnprepareMultithread',['../group__api__multithread__functions.html#ga011355a8978d438cec77b4e1f041cba7',1,'angelscript.h']]], + ['asword_506',['asWORD',['../angelscript_8h.html#a340da175136fbe283932fa3c3442cea0',1,'angelscript.h']]], + ['aswrong_5fcalling_5fconv_507',['asWRONG_CALLING_CONV',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a2774780aba35e11f224f8c0bd0937207',1,'angelscript.h']]], + ['aswrong_5fconfig_5fgroup_508',['asWRONG_CONFIG_GROUP',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ace5f5b97f2832c2f3aed3bb47ac1e486',1,'angelscript.h']]], + ['add_2dons_509',['Add-ons',['../doc_addon.html',1,'main_topics']]], + ['any_20object_510',['any object',['../doc_addon_any.html',1,'doc_addon_script']]], + ['application_20modules_511',['Application modules',['../doc_addon_application.html',1,'doc_addon']]], + ['array_20template_20object_512',['array template object',['../doc_addon_array.html',1,'doc_addon_script']]], + ['automatic_20wrapper_20functions_513',['Automatic wrapper functions',['../doc_addon_autowrap.html',1,'doc_addon_application']]], + ['access_20masks_20and_20exposing_20different_20interfaces_514',['Access masks and exposing different interfaces',['../doc_adv_access_mask.html',1,'doc_advanced']]], + ['advanced_20topics_515',['Advanced topics',['../doc_advanced.html',1,'main_topics']]], + ['advanced_20application_20interface_516',['Advanced application interface',['../doc_advanced_api.html',1,'doc_register_api_topic']]], + ['array_517',['array',['../doc_datatypes_arrays.html',1,'doc_script_stdlib']]], + ['auto_20declarations_518',['Auto declarations',['../doc_datatypes_auto.html',1,'doc_datatypes']]], + ['asrun_20manual_519',['asrun manual',['../doc_samples_asrun_manual.html',1,'doc_samples_asrun']]], + ['anonymous_20functions_520',['Anonymous functions',['../doc_script_anonfunc.html',1,'doc_script_func']]] +]; diff --git a/docs/manual/search/all_1.html b/docs/manual/search/all_1.html new file mode 100644 index 0000000..86b0682 --- /dev/null +++ b/docs/manual/search/all_1.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_1.js b/docs/manual/search/all_1.js new file mode 100644 index 0000000..ce9743b --- /dev/null +++ b/docs/manual/search/all_1.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['bc_521',['bc',['../structas_s_b_c_info.html#a44543d80233f6d2158b300e7049e23ab',1,'asSBCInfo']]], + ['beginconfiggroup_522',['BeginConfigGroup',['../classas_i_script_engine.html#ac81014e50dd7efc1920adcb3fd2d1e5d',1,'asIScriptEngine']]], + ['bindallimportedfunctions_523',['BindAllImportedFunctions',['../classas_i_script_module.html#a3f0c215576adefd922c2cc95d16b55d8',1,'asIScriptModule']]], + ['bindimportedfunction_524',['BindImportedFunction',['../classas_i_script_module.html#ab24a8b95ce887c3f731eb906e3b518e5',1,'asIScriptModule']]], + ['build_525',['Build',['../classas_i_script_module.html#a8acf107194c5f079d7f7507309ebe613',1,'asIScriptModule']]], + ['byte_20code_20instructions_526',['Byte code instructions',['../doc_adv_jit_1.html',1,'doc_adv_jit_topic']]] +]; diff --git a/docs/manual/search/all_10.html b/docs/manual/search/all_10.html new file mode 100644 index 0000000..b910674 --- /dev/null +++ b/docs/manual/search/all_10.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_10.js b/docs/manual/search/all_10.js new file mode 100644 index 0000000..a293ed5 --- /dev/null +++ b/docs/manual/search/all_10.js @@ -0,0 +1,66 @@ +var searchData= +[ + ['secondary_20interfaces_846',['Secondary interfaces',['../group__api__secondary__interfaces.html',1,'']]], + ['script_20builder_847',['Script builder',['../doc_addon_build.html',1,'doc_addon_application']]], + ['script_20extensions_848',['Script extensions',['../doc_addon_script.html',1,'doc_addon']]], + ['serializer_849',['Serializer',['../doc_addon_serializer.html',1,'doc_addon_application']]], + ['string_20object_850',['string object',['../doc_addon_std_string.html',1,'doc_addon_script']]], + ['strings_851',['Strings',['../doc_datatypes_strings.html',1,'doc_datatypes']]], + ['script_20classes_852',['Script classes',['../doc_global_class.html',1,'doc_script_global']]], + ['script_20modules_853',['Script modules',['../doc_module.html',1,'doc_understanding_as']]], + ['samples_854',['Samples',['../doc_samples.html',1,'main_topics']]], + ['script_20language_20grammar_855',['Script language grammar',['../doc_script_bnf.html',1,'doc_script']]], + ['script_20classes_856',['Script classes',['../doc_script_class.html',1,'doc_script']]], + ['script_20class_20overview_857',['Script class overview',['../doc_script_class_desc.html',1,'doc_script_class']]], + ['shared_20script_20entities_858',['Shared script entities',['../doc_script_shared.html',1,'doc_script']]], + ['statements_859',['Statements',['../doc_script_statements.html',1,'doc_script']]], + ['standard_20library_860',['Standard library',['../doc_script_stdlib.html',1,'doc_script']]], + ['string_861',['string',['../doc_script_stdlib_string.html',1,'doc_script_stdlib']]], + ['system_20functions_862',['System functions',['../doc_script_stdlib_system.html',1,'doc_script_stdlib']]], + ['savebytecode_863',['SaveByteCode',['../classas_i_script_module.html#ac6cd95dd97cc6abf28ab4d82257f5aeb',1,'asIScriptModule']]], + ['section_864',['section',['../structas_s_message_info.html#aeca6368be12c84b62ed8c659b1e4615c',1,'asSMessageInfo']]], + ['set_865',['Set',['../classas_i_lockable_shared_bool.html#aa29488ac2f1c38788d5e79545fdfc8c7',1,'asILockableSharedBool']]], + ['setaccessmask_866',['SetAccessMask',['../classas_i_script_module.html#a76733de5a86875c4a0f021f7f92a6d12',1,'asIScriptModule']]], + ['setargaddress_867',['SetArgAddress',['../classas_i_script_context.html#aa8de8f21dfbb2cdf0becbabaa3e883ed',1,'asIScriptContext']]], + ['setargbyte_868',['SetArgByte',['../classas_i_script_context.html#ac5ac8ce5bb209f43d4da620db5d271da',1,'asIScriptContext']]], + ['setargdouble_869',['SetArgDouble',['../classas_i_script_context.html#acbdddda3b80c37b70b8fd35c8e7383b9',1,'asIScriptContext']]], + ['setargdword_870',['SetArgDWord',['../classas_i_script_context.html#a14cac831c1b419f552ca62a239dfcf45',1,'asIScriptContext']]], + ['setargfloat_871',['SetArgFloat',['../classas_i_script_context.html#a702a40cfe539e4e655a84e15161f8db8',1,'asIScriptContext']]], + ['setargobject_872',['SetArgObject',['../classas_i_script_context.html#a09044a12dfb2d44d19bd8a4025cb814d',1,'asIScriptContext']]], + ['setargqword_873',['SetArgQWord',['../classas_i_script_context.html#a742c870360588e99528f09bae6156482',1,'asIScriptContext']]], + ['setargvartype_874',['SetArgVarType',['../classas_i_script_context.html#a626d97ec564c92120e2abaf69f6e3698',1,'asIScriptContext']]], + ['setargword_875',['SetArgWord',['../classas_i_script_context.html#ac882e19b922c681052a0a88d69289a47',1,'asIScriptContext']]], + ['setcircularrefdetectedcallback_876',['SetCircularRefDetectedCallback',['../classas_i_script_engine.html#aac3d5b7c9920b4f98405a19e515ceb26',1,'asIScriptEngine']]], + ['setcontextcallbacks_877',['SetContextCallbacks',['../classas_i_script_engine.html#ae5ba9fe99b72c60392cdaeef164f2c65',1,'asIScriptEngine']]], + ['setcontextuserdatacleanupcallback_878',['SetContextUserDataCleanupCallback',['../classas_i_script_engine.html#acaced7eb9ebe013ede23f7593daf58e3',1,'asIScriptEngine']]], + ['setdefaultaccessmask_879',['SetDefaultAccessMask',['../classas_i_script_engine.html#a570df3e676f2d9e03e87d97b8cede1c7',1,'asIScriptEngine']]], + ['setdefaultnamespace_880',['SetDefaultNamespace',['../classas_i_script_engine.html#a605f114814f1f64804c04391816d948b',1,'asIScriptEngine::SetDefaultNamespace()'],['../classas_i_script_module.html#ab8629af79cee8212d0d244314d36f42a',1,'asIScriptModule::SetDefaultNamespace()']]], + ['setengineproperty_881',['SetEngineProperty',['../classas_i_script_engine.html#a1bce4e5f573a2ca0ff55163e28f761dd',1,'asIScriptEngine']]], + ['setengineuserdatacleanupcallback_882',['SetEngineUserDataCleanupCallback',['../classas_i_script_engine.html#a8fa4fc9aacb99db6d4be0a5542b85e35',1,'asIScriptEngine']]], + ['setexception_883',['SetException',['../classas_i_script_context.html#a6f0f071215e0f7effc0b765043f01275',1,'asIScriptContext']]], + ['setexceptioncallback_884',['SetExceptionCallback',['../classas_i_script_context.html#a4d1f481473df3f7aefccc5bb6904e405',1,'asIScriptContext']]], + ['setfunctionuserdatacleanupcallback_885',['SetFunctionUserDataCleanupCallback',['../classas_i_script_engine.html#ae75ee087fe6608cf0af1c24794ca73c7',1,'asIScriptEngine']]], + ['setjitcompiler_886',['SetJITCompiler',['../classas_i_script_engine.html#aee4f910163604203a27db1ffea3b1c9c',1,'asIScriptEngine']]], + ['setlinecallback_887',['SetLineCallback',['../classas_i_script_context.html#ae2747f643bf9a07364f922c460ef57dd',1,'asIScriptContext']]], + ['setmessagecallback_888',['SetMessageCallback',['../classas_i_script_engine.html#a74192fe950808eb72a64e3e371f0ea02',1,'asIScriptEngine']]], + ['setmoduleuserdatacleanupcallback_889',['SetModuleUserDataCleanupCallback',['../classas_i_script_engine.html#a7523853b9a9bf7dab603fa6a06393d51',1,'asIScriptEngine']]], + ['setname_890',['SetName',['../classas_i_script_module.html#a1a7534bace9eefdc3175a1999f9cbf4a',1,'asIScriptModule']]], + ['setobject_891',['SetObject',['../classas_i_script_context.html#a10d3c152b25d07584999f4d9fe5ce8b1',1,'asIScriptContext']]], + ['setreturnaddress_892',['SetReturnAddress',['../classas_i_script_generic.html#afd8ead96f17d6e77f3a26c70c3a1d80c',1,'asIScriptGeneric']]], + ['setreturnbyte_893',['SetReturnByte',['../classas_i_script_generic.html#a81c42965dfccfd242e955f50b02a641c',1,'asIScriptGeneric']]], + ['setreturndouble_894',['SetReturnDouble',['../classas_i_script_generic.html#a8a720ef33859981dd941c616b2c83cad',1,'asIScriptGeneric']]], + ['setreturndword_895',['SetReturnDWord',['../classas_i_script_generic.html#a3260e1f3b76791713bced9af0b81bdbc',1,'asIScriptGeneric']]], + ['setreturnfloat_896',['SetReturnFloat',['../classas_i_script_generic.html#acc2fddd4175ad35854cec8f5c38a6495',1,'asIScriptGeneric']]], + ['setreturnobject_897',['SetReturnObject',['../classas_i_script_generic.html#a94c9ca32722cb44b09211e51fa906e6e',1,'asIScriptGeneric']]], + ['setreturnqword_898',['SetReturnQWord',['../classas_i_script_generic.html#a25f5ec30c666ffbb51edeedfd4c89546',1,'asIScriptGeneric']]], + ['setreturnword_899',['SetReturnWord',['../classas_i_script_generic.html#a9c51e3ff3f4fb37f6b4c82a050319955',1,'asIScriptGeneric']]], + ['setscriptobjectuserdatacleanupcallback_900',['SetScriptObjectUserDataCleanupCallback',['../classas_i_script_engine.html#a4654e2cae0690c50e19b177f1ec54592',1,'asIScriptEngine']]], + ['settranslateappexceptioncallback_901',['SetTranslateAppExceptionCallback',['../classas_i_script_engine.html#addce6a202934a4918f7776b2f77c43fd',1,'asIScriptEngine']]], + ['settypeinfouserdatacleanupcallback_902',['SetTypeInfoUserDataCleanupCallback',['../classas_i_script_engine.html#afa31e7c28c63a2c876d8e08305cf5d75',1,'asIScriptEngine']]], + ['setuserdata_903',['SetUserData',['../classas_i_script_engine.html#aabee8d6ef426c434adee85ec6d57f940',1,'asIScriptEngine::SetUserData()'],['../classas_i_script_module.html#a06582e57e7101df4157ee36c81867c13',1,'asIScriptModule::SetUserData()'],['../classas_i_script_context.html#a263dc70abb2a8c77adcea7c9ede0a479',1,'asIScriptContext::SetUserData()'],['../classas_i_script_object.html#ac85cea9bca5dd3868e027285e44dd6d0',1,'asIScriptObject::SetUserData()'],['../classas_i_type_info.html#a5e8ea071f1c1f3b7c6dfc1950bec73f4',1,'asITypeInfo::SetUserData()'],['../classas_i_script_function.html#a9dd036ce8e91d335eb5a3ad8851f1a41',1,'asIScriptFunction::SetUserData()']]], + ['shutdownandrelease_904',['ShutDownAndRelease',['../classas_i_script_engine.html#a28c3800620d4aeaca75d084391eb758e',1,'asIScriptEngine']]], + ['stackframepointer_905',['stackFramePointer',['../structas_s_v_m_registers.html#ab1d0ebdb2e9b1b57320ade00beaf229b',1,'asSVMRegisters']]], + ['stackinc_906',['stackInc',['../structas_s_b_c_info.html#afa46372104c863ec52c4f6c5e33eba89',1,'asSBCInfo']]], + ['stackpointer_907',['stackPointer',['../structas_s_v_m_registers.html#abb79cddcc4d38d286f221f2b4d323ab6',1,'asSVMRegisters']]], + ['suspend_908',['Suspend',['../classas_i_script_context.html#ad4ac8be3586c46069b5870e40c86544a',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/all_11.html b/docs/manual/search/all_11.html new file mode 100644 index 0000000..459c977 --- /dev/null +++ b/docs/manual/search/all_11.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_11.js b/docs/manual/search/all_11.js new file mode 100644 index 0000000..2dca5c9 --- /dev/null +++ b/docs/manual/search/all_11.js @@ -0,0 +1,12 @@ +var searchData= +[ + ['template_20types_909',['Template types',['../doc_adv_template.html',1,'doc_advanced_api']]], + ['timeout_20long_20running_20scripts_910',['Timeout long running scripts',['../doc_adv_timeout.html',1,'doc_advanced']]], + ['the_20variable_20parameter_20type_911',['The variable parameter type',['../doc_adv_var_type.html',1,'doc_advanced_api']]], + ['the_20generic_20calling_20convention_912',['The generic calling convention',['../doc_generic.html',1,'doc_advanced_api']]], + ['typedefs_913',['Typedefs',['../doc_global_typedef.html',1,'doc_script_global']]], + ['tutorial_914',['Tutorial',['../doc_samples_tutorial.html',1,'doc_samples']]], + ['the_20script_20language_915',['The script language',['../doc_script.html',1,'']]], + ['todo_20list_916',['Todo List',['../todo.html',1,'']]], + ['type_917',['type',['../structas_s_message_info.html#a6aa9231534b8aea2a3099cdc3206bcc8',1,'asSMessageInfo::type()'],['../structas_s_b_c_info.html#aa0579956f325760177250e0eddd52ab4',1,'asSBCInfo::type()']]] +]; diff --git a/docs/manual/search/all_12.html b/docs/manual/search/all_12.html new file mode 100644 index 0000000..290ee76 --- /dev/null +++ b/docs/manual/search/all_12.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_12.js b/docs/manual/search/all_12.js new file mode 100644 index 0000000..82a9987 --- /dev/null +++ b/docs/manual/search/all_12.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['using_20namespaces_918',['Using namespaces',['../doc_adv_namespace.html',1,'doc_advanced']]], + ['understanding_20angelscript_919',['Understanding AngelScript',['../doc_understanding_as.html',1,'main_topics']]], + ['using_20script_20classes_920',['Using script classes',['../doc_use_script_class.html',1,'main_topics']]], + ['unbindallimportedfunctions_921',['UnbindAllImportedFunctions',['../classas_i_script_module.html#ab7b4c4b94190779028776fd1057a658f',1,'asIScriptModule']]], + ['unbindimportedfunction_922',['UnbindImportedFunction',['../classas_i_script_module.html#a4d59b4e833bf139f6b7256d6b6bd40b6',1,'asIScriptModule']]], + ['unlock_923',['Unlock',['../classas_i_lockable_shared_bool.html#a863984c1b271df84f71fb5ba978ce2b8',1,'asILockableSharedBool']]], + ['unprepare_924',['Unprepare',['../classas_i_script_context.html#ae3c18a2cc66c56f840e6ee4310287f65',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/all_13.html b/docs/manual/search/all_13.html new file mode 100644 index 0000000..f7d46e7 --- /dev/null +++ b/docs/manual/search/all_13.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_13.js b/docs/manual/search/all_13.js new file mode 100644 index 0000000..a492b9b --- /dev/null +++ b/docs/manual/search/all_13.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['variables_925',['Variables',['../doc_global_variable.html',1,'doc_script_global']]], + ['virtual_20properties_926',['Virtual properties',['../doc_global_virtprop.html',1,'doc_script_global']]], + ['versions_927',['Versions',['../doc_versions.html',1,'doc_understanding_as']]], + ['valueregister_928',['valueRegister',['../structas_s_v_m_registers.html#aa87c457f97ce8e49fd808c8b6fd8e9d8',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/search/all_14.html b/docs/manual/search/all_14.html new file mode 100644 index 0000000..c0e4c76 --- /dev/null +++ b/docs/manual/search/all_14.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_14.js b/docs/manual/search/all_14.js new file mode 100644 index 0000000..6a850a4 --- /dev/null +++ b/docs/manual/search/all_14.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['weakref_20object_929',['weakref object',['../doc_addon_weakref.html',1,'doc_addon_script']]], + ['weak_20references_930',['Weak references',['../doc_adv_weakref.html',1,'doc_advanced_api']]], + ['weakref_931',['weakref',['../doc_datatypes_weakref.html',1,'doc_script_stdlib']]], + ['what_20can_20be_20registered_932',['What can be registered',['../doc_register_api.html',1,'doc_register_api_topic']]], + ['willexceptionbecaught_933',['WillExceptionBeCaught',['../classas_i_script_context.html#a57cfcc729b214fdaacb1358e03daf610',1,'asIScriptContext']]], + ['write_934',['Write',['../classas_i_binary_stream.html#a57724f9cd63a625a843bf97e7704d9a7',1,'asIBinaryStream']]], + ['writemessage_935',['WriteMessage',['../classas_i_script_engine.html#a936ce6566af958bb75ba1c0945d8b03a',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/all_15.html b/docs/manual/search/all_15.html new file mode 100644 index 0000000..ff41552 --- /dev/null +++ b/docs/manual/search/all_15.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_15.js b/docs/manual/search/all_15.js new file mode 100644 index 0000000..cb6fb76 --- /dev/null +++ b/docs/manual/search/all_15.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['your_20first_20script_936',['Your first script',['../doc_hello_world.html',1,'doc_start']]] +]; diff --git a/docs/manual/search/all_2.html b/docs/manual/search/all_2.html new file mode 100644 index 0000000..ffa7873 --- /dev/null +++ b/docs/manual/search/all_2.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_2.js b/docs/manual/search/all_2.js new file mode 100644 index 0000000..a59752e --- /dev/null +++ b/docs/manual/search/all_2.js @@ -0,0 +1,32 @@ +var searchData= +[ + ['clearexceptioncallback_527',['ClearExceptionCallback',['../classas_i_script_context.html#acb5cfe5703031fd76672a57d8afae547',1,'asIScriptContext']]], + ['clearlinecallback_528',['ClearLineCallback',['../classas_i_script_context.html#a3771cf314de339fa5d70edfbfcd88370',1,'asIScriptContext']]], + ['clearmessagecallback_529',['ClearMessageCallback',['../classas_i_script_engine.html#ada64567fc9621e5e98160c7f03efa064',1,'asIScriptEngine']]], + ['col_530',['col',['../structas_s_message_info.html#a08b23a360ac52110323bbf4aad553d9d',1,'asSMessageInfo']]], + ['compilefunction_531',['CompileFunction',['../classas_i_script_module.html#a1258d7cfeed965f36ba312beeb49e81c',1,'asIScriptModule::CompileFunction()'],['../classas_i_j_i_t_compiler.html#aa6270727e61d8708d651a0f5faada695',1,'asIJITCompiler::CompileFunction()']]], + ['compileglobalvar_532',['CompileGlobalVar',['../classas_i_script_module.html#a34850e152dcdcb58c53a2b6929cebf77',1,'asIScriptModule']]], + ['copyfrom_533',['CopyFrom',['../classas_i_script_object.html#ab83919a23c02ec07c66d9aedcbecf261',1,'asIScriptObject']]], + ['createcontext_534',['CreateContext',['../classas_i_script_engine.html#a2630e1cd03ffab0fee9b820bf0afe42a',1,'asIScriptEngine']]], + ['createdelegate_535',['CreateDelegate',['../classas_i_script_engine.html#ab4a4cea1cfeea361b8a44d80f3d928e3',1,'asIScriptEngine']]], + ['createscriptobject_536',['CreateScriptObject',['../classas_i_script_engine.html#a3101479b4340bc16bb9acb8e8d554266',1,'asIScriptEngine']]], + ['createscriptobjectcopy_537',['CreateScriptObjectCopy',['../classas_i_script_engine.html#ab2b1543ea6d24b912aebeb77e6764269',1,'asIScriptEngine']]], + ['createuninitializedscriptobject_538',['CreateUninitializedScriptObject',['../classas_i_script_engine.html#a9de3c5e4465f699ad698740d6037e1a6',1,'asIScriptEngine']]], + ['ctx_539',['ctx',['../structas_s_v_m_registers.html#aaaf2063a2786459281f9426f5083f8d1',1,'asSVMRegisters']]], + ['context_20manager_540',['Context manager',['../doc_addon_ctxmgr.html',1,'doc_addon_application']]], + ['class_20hierarchies_541',['Class hierarchies',['../doc_adv_class_hierarchy.html',1,'doc_advanced_api']]], + ['concurrent_20scripts_542',['Concurrent scripts',['../doc_adv_concurrent.html',1,'doc_advanced']]], + ['co_2droutines_543',['Co-routines',['../doc_adv_coroutine.html',1,'doc_advanced']]], + ['custom_20options_544',['Custom options',['../doc_adv_custom_options.html',1,'doc_advanced']]], + ['custom_20array_20type_545',['Custom array type',['../doc_arrays.html',1,'doc_advanced_api']]], + ['calling_20a_20script_20function_546',['Calling a script function',['../doc_call_script_func.html',1,'main_topics']]], + ['compile_20the_20library_547',['Compile the library',['../doc_compile_lib.html',1,'doc_start']]], + ['compiling_20scripts_548',['Compiling scripts',['../doc_compile_script.html',1,'main_topics']]], + ['c_2b_2b_20exceptions_20and_20longjmp_549',['C++ exceptions and longjmp',['../doc_cpp_exceptions.html',1,'doc_advanced_api']]], + ['command_20line_20runner_550',['Command line runner',['../doc_samples_asrun.html',1,'doc_samples']]], + ['concurrent_20scripts_551',['Concurrent scripts',['../doc_samples_concurrent.html',1,'doc_samples']]], + ['console_552',['Console',['../doc_samples_console.html',1,'doc_samples']]], + ['co_2droutines_553',['Co-routines',['../doc_samples_corout.html',1,'doc_samples']]], + ['co_2droutines_554',['Co-routines',['../doc_script_stdlib_coroutine.html',1,'doc_script_stdlib']]], + ['custom_20string_20type_555',['Custom string type',['../doc_strings.html',1,'doc_advanced_api']]] +]; diff --git a/docs/manual/search/all_3.html b/docs/manual/search/all_3.html new file mode 100644 index 0000000..f9df19b --- /dev/null +++ b/docs/manual/search/all_3.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_3.js b/docs/manual/search/all_3.js new file mode 100644 index 0000000..1448936 --- /dev/null +++ b/docs/manual/search/all_3.js @@ -0,0 +1,19 @@ +var searchData= +[ + ['derivesfrom_556',['DerivesFrom',['../classas_i_type_info.html#a4ce24b7a0ecd27bb7e34f1fa58c08d29',1,'asITypeInfo']]], + ['discard_557',['Discard',['../classas_i_script_module.html#a0e6a69be59f16c8b51d1e21d3905d95c',1,'asIScriptModule']]], + ['discardmodule_558',['DiscardModule',['../classas_i_script_engine.html#afb0ce55e5846eb18afdcf906aeb67cf7',1,'asIScriptEngine']]], + ['datetime_20object_559',['datetime object',['../doc_addon_datetime.html',1,'doc_addon_script']]], + ['debugger_560',['Debugger',['../doc_addon_debugger.html',1,'doc_addon_application']]], + ['dictionary_20object_561',['dictionary object',['../doc_addon_dict.html',1,'doc_addon_script']]], + ['dynamic_20compilations_562',['Dynamic compilations',['../doc_adv_dynamic_build.html',1,'doc_advanced']]], + ['dynamic_20configurations_563',['Dynamic configurations',['../doc_adv_dynamic_config.html',1,'doc_advanced']]], + ['datatypes_20in_20angelscript_20and_20c_2b_2b_564',['Datatypes in AngelScript and C++',['../doc_as_vs_cpp_types.html',1,'doc_understanding_as']]], + ['data_20types_565',['Data types',['../doc_datatypes.html',1,'doc_script']]], + ['dictionary_566',['dictionary',['../doc_datatypes_dictionary.html',1,'doc_script_stdlib']]], + ['debugging_20scripts_567',['Debugging scripts',['../doc_debug.html',1,'doc_advanced']]], + ['default_20arguments_568',['Default arguments',['../doc_script_func_defarg.html',1,'doc_script_func']]], + ['datetime_569',['datetime',['../doc_script_stdlib_datetime.html',1,'doc_script_stdlib']]], + ['doprocesssuspend_570',['doProcessSuspend',['../structas_s_v_m_registers.html#ae1fe3cb6cbcf870cfde3364e66909e4f',1,'asSVMRegisters']]], + ['developer_20manual_571',['Developer manual',['../main_topics.html',1,'']]] +]; diff --git a/docs/manual/search/all_4.html b/docs/manual/search/all_4.html new file mode 100644 index 0000000..aa2c933 --- /dev/null +++ b/docs/manual/search/all_4.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_4.js b/docs/manual/search/all_4.js new file mode 100644 index 0000000..67f9c1f --- /dev/null +++ b/docs/manual/search/all_4.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['exception_20routines_572',['Exception routines',['../doc_addon_helpers_try.html',1,'doc_addon_script']]], + ['expressions_573',['Expressions',['../doc_expressions.html',1,'doc_script']]], + ['enums_574',['Enums',['../doc_global_enums.html',1,'doc_script_global']]], + ['events_575',['Events',['../doc_samples_events.html',1,'doc_samples']]], + ['exception_20handling_576',['Exception handling',['../doc_script_stdlib_exception.html',1,'doc_script_stdlib']]], + ['endconfiggroup_577',['EndConfigGroup',['../classas_i_script_engine.html#a4cc5ed7ea71811655f7910d298bb5a02',1,'asIScriptEngine']]], + ['execute_578',['Execute',['../classas_i_script_context.html#a8e52894432737acac2e1a422e496bf84',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/all_5.html b/docs/manual/search/all_5.html new file mode 100644 index 0000000..71848af --- /dev/null +++ b/docs/manual/search/all_5.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_5.js b/docs/manual/search/all_5.js new file mode 100644 index 0000000..763e06d --- /dev/null +++ b/docs/manual/search/all_5.js @@ -0,0 +1,18 @@ +var searchData= +[ + ['file_20object_579',['file object',['../doc_addon_file.html',1,'doc_addon_script']]], + ['filesystem_20object_580',['filesystem object',['../doc_addon_filesystem.html',1,'doc_addon_script']]], + ['funcdefs_20and_20script_20callback_20functions_581',['Funcdefs and script callback functions',['../doc_callbacks.html',1,'main_topics']]], + ['function_20handles_582',['Function handles',['../doc_datatypes_funcptr.html',1,'doc_datatypes']]], + ['fine_20tuning_583',['Fine tuning',['../doc_finetuning.html',1,'doc_advanced']]], + ['functions_584',['Functions',['../doc_global_func.html',1,'doc_script_global']]], + ['funcdefs_585',['Funcdefs',['../doc_global_funcdef.html',1,'doc_script_global']]], + ['functions_586',['Functions',['../doc_script_func.html',1,'doc_script']]], + ['function_20declaration_587',['Function declaration',['../doc_script_func_decl.html',1,'doc_script_func']]], + ['function_20overloading_588',['Function overloading',['../doc_script_func_overload.html',1,'doc_script_func']]], + ['file_589',['file',['../doc_script_stdlib_file.html',1,'doc_script_stdlib']]], + ['filesystem_590',['filesystem',['../doc_script_stdlib_filesystem.html',1,'doc_script_stdlib']]], + ['findnextlinewithcode_591',['FindNextLineWithCode',['../classas_i_script_function.html#a30dc23991856a13f59e682b3b1498e2f',1,'asIScriptFunction']]], + ['forwardgcenumreferences_592',['ForwardGCEnumReferences',['../classas_i_script_engine.html#abe95ce0e45d914fec478fa112a7bb8dd',1,'asIScriptEngine']]], + ['forwardgcreleasereferences_593',['ForwardGCReleaseReferences',['../classas_i_script_engine.html#a60cdec608a18f6ebc0aebe29a143183f',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/all_6.html b/docs/manual/search/all_6.html new file mode 100644 index 0000000..a24601b --- /dev/null +++ b/docs/manual/search/all_6.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_6.js b/docs/manual/search/all_6.js new file mode 100644 index 0000000..62a9013 --- /dev/null +++ b/docs/manual/search/all_6.js @@ -0,0 +1,156 @@ +var searchData= +[ + ['grid_20template_20object_594',['grid template object',['../doc_addon_grid.html',1,'doc_addon_script']]], + ['garbage_20collection_595',['Garbage collection',['../doc_gc.html',1,'doc_advanced']]], + ['garbage_20collected_20objects_596',['Garbage collected objects',['../doc_gc_object.html',1,'doc_advanced_api']]], + ['good_20practices_597',['Good practices',['../doc_good_practice.html',1,'doc_start']]], + ['generic_20compiler_598',['Generic compiler',['../doc_samples_asbuild.html',1,'doc_samples']]], + ['game_599',['Game',['../doc_samples_game.html',1,'doc_samples']]], + ['global_20entities_600',['Global entities',['../doc_script_global.html',1,'doc_script']]], + ['getting_20started_601',['Getting started',['../doc_start.html',1,'main_topics']]], + ['garbagecollect_602',['GarbageCollect',['../classas_i_script_engine.html#a17511a1de72ecdb836b974768f2ec422',1,'asIScriptEngine']]], + ['gcenumcallback_603',['GCEnumCallback',['../classas_i_script_engine.html#a58ceeafd780dea3543e0ede4106199fd',1,'asIScriptEngine']]], + ['get_604',['Get',['../classas_i_lockable_shared_bool.html#abab39fc60f00ae8941423258ffc2c3c6',1,'asILockableSharedBool']]], + ['getaccessmask_605',['GetAccessMask',['../classas_i_type_info.html#a849e5890b225717b243c73e3d4f38204',1,'asITypeInfo::GetAccessMask()'],['../classas_i_script_function.html#a5c49841eb92a0993a16eb855577b590c',1,'asIScriptFunction::GetAccessMask()']]], + ['getaddressofarg_606',['GetAddressOfArg',['../classas_i_script_context.html#a0fbab94982862b30cd55996d4a24949c',1,'asIScriptContext::GetAddressOfArg()'],['../classas_i_script_generic.html#a08f922bc97867e1e97e923a5bdee4dbc',1,'asIScriptGeneric::GetAddressOfArg()']]], + ['getaddressofglobalvar_607',['GetAddressOfGlobalVar',['../classas_i_script_module.html#a0998d375ca1de02bc72f4544806da58c',1,'asIScriptModule']]], + ['getaddressofproperty_608',['GetAddressOfProperty',['../classas_i_script_object.html#a6a8a3c7d1e103e43923614b719e3cb3a',1,'asIScriptObject']]], + ['getaddressofreturnlocation_609',['GetAddressOfReturnLocation',['../classas_i_script_generic.html#a103a91f081ec894a116cd3db06b0d8d1',1,'asIScriptGeneric']]], + ['getaddressofreturnvalue_610',['GetAddressOfReturnValue',['../classas_i_script_context.html#a889bf11123beba669637849c8e9b2b86',1,'asIScriptContext']]], + ['getaddressofvar_611',['GetAddressOfVar',['../classas_i_script_context.html#acc916505d79de321a2ab2b46b1c61fb7',1,'asIScriptContext']]], + ['getargaddress_612',['GetArgAddress',['../classas_i_script_generic.html#ac5c73473ccefe029582c5e3793d1a41b',1,'asIScriptGeneric']]], + ['getargbyte_613',['GetArgByte',['../classas_i_script_generic.html#a20f30e6ed55ed952bcb5c70096eb83dd',1,'asIScriptGeneric']]], + ['getargcount_614',['GetArgCount',['../classas_i_script_generic.html#aafdaf0ed1ff5023b2aaf4ae1adfa3714',1,'asIScriptGeneric']]], + ['getargdouble_615',['GetArgDouble',['../classas_i_script_generic.html#ad0bb07a940b7ba08abc3ce114dca99fc',1,'asIScriptGeneric']]], + ['getargdword_616',['GetArgDWord',['../classas_i_script_generic.html#aab74bcbe4be32fc423b21b75a3f4d57a',1,'asIScriptGeneric']]], + ['getargfloat_617',['GetArgFloat',['../classas_i_script_generic.html#a487a68e409d79e61fcc624337c4ac991',1,'asIScriptGeneric']]], + ['getargobject_618',['GetArgObject',['../classas_i_script_generic.html#a6732b01132cd58e81cd0354ac274039a',1,'asIScriptGeneric']]], + ['getargqword_619',['GetArgQWord',['../classas_i_script_generic.html#a0fbd6ce45aebc29e29a64dac4affc111',1,'asIScriptGeneric']]], + ['getargtypeid_620',['GetArgTypeId',['../classas_i_script_generic.html#a2bdce6872b371355665e932a962548cb',1,'asIScriptGeneric']]], + ['getargword_621',['GetArgWord',['../classas_i_script_generic.html#afdb602c3c2e285c5f34bc477ebbd1534',1,'asIScriptGeneric']]], + ['getauxiliary_622',['GetAuxiliary',['../classas_i_script_generic.html#adf0ec41b9df5c93d72a950c78f6fea8e',1,'asIScriptGeneric::GetAuxiliary()'],['../classas_i_script_function.html#acbdd97f1c3658cb4f82a154591e100f6',1,'asIScriptFunction::GetAuxiliary()']]], + ['getbasetype_623',['GetBaseType',['../classas_i_type_info.html#a8722ecc6b7e47491cdb6e442a3bf1ba2',1,'asITypeInfo']]], + ['getbehaviourbyindex_624',['GetBehaviourByIndex',['../classas_i_type_info.html#ae91a1b2080e76a0dcad8106436728314',1,'asITypeInfo']]], + ['getbehaviourcount_625',['GetBehaviourCount',['../classas_i_type_info.html#ad7c3c757cc99df4d40c6b3b44896cb96',1,'asITypeInfo']]], + ['getbytecode_626',['GetByteCode',['../classas_i_script_function.html#afb38e9ba77ce8b49378e43dadd83ef94',1,'asIScriptFunction']]], + ['getcallstacksize_627',['GetCallstackSize',['../classas_i_script_context.html#aab359abc4563a8439338bfd655824bd7',1,'asIScriptContext']]], + ['getchildfuncdef_628',['GetChildFuncdef',['../classas_i_type_info.html#a01fe2f0b68614246a63e52cada374b69',1,'asITypeInfo']]], + ['getchildfuncdefcount_629',['GetChildFuncdefCount',['../classas_i_type_info.html#aa9b5a0281ff01d448e55cb10e42ba340',1,'asITypeInfo']]], + ['getconfiggroup_630',['GetConfigGroup',['../classas_i_type_info.html#aa181c094c192e86299b394ebcfa68760',1,'asITypeInfo::GetConfigGroup()'],['../classas_i_script_function.html#afea841f0923573cea81467ac90b71996',1,'asIScriptFunction::GetConfigGroup()']]], + ['getdeclaration_631',['GetDeclaration',['../classas_i_script_function.html#a2fb021b09ae0e7e87f8fa4fdfd39df83',1,'asIScriptFunction']]], + ['getdefaultarraytypeid_632',['GetDefaultArrayTypeId',['../classas_i_script_engine.html#ae86e5444979b0abd92777be83c53fc80',1,'asIScriptEngine']]], + ['getdefaultnamespace_633',['GetDefaultNamespace',['../classas_i_script_engine.html#a257a25e285faa25e8cf08e455528def7',1,'asIScriptEngine::GetDefaultNamespace()'],['../classas_i_script_module.html#aa1aa775a81fc2bbf84ff2b07fd9561e3',1,'asIScriptModule::GetDefaultNamespace()']]], + ['getdelegatefunction_634',['GetDelegateFunction',['../classas_i_script_function.html#aa28f4e68da8abb770d7f725375bcd2bb',1,'asIScriptFunction']]], + ['getdelegateobject_635',['GetDelegateObject',['../classas_i_script_function.html#ae1786c3f4341dc3bfcaacc3cb8900a57',1,'asIScriptFunction']]], + ['getdelegateobjecttype_636',['GetDelegateObjectType',['../classas_i_script_function.html#ad79461f80fcffd513b43564d75cc5360',1,'asIScriptFunction']]], + ['getengine_637',['GetEngine',['../classas_i_script_module.html#aef861826f4d09fd411aee7792854bfb8',1,'asIScriptModule::GetEngine()'],['../classas_i_script_context.html#a07f12016c5435aec5b63449abb6e4d8d',1,'asIScriptContext::GetEngine()'],['../classas_i_script_generic.html#a3f3b0838588e3afa7172f9bbb87f5445',1,'asIScriptGeneric::GetEngine()'],['../classas_i_script_object.html#a5dda2d380ae1580e15ddf9d95893c57a',1,'asIScriptObject::GetEngine()'],['../classas_i_type_info.html#abafbb3a12cbd94f56a4f3c1739fd6ada',1,'asITypeInfo::GetEngine()'],['../classas_i_script_function.html#a7a0ef04f035d1809fb8b7702134afd06',1,'asIScriptFunction::GetEngine()']]], + ['getengineproperty_638',['GetEngineProperty',['../classas_i_script_engine.html#a5531bf5310a0c933aa698725a6828e5f',1,'asIScriptEngine']]], + ['getenumbyindex_639',['GetEnumByIndex',['../classas_i_script_engine.html#adedc8b2ad11a84ec12aef4f98e27a4c4',1,'asIScriptEngine::GetEnumByIndex()'],['../classas_i_script_module.html#a0ec42bef3874f0fc0e6b929068ae927c',1,'asIScriptModule::GetEnumByIndex()']]], + ['getenumcount_640',['GetEnumCount',['../classas_i_script_engine.html#a4b4307dab64061be43db84ffb97e3782',1,'asIScriptEngine::GetEnumCount()'],['../classas_i_script_module.html#a1a241b3dfd47f7ab5bb475c757e38df9',1,'asIScriptModule::GetEnumCount()']]], + ['getenumvaluebyindex_641',['GetEnumValueByIndex',['../classas_i_type_info.html#aaece7c2106dbced04436b52515f1f7ac',1,'asITypeInfo']]], + ['getenumvaluecount_642',['GetEnumValueCount',['../classas_i_type_info.html#abe22697bab6560c30c9b613187d6b4d7',1,'asITypeInfo']]], + ['getexceptionfunction_643',['GetExceptionFunction',['../classas_i_script_context.html#a8e59aceec42080d29e08b44460ceb8b3',1,'asIScriptContext']]], + ['getexceptionlinenumber_644',['GetExceptionLineNumber',['../classas_i_script_context.html#a22e3c351fe6b13ba0a62010dfc305080',1,'asIScriptContext']]], + ['getexceptionstring_645',['GetExceptionString',['../classas_i_script_context.html#a46e2411bc84e99f57e7d9fe2374bb479',1,'asIScriptContext']]], + ['getfactorybydecl_646',['GetFactoryByDecl',['../classas_i_type_info.html#aca1e08cd395231d30ad78a7ca3fea142',1,'asITypeInfo']]], + ['getfactorybyindex_647',['GetFactoryByIndex',['../classas_i_type_info.html#a6a8b52fefd309102142ba74621d35714',1,'asITypeInfo']]], + ['getfactorycount_648',['GetFactoryCount',['../classas_i_type_info.html#a22cb802db08d6f464f6ee12337390d12',1,'asITypeInfo']]], + ['getflags_649',['GetFlags',['../classas_i_type_info.html#a068900ec359ff7fc2ee59a938ffe20ab',1,'asITypeInfo']]], + ['getfuncdefbyindex_650',['GetFuncdefByIndex',['../classas_i_script_engine.html#ad4228220347347384c0aa0e0dd8308c6',1,'asIScriptEngine']]], + ['getfuncdefcount_651',['GetFuncdefCount',['../classas_i_script_engine.html#a48aceb1556f88ce3bec3e0f84abe127f',1,'asIScriptEngine']]], + ['getfuncdefsignature_652',['GetFuncdefSignature',['../classas_i_type_info.html#abf4e686097f0c485e6dcd330fe47f91e',1,'asITypeInfo']]], + ['getfunction_653',['GetFunction',['../classas_i_script_context.html#a1c101300447f2909e5d188409a7180f6',1,'asIScriptContext::GetFunction()'],['../classas_i_script_generic.html#acf00e806a36e0b42686c0f8df25b0898',1,'asIScriptGeneric::GetFunction()']]], + ['getfunctionbydecl_654',['GetFunctionByDecl',['../classas_i_script_module.html#ab4754d55d8667aefbed135b4794d461b',1,'asIScriptModule']]], + ['getfunctionbyid_655',['GetFunctionById',['../classas_i_script_engine.html#aaf67dc0b1f26be437ccbcc0ac5f330c9',1,'asIScriptEngine']]], + ['getfunctionbyindex_656',['GetFunctionByIndex',['../classas_i_script_module.html#afd4d9951ee006caa8ec1bab3d3d206fc',1,'asIScriptModule']]], + ['getfunctionbyname_657',['GetFunctionByName',['../classas_i_script_module.html#a81d727c9677b683942b6087df4ce95ad',1,'asIScriptModule']]], + ['getfunctioncount_658',['GetFunctionCount',['../classas_i_script_module.html#a373d102f109ae0fa20584f243ead4035',1,'asIScriptModule']]], + ['getfunctype_659',['GetFuncType',['../classas_i_script_function.html#aa4d06c7d590e7eb4df280a8224f4499c',1,'asIScriptFunction']]], + ['getgcstatistics_660',['GetGCStatistics',['../classas_i_script_engine.html#a166e6cdd0cb35bcfd942824d8e882783',1,'asIScriptEngine']]], + ['getglobalfunctionbydecl_661',['GetGlobalFunctionByDecl',['../classas_i_script_engine.html#a42edd02e95731c795e13706400e8665a',1,'asIScriptEngine']]], + ['getglobalfunctionbyindex_662',['GetGlobalFunctionByIndex',['../classas_i_script_engine.html#aaf2b79cef75adb4099a24e3412e4ea79',1,'asIScriptEngine']]], + ['getglobalfunctioncount_663',['GetGlobalFunctionCount',['../classas_i_script_engine.html#a72aa1a3a5ac88a5a1dba4fa3655141d6',1,'asIScriptEngine']]], + ['getglobalpropertybyindex_664',['GetGlobalPropertyByIndex',['../classas_i_script_engine.html#a93bd686853a48647d2136792e27380fb',1,'asIScriptEngine']]], + ['getglobalpropertycount_665',['GetGlobalPropertyCount',['../classas_i_script_engine.html#aa69f6b37f9c7bdf9b52b9c1692daf048',1,'asIScriptEngine']]], + ['getglobalpropertyindexbydecl_666',['GetGlobalPropertyIndexByDecl',['../classas_i_script_engine.html#a91a4cc8af51ca439ca82b9b6630439b3',1,'asIScriptEngine']]], + ['getglobalpropertyindexbyname_667',['GetGlobalPropertyIndexByName',['../classas_i_script_engine.html#a07e85878869e4d0597c1177d767dc717',1,'asIScriptEngine']]], + ['getglobalvar_668',['GetGlobalVar',['../classas_i_script_module.html#a939e6caf004c6fdae78fe89bb244d962',1,'asIScriptModule']]], + ['getglobalvarcount_669',['GetGlobalVarCount',['../classas_i_script_module.html#a87e29773f7e6f2980d75288faaa74d02',1,'asIScriptModule']]], + ['getglobalvardeclaration_670',['GetGlobalVarDeclaration',['../classas_i_script_module.html#aebe27735e0ce4c06bf79b2b4282192cd',1,'asIScriptModule']]], + ['getglobalvarindexbydecl_671',['GetGlobalVarIndexByDecl',['../classas_i_script_module.html#ac3d5dafe8ca92bf618f438dc79ef2906',1,'asIScriptModule']]], + ['getglobalvarindexbyname_672',['GetGlobalVarIndexByName',['../classas_i_script_module.html#a00cff95b43c256cc6b9062e135a473a2',1,'asIScriptModule']]], + ['getid_673',['GetId',['../classas_i_script_function.html#a7aca255486dd77b8846f545495128cac',1,'asIScriptFunction']]], + ['getimportedfunctioncount_674',['GetImportedFunctionCount',['../classas_i_script_module.html#a12273a6a6dd9bd39ca9675bcd84b0cc7',1,'asIScriptModule']]], + ['getimportedfunctiondeclaration_675',['GetImportedFunctionDeclaration',['../classas_i_script_module.html#a20e46ad7ea467f98bbf35ee052b86868',1,'asIScriptModule']]], + ['getimportedfunctionindexbydecl_676',['GetImportedFunctionIndexByDecl',['../classas_i_script_module.html#a6de1053c8317e7134e7e59e4527339f6',1,'asIScriptModule']]], + ['getimportedfunctionsourcemodule_677',['GetImportedFunctionSourceModule',['../classas_i_script_module.html#adc01b24a82ad14356f2edc082af4c146',1,'asIScriptModule']]], + ['getinterface_678',['GetInterface',['../classas_i_type_info.html#a320141f6c331a9e49334de2576c725f7',1,'asITypeInfo']]], + ['getinterfacecount_679',['GetInterfaceCount',['../classas_i_type_info.html#a47a4bdc2462b38a5659c3cb96e61c649',1,'asITypeInfo']]], + ['getjitcompiler_680',['GetJITCompiler',['../classas_i_script_engine.html#a2fb6db9085df3c7d487c0d58de76bb83',1,'asIScriptEngine']]], + ['getlinenumber_681',['GetLineNumber',['../classas_i_script_context.html#adf82981def59c6ec5dd9f74f034be2af',1,'asIScriptContext']]], + ['getmethodbydecl_682',['GetMethodByDecl',['../classas_i_type_info.html#a80c61bb4d018647561ce3af24fedf65b',1,'asITypeInfo']]], + ['getmethodbyindex_683',['GetMethodByIndex',['../classas_i_type_info.html#a235262cb0bacaf1f160e5ac5156db4e8',1,'asITypeInfo']]], + ['getmethodbyname_684',['GetMethodByName',['../classas_i_type_info.html#af3febbb10e7e85425f0960aad892f9b8',1,'asITypeInfo']]], + ['getmethodcount_685',['GetMethodCount',['../classas_i_type_info.html#a50877d3602e460e784df4f611ae6f360',1,'asITypeInfo']]], + ['getmodule_686',['GetModule',['../classas_i_script_engine.html#a9f7cdc52b59034e6e55eb8a56b427aa4',1,'asIScriptEngine::GetModule()'],['../classas_i_type_info.html#a3e08d6c6ee1957c421bb297f94a81d54',1,'asITypeInfo::GetModule()'],['../classas_i_script_function.html#a5c3477dd6b634e6b6ca3d5b97f6d5b30',1,'asIScriptFunction::GetModule()']]], + ['getmodulebyindex_687',['GetModuleByIndex',['../classas_i_script_engine.html#a31b95df21e6f1990cf84b3b286067675',1,'asIScriptEngine']]], + ['getmodulecount_688',['GetModuleCount',['../classas_i_script_engine.html#a457cf6202cc64ce8ee242dcc97d3422f',1,'asIScriptEngine']]], + ['getmodulename_689',['GetModuleName',['../classas_i_script_function.html#af03c30e4764f81c01400d7f77a8d0832',1,'asIScriptFunction']]], + ['getname_690',['GetName',['../classas_i_script_module.html#a4967db3ed89836ac2f3b529c499d473d',1,'asIScriptModule::GetName()'],['../classas_i_type_info.html#a49f83d3a9158331029324bfbe9ae46a8',1,'asITypeInfo::GetName()'],['../classas_i_script_function.html#a96cf134f1369f312aa182de5006f8b71',1,'asIScriptFunction::GetName()']]], + ['getnamespace_691',['GetNamespace',['../classas_i_type_info.html#a90b16019d2569d6c721130f3049786a2',1,'asITypeInfo::GetNamespace()'],['../classas_i_script_function.html#ab692c00b9a7111778acb4fbca1c63df7',1,'asIScriptFunction::GetNamespace()']]], + ['getobject_692',['GetObject',['../classas_i_script_generic.html#ab9e6627ec3920b1e1576d82586cac84d',1,'asIScriptGeneric']]], + ['getobjectingc_693',['GetObjectInGC',['../classas_i_script_engine.html#a39a5f221baa01d43e7471c0e9f5378e4',1,'asIScriptEngine']]], + ['getobjectname_694',['GetObjectName',['../classas_i_script_function.html#a69e30464d13867fb72e66ce3365fdec8',1,'asIScriptFunction']]], + ['getobjecttype_695',['GetObjectType',['../classas_i_script_object.html#aec79a2608f633a63169365d1ba79f611',1,'asIScriptObject::GetObjectType()'],['../classas_i_script_function.html#af930b362c37e5c4c117485d0bd4a34fb',1,'asIScriptFunction::GetObjectType()']]], + ['getobjecttypebyindex_696',['GetObjectTypeByIndex',['../classas_i_script_engine.html#afac08d4f81e587031c7863574c6783ba',1,'asIScriptEngine::GetObjectTypeByIndex()'],['../classas_i_script_module.html#a49ebfdd345f18d88e489edebd4888af7',1,'asIScriptModule::GetObjectTypeByIndex()']]], + ['getobjecttypecount_697',['GetObjectTypeCount',['../classas_i_script_engine.html#ac2667fbe30dd00ed14bc14e6ef7fc725',1,'asIScriptEngine::GetObjectTypeCount()'],['../classas_i_script_module.html#a931d0c00cba2df1b4e368e59bac1a207',1,'asIScriptModule::GetObjectTypeCount()']]], + ['getobjecttypeid_698',['GetObjectTypeId',['../classas_i_script_generic.html#a3de95071fa358d554137cae88a5229ea',1,'asIScriptGeneric']]], + ['getparam_699',['GetParam',['../classas_i_script_function.html#a2b3000b9fc5d3f2cfeea490d8c0c062a',1,'asIScriptFunction']]], + ['getparamcount_700',['GetParamCount',['../classas_i_script_function.html#a8ca059886317b944c52933b7bbe85cfa',1,'asIScriptFunction']]], + ['getparenttype_701',['GetParentType',['../classas_i_type_info.html#aa2836268d01f3a4424263190b57d9b04',1,'asITypeInfo']]], + ['getproperty_702',['GetProperty',['../classas_i_type_info.html#a48f468bd5b6b0e22c852b40639a7a2b5',1,'asITypeInfo']]], + ['getpropertycount_703',['GetPropertyCount',['../classas_i_script_object.html#a902a8e3f3b4d6d2e56b6e258febf6259',1,'asIScriptObject::GetPropertyCount()'],['../classas_i_type_info.html#a01d086e1bb97aa56a7b128c00c174ac6',1,'asITypeInfo::GetPropertyCount()']]], + ['getpropertydeclaration_704',['GetPropertyDeclaration',['../classas_i_type_info.html#a9e6916f51f09970d268378aef9601349',1,'asITypeInfo']]], + ['getpropertyname_705',['GetPropertyName',['../classas_i_script_object.html#af777076ab0d87e4995e1a343511f8a61',1,'asIScriptObject']]], + ['getpropertytypeid_706',['GetPropertyTypeId',['../classas_i_script_object.html#a0b39e0e07b126b43d12ad1ec944a333e',1,'asIScriptObject']]], + ['getrawstringdata_707',['GetRawStringData',['../classas_i_string_factory.html#ae798179f4d90b30371416f8c5c522333',1,'asIStringFactory']]], + ['getreturnaddress_708',['GetReturnAddress',['../classas_i_script_context.html#a2438a7fcf46faa2267bdb94057cd1f2e',1,'asIScriptContext']]], + ['getreturnbyte_709',['GetReturnByte',['../classas_i_script_context.html#a4c92259c03f1394310d3ea7d0774b3cb',1,'asIScriptContext']]], + ['getreturndouble_710',['GetReturnDouble',['../classas_i_script_context.html#a7e1ce03637cd5dd48ea652fdf7913bd7',1,'asIScriptContext']]], + ['getreturndword_711',['GetReturnDWord',['../classas_i_script_context.html#a43cd2fb72685aef96e8ddc622c9621bf',1,'asIScriptContext']]], + ['getreturnfloat_712',['GetReturnFloat',['../classas_i_script_context.html#a4ad325995e43fe6a929bcbd8fa592500',1,'asIScriptContext']]], + ['getreturnobject_713',['GetReturnObject',['../classas_i_script_context.html#a6d5739fac9c90bcd0fea55d01841d43a',1,'asIScriptContext']]], + ['getreturnqword_714',['GetReturnQWord',['../classas_i_script_context.html#a22bdd3b67dee3b1dbcb3f9f9a1f21fa4',1,'asIScriptContext']]], + ['getreturntypeid_715',['GetReturnTypeId',['../classas_i_script_generic.html#a9da6f7f81392cd25733ebc6c803a397a',1,'asIScriptGeneric::GetReturnTypeId()'],['../classas_i_script_function.html#a18968d49065c6af9833ee589b6d1e864',1,'asIScriptFunction::GetReturnTypeId()']]], + ['getreturnword_716',['GetReturnWord',['../classas_i_script_context.html#a5a3e054d35a6a361af67448d0a4930f9',1,'asIScriptContext']]], + ['getscriptsectionname_717',['GetScriptSectionName',['../classas_i_script_function.html#a62a77c029782162135d98d6e2b383eca',1,'asIScriptFunction']]], + ['getsize_718',['GetSize',['../classas_i_type_info.html#ad965398e393144e87c0436ef865b9b6d',1,'asITypeInfo']]], + ['getsizeofprimitivetype_719',['GetSizeOfPrimitiveType',['../classas_i_script_engine.html#a39b7207a6c4c55a5cbf10eab2ccfb8e6',1,'asIScriptEngine']]], + ['getstate_720',['GetState',['../classas_i_script_context.html#a17024a9e1648f66711a3182b21676aa7',1,'asIScriptContext']]], + ['getstringconstant_721',['GetStringConstant',['../classas_i_string_factory.html#a59d5d4d13a21105791e34bef5cb57e6b',1,'asIStringFactory']]], + ['getstringfactoryreturntypeid_722',['GetStringFactoryReturnTypeId',['../classas_i_script_engine.html#afb3935d85494231e2f02af5816ba9830',1,'asIScriptEngine']]], + ['getsubtype_723',['GetSubType',['../classas_i_type_info.html#a8e947504f268c7f0e1c26973dd7d3837',1,'asITypeInfo']]], + ['getsubtypecount_724',['GetSubTypeCount',['../classas_i_type_info.html#a1657d5094afa550c93d8cc74c216c3c6',1,'asITypeInfo']]], + ['getsubtypeid_725',['GetSubTypeId',['../classas_i_type_info.html#aa1a56809ce5c340364ecd8beac508eb4',1,'asITypeInfo']]], + ['getsystemfunction_726',['GetSystemFunction',['../classas_i_script_context.html#a214cc16c4dd889072c1c24c089223a6a',1,'asIScriptContext']]], + ['getthispointer_727',['GetThisPointer',['../classas_i_script_context.html#a4f6761a7a0c872dda681d8e180830ff9',1,'asIScriptContext']]], + ['getthistypeid_728',['GetThisTypeId',['../classas_i_script_context.html#a404681f8950c1ebd9382d30ef1ed3b89',1,'asIScriptContext']]], + ['gettypedeclaration_729',['GetTypeDeclaration',['../classas_i_script_engine.html#a3ae23fcde6af0d816ff97097cd443281',1,'asIScriptEngine']]], + ['gettypedefbyindex_730',['GetTypedefByIndex',['../classas_i_script_engine.html#a635cd008ea123b510c66fbddcea735f5',1,'asIScriptEngine::GetTypedefByIndex()'],['../classas_i_script_module.html#a6a31f0767b01cc4203212fd531576de4',1,'asIScriptModule::GetTypedefByIndex()']]], + ['gettypedefcount_731',['GetTypedefCount',['../classas_i_script_engine.html#a0ebbbb86ea0e314cc2695f6276ebe507',1,'asIScriptEngine::GetTypedefCount()'],['../classas_i_script_module.html#ad30b22539655df3135f29ce28b89c820',1,'asIScriptModule::GetTypedefCount()']]], + ['gettypedeftypeid_732',['GetTypedefTypeId',['../classas_i_type_info.html#aca9edb046026db68d255e226dd419b3a',1,'asITypeInfo']]], + ['gettypeid_733',['GetTypeId',['../classas_i_script_object.html#a19c5ab9d8adb0f921bf0b6474d97f468',1,'asIScriptObject::GetTypeId()'],['../classas_i_type_info.html#a06698aa9dcc6dc315ec2651fc70dbe19',1,'asITypeInfo::GetTypeId()'],['../classas_i_script_function.html#a4a5e24c464e423a2a6724cb849babd21',1,'asIScriptFunction::GetTypeId()']]], + ['gettypeidbydecl_734',['GetTypeIdByDecl',['../classas_i_script_engine.html#ad1f6fecb0f53fd7966736b01f65c3dcb',1,'asIScriptEngine::GetTypeIdByDecl()'],['../classas_i_script_module.html#a7fbc2bd888b248d2c2ee2d953b49eefc',1,'asIScriptModule::GetTypeIdByDecl()']]], + ['gettypeinfobydecl_735',['GetTypeInfoByDecl',['../classas_i_script_engine.html#ab00808f9b762c4badf508ed511789d1b',1,'asIScriptEngine::GetTypeInfoByDecl()'],['../classas_i_script_module.html#a3c61bf81a0a88c0017a0e33aecc417ba',1,'asIScriptModule::GetTypeInfoByDecl()']]], + ['gettypeinfobyid_736',['GetTypeInfoById',['../classas_i_script_engine.html#a55cc2d9592651538efcf79eb8106a867',1,'asIScriptEngine']]], + ['gettypeinfobyname_737',['GetTypeInfoByName',['../classas_i_script_engine.html#aea2583b8aa724779b7c37df8b7fa437b',1,'asIScriptEngine::GetTypeInfoByName()'],['../classas_i_script_module.html#ae8460fa05f441072e14f984ccf507396',1,'asIScriptModule::GetTypeInfoByName()']]], + ['getuserdata_738',['GetUserData',['../classas_i_script_engine.html#a701aa6a7ddf51a22c62281f3dec9a772',1,'asIScriptEngine::GetUserData()'],['../classas_i_script_module.html#af292f99799d8358277298f749efedaaa',1,'asIScriptModule::GetUserData()'],['../classas_i_script_context.html#a0f8503675abfd473915d66a92c6e6df7',1,'asIScriptContext::GetUserData()'],['../classas_i_script_object.html#a63e8ab74fd7552d057e23e0ce550a157',1,'asIScriptObject::GetUserData()'],['../classas_i_type_info.html#a80b01b2ceadfaf91cc34988033a1598c',1,'asITypeInfo::GetUserData()'],['../classas_i_script_function.html#a0d0d4671e524fcd868a34bee33ee9fde',1,'asIScriptFunction::GetUserData()']]], + ['getvar_739',['GetVar',['../classas_i_script_function.html#aaf11dde60bec710bcd729127bfe12dd4',1,'asIScriptFunction']]], + ['getvarcount_740',['GetVarCount',['../classas_i_script_context.html#a3d735c6c7c5a166302cc4ba8ea38e3e8',1,'asIScriptContext::GetVarCount()'],['../classas_i_script_function.html#a92e14168997c0f67a975e7ed042d8328',1,'asIScriptFunction::GetVarCount()']]], + ['getvardecl_741',['GetVarDecl',['../classas_i_script_function.html#acef067f00f2a6a997d6955f5cf3c6d13',1,'asIScriptFunction']]], + ['getvardeclaration_742',['GetVarDeclaration',['../classas_i_script_context.html#ae3419d239a51d702870b1ab8ee1b7140',1,'asIScriptContext']]], + ['getvarname_743',['GetVarName',['../classas_i_script_context.html#aac398eb23d9f17fcbeaa3f3809f8923d',1,'asIScriptContext']]], + ['getvartypeid_744',['GetVarTypeId',['../classas_i_script_context.html#a8684e1931e54dbfe53da763fc334413d',1,'asIScriptContext']]], + ['getweakrefflag_745',['GetWeakRefFlag',['../classas_i_script_object.html#a9ccca7fe3453219377fc9bd190bf7903',1,'asIScriptObject']]], + ['getweakrefflagofscriptobject_746',['GetWeakRefFlagOfScriptObject',['../classas_i_script_engine.html#ab31103bef62096445fe03632de691827',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/all_7.html b/docs/manual/search/all_7.html new file mode 100644 index 0000000..e42e45b --- /dev/null +++ b/docs/manual/search/all_7.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_7.js b/docs/manual/search/all_7.js new file mode 100644 index 0000000..b90ec8d --- /dev/null +++ b/docs/manual/search/all_7.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['helper_20functions_747',['Helper functions',['../doc_addon_helpers.html',1,'doc_addon_application']]], + ['how_20to_20build_20a_20jit_20compiler_748',['How to build a JIT compiler',['../doc_adv_jit.html',1,'doc_adv_jit_topic']]] +]; diff --git a/docs/manual/search/all_8.html b/docs/manual/search/all_8.html new file mode 100644 index 0000000..888e619 --- /dev/null +++ b/docs/manual/search/all_8.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_8.js b/docs/manual/search/all_8.js new file mode 100644 index 0000000..ccd8bc7 --- /dev/null +++ b/docs/manual/search/all_8.js @@ -0,0 +1,22 @@ +var searchData= +[ + ['inheriting_20from_20application_20registered_20class_749',['Inheriting from application registered class',['../doc_adv_inheritappclass.html',1,'doc_advanced']]], + ['imports_750',['Imports',['../doc_global_import.html',1,'doc_script_global']]], + ['interfaces_751',['Interfaces',['../doc_global_interface.html',1,'doc_script_global']]], + ['include_20directive_752',['Include directive',['../doc_samples_incl.html',1,'doc_samples']]], + ['inheritance_20and_20polymorphism_753',['Inheritance and polymorphism',['../doc_script_class_inheritance.html',1,'doc_script_class']]], + ['initialization_20of_20class_20members_754',['Initialization of class members',['../doc_script_class_memberinit.html',1,'doc_script_class']]], + ['implements_755',['Implements',['../classas_i_type_info.html#a19bacd881681ee398de95a076f427726',1,'asITypeInfo']]], + ['introduction_756',['Introduction',['../index.html',1,'']]], + ['iscompatiblewithtypeid_757',['IsCompatibleWithTypeId',['../classas_i_script_function.html#a76715df2843cb37cc010fc3a5d999e84',1,'asIScriptFunction']]], + ['isexplicit_758',['IsExplicit',['../classas_i_script_function.html#aea24c6ba2ab0fcc5c42a734f72856814',1,'asIScriptFunction']]], + ['isfinal_759',['IsFinal',['../classas_i_script_function.html#aa071c702946372020a1245f901502d52',1,'asIScriptFunction']]], + ['isnested_760',['IsNested',['../classas_i_script_context.html#a378f3bbfa04ef7b806300c5d4f1a0d65',1,'asIScriptContext']]], + ['isoverride_761',['IsOverride',['../classas_i_script_function.html#a5aec17ae5639fb9cad403c835d429f6e',1,'asIScriptFunction']]], + ['isprivate_762',['IsPrivate',['../classas_i_script_function.html#a7ef1f42ff812a03e2a323046835159fb',1,'asIScriptFunction']]], + ['isproperty_763',['IsProperty',['../classas_i_script_function.html#ad6ecdae3667ebef1fc867e884504078c',1,'asIScriptFunction']]], + ['isprotected_764',['IsProtected',['../classas_i_script_function.html#a2e17b763527ba3a9b0d05c4cd35b5742',1,'asIScriptFunction']]], + ['isreadonly_765',['IsReadOnly',['../classas_i_script_function.html#a99bbe26ae0ec3f0cc09070bf89aff2f9',1,'asIScriptFunction']]], + ['isshared_766',['IsShared',['../classas_i_script_function.html#a805ae8064598ad12f44bb583118b6cc5',1,'asIScriptFunction']]], + ['isvarinscope_767',['IsVarInScope',['../classas_i_script_context.html#a45fcf7d8d711d5ec5cb9927e7839387a',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/all_9.html b/docs/manual/search/all_9.html new file mode 100644 index 0000000..dc988f4 --- /dev/null +++ b/docs/manual/search/all_9.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_9.js b/docs/manual/search/all_9.js new file mode 100644 index 0000000..07424e8 --- /dev/null +++ b/docs/manual/search/all_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['jit_20compilation_768',['JIT compilation',['../doc_adv_jit_topic.html',1,'doc_advanced']]] +]; diff --git a/docs/manual/search/all_a.html b/docs/manual/search/all_a.html new file mode 100644 index 0000000..0ce816b --- /dev/null +++ b/docs/manual/search/all_a.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_a.js b/docs/manual/search/all_a.js new file mode 100644 index 0000000..8909566 --- /dev/null +++ b/docs/manual/search/all_a.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['license_769',['License',['../doc_license.html',1,'main_topics']]], + ['loadbytecode_770',['LoadByteCode',['../classas_i_script_module.html#a8b4a222e5309c6b367f136b6d2f664ba',1,'asIScriptModule']]], + ['lock_771',['Lock',['../classas_i_lockable_shared_bool.html#aef12cc309395d682aa138da5eea9d82b',1,'asILockableSharedBool']]] +]; diff --git a/docs/manual/search/all_b.html b/docs/manual/search/all_b.html new file mode 100644 index 0000000..28c2413 --- /dev/null +++ b/docs/manual/search/all_b.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_b.js b/docs/manual/search/all_b.js new file mode 100644 index 0000000..5042a55 --- /dev/null +++ b/docs/manual/search/all_b.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['memory_20functions_772',['Memory functions',['../group__api__memory__functions.html',1,'']]], + ['multi_2dthread_20support_20functions_773',['Multi-thread support functions',['../group__api__multithread__functions.html',1,'']]], + ['math_20functions_774',['math functions',['../doc_addon_math.html',1,'doc_addon_script']]], + ['multithreading_775',['Multithreading',['../doc_adv_multithread.html',1,'doc_advanced']]], + ['memory_20management_776',['Memory management',['../doc_memory.html',1,'doc_understanding_as']]], + ['mixin_20class_777',['Mixin class',['../doc_script_mixin.html',1,'doc_script_global']]], + ['message_778',['message',['../structas_s_message_info.html#af76694c6342dd82ef6aca0dff42072f5',1,'asSMessageInfo']]] +]; diff --git a/docs/manual/search/all_c.html b/docs/manual/search/all_c.html new file mode 100644 index 0000000..39fc49b --- /dev/null +++ b/docs/manual/search/all_c.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_c.js b/docs/manual/search/all_c.js new file mode 100644 index 0000000..5def31e --- /dev/null +++ b/docs/manual/search/all_c.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['namespaces_779',['Namespaces',['../doc_global_namespace.html',1,'doc_script_global']]], + ['name_780',['name',['../structas_s_b_c_info.html#a0fec180d222e297a574000aa64bd3af5',1,'asSBCInfo']]], + ['notifygarbagecollectorofnewobject_781',['NotifyGarbageCollectorOfNewObject',['../classas_i_script_engine.html#a52a7644b48cbc771e33db5070814f6df',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/all_d.html b/docs/manual/search/all_d.html new file mode 100644 index 0000000..cc470e5 --- /dev/null +++ b/docs/manual/search/all_d.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_d.js b/docs/manual/search/all_d.js new file mode 100644 index 0000000..ce0c0ae --- /dev/null +++ b/docs/manual/search/all_d.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['objects_20and_20handles_782',['Objects and handles',['../doc_datatypes_obj.html',1,'doc_datatypes']]], + ['object_20handles_20to_20the_20application_783',['Object handles to the application',['../doc_obj_handle.html',1,'doc_understanding_as']]], + ['operator_20precedence_784',['Operator precedence',['../doc_operator_precedence.html',1,'doc_script']]], + ['overview_785',['Overview',['../doc_overview.html',1,'doc_start']]], + ['operator_20overloads_786',['Operator overloads',['../doc_script_class_ops.html',1,'doc_script_class']]], + ['object_20handles_787',['Object handles',['../doc_script_handle.html',1,'doc_script']]], + ['objectregister_788',['objectRegister',['../structas_s_v_m_registers.html#a12e6c46db50443d8f7faeec71abf42f7',1,'asSVMRegisters']]], + ['objecttype_789',['objectType',['../structas_s_v_m_registers.html#a6b6463e377e4f83bb8bd7b9afb3abb02',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/search/all_e.html b/docs/manual/search/all_e.html new file mode 100644 index 0000000..57cce76 --- /dev/null +++ b/docs/manual/search/all_e.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_e.js b/docs/manual/search/all_e.js new file mode 100644 index 0000000..d2210f5 --- /dev/null +++ b/docs/manual/search/all_e.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['principal_20functions_790',['Principal functions',['../group__api__principal__functions.html',1,'']]], + ['principal_20interfaces_791',['Principal interfaces',['../group__api__principal__interfaces.html',1,'']]], + ['pre_2dcompiled_20byte_20code_792',['Pre-compiled byte code',['../doc_adv_precompile.html',1,'doc_advanced']]], + ['primitives_793',['Primitives',['../doc_datatypes_primitives.html',1,'doc_datatypes']]], + ['protected_20and_20private_20class_20members_794',['Protected and private class members',['../doc_script_class_private.html',1,'doc_script_class']]], + ['property_20accessors_795',['Property accessors',['../doc_script_class_prop.html',1,'doc_script_class']]], + ['parameter_20references_796',['Parameter references',['../doc_script_func_ref.html',1,'doc_script_func']]], + ['parsetoken_797',['ParseToken',['../classas_i_script_engine.html#a57ecbd86ae9370684877c755e83cef0d',1,'asIScriptEngine']]], + ['popstate_798',['PopState',['../classas_i_script_context.html#a5d963974625e582799b5d911d182d9be',1,'asIScriptContext']]], + ['prepare_799',['Prepare',['../classas_i_script_context.html#a43976f42dfc6c1af23e132d36265173a',1,'asIScriptContext']]], + ['programpointer_800',['programPointer',['../structas_s_v_m_registers.html#abacce81d44b2387a2b66549bcba47643',1,'asSVMRegisters']]], + ['pushstate_801',['PushState',['../classas_i_script_context.html#ad8f7637a23d67e227d07f65621b6cdd6',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/all_f.html b/docs/manual/search/all_f.html new file mode 100644 index 0000000..ac1e704 --- /dev/null +++ b/docs/manual/search/all_f.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/all_f.js b/docs/manual/search/all_f.js new file mode 100644 index 0000000..ec7bc09 --- /dev/null +++ b/docs/manual/search/all_f.js @@ -0,0 +1,47 @@ +var searchData= +[ + ['ref_20object_802',['ref object',['../doc_addon_handle.html',1,'doc_addon_script']]], + ['registering_20a_20generic_20handle_20type_803',['Registering a generic handle type',['../doc_adv_generic_handle.html',1,'doc_advanced_api']]], + ['reflection_804',['Reflection',['../doc_adv_reflection.html',1,'doc_advanced']]], + ['registering_20a_20scoped_20reference_20type_805',['Registering a scoped reference type',['../doc_adv_scoped_type.html',1,'doc_advanced_api']]], + ['registering_20a_20single_2dreference_20type_806',['Registering a single-reference type',['../doc_adv_single_ref_type.html',1,'doc_advanced_api']]], + ['ref_807',['ref',['../doc_datatypes_ref.html',1,'doc_script_stdlib']]], + ['registering_20a_20reference_20type_808',['Registering a reference type',['../doc_reg_basicref.html',1,'doc_register_type']]], + ['registering_20object_20methods_809',['Registering object methods',['../doc_reg_objmeth.html',1,'doc_register_type']]], + ['registering_20object_20properties_810',['Registering object properties',['../doc_reg_objprop.html',1,'doc_register_type']]], + ['registering_20operator_20behaviours_811',['Registering operator behaviours',['../doc_reg_opbeh.html',1,'doc_register_type']]], + ['registering_20the_20application_20interface_812',['Registering the application interface',['../doc_register_api_topic.html',1,'main_topics']]], + ['registering_20a_20function_813',['Registering a function',['../doc_register_func.html',1,'doc_register_api_topic']]], + ['registering_20global_20properties_814',['Registering global properties',['../doc_register_prop.html',1,'doc_register_api_topic']]], + ['registering_20an_20object_20type_815',['Registering an object type',['../doc_register_type.html',1,'doc_register_api_topic']]], + ['registering_20a_20value_20type_816',['Registering a value type',['../doc_register_val_type.html',1,'doc_register_type']]], + ['reserved_20keywords_20and_20tokens_817',['Reserved keywords and tokens',['../doc_reserved_keywords.html',1,'doc_script']]], + ['return_20references_818',['Return references',['../doc_script_func_retref.html',1,'doc_script_func']]], + ['read_819',['Read',['../classas_i_binary_stream.html#a8bbd68cea1f96b42c723f9732ac19140',1,'asIBinaryStream']]], + ['refcastobject_820',['RefCastObject',['../classas_i_script_engine.html#a32c9d9aac77a67eeb046fc67d7473fa2',1,'asIScriptEngine']]], + ['registerdefaultarraytype_821',['RegisterDefaultArrayType',['../classas_i_script_engine.html#ac9451feece1297eba8d1649036039e82',1,'asIScriptEngine']]], + ['registerenum_822',['RegisterEnum',['../classas_i_script_engine.html#abed6e77f2a532c8a4f528650fa137d37',1,'asIScriptEngine']]], + ['registerenumvalue_823',['RegisterEnumValue',['../classas_i_script_engine.html#a4d331153596dd39838f3bed2a861af18',1,'asIScriptEngine']]], + ['registerfuncdef_824',['RegisterFuncdef',['../classas_i_script_engine.html#a03c1a2cc23ae4b742c927f3472a1a4f7',1,'asIScriptEngine']]], + ['registerglobalfunction_825',['RegisterGlobalFunction',['../classas_i_script_engine.html#a2f84b9b51733f22c68b8448b02c2f1c7',1,'asIScriptEngine']]], + ['registerglobalproperty_826',['RegisterGlobalProperty',['../classas_i_script_engine.html#aacd32f32b2922b8ffaed204812013169',1,'asIScriptEngine']]], + ['registerinterface_827',['RegisterInterface',['../classas_i_script_engine.html#ae2d89b82561b7f9843f35693c664589f',1,'asIScriptEngine']]], + ['registerinterfacemethod_828',['RegisterInterfaceMethod',['../classas_i_script_engine.html#a43bd2c12c94a55c22be76d209de93f1a',1,'asIScriptEngine']]], + ['registerobjectbehaviour_829',['RegisterObjectBehaviour',['../classas_i_script_engine.html#a9f122dd87394f3a83ac766ea19f37317',1,'asIScriptEngine']]], + ['registerobjectmethod_830',['RegisterObjectMethod',['../classas_i_script_engine.html#ad74043be9cc30f105c62f482ca720574',1,'asIScriptEngine']]], + ['registerobjectproperty_831',['RegisterObjectProperty',['../classas_i_script_engine.html#a0aa35bf824180fe6aed685b40f0e8c34',1,'asIScriptEngine']]], + ['registerobjecttype_832',['RegisterObjectType',['../classas_i_script_engine.html#a29c6c087c8c5b5cdb6271cfd161cc5a6',1,'asIScriptEngine']]], + ['registerstringfactory_833',['RegisterStringFactory',['../classas_i_script_engine.html#ac6598c07c36652b0270b4c2d61db1f01',1,'asIScriptEngine']]], + ['registertypedef_834',['RegisterTypedef',['../classas_i_script_engine.html#addb24466769dc52be96c7e37d5305245',1,'asIScriptEngine']]], + ['release_835',['Release',['../classas_i_script_engine.html#aae91a45da75af9234b87e825b5c08b81',1,'asIScriptEngine::Release()'],['../classas_i_script_context.html#a1b13a5f3e58627e9ff4300c0c6f0f3cf',1,'asIScriptContext::Release()'],['../classas_i_script_object.html#a4bed3c3ac9f16294985835747aa122d3',1,'asIScriptObject::Release()'],['../classas_i_type_info.html#a73b9059dc335b6fde8c7bbf4b1b95914',1,'asITypeInfo::Release()'],['../classas_i_script_function.html#a0a98f1f7f91574a11d7d8c5062bdcdee',1,'asIScriptFunction::Release()'],['../classas_i_lockable_shared_bool.html#a1dae71f6f1141b5b16520232a9ea5fb2',1,'asILockableSharedBool::Release()']]], + ['releasejitfunction_836',['ReleaseJITFunction',['../classas_i_j_i_t_compiler.html#afbf9390868269c9224df85d49aabd451',1,'asIJITCompiler']]], + ['releasescriptobject_837',['ReleaseScriptObject',['../classas_i_script_engine.html#a82873d3769ded547894a7c3d52c220fd',1,'asIScriptEngine']]], + ['releasestringconstant_838',['ReleaseStringConstant',['../classas_i_string_factory.html#ae4ca9e666eb711671a765dba8debe8b1',1,'asIStringFactory']]], + ['removeconfiggroup_839',['RemoveConfigGroup',['../classas_i_script_engine.html#ab607be7fe727cdcce502d2beedbf4c0a',1,'asIScriptEngine']]], + ['removefunction_840',['RemoveFunction',['../classas_i_script_module.html#a54b6f8e09787ad20880f73bc97a8ef10',1,'asIScriptModule']]], + ['removeglobalvar_841',['RemoveGlobalVar',['../classas_i_script_module.html#aac10878c3d16f18ace4db881f7a1bb11',1,'asIScriptModule']]], + ['requestcontext_842',['RequestContext',['../classas_i_script_engine.html#a32391ee83e58083b406ba068ab2ee049',1,'asIScriptEngine']]], + ['resetglobalvars_843',['ResetGlobalVars',['../classas_i_script_module.html#a7b084b6693a05616097d7059e54d983b',1,'asIScriptModule']]], + ['returncontext_844',['ReturnContext',['../classas_i_script_engine.html#a22e42bf32902cbd6885731a6beeaca20',1,'asIScriptEngine']]], + ['row_845',['row',['../structas_s_message_info.html#a21ef80321436f229a547411a6598ea21',1,'asSMessageInfo']]] +]; diff --git a/docs/manual/search/classes_0.html b/docs/manual/search/classes_0.html new file mode 100644 index 0000000..5b441a3 --- /dev/null +++ b/docs/manual/search/classes_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/classes_0.js b/docs/manual/search/classes_0.js new file mode 100644 index 0000000..a5fdde5 --- /dev/null +++ b/docs/manual/search/classes_0.js @@ -0,0 +1,19 @@ +var searchData= +[ + ['asibinarystream_937',['asIBinaryStream',['../classas_i_binary_stream.html',1,'']]], + ['asijitcompiler_938',['asIJITCompiler',['../classas_i_j_i_t_compiler.html',1,'']]], + ['asilockablesharedbool_939',['asILockableSharedBool',['../classas_i_lockable_shared_bool.html',1,'']]], + ['asiscriptcontext_940',['asIScriptContext',['../classas_i_script_context.html',1,'']]], + ['asiscriptengine_941',['asIScriptEngine',['../classas_i_script_engine.html',1,'']]], + ['asiscriptfunction_942',['asIScriptFunction',['../classas_i_script_function.html',1,'']]], + ['asiscriptgeneric_943',['asIScriptGeneric',['../classas_i_script_generic.html',1,'']]], + ['asiscriptmodule_944',['asIScriptModule',['../classas_i_script_module.html',1,'']]], + ['asiscriptobject_945',['asIScriptObject',['../classas_i_script_object.html',1,'']]], + ['asistringfactory_946',['asIStringFactory',['../classas_i_string_factory.html',1,'']]], + ['asithreadmanager_947',['asIThreadManager',['../classas_i_thread_manager.html',1,'']]], + ['asitypeinfo_948',['asITypeInfo',['../classas_i_type_info.html',1,'']]], + ['assbcinfo_949',['asSBCInfo',['../structas_s_b_c_info.html',1,'']]], + ['assfuncptr_950',['asSFuncPtr',['../structas_s_func_ptr.html',1,'']]], + ['assmessageinfo_951',['asSMessageInfo',['../structas_s_message_info.html',1,'']]], + ['assvmregisters_952',['asSVMRegisters',['../structas_s_v_m_registers.html',1,'']]] +]; diff --git a/docs/manual/search/close.png b/docs/manual/search/close.png new file mode 100644 index 0000000..9342d3d Binary files /dev/null and b/docs/manual/search/close.png differ diff --git a/docs/manual/search/defines_0.html b/docs/manual/search/defines_0.html new file mode 100644 index 0000000..54b9bc5 --- /dev/null +++ b/docs/manual/search/defines_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/defines_0.js b/docs/manual/search/defines_0.js new file mode 100644 index 0000000..aabbd8e --- /dev/null +++ b/docs/manual/search/defines_0.js @@ -0,0 +1,21 @@ +var searchData= +[ + ['angelscript_5fversion_1704',['ANGELSCRIPT_VERSION',['../angelscript_8h.html#a99c6b8b0882e45e5d0b2ed19f6f7a157',1,'angelscript.h']]], + ['as_5fapi_1705',['AS_API',['../angelscript_8h.html#a6412a04ba6b2737922fdb2d8f822f51c',1,'angelscript.h']]], + ['as_5fcan_5fuse_5fcpp11_1706',['AS_CAN_USE_CPP11',['../angelscript_8h.html#a9e0eb27a2013e875a33565dd3fe76f79',1,'angelscript.h']]], + ['asbc_5fdwordarg_1707',['asBC_DWORDARG',['../angelscript_8h.html#a7b3dbfcc3928ddd853a4ee53cbc13b69',1,'angelscript.h']]], + ['asbc_5ffloatarg_1708',['asBC_FLOATARG',['../angelscript_8h.html#a0183edd413564ff4897eb4a2473d01f6',1,'angelscript.h']]], + ['asbc_5fintarg_1709',['asBC_INTARG',['../angelscript_8h.html#a290586f7a153d5e8717b01680262b667',1,'angelscript.h']]], + ['asbc_5fptrarg_1710',['asBC_PTRARG',['../angelscript_8h.html#aac9eb586274fc44bb1b838d833963996',1,'angelscript.h']]], + ['asbc_5fqwordarg_1711',['asBC_QWORDARG',['../angelscript_8h.html#a92e1437ea399e8c545e15bffd651f45f',1,'angelscript.h']]], + ['asbc_5fswordarg0_1712',['asBC_SWORDARG0',['../angelscript_8h.html#a2287157faea7f6d32b316c17e0858ddf',1,'angelscript.h']]], + ['asbc_5fswordarg1_1713',['asBC_SWORDARG1',['../angelscript_8h.html#a92601565873cf5d29a6876c2638d7fec',1,'angelscript.h']]], + ['asbc_5fswordarg2_1714',['asBC_SWORDARG2',['../angelscript_8h.html#a698449bbbe369b8a479fb0dd82c9b18e',1,'angelscript.h']]], + ['asbc_5fwordarg0_1715',['asBC_WORDARG0',['../angelscript_8h.html#a942798ec89a8ac96550523d80570c703',1,'angelscript.h']]], + ['asbc_5fwordarg1_1716',['asBC_WORDARG1',['../angelscript_8h.html#a0a704bf4db31deda2a69d3216312618c',1,'angelscript.h']]], + ['asfunction_1717',['asFUNCTION',['../angelscript_8h.html#a78f8f2c7f1c88b12e74a5ac47b4184ae',1,'angelscript.h']]], + ['asfunctionpr_1718',['asFUNCTIONPR',['../angelscript_8h.html#a153aee5a6228913a469b6e6867e54efb',1,'angelscript.h']]], + ['asmethod_1719',['asMETHOD',['../angelscript_8h.html#a7345e6b3afabec24efd0ff77886d49a6',1,'angelscript.h']]], + ['asmethodpr_1720',['asMETHODPR',['../angelscript_8h.html#ac45ccb5854326cce38d721e2c00f1563',1,'angelscript.h']]], + ['asoffset_1721',['asOFFSET',['../angelscript_8h.html#a717eccea17214bc1eb64bb9789c4915a',1,'angelscript.h']]] +]; diff --git a/docs/manual/search/enums_0.html b/docs/manual/search/enums_0.html new file mode 100644 index 0000000..e99c489 --- /dev/null +++ b/docs/manual/search/enums_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/enums_0.js b/docs/manual/search/enums_0.js new file mode 100644 index 0000000..5649993 --- /dev/null +++ b/docs/manual/search/enums_0.js @@ -0,0 +1,19 @@ +var searchData= +[ + ['asebcinstr_1280',['asEBCInstr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0',1,'angelscript.h']]], + ['asebctype_1281',['asEBCType',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dc',1,'angelscript.h']]], + ['asebehaviours_1282',['asEBehaviours',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5',1,'angelscript.h']]], + ['asecallconvtypes_1283',['asECallConvTypes',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4',1,'angelscript.h']]], + ['asecompileflags_1284',['asECompileFlags',['../angelscript_8h.html#a2bf48c41455371788805269376ca5e41',1,'angelscript.h']]], + ['asecontextstate_1285',['asEContextState',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69',1,'angelscript.h']]], + ['aseengineprop_1286',['asEEngineProp',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0f',1,'angelscript.h']]], + ['asefunctype_1287',['asEFuncType',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648f',1,'angelscript.h']]], + ['asegcflags_1288',['asEGCFlags',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9d',1,'angelscript.h']]], + ['asegmflags_1289',['asEGMFlags',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0c',1,'angelscript.h']]], + ['asemsgtype_1290',['asEMsgType',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5',1,'angelscript.h']]], + ['aseobjtypeflags_1291',['asEObjTypeFlags',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7a',1,'angelscript.h']]], + ['aseretcodes_1292',['asERetCodes',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54',1,'angelscript.h']]], + ['asetokenclass_1293',['asETokenClass',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbca',1,'angelscript.h']]], + ['asetypeidflags_1294',['asETypeIdFlags',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83a',1,'angelscript.h']]], + ['asetypemodifiers_1295',['asETypeModifiers',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7',1,'angelscript.h']]] +]; diff --git a/docs/manual/search/enumvalues_0.html b/docs/manual/search/enumvalues_0.html new file mode 100644 index 0000000..f740569 --- /dev/null +++ b/docs/manual/search/enumvalues_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/enumvalues_0.js b/docs/manual/search/enumvalues_0.js new file mode 100644 index 0000000..315c615 --- /dev/null +++ b/docs/manual/search/enumvalues_0.js @@ -0,0 +1,411 @@ +var searchData= +[ + ['asalready_5fregistered_1296',['asALREADY_REGISTERED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a8025c1eca773e41db5f3102ae3c41690',1,'angelscript.h']]], + ['asbc_5faddd_1297',['asBC_ADDd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad2ff7a206ad788bd2b37b8ee92be7940',1,'angelscript.h']]], + ['asbc_5faddf_1298',['asBC_ADDf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab1bffd05b8b41e4a9dd09618b82bba9d',1,'angelscript.h']]], + ['asbc_5faddi_1299',['asBC_ADDi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a42520944f391260636e0eed5c9ab76a9',1,'angelscript.h']]], + ['asbc_5faddi64_1300',['asBC_ADDi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab1afb9b4dbebb726108b46887175c57e',1,'angelscript.h']]], + ['asbc_5faddif_1301',['asBC_ADDIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a15032e422f3346940aa37ec6dc6305d7',1,'angelscript.h']]], + ['asbc_5faddii_1302',['asBC_ADDIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1194db3e433a943156d548b2bb34ef13',1,'angelscript.h']]], + ['asbc_5faddsi_1303',['asBC_ADDSi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0219f343e6e7248e72d209ea22b63f4d',1,'angelscript.h']]], + ['asbc_5falloc_1304',['asBC_ALLOC',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac215e24151dbbf8ca218ee90b77953d2',1,'angelscript.h']]], + ['asbc_5fallocmem_1305',['asBC_AllocMem',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a60cb5c56bd8cd1dfd7bde88be588b19c',1,'angelscript.h']]], + ['asbc_5fband_1306',['asBC_BAND',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a051857d502a904223293d1604765c0f5',1,'angelscript.h']]], + ['asbc_5fband64_1307',['asBC_BAND64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af1dff3cce666a689e8b1d5ceb91f1b42',1,'angelscript.h']]], + ['asbc_5fbnot_1308',['asBC_BNOT',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac9e8418aad908e23c4e2e9cbbc71f8fe',1,'angelscript.h']]], + ['asbc_5fbnot64_1309',['asBC_BNOT64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a263c5cfa90baf8f63c5b4d110c3d9daa',1,'angelscript.h']]], + ['asbc_5fbor_1310',['asBC_BOR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4265bc99ed27ff3e3cd55e7de3f6ee57',1,'angelscript.h']]], + ['asbc_5fbor64_1311',['asBC_BOR64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a5d6d553690fa38dc7f2b6a7b9ee14345',1,'angelscript.h']]], + ['asbc_5fbsll_1312',['asBC_BSLL',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a671220a8df608a65acb7c5be7d950134',1,'angelscript.h']]], + ['asbc_5fbsll64_1313',['asBC_BSLL64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af18e856f167de0796acb84d3f5df09b2',1,'angelscript.h']]], + ['asbc_5fbsra_1314',['asBC_BSRA',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae7f2672c3c3a6859f17ebc25df4d95a1',1,'angelscript.h']]], + ['asbc_5fbsra64_1315',['asBC_BSRA64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4203e09b3bf5f15810f0e2076c0088a5',1,'angelscript.h']]], + ['asbc_5fbsrl_1316',['asBC_BSRL',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a427239dea36c73be86be67963dbc1935',1,'angelscript.h']]], + ['asbc_5fbsrl64_1317',['asBC_BSRL64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0abb511dcd15fb9875ba270d5b95fed24d',1,'angelscript.h']]], + ['asbc_5fbxor_1318',['asBC_BXOR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a099bdbc768c58ad62d2662dd9727806a',1,'angelscript.h']]], + ['asbc_5fbxor64_1319',['asBC_BXOR64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae4d7a6a1af23b2f14d5af7b6dfaa3f28',1,'angelscript.h']]], + ['asbc_5fcall_1320',['asBC_CALL',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4055fd59f44ce3f31eac60377b0967c8',1,'angelscript.h']]], + ['asbc_5fcallbnd_1321',['asBC_CALLBND',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a22f812924fa0048de540e0cca53a2718',1,'angelscript.h']]], + ['asbc_5fcallintf_1322',['asBC_CALLINTF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aedb4e479a4988aac48f1facb6a0048d6',1,'angelscript.h']]], + ['asbc_5fcallptr_1323',['asBC_CallPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a35c09c890b9f46160c193a3a07cdeedb',1,'angelscript.h']]], + ['asbc_5fcallsys_1324',['asBC_CALLSYS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac21b3ff5a3ecb6d834bfe2bf7ff36669',1,'angelscript.h']]], + ['asbc_5fcast_1325',['asBC_Cast',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4ef6c5e255ffe285bff104bacaed2ba9',1,'angelscript.h']]], + ['asbc_5fchknulls_1326',['asBC_ChkNullS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af859e97239e00dd003a8f75fbf963ded',1,'angelscript.h']]], + ['asbc_5fchknullv_1327',['asBC_ChkNullV',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a81142673f63ffd177e20b6296718d3aa',1,'angelscript.h']]], + ['asbc_5fchkref_1328',['asBC_CHKREF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0ae4b5ff463c26aad9fbd975a144f2fa',1,'angelscript.h']]], + ['asbc_5fchkrefs_1329',['asBC_ChkRefS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad0c18f6eab27072771563d4464d06a4a',1,'angelscript.h']]], + ['asbc_5fclrhi_1330',['asBC_ClrHi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1293f6086ce51f270a7d756413cabb9c',1,'angelscript.h']]], + ['asbc_5fclrvptr_1331',['asBC_ClrVPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8b5cd32b4b5bc6aaafb0456d931dc11e',1,'angelscript.h']]], + ['asbc_5fcmpd_1332',['asBC_CMPd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad72b54941de6dccfbea9c6ccb5d915df',1,'angelscript.h']]], + ['asbc_5fcmpf_1333',['asBC_CMPf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a158d7962cea577c9a18f639976c6c0ab',1,'angelscript.h']]], + ['asbc_5fcmpi_1334',['asBC_CMPi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af81b0602117dd9ef104dea7d2d526cfa',1,'angelscript.h']]], + ['asbc_5fcmpi64_1335',['asBC_CMPi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa2c75f0562b433b18406a939bcd62e95',1,'angelscript.h']]], + ['asbc_5fcmpif_1336',['asBC_CMPIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2f5efa47419aa3a053f1e8916b46e303',1,'angelscript.h']]], + ['asbc_5fcmpii_1337',['asBC_CMPIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a33a798d1fe04ec8e1794ddb0838039d9',1,'angelscript.h']]], + ['asbc_5fcmpiu_1338',['asBC_CMPIu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad7195755387f9159b4a2c5de9e60a068',1,'angelscript.h']]], + ['asbc_5fcmpptr_1339',['asBC_CmpPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a17c0368321613c9e38e438f96b80bdd7',1,'angelscript.h']]], + ['asbc_5fcmpu_1340',['asBC_CMPu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2d473195aba3ddcc8d6419c047d0c741',1,'angelscript.h']]], + ['asbc_5fcmpu64_1341',['asBC_CMPu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af521b982839cdc97e9b2413ac085b09f',1,'angelscript.h']]], + ['asbc_5fcopy_1342',['asBC_COPY',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa06ef833e37285449bfc72e0c93479a9',1,'angelscript.h']]], + ['asbc_5fcpygtov4_1343',['asBC_CpyGtoV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4ed62e4b84509466aef25d638026b883',1,'angelscript.h']]], + ['asbc_5fcpyrtov4_1344',['asBC_CpyRtoV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a27458705bfaa7f4e5b27f848c0e59c7c',1,'angelscript.h']]], + ['asbc_5fcpyrtov8_1345',['asBC_CpyRtoV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a399ae190caa78f468883f9736e8f9d40',1,'angelscript.h']]], + ['asbc_5fcpyvtog4_1346',['asBC_CpyVtoG4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4e7398002dfd57870657a8df142259a1',1,'angelscript.h']]], + ['asbc_5fcpyvtor4_1347',['asBC_CpyVtoR4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af77782bde1062e849fc6c02c8c4e0106',1,'angelscript.h']]], + ['asbc_5fcpyvtor8_1348',['asBC_CpyVtoR8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a25f9b87968cb0fea646d003a90bbd0a6',1,'angelscript.h']]], + ['asbc_5fcpyvtov4_1349',['asBC_CpyVtoV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac8e1a29718cf8958201d578d56cf74b4',1,'angelscript.h']]], + ['asbc_5fcpyvtov8_1350',['asBC_CpyVtoV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af0a7f6b4a1c14352e7cd02e03c1e7595',1,'angelscript.h']]], + ['asbc_5fdecd_1351',['asBC_DECd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a46ccee51c06462cd452c6a97a2854a22',1,'angelscript.h']]], + ['asbc_5fdecf_1352',['asBC_DECf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0fedf5312b600d2cd8e991139ff237f1',1,'angelscript.h']]], + ['asbc_5fdeci_1353',['asBC_DECi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad78d2aec3e51a9aaf3fb5f3c12afc420',1,'angelscript.h']]], + ['asbc_5fdeci16_1354',['asBC_DECi16',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9ea8e03a8da22997477fca4f79d55830',1,'angelscript.h']]], + ['asbc_5fdeci64_1355',['asBC_DECi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a27cdd04643b9331e2aedfb6c1af1c021',1,'angelscript.h']]], + ['asbc_5fdeci8_1356',['asBC_DECi8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aeb53c8898d91276563cf360539b2c4ce',1,'angelscript.h']]], + ['asbc_5fdecvi_1357',['asBC_DecVi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0f57e25fb34f2d086f35f60cfe51782e',1,'angelscript.h']]], + ['asbc_5fdivd_1358',['asBC_DIVd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a016b86c3e0706775fc653d6f94048765',1,'angelscript.h']]], + ['asbc_5fdivf_1359',['asBC_DIVf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0acf3448b40f2fc34b4007f27c4f8488a2',1,'angelscript.h']]], + ['asbc_5fdivi_1360',['asBC_DIVi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a27123834824beb61355869faf5e23cf4',1,'angelscript.h']]], + ['asbc_5fdivi64_1361',['asBC_DIVi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9f31be749c98afaa86f5b3a83218752b',1,'angelscript.h']]], + ['asbc_5fdivu_1362',['asBC_DIVu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4e171bc08a91c52a5eae821ff3435892',1,'angelscript.h']]], + ['asbc_5fdivu64_1363',['asBC_DIVu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8cc1a88aa5da6d91bbf7bccb7abc3327',1,'angelscript.h']]], + ['asbc_5fdtof_1364',['asBC_dTOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a854599de98fcbd9334c9223e8e9058db',1,'angelscript.h']]], + ['asbc_5fdtoi_1365',['asBC_dTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0afb5dbe4edea3e5cfa521fd3a5738ccf6',1,'angelscript.h']]], + ['asbc_5fdtoi64_1366',['asBC_dTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a043e40662a884a7c39bbd982d3e2266f',1,'angelscript.h']]], + ['asbc_5fdtou_1367',['asBC_dTOu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab316237649a76cf10a1b9bc68c2792c4',1,'angelscript.h']]], + ['asbc_5fdtou64_1368',['asBC_dTOu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a062cb021be1b64d913527c22c7dba896',1,'angelscript.h']]], + ['asbc_5ffree_1369',['asBC_FREE',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1d13cb9820edf1d65e09e3c70f67d3b9',1,'angelscript.h']]], + ['asbc_5fftod_1370',['asBC_fTOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8d1a589383ae9187b58a3f774cbe77cd',1,'angelscript.h']]], + ['asbc_5fftoi_1371',['asBC_fTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a505d5d669a5d046b5fe5edbde407d12a',1,'angelscript.h']]], + ['asbc_5fftoi64_1372',['asBC_fTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0acd75aec128802694c2674b122204e704',1,'angelscript.h']]], + ['asbc_5fftou_1373',['asBC_fTOu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9e9e1d16d150ca95e5f8abee59aaed51',1,'angelscript.h']]], + ['asbc_5fftou64_1374',['asBC_fTOu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae5bd9d9c6b756c2898f2776b0b08e793',1,'angelscript.h']]], + ['asbc_5ffuncptr_1375',['asBC_FuncPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab4a58c4177502bd6d3a034f2d4244404',1,'angelscript.h']]], + ['asbc_5fgetobj_1376',['asBC_GETOBJ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aaef456de01ad209271078728d304b803',1,'angelscript.h']]], + ['asbc_5fgetobjref_1377',['asBC_GETOBJREF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6b9d0ef0c8e981a591c384792acf2c6d',1,'angelscript.h']]], + ['asbc_5fgetref_1378',['asBC_GETREF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6ad13f895f055f69384efb4a67941369',1,'angelscript.h']]], + ['asbc_5fi64tod_1379',['asBC_i64TOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7e110775dee3e08f9ef7e2215fb48b26',1,'angelscript.h']]], + ['asbc_5fi64tof_1380',['asBC_i64TOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a22f2099b91cb1bde2df44760ea2efed7',1,'angelscript.h']]], + ['asbc_5fi64toi_1381',['asBC_i64TOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae66d679b16934aeb2c7047ea1b1fae85',1,'angelscript.h']]], + ['asbc_5fincd_1382',['asBC_INCd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a46b7c1d75685f454688e361e4da99994',1,'angelscript.h']]], + ['asbc_5fincf_1383',['asBC_INCf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aef2f50c2ed4d67c3da6630616ad00a7b',1,'angelscript.h']]], + ['asbc_5finci_1384',['asBC_INCi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a630408d0f3892bfa8ba01da409ca30e3',1,'angelscript.h']]], + ['asbc_5finci16_1385',['asBC_INCi16',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a4669b8c92a8b8d9c6e84d0ed1db14d33',1,'angelscript.h']]], + ['asbc_5finci64_1386',['asBC_INCi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6216ec910e53970e52e518da4786a37b',1,'angelscript.h']]], + ['asbc_5finci8_1387',['asBC_INCi8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a152dde2647cf17bf01f255cab7d7a398',1,'angelscript.h']]], + ['asbc_5fincvi_1388',['asBC_IncVi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af9579b13bff9bcc81710fe7dba9c0957',1,'angelscript.h']]], + ['asbc_5fitob_1389',['asBC_iTOb',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aea965df01399592f1e8c3950a35e837f',1,'angelscript.h']]], + ['asbc_5fitod_1390',['asBC_iTOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad9a5f8875c44b01fa6e1501bb70bae00',1,'angelscript.h']]], + ['asbc_5fitof_1391',['asBC_iTOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a92116eabda2e6b20e1ea2a13a316decd',1,'angelscript.h']]], + ['asbc_5fitoi64_1392',['asBC_iTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa48a1b118c32dc9d5667b9039aa06bff',1,'angelscript.h']]], + ['asbc_5fitow_1393',['asBC_iTOw',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0acdf698af6bd4a5e427922e9462244319',1,'angelscript.h']]], + ['asbc_5fjitentry_1394',['asBC_JitEntry',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6705ee9692b45f118cfe0ea24581fae5',1,'angelscript.h']]], + ['asbc_5fjlownz_1395',['asBC_JLowNZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a12e9c561f401be75a6db13a94a687d77',1,'angelscript.h']]], + ['asbc_5fjlowz_1396',['asBC_JLowZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9da365af8ea85e3eb538567207d4a705',1,'angelscript.h']]], + ['asbc_5fjmp_1397',['asBC_JMP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6742a11dd679468b98df9c45aabfb32b',1,'angelscript.h']]], + ['asbc_5fjmpp_1398',['asBC_JMPP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a31eae477a85a0b1ee618df42deb0519c',1,'angelscript.h']]], + ['asbc_5fjnp_1399',['asBC_JNP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae4f95a73cfe667f1928e7766ea09511e',1,'angelscript.h']]], + ['asbc_5fjns_1400',['asBC_JNS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a736796cbac759ad4fc43bb09267f36ca',1,'angelscript.h']]], + ['asbc_5fjnz_1401',['asBC_JNZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a262d3c0a50f45e6b6de3f1b77f4b4bf0',1,'angelscript.h']]], + ['asbc_5fjp_1402',['asBC_JP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac2792270f8022801384ccd0ae3b00604',1,'angelscript.h']]], + ['asbc_5fjs_1403',['asBC_JS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2357fddab027985d9af0398e304b0ec1',1,'angelscript.h']]], + ['asbc_5fjz_1404',['asBC_JZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a497ae321f5a5889c9bee415b7cc38e9c',1,'angelscript.h']]], + ['asbc_5fldg_1405',['asBC_LDG',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7eecc42f41efaa2a9e52a38b5b2e0761',1,'angelscript.h']]], + ['asbc_5fldgrdr4_1406',['asBC_LdGRdR4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2d39346b29e025ea48c3d1f9ad5be43e',1,'angelscript.h']]], + ['asbc_5fldv_1407',['asBC_LDV',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a506cf72989aae9c3f0613b3fdd788a96',1,'angelscript.h']]], + ['asbc_5floadobj_1408',['asBC_LOADOBJ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a05fa84bd9f65d7e99871d9b78da54e16',1,'angelscript.h']]], + ['asbc_5floadrobjr_1409',['asBC_LoadRObjR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a55e484687643f87565827249a81cf3a8',1,'angelscript.h']]], + ['asbc_5floadthisr_1410',['asBC_LoadThisR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8950187a9c91330124df91bb27d7a1a3',1,'angelscript.h']]], + ['asbc_5floadvobjr_1411',['asBC_LoadVObjR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2285121bf664f86d462560fde6dad0f7',1,'angelscript.h']]], + ['asbc_5fmodd_1412',['asBC_MODd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac2137a8a8fe7af5070f37e796d863af2',1,'angelscript.h']]], + ['asbc_5fmodf_1413',['asBC_MODf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae54338068d6b6e965c497c6b1d68c64e',1,'angelscript.h']]], + ['asbc_5fmodi_1414',['asBC_MODi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae8e569143d23f682b3aecfa100bdfd4e',1,'angelscript.h']]], + ['asbc_5fmodi64_1415',['asBC_MODi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a3bd852f5aa7c1a12da37a7ac91b1c83f',1,'angelscript.h']]], + ['asbc_5fmodu_1416',['asBC_MODu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a22772f5830ff9c17b6427e70128711f8',1,'angelscript.h']]], + ['asbc_5fmodu64_1417',['asBC_MODu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aaa0fe36a1a3467428d9d9bc06bf038fe',1,'angelscript.h']]], + ['asbc_5fmuld_1418',['asBC_MULd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a411e71202157cfece504379e6171a464',1,'angelscript.h']]], + ['asbc_5fmulf_1419',['asBC_MULf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab32f923ffcabab481a2e46f702b17f7a',1,'angelscript.h']]], + ['asbc_5fmuli_1420',['asBC_MULi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a93c630d303bb6e91e044d6afea71b798',1,'angelscript.h']]], + ['asbc_5fmuli64_1421',['asBC_MULi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a38931ac737104c4ccca730705bd7ec48',1,'angelscript.h']]], + ['asbc_5fmulif_1422',['asBC_MULIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a29cb2ee51427268cf549f90e110b1e38',1,'angelscript.h']]], + ['asbc_5fmulii_1423',['asBC_MULIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af29eb13449c228f4dead9ba6da590147',1,'angelscript.h']]], + ['asbc_5fnegd_1424',['asBC_NEGd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a928187662dfd857cf8edb10a632651d4',1,'angelscript.h']]], + ['asbc_5fnegf_1425',['asBC_NEGf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7de6d0118307feca68660e67c79ca7dc',1,'angelscript.h']]], + ['asbc_5fnegi_1426',['asBC_NEGi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a01fe11f3f95464cb3e409c3181a02c1a',1,'angelscript.h']]], + ['asbc_5fnegi64_1427',['asBC_NEGi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a3cf16372d571ec566ae93fd80e05b1ad',1,'angelscript.h']]], + ['asbc_5fnot_1428',['asBC_NOT',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a13a6093971474018818db5a76f012f26',1,'angelscript.h']]], + ['asbc_5fobjtype_1429',['asBC_OBJTYPE',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0dcad2ccee9332253501c3cef2200fad',1,'angelscript.h']]], + ['asbc_5fpga_1430',['asBC_PGA',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0adc83ae72a402eb4c8d8248ef2ef75d9c',1,'angelscript.h']]], + ['asbc_5fpopptr_1431',['asBC_PopPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a61f3044359836f88001928bcab382c1e',1,'angelscript.h']]], + ['asbc_5fpoprptr_1432',['asBC_PopRPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a567f07266bd50926c205460b31d579f6',1,'angelscript.h']]], + ['asbc_5fpowd_1433',['asBC_POWd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a17794eb37e2e24d3f92945e492fd8fdc',1,'angelscript.h']]], + ['asbc_5fpowdi_1434',['asBC_POWdi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a550ee3e286be8a70a06194206c0ae1b9',1,'angelscript.h']]], + ['asbc_5fpowf_1435',['asBC_POWf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aedc33b037796cfbb5879799a6bea3b0d',1,'angelscript.h']]], + ['asbc_5fpowi_1436',['asBC_POWi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1b9ae2022b484a3c44820b6528c68ac0',1,'angelscript.h']]], + ['asbc_5fpowi64_1437',['asBC_POWi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7546139b9cafeae5d71a345ec3b4424d',1,'angelscript.h']]], + ['asbc_5fpowu_1438',['asBC_POWu',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a45adae8be4e9dde1b77dc9346786cfef',1,'angelscript.h']]], + ['asbc_5fpowu64_1439',['asBC_POWu64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a23bbb267da86c108b4fe23f0443d5f1d',1,'angelscript.h']]], + ['asbc_5fpsf_1440',['asBC_PSF',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1c42ff5ba726e656b989e3408fe9648f',1,'angelscript.h']]], + ['asbc_5fpshc4_1441',['asBC_PshC4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a53fa213a7d3fed6add6d37dfe073e1cb',1,'angelscript.h']]], + ['asbc_5fpshc8_1442',['asBC_PshC8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac987a5f48ff66860142d01ed51670d91',1,'angelscript.h']]], + ['asbc_5fpshg4_1443',['asBC_PshG4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a71be4bc7beb5407aac980f73cce33bd6',1,'angelscript.h']]], + ['asbc_5fpshgptr_1444',['asBC_PshGPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0c1133692af5029feef4a1e5aec5c65b',1,'angelscript.h']]], + ['asbc_5fpshlistelmnt_1445',['asBC_PshListElmnt',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a980fccdeeebe67503f9623722ed893a5',1,'angelscript.h']]], + ['asbc_5fpshnull_1446',['asBC_PshNull',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9343148f733f970e3463f37fac57f998',1,'angelscript.h']]], + ['asbc_5fpshrptr_1447',['asBC_PshRPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a3ecef93739a85d45002cd073b00da52c',1,'angelscript.h']]], + ['asbc_5fpshv4_1448',['asBC_PshV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab858dd8ba0b9fed72638c549f40f60ba',1,'angelscript.h']]], + ['asbc_5fpshv8_1449',['asBC_PshV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ae2923dbf7fc9bb70c0c3cbbf8673467c',1,'angelscript.h']]], + ['asbc_5fpshvptr_1450',['asBC_PshVPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a15f565f207bdaab4d5b72867cdd25007',1,'angelscript.h']]], + ['asbc_5frdr1_1451',['asBC_RDR1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0375f41153eeaa6d250a6ee262ffa0ba',1,'angelscript.h']]], + ['asbc_5frdr2_1452',['asBC_RDR2',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa470ed962fa3e1a86296998914cbcc12',1,'angelscript.h']]], + ['asbc_5frdr4_1453',['asBC_RDR4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac66bc5d2959ef22b6c967313aa791b54',1,'angelscript.h']]], + ['asbc_5frdr8_1454',['asBC_RDR8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a36dc7a09798a7055d8faece1321e241a',1,'angelscript.h']]], + ['asbc_5frdsptr_1455',['asBC_RDSPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a2628264804fd19af3ce94e0336b3eeeb',1,'angelscript.h']]], + ['asbc_5frefcpy_1456',['asBC_REFCPY',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0509f97130860b6fe3477f66e9fb712d',1,'angelscript.h']]], + ['asbc_5frefcpyv_1457',['asBC_RefCpyV',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8b1c7e7b7c8054b36a9d48c3452adf79',1,'angelscript.h']]], + ['asbc_5fret_1458',['asBC_RET',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0adf0df27f972bc4edb9b2213fe6448f68',1,'angelscript.h']]], + ['asbc_5fsbtoi_1459',['asBC_sbTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0afbfb6f5aaf4d6599e16b4bfe458ce01e',1,'angelscript.h']]], + ['asbc_5fsetg4_1460',['asBC_SetG4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a880a2be05a247612df28ea4569a7a99b',1,'angelscript.h']]], + ['asbc_5fsetlistsize_1461',['asBC_SetListSize',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8c8a41c980d7b8f2054780da0153ae64',1,'angelscript.h']]], + ['asbc_5fsetlisttype_1462',['asBC_SetListType',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a7abb1d21f26401e75305a2b4cf7a4733',1,'angelscript.h']]], + ['asbc_5fsetv1_1463',['asBC_SetV1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af3909e9889d0994c0d0190a147eac3cb',1,'angelscript.h']]], + ['asbc_5fsetv2_1464',['asBC_SetV2',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a709cec30c38c5dc89dfcd92341dafd61',1,'angelscript.h']]], + ['asbc_5fsetv4_1465',['asBC_SetV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a95d9223bb76b2abcbc590318007aed93',1,'angelscript.h']]], + ['asbc_5fsetv8_1466',['asBC_SetV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ade5e3b21c7d1b9348ac12fc4cd1cbf8a',1,'angelscript.h']]], + ['asbc_5fstoreobj_1467',['asBC_STOREOBJ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aaa9dd5f07ce2b4b9d72750daa4b64294',1,'angelscript.h']]], + ['asbc_5fstr_1468',['asBC_STR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa9541dbcbb58f820d5d8e81414367d5e',1,'angelscript.h']]], + ['asbc_5fsubd_1469',['asBC_SUBd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a40632786e202cc6a617bbe63a8d4cc0f',1,'angelscript.h']]], + ['asbc_5fsubf_1470',['asBC_SUBf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aca247b39114dc45ae993dd1cf80226aa',1,'angelscript.h']]], + ['asbc_5fsubi_1471',['asBC_SUBi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af04edb64674c1c46b1769b4f31828441',1,'angelscript.h']]], + ['asbc_5fsubi64_1472',['asBC_SUBi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a14984f047b26178d73ea024e97b3718c',1,'angelscript.h']]], + ['asbc_5fsubif_1473',['asBC_SUBIf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a83fc6f0a163316a6be6c280df57fcd13',1,'angelscript.h']]], + ['asbc_5fsubii_1474',['asBC_SUBIi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ab77b30af827c52ee62a5ccab94d96003',1,'angelscript.h']]], + ['asbc_5fsuspend_1475',['asBC_SUSPEND',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a175714567c483ff439c1d2c125ca9608',1,'angelscript.h']]], + ['asbc_5fswapptr_1476',['asBC_SwapPtr',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac23d851c5aaffca166d6494bec9bcf24',1,'angelscript.h']]], + ['asbc_5fswtoi_1477',['asBC_swTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aad0cc8bb8012f257fa99f01b8b7035bd',1,'angelscript.h']]], + ['asbc_5fthiscall1_1478',['asBC_Thiscall1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a25fe35c5c31674255821ecc3c9a9d23c',1,'angelscript.h']]], + ['asbc_5ftnp_1479',['asBC_TNP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aa57f16a2b46be5e2ce7740389c8eb479',1,'angelscript.h']]], + ['asbc_5ftns_1480',['asBC_TNS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6283325ca6354974eec243ce918e6902',1,'angelscript.h']]], + ['asbc_5ftnz_1481',['asBC_TNZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac63ed68678f4e7490d67727fd3dc6a80',1,'angelscript.h']]], + ['asbc_5ftp_1482',['asBC_TP',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6dc225b22eecb133457b82700081cbcf',1,'angelscript.h']]], + ['asbc_5fts_1483',['asBC_TS',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a0136c50e72d9f3e09f053768373f8fd2',1,'angelscript.h']]], + ['asbc_5ftypeid_1484',['asBC_TYPEID',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a8f1ffc19b950ebc7b6a4b9ac97f8dc4d',1,'angelscript.h']]], + ['asbc_5ftz_1485',['asBC_TZ',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0afa0764106ecce859b73b84119cdbbb19',1,'angelscript.h']]], + ['asbc_5fu64tod_1486',['asBC_u64TOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a61a9abe7f4b17874cc1f2eff761bc3b2',1,'angelscript.h']]], + ['asbc_5fu64tof_1487',['asBC_u64TOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ad293bf12c4a8de3c50794a9eaeac636d',1,'angelscript.h']]], + ['asbc_5fubtoi_1488',['asBC_ubTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a9c20fcde56da1d0386a10490fb13a7d6',1,'angelscript.h']]], + ['asbc_5futod_1489',['asBC_uTOd',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0abb2e2f37012d6cb75b446fc992dba6c4',1,'angelscript.h']]], + ['asbc_5futof_1490',['asBC_uTOf',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a6f445f24f6501cf4c3711929a1d5e111',1,'angelscript.h']]], + ['asbc_5futoi64_1491',['asBC_uTOi64',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af5f7cad82e5cd2dc4a3d690a2ab46bce',1,'angelscript.h']]], + ['asbc_5fuwtoi_1492',['asBC_uwTOi',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a1d90e73c2b31b0e15282d092b46cf742',1,'angelscript.h']]], + ['asbc_5fvar_1493',['asBC_VAR',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0adb056673fe9802b5d8351835d0c4cea9',1,'angelscript.h']]], + ['asbc_5fwrtv1_1494',['asBC_WRTV1',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0a94dbdd03bb807ceb48c3ced7b08cbaf3',1,'angelscript.h']]], + ['asbc_5fwrtv2_1495',['asBC_WRTV2',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0af50492589b9b48fb6cce810ea12b2313',1,'angelscript.h']]], + ['asbc_5fwrtv4_1496',['asBC_WRTV4',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0aecc937d822668f3d443c2cf7c2c9a91b',1,'angelscript.h']]], + ['asbc_5fwrtv8_1497',['asBC_WRTV8',['../angelscript_8h.html#ab3692c4e5d47fc93f8c9646d1783aef0ac912670273a5cc5857967d6c4ee9fb71',1,'angelscript.h']]], + ['asbctype_5fdw_5farg_1498',['asBCTYPE_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcacda81b5a95de8ef351d80f7f007f3c1f',1,'angelscript.h']]], + ['asbctype_5fdw_5fdw_5farg_1499',['asBCTYPE_DW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcac7dee47b6d43b90ec5d3f348d9adb29b',1,'angelscript.h']]], + ['asbctype_5fno_5farg_1500',['asBCTYPE_NO_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca5d474089af62503917b5a9075ea884a0',1,'angelscript.h']]], + ['asbctype_5fqw_5farg_1501',['asBCTYPE_QW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcab5ccbe43d9de8e5261c5d98c0235e680',1,'angelscript.h']]], + ['asbctype_5fqw_5fdw_5farg_1502',['asBCTYPE_QW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca1923164123cd74d611b8ed4bf491a489',1,'angelscript.h']]], + ['asbctype_5frw_5farg_1503',['asBCTYPE_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca8f31f45900a4e5a456c8423e6efa2435',1,'angelscript.h']]], + ['asbctype_5frw_5fdw_5farg_1504',['asBCTYPE_rW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcab6ce6fd0303ba86f9933afba82af1da5',1,'angelscript.h']]], + ['asbctype_5frw_5fdw_5fdw_5farg_1505',['asBCTYPE_rW_DW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcae203bd09b5f39c9c2b6f9da1cb125fc9',1,'angelscript.h']]], + ['asbctype_5frw_5fqw_5farg_1506',['asBCTYPE_rW_QW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcac7dd4b17f956dd9f77154a969826c5b9',1,'angelscript.h']]], + ['asbctype_5frw_5frw_5farg_1507',['asBCTYPE_rW_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca3bab72c18fc7528b191c07fa69ce8592',1,'angelscript.h']]], + ['asbctype_5frw_5fw_5fdw_5farg_1508',['asBCTYPE_rW_W_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca21c4ffbfac771e092bf8b229d041bfa8',1,'angelscript.h']]], + ['asbctype_5fw_5farg_1509',['asBCTYPE_W_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca2ed4017596353fbfd8284abb87693479',1,'angelscript.h']]], + ['asbctype_5fw_5fdw_5farg_1510',['asBCTYPE_W_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca3363c16ca9a7dd52a6292e4006a97e25',1,'angelscript.h']]], + ['asbctype_5fww_5farg_1511',['asBCTYPE_wW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca35b791ccee8b22494cf5c0d1cd7c1bf1',1,'angelscript.h']]], + ['asbctype_5fww_5fdw_5farg_1512',['asBCTYPE_wW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcaca83b5ca2543f825bfb235a7c75bf861',1,'angelscript.h']]], + ['asbctype_5fww_5fqw_5farg_1513',['asBCTYPE_wW_QW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcad0f58ec314c7ee6b346428f181406462',1,'angelscript.h']]], + ['asbctype_5fww_5frw_5farg_1514',['asBCTYPE_wW_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca983e22175938d52ed285d05729082356',1,'angelscript.h']]], + ['asbctype_5fww_5frw_5fdw_5farg_1515',['asBCTYPE_wW_rW_DW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dcabd1019654afbbc88a6d7ec145d187d43',1,'angelscript.h']]], + ['asbctype_5fww_5frw_5frw_5farg_1516',['asBCTYPE_wW_rW_rW_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca70e3f2b6c20b552f734afa1237ffbfa1',1,'angelscript.h']]], + ['asbctype_5fww_5fw_5farg_1517',['asBCTYPE_wW_W_ARG',['../angelscript_8h.html#a05f4716428617975227a75eef995d3dca20eff83445fbfaeccf0099d04434ddff',1,'angelscript.h']]], + ['asbehave_5faddref_1518',['asBEHAVE_ADDREF',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a1dfa5b72ad69a7bf70636d4fcb1b1d84',1,'angelscript.h']]], + ['asbehave_5fconstruct_1519',['asBEHAVE_CONSTRUCT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5aa4cf235bfbf72ec03d0f651cea324101',1,'angelscript.h']]], + ['asbehave_5fdestruct_1520',['asBEHAVE_DESTRUCT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a0748a0f3a559354761ce15c2d1de2e51',1,'angelscript.h']]], + ['asbehave_5fenumrefs_1521',['asBEHAVE_ENUMREFS',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a08ccf78a37567b5dd192ff5d95c6667b',1,'angelscript.h']]], + ['asbehave_5ffactory_1522',['asBEHAVE_FACTORY',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a0b3db16eea35213b6f41f8d19dc1bd4c',1,'angelscript.h']]], + ['asbehave_5fget_5fweakref_5fflag_1523',['asBEHAVE_GET_WEAKREF_FLAG',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a7a5e435e88a5fc1dcdee13fce091b081',1,'angelscript.h']]], + ['asbehave_5fgetgcflag_1524',['asBEHAVE_GETGCFLAG',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5abfce2539609e667f15b24bbc8551c7b7',1,'angelscript.h']]], + ['asbehave_5fgetrefcount_1525',['asBEHAVE_GETREFCOUNT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5af998529f8ea1e54567997b8fb2867640',1,'angelscript.h']]], + ['asbehave_5flist_5fconstruct_1526',['asBEHAVE_LIST_CONSTRUCT',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a04c0b561986c6814e8a54ce3679178a2',1,'angelscript.h']]], + ['asbehave_5flist_5ffactory_1527',['asBEHAVE_LIST_FACTORY',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5aea078bc3b877ce33a2335e78ddb4938d',1,'angelscript.h']]], + ['asbehave_5frelease_1528',['asBEHAVE_RELEASE',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a7134ce13c81967191af401a1e5170a0c',1,'angelscript.h']]], + ['asbehave_5freleaserefs_1529',['asBEHAVE_RELEASEREFS',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a4275ebe0b4852f2d4a10d4d9db333fe9',1,'angelscript.h']]], + ['asbehave_5fsetgcflag_1530',['asBEHAVE_SETGCFLAG',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5aadbad474a338c3a0fe6e90df679bb2e6',1,'angelscript.h']]], + ['asbehave_5ftemplate_5fcallback_1531',['asBEHAVE_TEMPLATE_CALLBACK',['../angelscript_8h.html#a7e38df5b10ec8cbf2a688f1d114097c5a8c9afe12ff833cd09bd893e1408b9103',1,'angelscript.h']]], + ['asbuild_5fin_5fprogress_1532',['asBUILD_IN_PROGRESS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54abbab3f809b0eeea2c331e5239be517c1',1,'angelscript.h']]], + ['ascall_5fcdecl_1533',['asCALL_CDECL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a68ae43cc91cdfc3fa4590c9e6164e4f4',1,'angelscript.h']]], + ['ascall_5fcdecl_5fobjfirst_1534',['asCALL_CDECL_OBJFIRST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a7c3e88628c2722d0a103b411d4aceaa0',1,'angelscript.h']]], + ['ascall_5fcdecl_5fobjlast_1535',['asCALL_CDECL_OBJLAST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4ac08652c72f1cc0dc81c37812fab0e253',1,'angelscript.h']]], + ['ascall_5fgeneric_1536',['asCALL_GENERIC',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a750c26b6a6e0c9ccbb93078f532ef8ce',1,'angelscript.h']]], + ['ascall_5fstdcall_1537',['asCALL_STDCALL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a138a08e8363ebc695636dfe987674e2e',1,'angelscript.h']]], + ['ascall_5fthiscall_1538',['asCALL_THISCALL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4aea516c8742acc1edff6a43dc1bb09e96',1,'angelscript.h']]], + ['ascall_5fthiscall_5fasglobal_1539',['asCALL_THISCALL_ASGLOBAL',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4aa241a0c1deedaa2d55eb99a83829efad',1,'angelscript.h']]], + ['ascall_5fthiscall_5fobjfirst_1540',['asCALL_THISCALL_OBJFIRST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a613a388ed51315f6fce19f3824d6b17a',1,'angelscript.h']]], + ['ascall_5fthiscall_5fobjlast_1541',['asCALL_THISCALL_OBJLAST',['../angelscript_8h.html#a3ec92ea3c4762e44c2df788ceccdd1e4a491f0ab2b66032a7b5541364f7f225b1',1,'angelscript.h']]], + ['ascant_5fbind_5fall_5ffunctions_1542',['asCANT_BIND_ALL_FUNCTIONS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a412d2352693e848f46ccdd93c8d047e4',1,'angelscript.h']]], + ['ascomp_5fadd_5fto_5fmodule_1543',['asCOMP_ADD_TO_MODULE',['../angelscript_8h.html#a2bf48c41455371788805269376ca5e41a85d0a4fa51dbcc4ad4150f406185b918',1,'angelscript.h']]], + ['asconfig_5fgroup_5fis_5fin_5fuse_1544',['asCONFIG_GROUP_IS_IN_USE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ae38f8f5613a631df20d2cc105aafc612',1,'angelscript.h']]], + ['ascontext_5factive_1545',['asCONTEXT_ACTIVE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aa818a5cf319a2b2da155554d33cc91b4',1,'angelscript.h']]], + ['ascontext_5fnot_5ffinished_1546',['asCONTEXT_NOT_FINISHED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aaca0bfc695713c03655328bf0e2ff814',1,'angelscript.h']]], + ['ascontext_5fnot_5fprepared_1547',['asCONTEXT_NOT_PREPARED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a82940f46469cd8cee7b00b346611658c',1,'angelscript.h']]], + ['asep_5fallow_5fimplicit_5fhandle_5ftypes_1548',['asEP_ALLOW_IMPLICIT_HANDLE_TYPES',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa77c3747503489ca122aa61276dae3c1f',1,'angelscript.h']]], + ['asep_5fallow_5fmultiline_5fstrings_1549',['asEP_ALLOW_MULTILINE_STRINGS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa218fdf7e181bf9ee0498112f5a87c415',1,'angelscript.h']]], + ['asep_5fallow_5funicode_5fidentifiers_1550',['asEP_ALLOW_UNICODE_IDENTIFIERS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa651f1843c922a61ccee5c81fac58e4d1',1,'angelscript.h']]], + ['asep_5fallow_5funsafe_5freferences_1551',['asEP_ALLOW_UNSAFE_REFERENCES',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa8facaf887921a6b26e5a1f06e01ec37a',1,'angelscript.h']]], + ['asep_5falter_5fsyntax_5fnamed_5fargs_1552',['asEP_ALTER_SYNTAX_NAMED_ARGS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa9c876445c7d138ad096705fc18f311d1',1,'angelscript.h']]], + ['asep_5falways_5fimpl_5fdefault_5fconstruct_1553',['asEP_ALWAYS_IMPL_DEFAULT_CONSTRUCT',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6d80b60995ad046918b2376d7d79f2af',1,'angelscript.h']]], + ['asep_5fauto_5fgarbage_5fcollect_1554',['asEP_AUTO_GARBAGE_COLLECT',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa9b5d1d8ff5143a6a77dfd18143d87c7d',1,'angelscript.h']]], + ['asep_5fbuild_5fwithout_5fline_5fcues_1555',['asEP_BUILD_WITHOUT_LINE_CUES',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa73b396e4ea6376f0962d19add962bd91',1,'angelscript.h']]], + ['asep_5fcompiler_5fwarnings_1556',['asEP_COMPILER_WARNINGS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fadd96da828860b5de2352de07c2456633',1,'angelscript.h']]], + ['asep_5fcopy_5fscript_5fsections_1557',['asEP_COPY_SCRIPT_SECTIONS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fabf1577418b716c92f0a85be3e2617243',1,'angelscript.h']]], + ['asep_5fdisable_5finteger_5fdivision_1558',['asEP_DISABLE_INTEGER_DIVISION',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fae6af9c6963372e11c6da873868f594cd',1,'angelscript.h']]], + ['asep_5fdisallow_5fempty_5flist_5felements_1559',['asEP_DISALLOW_EMPTY_LIST_ELEMENTS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fabed7d49670612ec27227210021926692',1,'angelscript.h']]], + ['asep_5fdisallow_5fglobal_5fvars_1560',['asEP_DISALLOW_GLOBAL_VARS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fab81c81f4fdeb616dd6487da48a0c3456',1,'angelscript.h']]], + ['asep_5fdisallow_5fvalue_5fassign_5ffor_5fref_5ftype_1561',['asEP_DISALLOW_VALUE_ASSIGN_FOR_REF_TYPE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa563bec877e91b0646c47197b2ae7ac0c',1,'angelscript.h']]], + ['asep_5fexpand_5fdef_5farray_5fto_5ftmpl_1562',['asEP_EXPAND_DEF_ARRAY_TO_TMPL',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa530e8d9576f94a258446c5fb9b7bd7a5',1,'angelscript.h']]], + ['asep_5fgeneric_5fcall_5fmode_1563',['asEP_GENERIC_CALL_MODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa58fa0f29330923b24ab795e7c6ada52e',1,'angelscript.h']]], + ['asep_5fheredoc_5ftrim_5fmode_1564',['asEP_HEREDOC_TRIM_MODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa9658b61d2368cc84fe816c817444e0ba',1,'angelscript.h']]], + ['asep_5finclude_5fjit_5finstructions_1565',['asEP_INCLUDE_JIT_INSTRUCTIONS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa7ff74f4afa490b55839daaf217cf898c',1,'angelscript.h']]], + ['asep_5finit_5fcall_5fstack_5fsize_1566',['asEP_INIT_CALL_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0faabb0261a40d98af8a0f6d38c2150a4e8',1,'angelscript.h']]], + ['asep_5finit_5fglobal_5fvars_5fafter_5fbuild_1567',['asEP_INIT_GLOBAL_VARS_AFTER_BUILD',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0facac241d97facce4eaf9e5b0ca40dfcf1',1,'angelscript.h']]], + ['asep_5finit_5fstack_5fsize_1568',['asEP_INIT_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6d74b8325be718ace661484f1e8e7fb1',1,'angelscript.h']]], + ['asep_5fmax_5fcall_5fstack_5fsize_1569',['asEP_MAX_CALL_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa4d8ec81a881162a1f0689b56ba864346',1,'angelscript.h']]], + ['asep_5fmax_5fnested_5fcalls_1570',['asEP_MAX_NESTED_CALLS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fab441e1bdd7488bbe8f6dfa9c6b80e4fc',1,'angelscript.h']]], + ['asep_5fmax_5fstack_5fsize_1571',['asEP_MAX_STACK_SIZE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa1ab4c8f8734f0d90bee4005afd810f83',1,'angelscript.h']]], + ['asep_5foptimize_5fbytecode_1572',['asEP_OPTIMIZE_BYTECODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6159294272e4d20dd4b35359a25f3ac6',1,'angelscript.h']]], + ['asep_5fprivate_5fprop_5fas_5fprotected_1573',['asEP_PRIVATE_PROP_AS_PROTECTED',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0faa6f88a81f5706542acb94f3c470ac3f3',1,'angelscript.h']]], + ['asep_5fproperty_5faccessor_5fmode_1574',['asEP_PROPERTY_ACCESSOR_MODE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0facc694c9d52274a113262ebf5984f20ad',1,'angelscript.h']]], + ['asep_5frequire_5fenum_5fscope_1575',['asEP_REQUIRE_ENUM_SCOPE',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa90adb1e54ce0217235545941daa2dccd',1,'angelscript.h']]], + ['asep_5fscript_5fscanner_1576',['asEP_SCRIPT_SCANNER',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa02405d96a12b81aa816986b22bf752c2',1,'angelscript.h']]], + ['asep_5fstring_5fencoding_1577',['asEP_STRING_ENCODING',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fab6daa2ae0c712da7f6f16d698305fba1',1,'angelscript.h']]], + ['asep_5fuse_5fcharacter_5fliterals_1578',['asEP_USE_CHARACTER_LITERALS',['../angelscript_8h.html#a53c2e8a74ade77c928316396394ebe0fa6dc1c33f9227c66f18fc0f95a0c798b2',1,'angelscript.h']]], + ['aserror_1579',['asERROR',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ac265666b65474ec2848d93201a5bc8c8',1,'angelscript.h']]], + ['asexecution_5faborted_1580',['asEXECUTION_ABORTED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a6f384f00eac7033b4da1430ea7267bbf',1,'angelscript.h']]], + ['asexecution_5factive_1581',['asEXECUTION_ACTIVE',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a690200ba7f2d821b0f330ac4220b299a',1,'angelscript.h']]], + ['asexecution_5ferror_1582',['asEXECUTION_ERROR',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a9024318029d37f82b07b8c92a42b1bb2',1,'angelscript.h']]], + ['asexecution_5fexception_1583',['asEXECUTION_EXCEPTION',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69aa3d548fa7d2278d848e50222b700c6c8',1,'angelscript.h']]], + ['asexecution_5ffinished_1584',['asEXECUTION_FINISHED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a6d3730dd7a91aff81cafaaca4e93efaa',1,'angelscript.h']]], + ['asexecution_5fprepared_1585',['asEXECUTION_PREPARED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69ab976b0bdaae9969d72a7c73db62e61e1',1,'angelscript.h']]], + ['asexecution_5fsuspended_1586',['asEXECUTION_SUSPENDED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a7b5644be315c46f2fa44f032731242c7',1,'angelscript.h']]], + ['asexecution_5funinitialized_1587',['asEXECUTION_UNINITIALIZED',['../angelscript_8h.html#a867f14b4137dd4602fda1e616b217a69a684a042709702ab93417d7db98ae7090',1,'angelscript.h']]], + ['asfunc_5fdelegate_1588',['asFUNC_DELEGATE',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa02773b148f9c6fb3ed5d945a940f302a',1,'angelscript.h']]], + ['asfunc_5ffuncdef_1589',['asFUNC_FUNCDEF',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa73c9b6201770e89cb90212c793ca5173',1,'angelscript.h']]], + ['asfunc_5fimported_1590',['asFUNC_IMPORTED',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa9c44f646079e0592316cf5892e33d0ec',1,'angelscript.h']]], + ['asfunc_5finterface_1591',['asFUNC_INTERFACE',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fac245ebb3ca53d4037e28de80ae81991f',1,'angelscript.h']]], + ['asfunc_5fscript_1592',['asFUNC_SCRIPT',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fac5431c6f2ee2e7cf530739c01c1343eb',1,'angelscript.h']]], + ['asfunc_5fsystem_1593',['asFUNC_SYSTEM',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fa9ea0b7b39362f427b7449b11d70f306b',1,'angelscript.h']]], + ['asfunc_5fvirtual_1594',['asFUNC_VIRTUAL',['../angelscript_8h.html#a06fb2a1ebf5d007e0d542abced1b648fac6a82b2b64cfee8e143a41b4b627083a',1,'angelscript.h']]], + ['asgc_5fdestroy_5fgarbage_1595',['asGC_DESTROY_GARBAGE',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da61ab8361ad09823a287572d026efe7f1',1,'angelscript.h']]], + ['asgc_5fdetect_5fgarbage_1596',['asGC_DETECT_GARBAGE',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da3ff3b60e4d1bbc94f6ad46604994526a',1,'angelscript.h']]], + ['asgc_5ffull_5fcycle_1597',['asGC_FULL_CYCLE',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da31e476bfb875b0f4fb209a3ef2540709',1,'angelscript.h']]], + ['asgc_5fone_5fstep_1598',['asGC_ONE_STEP',['../angelscript_8h.html#ac06582350753eb4d89d6ba9442eadf9da33a4cea43ee17e4f01bef742762e5af8',1,'angelscript.h']]], + ['asgm_5falways_5fcreate_1599',['asGM_ALWAYS_CREATE',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0ca0843ab784ed9a9ea6cb47d915825186f',1,'angelscript.h']]], + ['asgm_5fcreate_5fif_5fnot_5fexists_1600',['asGM_CREATE_IF_NOT_EXISTS',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0cafaa7b80aa39b669fbe250c0822af63bb',1,'angelscript.h']]], + ['asgm_5fonly_5fif_5fexists_1601',['asGM_ONLY_IF_EXISTS',['../angelscript_8h.html#ae4cf50de5273eb8c03c6e91e6e014f0ca2feb963eb04c221e251867bc3a93d79d',1,'angelscript.h']]], + ['asillegal_5fbehaviour_5ffor_5ftype_1602',['asILLEGAL_BEHAVIOUR_FOR_TYPE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a5cd00c005a05345d8967021ebaae51f8',1,'angelscript.h']]], + ['asinit_5fglobal_5fvars_5ffailed_1603',['asINIT_GLOBAL_VARS_FAILED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a539a1fcf3f48feaaf7c0776c88123430',1,'angelscript.h']]], + ['asinvalid_5farg_1604',['asINVALID_ARG',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a04e0f0b1ea30eacff3b4a6dddf2060b8',1,'angelscript.h']]], + ['asinvalid_5fconfiguration_1605',['asINVALID_CONFIGURATION',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a7416ebaf18f32e180595fb366a072754',1,'angelscript.h']]], + ['asinvalid_5fdeclaration_1606',['asINVALID_DECLARATION',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ab25fab2dbf4379d7a95a800b765287e4',1,'angelscript.h']]], + ['asinvalid_5finterface_1607',['asINVALID_INTERFACE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a87279b314ed35fc9a6bff9e7cb05eb73',1,'angelscript.h']]], + ['asinvalid_5fname_1608',['asINVALID_NAME',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a85a932230d1622bcb5ec341d25db7775',1,'angelscript.h']]], + ['asinvalid_5fobject_1609',['asINVALID_OBJECT',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aa9b05e66771b2af2e7d14d32701a6015',1,'angelscript.h']]], + ['asinvalid_5ftype_1610',['asINVALID_TYPE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a4af648067b42f433f0b1d7141f6e487c',1,'angelscript.h']]], + ['aslower_5farray_5fdimension_5fnot_5fregistered_1611',['asLOWER_ARRAY_DIMENSION_NOT_REGISTERED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ab11ea721572e02e63498b681105fe8cc',1,'angelscript.h']]], + ['asmodule_5fis_5fin_5fuse_1612',['asMODULE_IS_IN_USE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54af1e13f62c802e525a94722429575a345',1,'angelscript.h']]], + ['asmsgtype_5ferror_1613',['asMSGTYPE_ERROR',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5a2e3d48fd09f1ca865fc5b81b0dbeb7d4',1,'angelscript.h']]], + ['asmsgtype_5finformation_1614',['asMSGTYPE_INFORMATION',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5ae29dba474231c07149dca09a9258f80d',1,'angelscript.h']]], + ['asmsgtype_5fwarning_1615',['asMSGTYPE_WARNING',['../angelscript_8h.html#a8badcd23652646db5c5c6981dc73d4f5a210c2023d6971d688a0302096acf945d',1,'angelscript.h']]], + ['asmultiple_5ffunctions_1616',['asMULTIPLE_FUNCTIONS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54acb8338c55edbf8c27e2eb0b2505a0773',1,'angelscript.h']]], + ['asname_5ftaken_1617',['asNAME_TAKEN',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a0210997973bc0b74288a2041757f2763',1,'angelscript.h']]], + ['asno_5ffunction_1618',['asNO_FUNCTION',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ad021afee96a6ef28423c2d37d3430eed',1,'angelscript.h']]], + ['asno_5fglobal_5fvar_1619',['asNO_GLOBAL_VAR',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54aa465751329c2a7315318f609b1c271d4',1,'angelscript.h']]], + ['asno_5fmodule_1620',['asNO_MODULE',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a4cf88b5ffb76ebe34cb57d4d983bae79',1,'angelscript.h']]], + ['asnot_5fsupported_1621',['asNOT_SUPPORTED',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a93ccbf6a4f741cb8c0c7ef3fae4c4084',1,'angelscript.h']]], + ['asobj_5fabstract_1622',['asOBJ_ABSTRACT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa7c3d513b69c810647dbb80d48da77ee5',1,'angelscript.h']]], + ['asobj_5fapp_5falign16_1623',['asOBJ_APP_ALIGN16',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aacb0a87a6461924a892502c0e7a861d24',1,'angelscript.h']]], + ['asobj_5fapp_5farray_1624',['asOBJ_APP_ARRAY',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa84a949c5cc6d4d872054baac1a085419',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_1625',['asOBJ_APP_CLASS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa103297ed88696a3c30ec12e533d902c3',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fa_1626',['asOBJ_APP_CLASS_A',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaf7389e5dc914e6ab121580430be6d88b',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fak_1627',['asOBJ_APP_CLASS_AK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa7b1ce7e4c79ba23fd26b01474d550173',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5falign8_1628',['asOBJ_APP_CLASS_ALIGN8',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa244efb813b401b3a6d087c3add802818',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fallfloats_1629',['asOBJ_APP_CLASS_ALLFLOATS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa12afb6a0fa4ac874ce89815d3611823d',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fallints_1630',['asOBJ_APP_CLASS_ALLINTS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa5b8de58c5be3145aaa3e54008fb2edeb',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fassignment_1631',['asOBJ_APP_CLASS_ASSIGNMENT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa6bf9b7bead31a40e7983538d8cecc3a4',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fc_1632',['asOBJ_APP_CLASS_C',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa3eb67e27cc0fac7602934c1ff101aed5',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fca_1633',['asOBJ_APP_CLASS_CA',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa90b85700943e8acb45316943f1951d04',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcak_1634',['asOBJ_APP_CLASS_CAK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa97b022a4656cd9f351cd68c3903170b2',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcd_1635',['asOBJ_APP_CLASS_CD',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaf15f3dd82be0e77e05ee0dbea096bb36',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcda_1636',['asOBJ_APP_CLASS_CDA',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aae13159e3ea949d52803cb635538a77f2',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcdak_1637',['asOBJ_APP_CLASS_CDAK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa12d358962300537f2b0da20106eb270c',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcdk_1638',['asOBJ_APP_CLASS_CDK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa2aa6c871af75df3852f52658bf284765',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fck_1639',['asOBJ_APP_CLASS_CK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa619d54158a026e44bc5cffbb30794497',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fconstructor_1640',['asOBJ_APP_CLASS_CONSTRUCTOR',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aafd799c0705cee720a12ceb2838796024',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fcopy_5fconstructor_1641',['asOBJ_APP_CLASS_COPY_CONSTRUCTOR',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa925febfd30b150d97a84b7c6ee6a8677',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fd_1642',['asOBJ_APP_CLASS_D',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa30a67a6e98721d20d41b70fe961ff778',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fda_1643',['asOBJ_APP_CLASS_DA',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa38dd93911127894c5594474b4f06db1a',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fdak_1644',['asOBJ_APP_CLASS_DAK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa4b7a67f596940218860dc36ad9a4c66c',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fdestructor_1645',['asOBJ_APP_CLASS_DESTRUCTOR',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa18d80c6d92e4bc104955da393c966917',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fdk_1646',['asOBJ_APP_CLASS_DK',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aab59c583cdcee2acce632f35db39139ae',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fk_1647',['asOBJ_APP_CLASS_K',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa54236f54163e1df076bef918a862bd82',1,'angelscript.h']]], + ['asobj_5fapp_5fclass_5fmore_5fconstructors_1648',['asOBJ_APP_CLASS_MORE_CONSTRUCTORS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa4d3329b6e6e223207da73c97f01533e7',1,'angelscript.h']]], + ['asobj_5fapp_5ffloat_1649',['asOBJ_APP_FLOAT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa7f7690d53d9bfc580e09ac7bf5868175',1,'angelscript.h']]], + ['asobj_5fapp_5fprimitive_1650',['asOBJ_APP_PRIMITIVE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa539ede421d313b03464c88cb15f08c75',1,'angelscript.h']]], + ['asobj_5fashandle_1651',['asOBJ_ASHANDLE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aadf3d1f30658e593f48c5c5f542ac4845',1,'angelscript.h']]], + ['asobj_5fenum_1652',['asOBJ_ENUM',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa018e73b8c343fe8f46fa7a7829643ff9',1,'angelscript.h']]], + ['asobj_5ffuncdef_1653',['asOBJ_FUNCDEF',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa5b0f6287649893c8a04b43ed1f71a182',1,'angelscript.h']]], + ['asobj_5fgc_1654',['asOBJ_GC',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aacc1d835f9c25043cef86026a4aa6a470',1,'angelscript.h']]], + ['asobj_5fimplicit_5fhandle_1655',['asOBJ_IMPLICIT_HANDLE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaee8bfdbc6c2faac1938bba7e3a8b5ff2',1,'angelscript.h']]], + ['asobj_5flist_5fpattern_1656',['asOBJ_LIST_PATTERN',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaa1094cbe2986e60ba82da9dea38bba05',1,'angelscript.h']]], + ['asobj_5fmask_5fvalid_5fflags_1657',['asOBJ_MASK_VALID_FLAGS',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa6570f63d7f13e7d945770228a82f1f12',1,'angelscript.h']]], + ['asobj_5fnocount_1658',['asOBJ_NOCOUNT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aad8b12da6bf9cd48990d48c2ddf13584d',1,'angelscript.h']]], + ['asobj_5fnohandle_1659',['asOBJ_NOHANDLE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aafa1830b02c4d51ddc25451e7ad1a7592',1,'angelscript.h']]], + ['asobj_5fnoinherit_1660',['asOBJ_NOINHERIT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa770f4012f052a1190edbac8931140091',1,'angelscript.h']]], + ['asobj_5fpod_1661',['asOBJ_POD',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa8ad017ddf25368870b28ee0fba96495a',1,'angelscript.h']]], + ['asobj_5fref_1662',['asOBJ_REF',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa9450e038342b36c745858d2e5ae4b861',1,'angelscript.h']]], + ['asobj_5fscoped_1663',['asOBJ_SCOPED',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaaae92b24e278976320f19d9dc75fe6db',1,'angelscript.h']]], + ['asobj_5fscript_5fobject_1664',['asOBJ_SCRIPT_OBJECT',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aaa82f3ef517372e0db029f7dcfe7f88eb',1,'angelscript.h']]], + ['asobj_5fshared_1665',['asOBJ_SHARED',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa92354ace56201eb543c818b6c0852baf',1,'angelscript.h']]], + ['asobj_5ftemplate_1666',['asOBJ_TEMPLATE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aae8de459b4106475aa8766edb5b088aac',1,'angelscript.h']]], + ['asobj_5ftemplate_5fsubtype_1667',['asOBJ_TEMPLATE_SUBTYPE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa8e4f2ff9cea9a561be32711c91bf71e6',1,'angelscript.h']]], + ['asobj_5ftypedef_1668',['asOBJ_TYPEDEF',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aad9ec544ec0cca5ec329d19bceefadf0c',1,'angelscript.h']]], + ['asobj_5fvalue_1669',['asOBJ_VALUE',['../angelscript_8h.html#a855d86fa9ee15b9f75e553ee376b5c7aa9fc16a8ac0f30f9ff9c6568e0b7be91d',1,'angelscript.h']]], + ['asout_5fof_5fmemory_1670',['asOUT_OF_MEMORY',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a9a5232a5c1028cd729a744f592387059',1,'angelscript.h']]], + ['assuccess_1671',['asSUCCESS',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a0bf59062f03c90599e66a87275f37854',1,'angelscript.h']]], + ['astc_5fcomment_1672',['asTC_COMMENT',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaac738f8a91d1e0badd12d456206372224',1,'angelscript.h']]], + ['astc_5fidentifier_1673',['asTC_IDENTIFIER',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaad31e06870d87e2eb0d37da0bdd06d87f',1,'angelscript.h']]], + ['astc_5fkeyword_1674',['asTC_KEYWORD',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa96a4ebcca4fd7cade65c6163d4eb2bc0',1,'angelscript.h']]], + ['astc_5funknown_1675',['asTC_UNKNOWN',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa2a6ba011564d30250b5664beee57f727',1,'angelscript.h']]], + ['astc_5fvalue_1676',['asTC_VALUE',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa75fd6044f67010b490a65ff3718d93e2',1,'angelscript.h']]], + ['astc_5fwhitespace_1677',['asTC_WHITESPACE',['../angelscript_8h.html#a012a602727ca3fe1efa27053bc58cbcaa7ca0b961e4d799140f79c971d3596cf8',1,'angelscript.h']]], + ['astm_5fconst_1678',['asTM_CONST',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7a75422a76c05f8b084895e73f90972e34',1,'angelscript.h']]], + ['astm_5finoutref_1679',['asTM_INOUTREF',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7aaefa7d0cb8d421469fcfc4248d3ba5c5',1,'angelscript.h']]], + ['astm_5finref_1680',['asTM_INREF',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7a8de0af7f268793bb251f0607b72cad19',1,'angelscript.h']]], + ['astm_5fnone_1681',['asTM_NONE',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7aad24888f100d685b7eb4c330e8e09047',1,'angelscript.h']]], + ['astm_5foutref_1682',['asTM_OUTREF',['../angelscript_8h.html#a335bd4a1384b6e408bf9b37ffdeb54c7a8ebee94d0968a789e3953d0100a9d2ee',1,'angelscript.h']]], + ['astypeid_5fappobject_1683',['asTYPEID_APPOBJECT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa3b1403bbf7d1c617f734c39a574c7aa1',1,'angelscript.h']]], + ['astypeid_5fbool_1684',['asTYPEID_BOOL',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa502865ff428df06342ac9d94d69318ec',1,'angelscript.h']]], + ['astypeid_5fdouble_1685',['asTYPEID_DOUBLE',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa8b069e24ecddd678b3811126832df49f',1,'angelscript.h']]], + ['astypeid_5ffloat_1686',['asTYPEID_FLOAT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa43ec6e15e840ebf165070c2ebe9c954d',1,'angelscript.h']]], + ['astypeid_5fhandletoconst_1687',['asTYPEID_HANDLETOCONST',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aaa4c35253b679ef667c30153f586ecbb5',1,'angelscript.h']]], + ['astypeid_5fint16_1688',['asTYPEID_INT16',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa3d246e59038d67ba2945b9c89ed874c0',1,'angelscript.h']]], + ['astypeid_5fint32_1689',['asTYPEID_INT32',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aabcc8e086d59505f6ba18ea85e72afc33',1,'angelscript.h']]], + ['astypeid_5fint64_1690',['asTYPEID_INT64',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aaa73d32346b63cef156c6783703414a21',1,'angelscript.h']]], + ['astypeid_5fint8_1691',['asTYPEID_INT8',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa7e647a9a1ce963f22d5c384673d0dc5f',1,'angelscript.h']]], + ['astypeid_5fmask_5fobject_1692',['asTYPEID_MASK_OBJECT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa09eef59280d15a58c75e0c8983a3c3af',1,'angelscript.h']]], + ['astypeid_5fmask_5fseqnbr_1693',['asTYPEID_MASK_SEQNBR',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa8a0789b5d397d79ba34a441116a6321b',1,'angelscript.h']]], + ['astypeid_5fobjhandle_1694',['asTYPEID_OBJHANDLE',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa63249041dff18d01e362d71efca2b4ed',1,'angelscript.h']]], + ['astypeid_5fscriptobject_1695',['asTYPEID_SCRIPTOBJECT',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa29f9a7c07904452b512431b7b4b5b6e4',1,'angelscript.h']]], + ['astypeid_5ftemplate_1696',['asTYPEID_TEMPLATE',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aab5fde5eaa0401712c8abd01fc366e9cc',1,'angelscript.h']]], + ['astypeid_5fuint16_1697',['asTYPEID_UINT16',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aae72cf12a6d4a77c74b278972256d11f3',1,'angelscript.h']]], + ['astypeid_5fuint32_1698',['asTYPEID_UINT32',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aac069cb7584e126ac4cf6faeb33fa87a3',1,'angelscript.h']]], + ['astypeid_5fuint64_1699',['asTYPEID_UINT64',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aaf22925e9946a4493c2e1c238c6043844',1,'angelscript.h']]], + ['astypeid_5fuint8_1700',['asTYPEID_UINT8',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aa32fa8c495f1eed78592d3898d35e1a46',1,'angelscript.h']]], + ['astypeid_5fvoid_1701',['asTYPEID_VOID',['../angelscript_8h.html#ae8c3a67a97321be53181e9ed396ad83aad924c0d48ab734431bbd7467a9bfa819',1,'angelscript.h']]], + ['aswrong_5fcalling_5fconv_1702',['asWRONG_CALLING_CONV',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54a2774780aba35e11f224f8c0bd0937207',1,'angelscript.h']]], + ['aswrong_5fconfig_5fgroup_1703',['asWRONG_CONFIG_GROUP',['../angelscript_8h.html#a6e2a1647f02f2c5da931bab09e860f54ace5f5b97f2832c2f3aed3bb47ac1e486',1,'angelscript.h']]] +]; diff --git a/docs/manual/search/files_0.html b/docs/manual/search/files_0.html new file mode 100644 index 0000000..182d7eb --- /dev/null +++ b/docs/manual/search/files_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/files_0.js b/docs/manual/search/files_0.js new file mode 100644 index 0000000..e3ae967 --- /dev/null +++ b/docs/manual/search/files_0.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['angelscript_2eh_953',['angelscript.h',['../angelscript_8h.html',1,'']]] +]; diff --git a/docs/manual/search/functions_0.html b/docs/manual/search/functions_0.html new file mode 100644 index 0000000..4fcbb9c --- /dev/null +++ b/docs/manual/search/functions_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_0.js b/docs/manual/search/functions_0.js new file mode 100644 index 0000000..6d7b5d0 --- /dev/null +++ b/docs/manual/search/functions_0.js @@ -0,0 +1,28 @@ +var searchData= +[ + ['abort_954',['Abort',['../classas_i_script_context.html#a374befd21b8c14de81ef0ed9d2dea334',1,'asIScriptContext']]], + ['addref_955',['AddRef',['../classas_i_script_engine.html#aa95a5d9b5d9e7e6a230fedf056eaf8ce',1,'asIScriptEngine::AddRef()'],['../classas_i_script_context.html#a5e24f4cb5773f732a1d46b818d963a1d',1,'asIScriptContext::AddRef()'],['../classas_i_script_object.html#a3e08890e31163e4d33c0f27dc9072662',1,'asIScriptObject::AddRef()'],['../classas_i_type_info.html#a532069932de1f584ab52e4c2afacf95e',1,'asITypeInfo::AddRef()'],['../classas_i_script_function.html#a0a00f9581e7ece5f2a536d0e22c10d0c',1,'asIScriptFunction::AddRef()'],['../classas_i_lockable_shared_bool.html#a1183742552ce6b952cc3742bd456d787',1,'asILockableSharedBool::AddRef()']]], + ['addrefscriptobject_956',['AddRefScriptObject',['../classas_i_script_engine.html#ade1d309876c876c733d437a53e708c28',1,'asIScriptEngine']]], + ['addscriptsection_957',['AddScriptSection',['../classas_i_script_module.html#a330835919b565c76c25e9425536f50b7',1,'asIScriptModule']]], + ['asacquireexclusivelock_958',['asAcquireExclusiveLock',['../group__api__multithread__functions.html#ga016dbf716a1c761b3f903b92eb8bb580',1,'angelscript.h']]], + ['asacquiresharedlock_959',['asAcquireSharedLock',['../group__api__multithread__functions.html#gaa45545a038adcc8c73348cfe9488f32d',1,'angelscript.h']]], + ['asallocmem_960',['asAllocMem',['../group__api__memory__functions.html#ga54a201f99d19e648526abf30ae31e466',1,'angelscript.h']]], + ['asatomicdec_961',['asAtomicDec',['../group__api__multithread__functions.html#ga0565bcb53be170dd85ae27a5b6f2b828',1,'angelscript.h']]], + ['asatomicinc_962',['asAtomicInc',['../group__api__multithread__functions.html#gaf0074d581ac2edd06e63e56e4be52c8e',1,'angelscript.h']]], + ['ascreatelockablesharedbool_963',['asCreateLockableSharedBool',['../group__api__multithread__functions.html#gaa0ffb789dab56b5617e2f961f9c79fdb',1,'angelscript.h']]], + ['ascreatescriptengine_964',['asCreateScriptEngine',['../group__api__principal__functions.html#gacb6a62345d9cca6c9b5a3dac67d80d0b',1,'angelscript.h']]], + ['asfreemem_965',['asFreeMem',['../group__api__memory__functions.html#ga9da61275bbfd5f7bd55ed411d05fe103',1,'angelscript.h']]], + ['asgetactivecontext_966',['asGetActiveContext',['../group__api__principal__functions.html#gad3a20dc58093b92a5a44c7b6ada34a10',1,'angelscript.h']]], + ['asgetlibraryoptions_967',['asGetLibraryOptions',['../group__api__auxiliary__functions.html#gaba86cba765a7148e2a306b4305ba48f9',1,'angelscript.h']]], + ['asgetlibraryversion_968',['asGetLibraryVersion',['../group__api__auxiliary__functions.html#ga79cbcfe1a47e436da6f2f28ff0314f75',1,'angelscript.h']]], + ['asgetthreadmanager_969',['asGetThreadManager',['../group__api__multithread__functions.html#ga948def50c98db90596b706ca4b58041e',1,'angelscript.h']]], + ['asgettypetraits_970',['asGetTypeTraits',['../group__api__principal__functions.html#ga863f2a1e60e6c19eea9c6b34690dcc00',1,'angelscript.h']]], + ['aspreparemultithread_971',['asPrepareMultithread',['../group__api__multithread__functions.html#gaa5bea65c3f2a224bb1c677515e3bb0e2',1,'angelscript.h']]], + ['asreleaseexclusivelock_972',['asReleaseExclusiveLock',['../group__api__multithread__functions.html#ga8a0617637eea3d76e33a52758b2cd49f',1,'angelscript.h']]], + ['asreleasesharedlock_973',['asReleaseSharedLock',['../group__api__multithread__functions.html#ga44f7327c5601e8dbf74768a2f3cc0dc3',1,'angelscript.h']]], + ['asresetglobalmemoryfunctions_974',['asResetGlobalMemoryFunctions',['../group__api__memory__functions.html#ga9267c4ad35aceaf7cc0961cd42147ee7',1,'angelscript.h']]], + ['assetglobalmemoryfunctions_975',['asSetGlobalMemoryFunctions',['../group__api__memory__functions.html#ga527ab125defc58aa40cc151a25582a31',1,'angelscript.h']]], + ['assignscriptobject_976',['AssignScriptObject',['../classas_i_script_engine.html#a9180da5fd475f52916be6b39e522fabb',1,'asIScriptEngine']]], + ['asthreadcleanup_977',['asThreadCleanup',['../group__api__multithread__functions.html#ga51079811680d5217046aad2a2b695dc7',1,'angelscript.h']]], + ['asunpreparemultithread_978',['asUnprepareMultithread',['../group__api__multithread__functions.html#ga011355a8978d438cec77b4e1f041cba7',1,'angelscript.h']]] +]; diff --git a/docs/manual/search/functions_1.html b/docs/manual/search/functions_1.html new file mode 100644 index 0000000..9b0e1f0 --- /dev/null +++ b/docs/manual/search/functions_1.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_1.js b/docs/manual/search/functions_1.js new file mode 100644 index 0000000..cff50d1 --- /dev/null +++ b/docs/manual/search/functions_1.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['beginconfiggroup_979',['BeginConfigGroup',['../classas_i_script_engine.html#ac81014e50dd7efc1920adcb3fd2d1e5d',1,'asIScriptEngine']]], + ['bindallimportedfunctions_980',['BindAllImportedFunctions',['../classas_i_script_module.html#a3f0c215576adefd922c2cc95d16b55d8',1,'asIScriptModule']]], + ['bindimportedfunction_981',['BindImportedFunction',['../classas_i_script_module.html#ab24a8b95ce887c3f731eb906e3b518e5',1,'asIScriptModule']]], + ['build_982',['Build',['../classas_i_script_module.html#a8acf107194c5f079d7f7507309ebe613',1,'asIScriptModule']]] +]; diff --git a/docs/manual/search/functions_2.html b/docs/manual/search/functions_2.html new file mode 100644 index 0000000..eb51f80 --- /dev/null +++ b/docs/manual/search/functions_2.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_2.js b/docs/manual/search/functions_2.js new file mode 100644 index 0000000..063f29c --- /dev/null +++ b/docs/manual/search/functions_2.js @@ -0,0 +1,14 @@ +var searchData= +[ + ['clearexceptioncallback_983',['ClearExceptionCallback',['../classas_i_script_context.html#acb5cfe5703031fd76672a57d8afae547',1,'asIScriptContext']]], + ['clearlinecallback_984',['ClearLineCallback',['../classas_i_script_context.html#a3771cf314de339fa5d70edfbfcd88370',1,'asIScriptContext']]], + ['clearmessagecallback_985',['ClearMessageCallback',['../classas_i_script_engine.html#ada64567fc9621e5e98160c7f03efa064',1,'asIScriptEngine']]], + ['compilefunction_986',['CompileFunction',['../classas_i_script_module.html#a1258d7cfeed965f36ba312beeb49e81c',1,'asIScriptModule::CompileFunction()'],['../classas_i_j_i_t_compiler.html#aa6270727e61d8708d651a0f5faada695',1,'asIJITCompiler::CompileFunction()']]], + ['compileglobalvar_987',['CompileGlobalVar',['../classas_i_script_module.html#a34850e152dcdcb58c53a2b6929cebf77',1,'asIScriptModule']]], + ['copyfrom_988',['CopyFrom',['../classas_i_script_object.html#ab83919a23c02ec07c66d9aedcbecf261',1,'asIScriptObject']]], + ['createcontext_989',['CreateContext',['../classas_i_script_engine.html#a2630e1cd03ffab0fee9b820bf0afe42a',1,'asIScriptEngine']]], + ['createdelegate_990',['CreateDelegate',['../classas_i_script_engine.html#ab4a4cea1cfeea361b8a44d80f3d928e3',1,'asIScriptEngine']]], + ['createscriptobject_991',['CreateScriptObject',['../classas_i_script_engine.html#a3101479b4340bc16bb9acb8e8d554266',1,'asIScriptEngine']]], + ['createscriptobjectcopy_992',['CreateScriptObjectCopy',['../classas_i_script_engine.html#ab2b1543ea6d24b912aebeb77e6764269',1,'asIScriptEngine']]], + ['createuninitializedscriptobject_993',['CreateUninitializedScriptObject',['../classas_i_script_engine.html#a9de3c5e4465f699ad698740d6037e1a6',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/functions_3.html b/docs/manual/search/functions_3.html new file mode 100644 index 0000000..e53b9d0 --- /dev/null +++ b/docs/manual/search/functions_3.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_3.js b/docs/manual/search/functions_3.js new file mode 100644 index 0000000..2a4af87 --- /dev/null +++ b/docs/manual/search/functions_3.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['derivesfrom_994',['DerivesFrom',['../classas_i_type_info.html#a4ce24b7a0ecd27bb7e34f1fa58c08d29',1,'asITypeInfo']]], + ['discard_995',['Discard',['../classas_i_script_module.html#a0e6a69be59f16c8b51d1e21d3905d95c',1,'asIScriptModule']]], + ['discardmodule_996',['DiscardModule',['../classas_i_script_engine.html#afb0ce55e5846eb18afdcf906aeb67cf7',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/functions_4.html b/docs/manual/search/functions_4.html new file mode 100644 index 0000000..d049621 --- /dev/null +++ b/docs/manual/search/functions_4.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_4.js b/docs/manual/search/functions_4.js new file mode 100644 index 0000000..99832f0 --- /dev/null +++ b/docs/manual/search/functions_4.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['endconfiggroup_997',['EndConfigGroup',['../classas_i_script_engine.html#a4cc5ed7ea71811655f7910d298bb5a02',1,'asIScriptEngine']]], + ['execute_998',['Execute',['../classas_i_script_context.html#a8e52894432737acac2e1a422e496bf84',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/functions_5.html b/docs/manual/search/functions_5.html new file mode 100644 index 0000000..342487b --- /dev/null +++ b/docs/manual/search/functions_5.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_5.js b/docs/manual/search/functions_5.js new file mode 100644 index 0000000..1f7b688 --- /dev/null +++ b/docs/manual/search/functions_5.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['findnextlinewithcode_999',['FindNextLineWithCode',['../classas_i_script_function.html#a30dc23991856a13f59e682b3b1498e2f',1,'asIScriptFunction']]], + ['forwardgcenumreferences_1000',['ForwardGCEnumReferences',['../classas_i_script_engine.html#abe95ce0e45d914fec478fa112a7bb8dd',1,'asIScriptEngine']]], + ['forwardgcreleasereferences_1001',['ForwardGCReleaseReferences',['../classas_i_script_engine.html#a60cdec608a18f6ebc0aebe29a143183f',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/functions_6.html b/docs/manual/search/functions_6.html new file mode 100644 index 0000000..4bf3bd6 --- /dev/null +++ b/docs/manual/search/functions_6.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_6.js b/docs/manual/search/functions_6.js new file mode 100644 index 0000000..37194fc --- /dev/null +++ b/docs/manual/search/functions_6.js @@ -0,0 +1,148 @@ +var searchData= +[ + ['garbagecollect_1002',['GarbageCollect',['../classas_i_script_engine.html#a17511a1de72ecdb836b974768f2ec422',1,'asIScriptEngine']]], + ['gcenumcallback_1003',['GCEnumCallback',['../classas_i_script_engine.html#a58ceeafd780dea3543e0ede4106199fd',1,'asIScriptEngine']]], + ['get_1004',['Get',['../classas_i_lockable_shared_bool.html#abab39fc60f00ae8941423258ffc2c3c6',1,'asILockableSharedBool']]], + ['getaccessmask_1005',['GetAccessMask',['../classas_i_type_info.html#a849e5890b225717b243c73e3d4f38204',1,'asITypeInfo::GetAccessMask()'],['../classas_i_script_function.html#a5c49841eb92a0993a16eb855577b590c',1,'asIScriptFunction::GetAccessMask()']]], + ['getaddressofarg_1006',['GetAddressOfArg',['../classas_i_script_context.html#a0fbab94982862b30cd55996d4a24949c',1,'asIScriptContext::GetAddressOfArg()'],['../classas_i_script_generic.html#a08f922bc97867e1e97e923a5bdee4dbc',1,'asIScriptGeneric::GetAddressOfArg()']]], + ['getaddressofglobalvar_1007',['GetAddressOfGlobalVar',['../classas_i_script_module.html#a0998d375ca1de02bc72f4544806da58c',1,'asIScriptModule']]], + ['getaddressofproperty_1008',['GetAddressOfProperty',['../classas_i_script_object.html#a6a8a3c7d1e103e43923614b719e3cb3a',1,'asIScriptObject']]], + ['getaddressofreturnlocation_1009',['GetAddressOfReturnLocation',['../classas_i_script_generic.html#a103a91f081ec894a116cd3db06b0d8d1',1,'asIScriptGeneric']]], + ['getaddressofreturnvalue_1010',['GetAddressOfReturnValue',['../classas_i_script_context.html#a889bf11123beba669637849c8e9b2b86',1,'asIScriptContext']]], + ['getaddressofvar_1011',['GetAddressOfVar',['../classas_i_script_context.html#acc916505d79de321a2ab2b46b1c61fb7',1,'asIScriptContext']]], + ['getargaddress_1012',['GetArgAddress',['../classas_i_script_generic.html#ac5c73473ccefe029582c5e3793d1a41b',1,'asIScriptGeneric']]], + ['getargbyte_1013',['GetArgByte',['../classas_i_script_generic.html#a20f30e6ed55ed952bcb5c70096eb83dd',1,'asIScriptGeneric']]], + ['getargcount_1014',['GetArgCount',['../classas_i_script_generic.html#aafdaf0ed1ff5023b2aaf4ae1adfa3714',1,'asIScriptGeneric']]], + ['getargdouble_1015',['GetArgDouble',['../classas_i_script_generic.html#ad0bb07a940b7ba08abc3ce114dca99fc',1,'asIScriptGeneric']]], + ['getargdword_1016',['GetArgDWord',['../classas_i_script_generic.html#aab74bcbe4be32fc423b21b75a3f4d57a',1,'asIScriptGeneric']]], + ['getargfloat_1017',['GetArgFloat',['../classas_i_script_generic.html#a487a68e409d79e61fcc624337c4ac991',1,'asIScriptGeneric']]], + ['getargobject_1018',['GetArgObject',['../classas_i_script_generic.html#a6732b01132cd58e81cd0354ac274039a',1,'asIScriptGeneric']]], + ['getargqword_1019',['GetArgQWord',['../classas_i_script_generic.html#a0fbd6ce45aebc29e29a64dac4affc111',1,'asIScriptGeneric']]], + ['getargtypeid_1020',['GetArgTypeId',['../classas_i_script_generic.html#a2bdce6872b371355665e932a962548cb',1,'asIScriptGeneric']]], + ['getargword_1021',['GetArgWord',['../classas_i_script_generic.html#afdb602c3c2e285c5f34bc477ebbd1534',1,'asIScriptGeneric']]], + ['getauxiliary_1022',['GetAuxiliary',['../classas_i_script_generic.html#adf0ec41b9df5c93d72a950c78f6fea8e',1,'asIScriptGeneric::GetAuxiliary()'],['../classas_i_script_function.html#acbdd97f1c3658cb4f82a154591e100f6',1,'asIScriptFunction::GetAuxiliary()']]], + ['getbasetype_1023',['GetBaseType',['../classas_i_type_info.html#a8722ecc6b7e47491cdb6e442a3bf1ba2',1,'asITypeInfo']]], + ['getbehaviourbyindex_1024',['GetBehaviourByIndex',['../classas_i_type_info.html#ae91a1b2080e76a0dcad8106436728314',1,'asITypeInfo']]], + ['getbehaviourcount_1025',['GetBehaviourCount',['../classas_i_type_info.html#ad7c3c757cc99df4d40c6b3b44896cb96',1,'asITypeInfo']]], + ['getbytecode_1026',['GetByteCode',['../classas_i_script_function.html#afb38e9ba77ce8b49378e43dadd83ef94',1,'asIScriptFunction']]], + ['getcallstacksize_1027',['GetCallstackSize',['../classas_i_script_context.html#aab359abc4563a8439338bfd655824bd7',1,'asIScriptContext']]], + ['getchildfuncdef_1028',['GetChildFuncdef',['../classas_i_type_info.html#a01fe2f0b68614246a63e52cada374b69',1,'asITypeInfo']]], + ['getchildfuncdefcount_1029',['GetChildFuncdefCount',['../classas_i_type_info.html#aa9b5a0281ff01d448e55cb10e42ba340',1,'asITypeInfo']]], + ['getconfiggroup_1030',['GetConfigGroup',['../classas_i_type_info.html#aa181c094c192e86299b394ebcfa68760',1,'asITypeInfo::GetConfigGroup()'],['../classas_i_script_function.html#afea841f0923573cea81467ac90b71996',1,'asIScriptFunction::GetConfigGroup()']]], + ['getdeclaration_1031',['GetDeclaration',['../classas_i_script_function.html#a2fb021b09ae0e7e87f8fa4fdfd39df83',1,'asIScriptFunction']]], + ['getdefaultarraytypeid_1032',['GetDefaultArrayTypeId',['../classas_i_script_engine.html#ae86e5444979b0abd92777be83c53fc80',1,'asIScriptEngine']]], + ['getdefaultnamespace_1033',['GetDefaultNamespace',['../classas_i_script_engine.html#a257a25e285faa25e8cf08e455528def7',1,'asIScriptEngine::GetDefaultNamespace()'],['../classas_i_script_module.html#aa1aa775a81fc2bbf84ff2b07fd9561e3',1,'asIScriptModule::GetDefaultNamespace()']]], + ['getdelegatefunction_1034',['GetDelegateFunction',['../classas_i_script_function.html#aa28f4e68da8abb770d7f725375bcd2bb',1,'asIScriptFunction']]], + ['getdelegateobject_1035',['GetDelegateObject',['../classas_i_script_function.html#ae1786c3f4341dc3bfcaacc3cb8900a57',1,'asIScriptFunction']]], + ['getdelegateobjecttype_1036',['GetDelegateObjectType',['../classas_i_script_function.html#ad79461f80fcffd513b43564d75cc5360',1,'asIScriptFunction']]], + ['getengine_1037',['GetEngine',['../classas_i_script_module.html#aef861826f4d09fd411aee7792854bfb8',1,'asIScriptModule::GetEngine()'],['../classas_i_script_context.html#a07f12016c5435aec5b63449abb6e4d8d',1,'asIScriptContext::GetEngine()'],['../classas_i_script_generic.html#a3f3b0838588e3afa7172f9bbb87f5445',1,'asIScriptGeneric::GetEngine()'],['../classas_i_script_object.html#a5dda2d380ae1580e15ddf9d95893c57a',1,'asIScriptObject::GetEngine()'],['../classas_i_type_info.html#abafbb3a12cbd94f56a4f3c1739fd6ada',1,'asITypeInfo::GetEngine()'],['../classas_i_script_function.html#a7a0ef04f035d1809fb8b7702134afd06',1,'asIScriptFunction::GetEngine()']]], + ['getengineproperty_1038',['GetEngineProperty',['../classas_i_script_engine.html#a5531bf5310a0c933aa698725a6828e5f',1,'asIScriptEngine']]], + ['getenumbyindex_1039',['GetEnumByIndex',['../classas_i_script_engine.html#adedc8b2ad11a84ec12aef4f98e27a4c4',1,'asIScriptEngine::GetEnumByIndex()'],['../classas_i_script_module.html#a0ec42bef3874f0fc0e6b929068ae927c',1,'asIScriptModule::GetEnumByIndex()']]], + ['getenumcount_1040',['GetEnumCount',['../classas_i_script_engine.html#a4b4307dab64061be43db84ffb97e3782',1,'asIScriptEngine::GetEnumCount()'],['../classas_i_script_module.html#a1a241b3dfd47f7ab5bb475c757e38df9',1,'asIScriptModule::GetEnumCount()']]], + ['getenumvaluebyindex_1041',['GetEnumValueByIndex',['../classas_i_type_info.html#aaece7c2106dbced04436b52515f1f7ac',1,'asITypeInfo']]], + ['getenumvaluecount_1042',['GetEnumValueCount',['../classas_i_type_info.html#abe22697bab6560c30c9b613187d6b4d7',1,'asITypeInfo']]], + ['getexceptionfunction_1043',['GetExceptionFunction',['../classas_i_script_context.html#a8e59aceec42080d29e08b44460ceb8b3',1,'asIScriptContext']]], + ['getexceptionlinenumber_1044',['GetExceptionLineNumber',['../classas_i_script_context.html#a22e3c351fe6b13ba0a62010dfc305080',1,'asIScriptContext']]], + ['getexceptionstring_1045',['GetExceptionString',['../classas_i_script_context.html#a46e2411bc84e99f57e7d9fe2374bb479',1,'asIScriptContext']]], + ['getfactorybydecl_1046',['GetFactoryByDecl',['../classas_i_type_info.html#aca1e08cd395231d30ad78a7ca3fea142',1,'asITypeInfo']]], + ['getfactorybyindex_1047',['GetFactoryByIndex',['../classas_i_type_info.html#a6a8b52fefd309102142ba74621d35714',1,'asITypeInfo']]], + ['getfactorycount_1048',['GetFactoryCount',['../classas_i_type_info.html#a22cb802db08d6f464f6ee12337390d12',1,'asITypeInfo']]], + ['getflags_1049',['GetFlags',['../classas_i_type_info.html#a068900ec359ff7fc2ee59a938ffe20ab',1,'asITypeInfo']]], + ['getfuncdefbyindex_1050',['GetFuncdefByIndex',['../classas_i_script_engine.html#ad4228220347347384c0aa0e0dd8308c6',1,'asIScriptEngine']]], + ['getfuncdefcount_1051',['GetFuncdefCount',['../classas_i_script_engine.html#a48aceb1556f88ce3bec3e0f84abe127f',1,'asIScriptEngine']]], + ['getfuncdefsignature_1052',['GetFuncdefSignature',['../classas_i_type_info.html#abf4e686097f0c485e6dcd330fe47f91e',1,'asITypeInfo']]], + ['getfunction_1053',['GetFunction',['../classas_i_script_context.html#a1c101300447f2909e5d188409a7180f6',1,'asIScriptContext::GetFunction()'],['../classas_i_script_generic.html#acf00e806a36e0b42686c0f8df25b0898',1,'asIScriptGeneric::GetFunction()']]], + ['getfunctionbydecl_1054',['GetFunctionByDecl',['../classas_i_script_module.html#ab4754d55d8667aefbed135b4794d461b',1,'asIScriptModule']]], + ['getfunctionbyid_1055',['GetFunctionById',['../classas_i_script_engine.html#aaf67dc0b1f26be437ccbcc0ac5f330c9',1,'asIScriptEngine']]], + ['getfunctionbyindex_1056',['GetFunctionByIndex',['../classas_i_script_module.html#afd4d9951ee006caa8ec1bab3d3d206fc',1,'asIScriptModule']]], + ['getfunctionbyname_1057',['GetFunctionByName',['../classas_i_script_module.html#a81d727c9677b683942b6087df4ce95ad',1,'asIScriptModule']]], + ['getfunctioncount_1058',['GetFunctionCount',['../classas_i_script_module.html#a373d102f109ae0fa20584f243ead4035',1,'asIScriptModule']]], + ['getfunctype_1059',['GetFuncType',['../classas_i_script_function.html#aa4d06c7d590e7eb4df280a8224f4499c',1,'asIScriptFunction']]], + ['getgcstatistics_1060',['GetGCStatistics',['../classas_i_script_engine.html#a166e6cdd0cb35bcfd942824d8e882783',1,'asIScriptEngine']]], + ['getglobalfunctionbydecl_1061',['GetGlobalFunctionByDecl',['../classas_i_script_engine.html#a42edd02e95731c795e13706400e8665a',1,'asIScriptEngine']]], + ['getglobalfunctionbyindex_1062',['GetGlobalFunctionByIndex',['../classas_i_script_engine.html#aaf2b79cef75adb4099a24e3412e4ea79',1,'asIScriptEngine']]], + ['getglobalfunctioncount_1063',['GetGlobalFunctionCount',['../classas_i_script_engine.html#a72aa1a3a5ac88a5a1dba4fa3655141d6',1,'asIScriptEngine']]], + ['getglobalpropertybyindex_1064',['GetGlobalPropertyByIndex',['../classas_i_script_engine.html#a93bd686853a48647d2136792e27380fb',1,'asIScriptEngine']]], + ['getglobalpropertycount_1065',['GetGlobalPropertyCount',['../classas_i_script_engine.html#aa69f6b37f9c7bdf9b52b9c1692daf048',1,'asIScriptEngine']]], + ['getglobalpropertyindexbydecl_1066',['GetGlobalPropertyIndexByDecl',['../classas_i_script_engine.html#a91a4cc8af51ca439ca82b9b6630439b3',1,'asIScriptEngine']]], + ['getglobalpropertyindexbyname_1067',['GetGlobalPropertyIndexByName',['../classas_i_script_engine.html#a07e85878869e4d0597c1177d767dc717',1,'asIScriptEngine']]], + ['getglobalvar_1068',['GetGlobalVar',['../classas_i_script_module.html#a939e6caf004c6fdae78fe89bb244d962',1,'asIScriptModule']]], + ['getglobalvarcount_1069',['GetGlobalVarCount',['../classas_i_script_module.html#a87e29773f7e6f2980d75288faaa74d02',1,'asIScriptModule']]], + ['getglobalvardeclaration_1070',['GetGlobalVarDeclaration',['../classas_i_script_module.html#aebe27735e0ce4c06bf79b2b4282192cd',1,'asIScriptModule']]], + ['getglobalvarindexbydecl_1071',['GetGlobalVarIndexByDecl',['../classas_i_script_module.html#ac3d5dafe8ca92bf618f438dc79ef2906',1,'asIScriptModule']]], + ['getglobalvarindexbyname_1072',['GetGlobalVarIndexByName',['../classas_i_script_module.html#a00cff95b43c256cc6b9062e135a473a2',1,'asIScriptModule']]], + ['getid_1073',['GetId',['../classas_i_script_function.html#a7aca255486dd77b8846f545495128cac',1,'asIScriptFunction']]], + ['getimportedfunctioncount_1074',['GetImportedFunctionCount',['../classas_i_script_module.html#a12273a6a6dd9bd39ca9675bcd84b0cc7',1,'asIScriptModule']]], + ['getimportedfunctiondeclaration_1075',['GetImportedFunctionDeclaration',['../classas_i_script_module.html#a20e46ad7ea467f98bbf35ee052b86868',1,'asIScriptModule']]], + ['getimportedfunctionindexbydecl_1076',['GetImportedFunctionIndexByDecl',['../classas_i_script_module.html#a6de1053c8317e7134e7e59e4527339f6',1,'asIScriptModule']]], + ['getimportedfunctionsourcemodule_1077',['GetImportedFunctionSourceModule',['../classas_i_script_module.html#adc01b24a82ad14356f2edc082af4c146',1,'asIScriptModule']]], + ['getinterface_1078',['GetInterface',['../classas_i_type_info.html#a320141f6c331a9e49334de2576c725f7',1,'asITypeInfo']]], + ['getinterfacecount_1079',['GetInterfaceCount',['../classas_i_type_info.html#a47a4bdc2462b38a5659c3cb96e61c649',1,'asITypeInfo']]], + ['getjitcompiler_1080',['GetJITCompiler',['../classas_i_script_engine.html#a2fb6db9085df3c7d487c0d58de76bb83',1,'asIScriptEngine']]], + ['getlinenumber_1081',['GetLineNumber',['../classas_i_script_context.html#adf82981def59c6ec5dd9f74f034be2af',1,'asIScriptContext']]], + ['getmethodbydecl_1082',['GetMethodByDecl',['../classas_i_type_info.html#a80c61bb4d018647561ce3af24fedf65b',1,'asITypeInfo']]], + ['getmethodbyindex_1083',['GetMethodByIndex',['../classas_i_type_info.html#a235262cb0bacaf1f160e5ac5156db4e8',1,'asITypeInfo']]], + ['getmethodbyname_1084',['GetMethodByName',['../classas_i_type_info.html#af3febbb10e7e85425f0960aad892f9b8',1,'asITypeInfo']]], + ['getmethodcount_1085',['GetMethodCount',['../classas_i_type_info.html#a50877d3602e460e784df4f611ae6f360',1,'asITypeInfo']]], + ['getmodule_1086',['GetModule',['../classas_i_script_engine.html#a9f7cdc52b59034e6e55eb8a56b427aa4',1,'asIScriptEngine::GetModule()'],['../classas_i_type_info.html#a3e08d6c6ee1957c421bb297f94a81d54',1,'asITypeInfo::GetModule()'],['../classas_i_script_function.html#a5c3477dd6b634e6b6ca3d5b97f6d5b30',1,'asIScriptFunction::GetModule()']]], + ['getmodulebyindex_1087',['GetModuleByIndex',['../classas_i_script_engine.html#a31b95df21e6f1990cf84b3b286067675',1,'asIScriptEngine']]], + ['getmodulecount_1088',['GetModuleCount',['../classas_i_script_engine.html#a457cf6202cc64ce8ee242dcc97d3422f',1,'asIScriptEngine']]], + ['getmodulename_1089',['GetModuleName',['../classas_i_script_function.html#af03c30e4764f81c01400d7f77a8d0832',1,'asIScriptFunction']]], + ['getname_1090',['GetName',['../classas_i_script_module.html#a4967db3ed89836ac2f3b529c499d473d',1,'asIScriptModule::GetName()'],['../classas_i_type_info.html#a49f83d3a9158331029324bfbe9ae46a8',1,'asITypeInfo::GetName()'],['../classas_i_script_function.html#a96cf134f1369f312aa182de5006f8b71',1,'asIScriptFunction::GetName()']]], + ['getnamespace_1091',['GetNamespace',['../classas_i_type_info.html#a90b16019d2569d6c721130f3049786a2',1,'asITypeInfo::GetNamespace()'],['../classas_i_script_function.html#ab692c00b9a7111778acb4fbca1c63df7',1,'asIScriptFunction::GetNamespace()']]], + ['getobject_1092',['GetObject',['../classas_i_script_generic.html#ab9e6627ec3920b1e1576d82586cac84d',1,'asIScriptGeneric']]], + ['getobjectingc_1093',['GetObjectInGC',['../classas_i_script_engine.html#a39a5f221baa01d43e7471c0e9f5378e4',1,'asIScriptEngine']]], + ['getobjectname_1094',['GetObjectName',['../classas_i_script_function.html#a69e30464d13867fb72e66ce3365fdec8',1,'asIScriptFunction']]], + ['getobjecttype_1095',['GetObjectType',['../classas_i_script_object.html#aec79a2608f633a63169365d1ba79f611',1,'asIScriptObject::GetObjectType()'],['../classas_i_script_function.html#af930b362c37e5c4c117485d0bd4a34fb',1,'asIScriptFunction::GetObjectType()']]], + ['getobjecttypebyindex_1096',['GetObjectTypeByIndex',['../classas_i_script_engine.html#afac08d4f81e587031c7863574c6783ba',1,'asIScriptEngine::GetObjectTypeByIndex()'],['../classas_i_script_module.html#a49ebfdd345f18d88e489edebd4888af7',1,'asIScriptModule::GetObjectTypeByIndex()']]], + ['getobjecttypecount_1097',['GetObjectTypeCount',['../classas_i_script_engine.html#ac2667fbe30dd00ed14bc14e6ef7fc725',1,'asIScriptEngine::GetObjectTypeCount()'],['../classas_i_script_module.html#a931d0c00cba2df1b4e368e59bac1a207',1,'asIScriptModule::GetObjectTypeCount()']]], + ['getobjecttypeid_1098',['GetObjectTypeId',['../classas_i_script_generic.html#a3de95071fa358d554137cae88a5229ea',1,'asIScriptGeneric']]], + ['getparam_1099',['GetParam',['../classas_i_script_function.html#a2b3000b9fc5d3f2cfeea490d8c0c062a',1,'asIScriptFunction']]], + ['getparamcount_1100',['GetParamCount',['../classas_i_script_function.html#a8ca059886317b944c52933b7bbe85cfa',1,'asIScriptFunction']]], + ['getparenttype_1101',['GetParentType',['../classas_i_type_info.html#aa2836268d01f3a4424263190b57d9b04',1,'asITypeInfo']]], + ['getproperty_1102',['GetProperty',['../classas_i_type_info.html#a48f468bd5b6b0e22c852b40639a7a2b5',1,'asITypeInfo']]], + ['getpropertycount_1103',['GetPropertyCount',['../classas_i_script_object.html#a902a8e3f3b4d6d2e56b6e258febf6259',1,'asIScriptObject::GetPropertyCount()'],['../classas_i_type_info.html#a01d086e1bb97aa56a7b128c00c174ac6',1,'asITypeInfo::GetPropertyCount()']]], + ['getpropertydeclaration_1104',['GetPropertyDeclaration',['../classas_i_type_info.html#a9e6916f51f09970d268378aef9601349',1,'asITypeInfo']]], + ['getpropertyname_1105',['GetPropertyName',['../classas_i_script_object.html#af777076ab0d87e4995e1a343511f8a61',1,'asIScriptObject']]], + ['getpropertytypeid_1106',['GetPropertyTypeId',['../classas_i_script_object.html#a0b39e0e07b126b43d12ad1ec944a333e',1,'asIScriptObject']]], + ['getrawstringdata_1107',['GetRawStringData',['../classas_i_string_factory.html#ae798179f4d90b30371416f8c5c522333',1,'asIStringFactory']]], + ['getreturnaddress_1108',['GetReturnAddress',['../classas_i_script_context.html#a2438a7fcf46faa2267bdb94057cd1f2e',1,'asIScriptContext']]], + ['getreturnbyte_1109',['GetReturnByte',['../classas_i_script_context.html#a4c92259c03f1394310d3ea7d0774b3cb',1,'asIScriptContext']]], + ['getreturndouble_1110',['GetReturnDouble',['../classas_i_script_context.html#a7e1ce03637cd5dd48ea652fdf7913bd7',1,'asIScriptContext']]], + ['getreturndword_1111',['GetReturnDWord',['../classas_i_script_context.html#a43cd2fb72685aef96e8ddc622c9621bf',1,'asIScriptContext']]], + ['getreturnfloat_1112',['GetReturnFloat',['../classas_i_script_context.html#a4ad325995e43fe6a929bcbd8fa592500',1,'asIScriptContext']]], + ['getreturnobject_1113',['GetReturnObject',['../classas_i_script_context.html#a6d5739fac9c90bcd0fea55d01841d43a',1,'asIScriptContext']]], + ['getreturnqword_1114',['GetReturnQWord',['../classas_i_script_context.html#a22bdd3b67dee3b1dbcb3f9f9a1f21fa4',1,'asIScriptContext']]], + ['getreturntypeid_1115',['GetReturnTypeId',['../classas_i_script_generic.html#a9da6f7f81392cd25733ebc6c803a397a',1,'asIScriptGeneric::GetReturnTypeId()'],['../classas_i_script_function.html#a18968d49065c6af9833ee589b6d1e864',1,'asIScriptFunction::GetReturnTypeId()']]], + ['getreturnword_1116',['GetReturnWord',['../classas_i_script_context.html#a5a3e054d35a6a361af67448d0a4930f9',1,'asIScriptContext']]], + ['getscriptsectionname_1117',['GetScriptSectionName',['../classas_i_script_function.html#a62a77c029782162135d98d6e2b383eca',1,'asIScriptFunction']]], + ['getsize_1118',['GetSize',['../classas_i_type_info.html#ad965398e393144e87c0436ef865b9b6d',1,'asITypeInfo']]], + ['getsizeofprimitivetype_1119',['GetSizeOfPrimitiveType',['../classas_i_script_engine.html#a39b7207a6c4c55a5cbf10eab2ccfb8e6',1,'asIScriptEngine']]], + ['getstate_1120',['GetState',['../classas_i_script_context.html#a17024a9e1648f66711a3182b21676aa7',1,'asIScriptContext']]], + ['getstringconstant_1121',['GetStringConstant',['../classas_i_string_factory.html#a59d5d4d13a21105791e34bef5cb57e6b',1,'asIStringFactory']]], + ['getstringfactoryreturntypeid_1122',['GetStringFactoryReturnTypeId',['../classas_i_script_engine.html#afb3935d85494231e2f02af5816ba9830',1,'asIScriptEngine']]], + ['getsubtype_1123',['GetSubType',['../classas_i_type_info.html#a8e947504f268c7f0e1c26973dd7d3837',1,'asITypeInfo']]], + ['getsubtypecount_1124',['GetSubTypeCount',['../classas_i_type_info.html#a1657d5094afa550c93d8cc74c216c3c6',1,'asITypeInfo']]], + ['getsubtypeid_1125',['GetSubTypeId',['../classas_i_type_info.html#aa1a56809ce5c340364ecd8beac508eb4',1,'asITypeInfo']]], + ['getsystemfunction_1126',['GetSystemFunction',['../classas_i_script_context.html#a214cc16c4dd889072c1c24c089223a6a',1,'asIScriptContext']]], + ['getthispointer_1127',['GetThisPointer',['../classas_i_script_context.html#a4f6761a7a0c872dda681d8e180830ff9',1,'asIScriptContext']]], + ['getthistypeid_1128',['GetThisTypeId',['../classas_i_script_context.html#a404681f8950c1ebd9382d30ef1ed3b89',1,'asIScriptContext']]], + ['gettypedeclaration_1129',['GetTypeDeclaration',['../classas_i_script_engine.html#a3ae23fcde6af0d816ff97097cd443281',1,'asIScriptEngine']]], + ['gettypedefbyindex_1130',['GetTypedefByIndex',['../classas_i_script_engine.html#a635cd008ea123b510c66fbddcea735f5',1,'asIScriptEngine::GetTypedefByIndex()'],['../classas_i_script_module.html#a6a31f0767b01cc4203212fd531576de4',1,'asIScriptModule::GetTypedefByIndex()']]], + ['gettypedefcount_1131',['GetTypedefCount',['../classas_i_script_engine.html#a0ebbbb86ea0e314cc2695f6276ebe507',1,'asIScriptEngine::GetTypedefCount()'],['../classas_i_script_module.html#ad30b22539655df3135f29ce28b89c820',1,'asIScriptModule::GetTypedefCount()']]], + ['gettypedeftypeid_1132',['GetTypedefTypeId',['../classas_i_type_info.html#aca9edb046026db68d255e226dd419b3a',1,'asITypeInfo']]], + ['gettypeid_1133',['GetTypeId',['../classas_i_script_object.html#a19c5ab9d8adb0f921bf0b6474d97f468',1,'asIScriptObject::GetTypeId()'],['../classas_i_type_info.html#a06698aa9dcc6dc315ec2651fc70dbe19',1,'asITypeInfo::GetTypeId()'],['../classas_i_script_function.html#a4a5e24c464e423a2a6724cb849babd21',1,'asIScriptFunction::GetTypeId()']]], + ['gettypeidbydecl_1134',['GetTypeIdByDecl',['../classas_i_script_engine.html#ad1f6fecb0f53fd7966736b01f65c3dcb',1,'asIScriptEngine::GetTypeIdByDecl()'],['../classas_i_script_module.html#a7fbc2bd888b248d2c2ee2d953b49eefc',1,'asIScriptModule::GetTypeIdByDecl()']]], + ['gettypeinfobydecl_1135',['GetTypeInfoByDecl',['../classas_i_script_engine.html#ab00808f9b762c4badf508ed511789d1b',1,'asIScriptEngine::GetTypeInfoByDecl()'],['../classas_i_script_module.html#a3c61bf81a0a88c0017a0e33aecc417ba',1,'asIScriptModule::GetTypeInfoByDecl()']]], + ['gettypeinfobyid_1136',['GetTypeInfoById',['../classas_i_script_engine.html#a55cc2d9592651538efcf79eb8106a867',1,'asIScriptEngine']]], + ['gettypeinfobyname_1137',['GetTypeInfoByName',['../classas_i_script_engine.html#aea2583b8aa724779b7c37df8b7fa437b',1,'asIScriptEngine::GetTypeInfoByName()'],['../classas_i_script_module.html#ae8460fa05f441072e14f984ccf507396',1,'asIScriptModule::GetTypeInfoByName()']]], + ['getuserdata_1138',['GetUserData',['../classas_i_script_engine.html#a701aa6a7ddf51a22c62281f3dec9a772',1,'asIScriptEngine::GetUserData()'],['../classas_i_script_module.html#af292f99799d8358277298f749efedaaa',1,'asIScriptModule::GetUserData()'],['../classas_i_script_context.html#a0f8503675abfd473915d66a92c6e6df7',1,'asIScriptContext::GetUserData()'],['../classas_i_script_object.html#a63e8ab74fd7552d057e23e0ce550a157',1,'asIScriptObject::GetUserData()'],['../classas_i_type_info.html#a80b01b2ceadfaf91cc34988033a1598c',1,'asITypeInfo::GetUserData()'],['../classas_i_script_function.html#a0d0d4671e524fcd868a34bee33ee9fde',1,'asIScriptFunction::GetUserData()']]], + ['getvar_1139',['GetVar',['../classas_i_script_function.html#aaf11dde60bec710bcd729127bfe12dd4',1,'asIScriptFunction']]], + ['getvarcount_1140',['GetVarCount',['../classas_i_script_context.html#a3d735c6c7c5a166302cc4ba8ea38e3e8',1,'asIScriptContext::GetVarCount()'],['../classas_i_script_function.html#a92e14168997c0f67a975e7ed042d8328',1,'asIScriptFunction::GetVarCount()']]], + ['getvardecl_1141',['GetVarDecl',['../classas_i_script_function.html#acef067f00f2a6a997d6955f5cf3c6d13',1,'asIScriptFunction']]], + ['getvardeclaration_1142',['GetVarDeclaration',['../classas_i_script_context.html#ae3419d239a51d702870b1ab8ee1b7140',1,'asIScriptContext']]], + ['getvarname_1143',['GetVarName',['../classas_i_script_context.html#aac398eb23d9f17fcbeaa3f3809f8923d',1,'asIScriptContext']]], + ['getvartypeid_1144',['GetVarTypeId',['../classas_i_script_context.html#a8684e1931e54dbfe53da763fc334413d',1,'asIScriptContext']]], + ['getweakrefflag_1145',['GetWeakRefFlag',['../classas_i_script_object.html#a9ccca7fe3453219377fc9bd190bf7903',1,'asIScriptObject']]], + ['getweakrefflagofscriptobject_1146',['GetWeakRefFlagOfScriptObject',['../classas_i_script_engine.html#ab31103bef62096445fe03632de691827',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/functions_7.html b/docs/manual/search/functions_7.html new file mode 100644 index 0000000..d7ad9dd --- /dev/null +++ b/docs/manual/search/functions_7.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_7.js b/docs/manual/search/functions_7.js new file mode 100644 index 0000000..716e075 --- /dev/null +++ b/docs/manual/search/functions_7.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['implements_1147',['Implements',['../classas_i_type_info.html#a19bacd881681ee398de95a076f427726',1,'asITypeInfo']]], + ['iscompatiblewithtypeid_1148',['IsCompatibleWithTypeId',['../classas_i_script_function.html#a76715df2843cb37cc010fc3a5d999e84',1,'asIScriptFunction']]], + ['isexplicit_1149',['IsExplicit',['../classas_i_script_function.html#aea24c6ba2ab0fcc5c42a734f72856814',1,'asIScriptFunction']]], + ['isfinal_1150',['IsFinal',['../classas_i_script_function.html#aa071c702946372020a1245f901502d52',1,'asIScriptFunction']]], + ['isnested_1151',['IsNested',['../classas_i_script_context.html#a378f3bbfa04ef7b806300c5d4f1a0d65',1,'asIScriptContext']]], + ['isoverride_1152',['IsOverride',['../classas_i_script_function.html#a5aec17ae5639fb9cad403c835d429f6e',1,'asIScriptFunction']]], + ['isprivate_1153',['IsPrivate',['../classas_i_script_function.html#a7ef1f42ff812a03e2a323046835159fb',1,'asIScriptFunction']]], + ['isproperty_1154',['IsProperty',['../classas_i_script_function.html#ad6ecdae3667ebef1fc867e884504078c',1,'asIScriptFunction']]], + ['isprotected_1155',['IsProtected',['../classas_i_script_function.html#a2e17b763527ba3a9b0d05c4cd35b5742',1,'asIScriptFunction']]], + ['isreadonly_1156',['IsReadOnly',['../classas_i_script_function.html#a99bbe26ae0ec3f0cc09070bf89aff2f9',1,'asIScriptFunction']]], + ['isshared_1157',['IsShared',['../classas_i_script_function.html#a805ae8064598ad12f44bb583118b6cc5',1,'asIScriptFunction']]], + ['isvarinscope_1158',['IsVarInScope',['../classas_i_script_context.html#a45fcf7d8d711d5ec5cb9927e7839387a',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/functions_8.html b/docs/manual/search/functions_8.html new file mode 100644 index 0000000..8600cab --- /dev/null +++ b/docs/manual/search/functions_8.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_8.js b/docs/manual/search/functions_8.js new file mode 100644 index 0000000..dad3b9a --- /dev/null +++ b/docs/manual/search/functions_8.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['loadbytecode_1159',['LoadByteCode',['../classas_i_script_module.html#a8b4a222e5309c6b367f136b6d2f664ba',1,'asIScriptModule']]], + ['lock_1160',['Lock',['../classas_i_lockable_shared_bool.html#aef12cc309395d682aa138da5eea9d82b',1,'asILockableSharedBool']]] +]; diff --git a/docs/manual/search/functions_9.html b/docs/manual/search/functions_9.html new file mode 100644 index 0000000..76e3e2c --- /dev/null +++ b/docs/manual/search/functions_9.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_9.js b/docs/manual/search/functions_9.js new file mode 100644 index 0000000..24212e0 --- /dev/null +++ b/docs/manual/search/functions_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['notifygarbagecollectorofnewobject_1161',['NotifyGarbageCollectorOfNewObject',['../classas_i_script_engine.html#a52a7644b48cbc771e33db5070814f6df',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/functions_a.html b/docs/manual/search/functions_a.html new file mode 100644 index 0000000..81836b9 --- /dev/null +++ b/docs/manual/search/functions_a.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_a.js b/docs/manual/search/functions_a.js new file mode 100644 index 0000000..3ee38a8 --- /dev/null +++ b/docs/manual/search/functions_a.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['parsetoken_1162',['ParseToken',['../classas_i_script_engine.html#a57ecbd86ae9370684877c755e83cef0d',1,'asIScriptEngine']]], + ['popstate_1163',['PopState',['../classas_i_script_context.html#a5d963974625e582799b5d911d182d9be',1,'asIScriptContext']]], + ['prepare_1164',['Prepare',['../classas_i_script_context.html#a43976f42dfc6c1af23e132d36265173a',1,'asIScriptContext']]], + ['pushstate_1165',['PushState',['../classas_i_script_context.html#ad8f7637a23d67e227d07f65621b6cdd6',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/functions_b.html b/docs/manual/search/functions_b.html new file mode 100644 index 0000000..8c270d2 --- /dev/null +++ b/docs/manual/search/functions_b.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_b.js b/docs/manual/search/functions_b.js new file mode 100644 index 0000000..aed0ed0 --- /dev/null +++ b/docs/manual/search/functions_b.js @@ -0,0 +1,29 @@ +var searchData= +[ + ['read_1166',['Read',['../classas_i_binary_stream.html#a8bbd68cea1f96b42c723f9732ac19140',1,'asIBinaryStream']]], + ['refcastobject_1167',['RefCastObject',['../classas_i_script_engine.html#a32c9d9aac77a67eeb046fc67d7473fa2',1,'asIScriptEngine']]], + ['registerdefaultarraytype_1168',['RegisterDefaultArrayType',['../classas_i_script_engine.html#ac9451feece1297eba8d1649036039e82',1,'asIScriptEngine']]], + ['registerenum_1169',['RegisterEnum',['../classas_i_script_engine.html#abed6e77f2a532c8a4f528650fa137d37',1,'asIScriptEngine']]], + ['registerenumvalue_1170',['RegisterEnumValue',['../classas_i_script_engine.html#a4d331153596dd39838f3bed2a861af18',1,'asIScriptEngine']]], + ['registerfuncdef_1171',['RegisterFuncdef',['../classas_i_script_engine.html#a03c1a2cc23ae4b742c927f3472a1a4f7',1,'asIScriptEngine']]], + ['registerglobalfunction_1172',['RegisterGlobalFunction',['../classas_i_script_engine.html#a2f84b9b51733f22c68b8448b02c2f1c7',1,'asIScriptEngine']]], + ['registerglobalproperty_1173',['RegisterGlobalProperty',['../classas_i_script_engine.html#aacd32f32b2922b8ffaed204812013169',1,'asIScriptEngine']]], + ['registerinterface_1174',['RegisterInterface',['../classas_i_script_engine.html#ae2d89b82561b7f9843f35693c664589f',1,'asIScriptEngine']]], + ['registerinterfacemethod_1175',['RegisterInterfaceMethod',['../classas_i_script_engine.html#a43bd2c12c94a55c22be76d209de93f1a',1,'asIScriptEngine']]], + ['registerobjectbehaviour_1176',['RegisterObjectBehaviour',['../classas_i_script_engine.html#a9f122dd87394f3a83ac766ea19f37317',1,'asIScriptEngine']]], + ['registerobjectmethod_1177',['RegisterObjectMethod',['../classas_i_script_engine.html#ad74043be9cc30f105c62f482ca720574',1,'asIScriptEngine']]], + ['registerobjectproperty_1178',['RegisterObjectProperty',['../classas_i_script_engine.html#a0aa35bf824180fe6aed685b40f0e8c34',1,'asIScriptEngine']]], + ['registerobjecttype_1179',['RegisterObjectType',['../classas_i_script_engine.html#a29c6c087c8c5b5cdb6271cfd161cc5a6',1,'asIScriptEngine']]], + ['registerstringfactory_1180',['RegisterStringFactory',['../classas_i_script_engine.html#ac6598c07c36652b0270b4c2d61db1f01',1,'asIScriptEngine']]], + ['registertypedef_1181',['RegisterTypedef',['../classas_i_script_engine.html#addb24466769dc52be96c7e37d5305245',1,'asIScriptEngine']]], + ['release_1182',['Release',['../classas_i_script_engine.html#aae91a45da75af9234b87e825b5c08b81',1,'asIScriptEngine::Release()'],['../classas_i_script_context.html#a1b13a5f3e58627e9ff4300c0c6f0f3cf',1,'asIScriptContext::Release()'],['../classas_i_script_object.html#a4bed3c3ac9f16294985835747aa122d3',1,'asIScriptObject::Release()'],['../classas_i_type_info.html#a73b9059dc335b6fde8c7bbf4b1b95914',1,'asITypeInfo::Release()'],['../classas_i_script_function.html#a0a98f1f7f91574a11d7d8c5062bdcdee',1,'asIScriptFunction::Release()'],['../classas_i_lockable_shared_bool.html#a1dae71f6f1141b5b16520232a9ea5fb2',1,'asILockableSharedBool::Release()']]], + ['releasejitfunction_1183',['ReleaseJITFunction',['../classas_i_j_i_t_compiler.html#afbf9390868269c9224df85d49aabd451',1,'asIJITCompiler']]], + ['releasescriptobject_1184',['ReleaseScriptObject',['../classas_i_script_engine.html#a82873d3769ded547894a7c3d52c220fd',1,'asIScriptEngine']]], + ['releasestringconstant_1185',['ReleaseStringConstant',['../classas_i_string_factory.html#ae4ca9e666eb711671a765dba8debe8b1',1,'asIStringFactory']]], + ['removeconfiggroup_1186',['RemoveConfigGroup',['../classas_i_script_engine.html#ab607be7fe727cdcce502d2beedbf4c0a',1,'asIScriptEngine']]], + ['removefunction_1187',['RemoveFunction',['../classas_i_script_module.html#a54b6f8e09787ad20880f73bc97a8ef10',1,'asIScriptModule']]], + ['removeglobalvar_1188',['RemoveGlobalVar',['../classas_i_script_module.html#aac10878c3d16f18ace4db881f7a1bb11',1,'asIScriptModule']]], + ['requestcontext_1189',['RequestContext',['../classas_i_script_engine.html#a32391ee83e58083b406ba068ab2ee049',1,'asIScriptEngine']]], + ['resetglobalvars_1190',['ResetGlobalVars',['../classas_i_script_module.html#a7b084b6693a05616097d7059e54d983b',1,'asIScriptModule']]], + ['returncontext_1191',['ReturnContext',['../classas_i_script_engine.html#a22e42bf32902cbd6885731a6beeaca20',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/functions_c.html b/docs/manual/search/functions_c.html new file mode 100644 index 0000000..af1234d --- /dev/null +++ b/docs/manual/search/functions_c.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_c.js b/docs/manual/search/functions_c.js new file mode 100644 index 0000000..80521cf --- /dev/null +++ b/docs/manual/search/functions_c.js @@ -0,0 +1,45 @@ +var searchData= +[ + ['savebytecode_1192',['SaveByteCode',['../classas_i_script_module.html#ac6cd95dd97cc6abf28ab4d82257f5aeb',1,'asIScriptModule']]], + ['set_1193',['Set',['../classas_i_lockable_shared_bool.html#aa29488ac2f1c38788d5e79545fdfc8c7',1,'asILockableSharedBool']]], + ['setaccessmask_1194',['SetAccessMask',['../classas_i_script_module.html#a76733de5a86875c4a0f021f7f92a6d12',1,'asIScriptModule']]], + ['setargaddress_1195',['SetArgAddress',['../classas_i_script_context.html#aa8de8f21dfbb2cdf0becbabaa3e883ed',1,'asIScriptContext']]], + ['setargbyte_1196',['SetArgByte',['../classas_i_script_context.html#ac5ac8ce5bb209f43d4da620db5d271da',1,'asIScriptContext']]], + ['setargdouble_1197',['SetArgDouble',['../classas_i_script_context.html#acbdddda3b80c37b70b8fd35c8e7383b9',1,'asIScriptContext']]], + ['setargdword_1198',['SetArgDWord',['../classas_i_script_context.html#a14cac831c1b419f552ca62a239dfcf45',1,'asIScriptContext']]], + ['setargfloat_1199',['SetArgFloat',['../classas_i_script_context.html#a702a40cfe539e4e655a84e15161f8db8',1,'asIScriptContext']]], + ['setargobject_1200',['SetArgObject',['../classas_i_script_context.html#a09044a12dfb2d44d19bd8a4025cb814d',1,'asIScriptContext']]], + ['setargqword_1201',['SetArgQWord',['../classas_i_script_context.html#a742c870360588e99528f09bae6156482',1,'asIScriptContext']]], + ['setargvartype_1202',['SetArgVarType',['../classas_i_script_context.html#a626d97ec564c92120e2abaf69f6e3698',1,'asIScriptContext']]], + ['setargword_1203',['SetArgWord',['../classas_i_script_context.html#ac882e19b922c681052a0a88d69289a47',1,'asIScriptContext']]], + ['setcircularrefdetectedcallback_1204',['SetCircularRefDetectedCallback',['../classas_i_script_engine.html#aac3d5b7c9920b4f98405a19e515ceb26',1,'asIScriptEngine']]], + ['setcontextcallbacks_1205',['SetContextCallbacks',['../classas_i_script_engine.html#ae5ba9fe99b72c60392cdaeef164f2c65',1,'asIScriptEngine']]], + ['setcontextuserdatacleanupcallback_1206',['SetContextUserDataCleanupCallback',['../classas_i_script_engine.html#acaced7eb9ebe013ede23f7593daf58e3',1,'asIScriptEngine']]], + ['setdefaultaccessmask_1207',['SetDefaultAccessMask',['../classas_i_script_engine.html#a570df3e676f2d9e03e87d97b8cede1c7',1,'asIScriptEngine']]], + ['setdefaultnamespace_1208',['SetDefaultNamespace',['../classas_i_script_engine.html#a605f114814f1f64804c04391816d948b',1,'asIScriptEngine::SetDefaultNamespace()'],['../classas_i_script_module.html#ab8629af79cee8212d0d244314d36f42a',1,'asIScriptModule::SetDefaultNamespace()']]], + ['setengineproperty_1209',['SetEngineProperty',['../classas_i_script_engine.html#a1bce4e5f573a2ca0ff55163e28f761dd',1,'asIScriptEngine']]], + ['setengineuserdatacleanupcallback_1210',['SetEngineUserDataCleanupCallback',['../classas_i_script_engine.html#a8fa4fc9aacb99db6d4be0a5542b85e35',1,'asIScriptEngine']]], + ['setexception_1211',['SetException',['../classas_i_script_context.html#a6f0f071215e0f7effc0b765043f01275',1,'asIScriptContext']]], + ['setexceptioncallback_1212',['SetExceptionCallback',['../classas_i_script_context.html#a4d1f481473df3f7aefccc5bb6904e405',1,'asIScriptContext']]], + ['setfunctionuserdatacleanupcallback_1213',['SetFunctionUserDataCleanupCallback',['../classas_i_script_engine.html#ae75ee087fe6608cf0af1c24794ca73c7',1,'asIScriptEngine']]], + ['setjitcompiler_1214',['SetJITCompiler',['../classas_i_script_engine.html#aee4f910163604203a27db1ffea3b1c9c',1,'asIScriptEngine']]], + ['setlinecallback_1215',['SetLineCallback',['../classas_i_script_context.html#ae2747f643bf9a07364f922c460ef57dd',1,'asIScriptContext']]], + ['setmessagecallback_1216',['SetMessageCallback',['../classas_i_script_engine.html#a74192fe950808eb72a64e3e371f0ea02',1,'asIScriptEngine']]], + ['setmoduleuserdatacleanupcallback_1217',['SetModuleUserDataCleanupCallback',['../classas_i_script_engine.html#a7523853b9a9bf7dab603fa6a06393d51',1,'asIScriptEngine']]], + ['setname_1218',['SetName',['../classas_i_script_module.html#a1a7534bace9eefdc3175a1999f9cbf4a',1,'asIScriptModule']]], + ['setobject_1219',['SetObject',['../classas_i_script_context.html#a10d3c152b25d07584999f4d9fe5ce8b1',1,'asIScriptContext']]], + ['setreturnaddress_1220',['SetReturnAddress',['../classas_i_script_generic.html#afd8ead96f17d6e77f3a26c70c3a1d80c',1,'asIScriptGeneric']]], + ['setreturnbyte_1221',['SetReturnByte',['../classas_i_script_generic.html#a81c42965dfccfd242e955f50b02a641c',1,'asIScriptGeneric']]], + ['setreturndouble_1222',['SetReturnDouble',['../classas_i_script_generic.html#a8a720ef33859981dd941c616b2c83cad',1,'asIScriptGeneric']]], + ['setreturndword_1223',['SetReturnDWord',['../classas_i_script_generic.html#a3260e1f3b76791713bced9af0b81bdbc',1,'asIScriptGeneric']]], + ['setreturnfloat_1224',['SetReturnFloat',['../classas_i_script_generic.html#acc2fddd4175ad35854cec8f5c38a6495',1,'asIScriptGeneric']]], + ['setreturnobject_1225',['SetReturnObject',['../classas_i_script_generic.html#a94c9ca32722cb44b09211e51fa906e6e',1,'asIScriptGeneric']]], + ['setreturnqword_1226',['SetReturnQWord',['../classas_i_script_generic.html#a25f5ec30c666ffbb51edeedfd4c89546',1,'asIScriptGeneric']]], + ['setreturnword_1227',['SetReturnWord',['../classas_i_script_generic.html#a9c51e3ff3f4fb37f6b4c82a050319955',1,'asIScriptGeneric']]], + ['setscriptobjectuserdatacleanupcallback_1228',['SetScriptObjectUserDataCleanupCallback',['../classas_i_script_engine.html#a4654e2cae0690c50e19b177f1ec54592',1,'asIScriptEngine']]], + ['settranslateappexceptioncallback_1229',['SetTranslateAppExceptionCallback',['../classas_i_script_engine.html#addce6a202934a4918f7776b2f77c43fd',1,'asIScriptEngine']]], + ['settypeinfouserdatacleanupcallback_1230',['SetTypeInfoUserDataCleanupCallback',['../classas_i_script_engine.html#afa31e7c28c63a2c876d8e08305cf5d75',1,'asIScriptEngine']]], + ['setuserdata_1231',['SetUserData',['../classas_i_script_engine.html#aabee8d6ef426c434adee85ec6d57f940',1,'asIScriptEngine::SetUserData()'],['../classas_i_script_module.html#a06582e57e7101df4157ee36c81867c13',1,'asIScriptModule::SetUserData()'],['../classas_i_script_context.html#a263dc70abb2a8c77adcea7c9ede0a479',1,'asIScriptContext::SetUserData()'],['../classas_i_script_object.html#ac85cea9bca5dd3868e027285e44dd6d0',1,'asIScriptObject::SetUserData()'],['../classas_i_type_info.html#a5e8ea071f1c1f3b7c6dfc1950bec73f4',1,'asITypeInfo::SetUserData()'],['../classas_i_script_function.html#a9dd036ce8e91d335eb5a3ad8851f1a41',1,'asIScriptFunction::SetUserData()']]], + ['shutdownandrelease_1232',['ShutDownAndRelease',['../classas_i_script_engine.html#a28c3800620d4aeaca75d084391eb758e',1,'asIScriptEngine']]], + ['suspend_1233',['Suspend',['../classas_i_script_context.html#ad4ac8be3586c46069b5870e40c86544a',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/functions_d.html b/docs/manual/search/functions_d.html new file mode 100644 index 0000000..7116594 --- /dev/null +++ b/docs/manual/search/functions_d.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_d.js b/docs/manual/search/functions_d.js new file mode 100644 index 0000000..f177258 --- /dev/null +++ b/docs/manual/search/functions_d.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['unbindallimportedfunctions_1234',['UnbindAllImportedFunctions',['../classas_i_script_module.html#ab7b4c4b94190779028776fd1057a658f',1,'asIScriptModule']]], + ['unbindimportedfunction_1235',['UnbindImportedFunction',['../classas_i_script_module.html#a4d59b4e833bf139f6b7256d6b6bd40b6',1,'asIScriptModule']]], + ['unlock_1236',['Unlock',['../classas_i_lockable_shared_bool.html#a863984c1b271df84f71fb5ba978ce2b8',1,'asILockableSharedBool']]], + ['unprepare_1237',['Unprepare',['../classas_i_script_context.html#ae3c18a2cc66c56f840e6ee4310287f65',1,'asIScriptContext']]] +]; diff --git a/docs/manual/search/functions_e.html b/docs/manual/search/functions_e.html new file mode 100644 index 0000000..705e3de --- /dev/null +++ b/docs/manual/search/functions_e.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/functions_e.js b/docs/manual/search/functions_e.js new file mode 100644 index 0000000..ac8e04d --- /dev/null +++ b/docs/manual/search/functions_e.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['willexceptionbecaught_1238',['WillExceptionBeCaught',['../classas_i_script_context.html#a57cfcc729b214fdaacb1358e03daf610',1,'asIScriptContext']]], + ['write_1239',['Write',['../classas_i_binary_stream.html#a57724f9cd63a625a843bf97e7704d9a7',1,'asIBinaryStream']]], + ['writemessage_1240',['WriteMessage',['../classas_i_script_engine.html#a936ce6566af958bb75ba1c0945d8b03a',1,'asIScriptEngine']]] +]; diff --git a/docs/manual/search/groups_0.html b/docs/manual/search/groups_0.html new file mode 100644 index 0000000..5d72bbb --- /dev/null +++ b/docs/manual/search/groups_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/groups_0.js b/docs/manual/search/groups_0.js new file mode 100644 index 0000000..b09cdc7 --- /dev/null +++ b/docs/manual/search/groups_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['auxiliary_20functions_1722',['Auxiliary functions',['../group__api__auxiliary__functions.html',1,'']]], + ['auxiliary_20interfaces_1723',['Auxiliary interfaces',['../group__api__auxiliary__interfaces.html',1,'']]] +]; diff --git a/docs/manual/search/groups_1.html b/docs/manual/search/groups_1.html new file mode 100644 index 0000000..2909493 --- /dev/null +++ b/docs/manual/search/groups_1.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/groups_1.js b/docs/manual/search/groups_1.js new file mode 100644 index 0000000..02a6603 --- /dev/null +++ b/docs/manual/search/groups_1.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['memory_20functions_1724',['Memory functions',['../group__api__memory__functions.html',1,'']]], + ['multi_2dthread_20support_20functions_1725',['Multi-thread support functions',['../group__api__multithread__functions.html',1,'']]] +]; diff --git a/docs/manual/search/groups_2.html b/docs/manual/search/groups_2.html new file mode 100644 index 0000000..ec36b21 --- /dev/null +++ b/docs/manual/search/groups_2.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/groups_2.js b/docs/manual/search/groups_2.js new file mode 100644 index 0000000..1b080f2 --- /dev/null +++ b/docs/manual/search/groups_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['principal_20functions_1726',['Principal functions',['../group__api__principal__functions.html',1,'']]], + ['principal_20interfaces_1727',['Principal interfaces',['../group__api__principal__interfaces.html',1,'']]] +]; diff --git a/docs/manual/search/groups_3.html b/docs/manual/search/groups_3.html new file mode 100644 index 0000000..fc86ed9 --- /dev/null +++ b/docs/manual/search/groups_3.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/groups_3.js b/docs/manual/search/groups_3.js new file mode 100644 index 0000000..2588f4d --- /dev/null +++ b/docs/manual/search/groups_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['secondary_20interfaces_1728',['Secondary interfaces',['../group__api__secondary__interfaces.html',1,'']]] +]; diff --git a/docs/manual/search/mag_sel.png b/docs/manual/search/mag_sel.png new file mode 100644 index 0000000..39c0ed5 Binary files /dev/null and b/docs/manual/search/mag_sel.png differ diff --git a/docs/manual/search/nomatches.html b/docs/manual/search/nomatches.html new file mode 100644 index 0000000..4377320 --- /dev/null +++ b/docs/manual/search/nomatches.html @@ -0,0 +1,12 @@ + + + + + + + +
+
No Matches
+
+ + diff --git a/docs/manual/search/pages_0.html b/docs/manual/search/pages_0.html new file mode 100644 index 0000000..ca7755f --- /dev/null +++ b/docs/manual/search/pages_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_0.js b/docs/manual/search/pages_0.js new file mode 100644 index 0000000..407eb3f --- /dev/null +++ b/docs/manual/search/pages_0.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['add_2dons_1729',['Add-ons',['../doc_addon.html',1,'main_topics']]], + ['any_20object_1730',['any object',['../doc_addon_any.html',1,'doc_addon_script']]], + ['application_20modules_1731',['Application modules',['../doc_addon_application.html',1,'doc_addon']]], + ['array_20template_20object_1732',['array template object',['../doc_addon_array.html',1,'doc_addon_script']]], + ['automatic_20wrapper_20functions_1733',['Automatic wrapper functions',['../doc_addon_autowrap.html',1,'doc_addon_application']]], + ['access_20masks_20and_20exposing_20different_20interfaces_1734',['Access masks and exposing different interfaces',['../doc_adv_access_mask.html',1,'doc_advanced']]], + ['advanced_20topics_1735',['Advanced topics',['../doc_advanced.html',1,'main_topics']]], + ['advanced_20application_20interface_1736',['Advanced application interface',['../doc_advanced_api.html',1,'doc_register_api_topic']]], + ['array_1737',['array',['../doc_datatypes_arrays.html',1,'doc_script_stdlib']]], + ['auto_20declarations_1738',['Auto declarations',['../doc_datatypes_auto.html',1,'doc_datatypes']]], + ['asrun_20manual_1739',['asrun manual',['../doc_samples_asrun_manual.html',1,'doc_samples_asrun']]], + ['anonymous_20functions_1740',['Anonymous functions',['../doc_script_anonfunc.html',1,'doc_script_func']]] +]; diff --git a/docs/manual/search/pages_1.html b/docs/manual/search/pages_1.html new file mode 100644 index 0000000..4e469b4 --- /dev/null +++ b/docs/manual/search/pages_1.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_1.js b/docs/manual/search/pages_1.js new file mode 100644 index 0000000..36da079 --- /dev/null +++ b/docs/manual/search/pages_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['byte_20code_20instructions_1741',['Byte code instructions',['../doc_adv_jit_1.html',1,'doc_adv_jit_topic']]] +]; diff --git a/docs/manual/search/pages_10.html b/docs/manual/search/pages_10.html new file mode 100644 index 0000000..de85187 --- /dev/null +++ b/docs/manual/search/pages_10.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_10.js b/docs/manual/search/pages_10.js new file mode 100644 index 0000000..996ba44 --- /dev/null +++ b/docs/manual/search/pages_10.js @@ -0,0 +1,19 @@ +var searchData= +[ + ['script_20builder_1839',['Script builder',['../doc_addon_build.html',1,'doc_addon_application']]], + ['script_20extensions_1840',['Script extensions',['../doc_addon_script.html',1,'doc_addon']]], + ['serializer_1841',['Serializer',['../doc_addon_serializer.html',1,'doc_addon_application']]], + ['string_20object_1842',['string object',['../doc_addon_std_string.html',1,'doc_addon_script']]], + ['strings_1843',['Strings',['../doc_datatypes_strings.html',1,'doc_datatypes']]], + ['script_20classes_1844',['Script classes',['../doc_global_class.html',1,'doc_script_global']]], + ['script_20modules_1845',['Script modules',['../doc_module.html',1,'doc_understanding_as']]], + ['samples_1846',['Samples',['../doc_samples.html',1,'main_topics']]], + ['script_20language_20grammar_1847',['Script language grammar',['../doc_script_bnf.html',1,'doc_script']]], + ['script_20classes_1848',['Script classes',['../doc_script_class.html',1,'doc_script']]], + ['script_20class_20overview_1849',['Script class overview',['../doc_script_class_desc.html',1,'doc_script_class']]], + ['shared_20script_20entities_1850',['Shared script entities',['../doc_script_shared.html',1,'doc_script']]], + ['statements_1851',['Statements',['../doc_script_statements.html',1,'doc_script']]], + ['standard_20library_1852',['Standard library',['../doc_script_stdlib.html',1,'doc_script']]], + ['string_1853',['string',['../doc_script_stdlib_string.html',1,'doc_script_stdlib']]], + ['system_20functions_1854',['System functions',['../doc_script_stdlib_system.html',1,'doc_script_stdlib']]] +]; diff --git a/docs/manual/search/pages_11.html b/docs/manual/search/pages_11.html new file mode 100644 index 0000000..97bfc0c --- /dev/null +++ b/docs/manual/search/pages_11.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_11.js b/docs/manual/search/pages_11.js new file mode 100644 index 0000000..d3e6c87 --- /dev/null +++ b/docs/manual/search/pages_11.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['template_20types_1855',['Template types',['../doc_adv_template.html',1,'doc_advanced_api']]], + ['timeout_20long_20running_20scripts_1856',['Timeout long running scripts',['../doc_adv_timeout.html',1,'doc_advanced']]], + ['the_20variable_20parameter_20type_1857',['The variable parameter type',['../doc_adv_var_type.html',1,'doc_advanced_api']]], + ['the_20generic_20calling_20convention_1858',['The generic calling convention',['../doc_generic.html',1,'doc_advanced_api']]], + ['typedefs_1859',['Typedefs',['../doc_global_typedef.html',1,'doc_script_global']]], + ['tutorial_1860',['Tutorial',['../doc_samples_tutorial.html',1,'doc_samples']]], + ['the_20script_20language_1861',['The script language',['../doc_script.html',1,'']]], + ['todo_20list_1862',['Todo List',['../todo.html',1,'']]] +]; diff --git a/docs/manual/search/pages_12.html b/docs/manual/search/pages_12.html new file mode 100644 index 0000000..e1b3331 --- /dev/null +++ b/docs/manual/search/pages_12.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_12.js b/docs/manual/search/pages_12.js new file mode 100644 index 0000000..80312ed --- /dev/null +++ b/docs/manual/search/pages_12.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['using_20namespaces_1863',['Using namespaces',['../doc_adv_namespace.html',1,'doc_advanced']]], + ['understanding_20angelscript_1864',['Understanding AngelScript',['../doc_understanding_as.html',1,'main_topics']]], + ['using_20script_20classes_1865',['Using script classes',['../doc_use_script_class.html',1,'main_topics']]] +]; diff --git a/docs/manual/search/pages_13.html b/docs/manual/search/pages_13.html new file mode 100644 index 0000000..a10129c --- /dev/null +++ b/docs/manual/search/pages_13.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_13.js b/docs/manual/search/pages_13.js new file mode 100644 index 0000000..a1846b2 --- /dev/null +++ b/docs/manual/search/pages_13.js @@ -0,0 +1,6 @@ +var searchData= +[ + ['variables_1866',['Variables',['../doc_global_variable.html',1,'doc_script_global']]], + ['virtual_20properties_1867',['Virtual properties',['../doc_global_virtprop.html',1,'doc_script_global']]], + ['versions_1868',['Versions',['../doc_versions.html',1,'doc_understanding_as']]] +]; diff --git a/docs/manual/search/pages_14.html b/docs/manual/search/pages_14.html new file mode 100644 index 0000000..81aaddb --- /dev/null +++ b/docs/manual/search/pages_14.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_14.js b/docs/manual/search/pages_14.js new file mode 100644 index 0000000..dadacd9 --- /dev/null +++ b/docs/manual/search/pages_14.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['weakref_20object_1869',['weakref object',['../doc_addon_weakref.html',1,'doc_addon_script']]], + ['weak_20references_1870',['Weak references',['../doc_adv_weakref.html',1,'doc_advanced_api']]], + ['weakref_1871',['weakref',['../doc_datatypes_weakref.html',1,'doc_script_stdlib']]], + ['what_20can_20be_20registered_1872',['What can be registered',['../doc_register_api.html',1,'doc_register_api_topic']]] +]; diff --git a/docs/manual/search/pages_15.html b/docs/manual/search/pages_15.html new file mode 100644 index 0000000..3629615 --- /dev/null +++ b/docs/manual/search/pages_15.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_15.js b/docs/manual/search/pages_15.js new file mode 100644 index 0000000..46229f5 --- /dev/null +++ b/docs/manual/search/pages_15.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['your_20first_20script_1873',['Your first script',['../doc_hello_world.html',1,'doc_start']]] +]; diff --git a/docs/manual/search/pages_2.html b/docs/manual/search/pages_2.html new file mode 100644 index 0000000..7029153 --- /dev/null +++ b/docs/manual/search/pages_2.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_2.js b/docs/manual/search/pages_2.js new file mode 100644 index 0000000..47f82dc --- /dev/null +++ b/docs/manual/search/pages_2.js @@ -0,0 +1,19 @@ +var searchData= +[ + ['context_20manager_1742',['Context manager',['../doc_addon_ctxmgr.html',1,'doc_addon_application']]], + ['class_20hierarchies_1743',['Class hierarchies',['../doc_adv_class_hierarchy.html',1,'doc_advanced_api']]], + ['concurrent_20scripts_1744',['Concurrent scripts',['../doc_adv_concurrent.html',1,'doc_advanced']]], + ['co_2droutines_1745',['Co-routines',['../doc_adv_coroutine.html',1,'doc_advanced']]], + ['custom_20options_1746',['Custom options',['../doc_adv_custom_options.html',1,'doc_advanced']]], + ['custom_20array_20type_1747',['Custom array type',['../doc_arrays.html',1,'doc_advanced_api']]], + ['calling_20a_20script_20function_1748',['Calling a script function',['../doc_call_script_func.html',1,'main_topics']]], + ['compile_20the_20library_1749',['Compile the library',['../doc_compile_lib.html',1,'doc_start']]], + ['compiling_20scripts_1750',['Compiling scripts',['../doc_compile_script.html',1,'main_topics']]], + ['c_2b_2b_20exceptions_20and_20longjmp_1751',['C++ exceptions and longjmp',['../doc_cpp_exceptions.html',1,'doc_advanced_api']]], + ['command_20line_20runner_1752',['Command line runner',['../doc_samples_asrun.html',1,'doc_samples']]], + ['concurrent_20scripts_1753',['Concurrent scripts',['../doc_samples_concurrent.html',1,'doc_samples']]], + ['console_1754',['Console',['../doc_samples_console.html',1,'doc_samples']]], + ['co_2droutines_1755',['Co-routines',['../doc_samples_corout.html',1,'doc_samples']]], + ['co_2droutines_1756',['Co-routines',['../doc_script_stdlib_coroutine.html',1,'doc_script_stdlib']]], + ['custom_20string_20type_1757',['Custom string type',['../doc_strings.html',1,'doc_advanced_api']]] +]; diff --git a/docs/manual/search/pages_3.html b/docs/manual/search/pages_3.html new file mode 100644 index 0000000..fce1ba4 --- /dev/null +++ b/docs/manual/search/pages_3.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_3.js b/docs/manual/search/pages_3.js new file mode 100644 index 0000000..9e6af1f --- /dev/null +++ b/docs/manual/search/pages_3.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['datetime_20object_1758',['datetime object',['../doc_addon_datetime.html',1,'doc_addon_script']]], + ['debugger_1759',['Debugger',['../doc_addon_debugger.html',1,'doc_addon_application']]], + ['dictionary_20object_1760',['dictionary object',['../doc_addon_dict.html',1,'doc_addon_script']]], + ['dynamic_20compilations_1761',['Dynamic compilations',['../doc_adv_dynamic_build.html',1,'doc_advanced']]], + ['dynamic_20configurations_1762',['Dynamic configurations',['../doc_adv_dynamic_config.html',1,'doc_advanced']]], + ['datatypes_20in_20angelscript_20and_20c_2b_2b_1763',['Datatypes in AngelScript and C++',['../doc_as_vs_cpp_types.html',1,'doc_understanding_as']]], + ['data_20types_1764',['Data types',['../doc_datatypes.html',1,'doc_script']]], + ['dictionary_1765',['dictionary',['../doc_datatypes_dictionary.html',1,'doc_script_stdlib']]], + ['debugging_20scripts_1766',['Debugging scripts',['../doc_debug.html',1,'doc_advanced']]], + ['default_20arguments_1767',['Default arguments',['../doc_script_func_defarg.html',1,'doc_script_func']]], + ['datetime_1768',['datetime',['../doc_script_stdlib_datetime.html',1,'doc_script_stdlib']]], + ['developer_20manual_1769',['Developer manual',['../main_topics.html',1,'']]] +]; diff --git a/docs/manual/search/pages_4.html b/docs/manual/search/pages_4.html new file mode 100644 index 0000000..6303829 --- /dev/null +++ b/docs/manual/search/pages_4.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_4.js b/docs/manual/search/pages_4.js new file mode 100644 index 0000000..8899d08 --- /dev/null +++ b/docs/manual/search/pages_4.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['exception_20routines_1770',['Exception routines',['../doc_addon_helpers_try.html',1,'doc_addon_script']]], + ['expressions_1771',['Expressions',['../doc_expressions.html',1,'doc_script']]], + ['enums_1772',['Enums',['../doc_global_enums.html',1,'doc_script_global']]], + ['events_1773',['Events',['../doc_samples_events.html',1,'doc_samples']]], + ['exception_20handling_1774',['Exception handling',['../doc_script_stdlib_exception.html',1,'doc_script_stdlib']]] +]; diff --git a/docs/manual/search/pages_5.html b/docs/manual/search/pages_5.html new file mode 100644 index 0000000..adf59e2 --- /dev/null +++ b/docs/manual/search/pages_5.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_5.js b/docs/manual/search/pages_5.js new file mode 100644 index 0000000..48abb97 --- /dev/null +++ b/docs/manual/search/pages_5.js @@ -0,0 +1,15 @@ +var searchData= +[ + ['file_20object_1775',['file object',['../doc_addon_file.html',1,'doc_addon_script']]], + ['filesystem_20object_1776',['filesystem object',['../doc_addon_filesystem.html',1,'doc_addon_script']]], + ['funcdefs_20and_20script_20callback_20functions_1777',['Funcdefs and script callback functions',['../doc_callbacks.html',1,'main_topics']]], + ['function_20handles_1778',['Function handles',['../doc_datatypes_funcptr.html',1,'doc_datatypes']]], + ['fine_20tuning_1779',['Fine tuning',['../doc_finetuning.html',1,'doc_advanced']]], + ['functions_1780',['Functions',['../doc_global_func.html',1,'doc_script_global']]], + ['funcdefs_1781',['Funcdefs',['../doc_global_funcdef.html',1,'doc_script_global']]], + ['functions_1782',['Functions',['../doc_script_func.html',1,'doc_script']]], + ['function_20declaration_1783',['Function declaration',['../doc_script_func_decl.html',1,'doc_script_func']]], + ['function_20overloading_1784',['Function overloading',['../doc_script_func_overload.html',1,'doc_script_func']]], + ['file_1785',['file',['../doc_script_stdlib_file.html',1,'doc_script_stdlib']]], + ['filesystem_1786',['filesystem',['../doc_script_stdlib_filesystem.html',1,'doc_script_stdlib']]] +]; diff --git a/docs/manual/search/pages_6.html b/docs/manual/search/pages_6.html new file mode 100644 index 0000000..575871b --- /dev/null +++ b/docs/manual/search/pages_6.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_6.js b/docs/manual/search/pages_6.js new file mode 100644 index 0000000..2127fbf --- /dev/null +++ b/docs/manual/search/pages_6.js @@ -0,0 +1,11 @@ +var searchData= +[ + ['grid_20template_20object_1787',['grid template object',['../doc_addon_grid.html',1,'doc_addon_script']]], + ['garbage_20collection_1788',['Garbage collection',['../doc_gc.html',1,'doc_advanced']]], + ['garbage_20collected_20objects_1789',['Garbage collected objects',['../doc_gc_object.html',1,'doc_advanced_api']]], + ['good_20practices_1790',['Good practices',['../doc_good_practice.html',1,'doc_start']]], + ['generic_20compiler_1791',['Generic compiler',['../doc_samples_asbuild.html',1,'doc_samples']]], + ['game_1792',['Game',['../doc_samples_game.html',1,'doc_samples']]], + ['global_20entities_1793',['Global entities',['../doc_script_global.html',1,'doc_script']]], + ['getting_20started_1794',['Getting started',['../doc_start.html',1,'main_topics']]] +]; diff --git a/docs/manual/search/pages_7.html b/docs/manual/search/pages_7.html new file mode 100644 index 0000000..c355685 --- /dev/null +++ b/docs/manual/search/pages_7.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_7.js b/docs/manual/search/pages_7.js new file mode 100644 index 0000000..310e18a --- /dev/null +++ b/docs/manual/search/pages_7.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['helper_20functions_1795',['Helper functions',['../doc_addon_helpers.html',1,'doc_addon_application']]], + ['how_20to_20build_20a_20jit_20compiler_1796',['How to build a JIT compiler',['../doc_adv_jit.html',1,'doc_adv_jit_topic']]] +]; diff --git a/docs/manual/search/pages_8.html b/docs/manual/search/pages_8.html new file mode 100644 index 0000000..bb5201a --- /dev/null +++ b/docs/manual/search/pages_8.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_8.js b/docs/manual/search/pages_8.js new file mode 100644 index 0000000..ba47b5c --- /dev/null +++ b/docs/manual/search/pages_8.js @@ -0,0 +1,10 @@ +var searchData= +[ + ['inheriting_20from_20application_20registered_20class_1797',['Inheriting from application registered class',['../doc_adv_inheritappclass.html',1,'doc_advanced']]], + ['imports_1798',['Imports',['../doc_global_import.html',1,'doc_script_global']]], + ['interfaces_1799',['Interfaces',['../doc_global_interface.html',1,'doc_script_global']]], + ['include_20directive_1800',['Include directive',['../doc_samples_incl.html',1,'doc_samples']]], + ['inheritance_20and_20polymorphism_1801',['Inheritance and polymorphism',['../doc_script_class_inheritance.html',1,'doc_script_class']]], + ['initialization_20of_20class_20members_1802',['Initialization of class members',['../doc_script_class_memberinit.html',1,'doc_script_class']]], + ['introduction_1803',['Introduction',['../index.html',1,'']]] +]; diff --git a/docs/manual/search/pages_9.html b/docs/manual/search/pages_9.html new file mode 100644 index 0000000..d1d1170 --- /dev/null +++ b/docs/manual/search/pages_9.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_9.js b/docs/manual/search/pages_9.js new file mode 100644 index 0000000..c5c2cd3 --- /dev/null +++ b/docs/manual/search/pages_9.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['jit_20compilation_1804',['JIT compilation',['../doc_adv_jit_topic.html',1,'doc_advanced']]] +]; diff --git a/docs/manual/search/pages_a.html b/docs/manual/search/pages_a.html new file mode 100644 index 0000000..6c10030 --- /dev/null +++ b/docs/manual/search/pages_a.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_a.js b/docs/manual/search/pages_a.js new file mode 100644 index 0000000..4da920a --- /dev/null +++ b/docs/manual/search/pages_a.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['license_1805',['License',['../doc_license.html',1,'main_topics']]] +]; diff --git a/docs/manual/search/pages_b.html b/docs/manual/search/pages_b.html new file mode 100644 index 0000000..b86cb02 --- /dev/null +++ b/docs/manual/search/pages_b.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_b.js b/docs/manual/search/pages_b.js new file mode 100644 index 0000000..91a5f96 --- /dev/null +++ b/docs/manual/search/pages_b.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['math_20functions_1806',['math functions',['../doc_addon_math.html',1,'doc_addon_script']]], + ['multithreading_1807',['Multithreading',['../doc_adv_multithread.html',1,'doc_advanced']]], + ['memory_20management_1808',['Memory management',['../doc_memory.html',1,'doc_understanding_as']]], + ['mixin_20class_1809',['Mixin class',['../doc_script_mixin.html',1,'doc_script_global']]] +]; diff --git a/docs/manual/search/pages_c.html b/docs/manual/search/pages_c.html new file mode 100644 index 0000000..fd2187f --- /dev/null +++ b/docs/manual/search/pages_c.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_c.js b/docs/manual/search/pages_c.js new file mode 100644 index 0000000..7b0749b --- /dev/null +++ b/docs/manual/search/pages_c.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['namespaces_1810',['Namespaces',['../doc_global_namespace.html',1,'doc_script_global']]] +]; diff --git a/docs/manual/search/pages_d.html b/docs/manual/search/pages_d.html new file mode 100644 index 0000000..af21932 --- /dev/null +++ b/docs/manual/search/pages_d.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_d.js b/docs/manual/search/pages_d.js new file mode 100644 index 0000000..cb3a108 --- /dev/null +++ b/docs/manual/search/pages_d.js @@ -0,0 +1,9 @@ +var searchData= +[ + ['objects_20and_20handles_1811',['Objects and handles',['../doc_datatypes_obj.html',1,'doc_datatypes']]], + ['object_20handles_20to_20the_20application_1812',['Object handles to the application',['../doc_obj_handle.html',1,'doc_understanding_as']]], + ['operator_20precedence_1813',['Operator precedence',['../doc_operator_precedence.html',1,'doc_script']]], + ['overview_1814',['Overview',['../doc_overview.html',1,'doc_start']]], + ['operator_20overloads_1815',['Operator overloads',['../doc_script_class_ops.html',1,'doc_script_class']]], + ['object_20handles_1816',['Object handles',['../doc_script_handle.html',1,'doc_script']]] +]; diff --git a/docs/manual/search/pages_e.html b/docs/manual/search/pages_e.html new file mode 100644 index 0000000..4bee32a --- /dev/null +++ b/docs/manual/search/pages_e.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_e.js b/docs/manual/search/pages_e.js new file mode 100644 index 0000000..f2d0736 --- /dev/null +++ b/docs/manual/search/pages_e.js @@ -0,0 +1,8 @@ +var searchData= +[ + ['pre_2dcompiled_20byte_20code_1817',['Pre-compiled byte code',['../doc_adv_precompile.html',1,'doc_advanced']]], + ['primitives_1818',['Primitives',['../doc_datatypes_primitives.html',1,'doc_datatypes']]], + ['protected_20and_20private_20class_20members_1819',['Protected and private class members',['../doc_script_class_private.html',1,'doc_script_class']]], + ['property_20accessors_1820',['Property accessors',['../doc_script_class_prop.html',1,'doc_script_class']]], + ['parameter_20references_1821',['Parameter references',['../doc_script_func_ref.html',1,'doc_script_func']]] +]; diff --git a/docs/manual/search/pages_f.html b/docs/manual/search/pages_f.html new file mode 100644 index 0000000..8b36eef --- /dev/null +++ b/docs/manual/search/pages_f.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/pages_f.js b/docs/manual/search/pages_f.js new file mode 100644 index 0000000..1d54baa --- /dev/null +++ b/docs/manual/search/pages_f.js @@ -0,0 +1,20 @@ +var searchData= +[ + ['ref_20object_1822',['ref object',['../doc_addon_handle.html',1,'doc_addon_script']]], + ['registering_20a_20generic_20handle_20type_1823',['Registering a generic handle type',['../doc_adv_generic_handle.html',1,'doc_advanced_api']]], + ['reflection_1824',['Reflection',['../doc_adv_reflection.html',1,'doc_advanced']]], + ['registering_20a_20scoped_20reference_20type_1825',['Registering a scoped reference type',['../doc_adv_scoped_type.html',1,'doc_advanced_api']]], + ['registering_20a_20single_2dreference_20type_1826',['Registering a single-reference type',['../doc_adv_single_ref_type.html',1,'doc_advanced_api']]], + ['ref_1827',['ref',['../doc_datatypes_ref.html',1,'doc_script_stdlib']]], + ['registering_20a_20reference_20type_1828',['Registering a reference type',['../doc_reg_basicref.html',1,'doc_register_type']]], + ['registering_20object_20methods_1829',['Registering object methods',['../doc_reg_objmeth.html',1,'doc_register_type']]], + ['registering_20object_20properties_1830',['Registering object properties',['../doc_reg_objprop.html',1,'doc_register_type']]], + ['registering_20operator_20behaviours_1831',['Registering operator behaviours',['../doc_reg_opbeh.html',1,'doc_register_type']]], + ['registering_20the_20application_20interface_1832',['Registering the application interface',['../doc_register_api_topic.html',1,'main_topics']]], + ['registering_20a_20function_1833',['Registering a function',['../doc_register_func.html',1,'doc_register_api_topic']]], + ['registering_20global_20properties_1834',['Registering global properties',['../doc_register_prop.html',1,'doc_register_api_topic']]], + ['registering_20an_20object_20type_1835',['Registering an object type',['../doc_register_type.html',1,'doc_register_api_topic']]], + ['registering_20a_20value_20type_1836',['Registering a value type',['../doc_register_val_type.html',1,'doc_register_type']]], + ['reserved_20keywords_20and_20tokens_1837',['Reserved keywords and tokens',['../doc_reserved_keywords.html',1,'doc_script']]], + ['return_20references_1838',['Return references',['../doc_script_func_retref.html',1,'doc_script_func']]] +]; diff --git a/docs/manual/search/search.css b/docs/manual/search/search.css new file mode 100644 index 0000000..a0dba44 --- /dev/null +++ b/docs/manual/search/search.css @@ -0,0 +1,273 @@ +/*---------------- Search Box */ + +#FSearchBox { + float: left; +} + +#MSearchBox { + white-space : nowrap; + float: none; + margin-top: 0px; + right: 0px; + width: 170px; + height: 24px; + z-index: 102; + display: inline; + position: absolute; +} + +#MSearchBox .left +{ + display:block; + position:absolute; + left:10px; + width:20px; + height:19px; + background:url('search_l.png') no-repeat; + background-position:right; +} + +#MSearchSelect { + display:block; + position:absolute; + width:20px; + height:19px; +} + +.left #MSearchSelect { + left:4px; +} + +.right #MSearchSelect { + right:5px; +} + +#MSearchField { + display:block; + position:absolute; + height:19px; + background:url('search_m.png') repeat-x; + border:none; + width:111px; + margin-left:20px; + padding-left:4px; + color: #909090; + outline: none; + font: 9pt Arial, Verdana, sans-serif; + -webkit-border-radius: 0px; +} + +#FSearchBox #MSearchField { + margin-left:15px; +} + +#MSearchBox .right { + display:block; + position:absolute; + right:10px; + top:0px; + width:20px; + height:19px; + background:url('search_r.png') no-repeat; + background-position:left; +} + +#MSearchClose { + display: none; + position: absolute; + top: 4px; + background : none; + border: none; + margin: 0px 4px 0px 0px; + padding: 0px 0px; + outline: none; +} + +.left #MSearchClose { + left: 6px; +} + +.right #MSearchClose { + right: 2px; +} + +.MSearchBoxActive #MSearchField { + color: #000000; +} + +/*---------------- Search filter selection */ + +#MSearchSelectWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #90A5CE; + background-color: #F9FAFC; + z-index: 10001; + padding-top: 4px; + padding-bottom: 4px; + -moz-border-radius: 4px; + -webkit-border-top-left-radius: 4px; + -webkit-border-top-right-radius: 4px; + -webkit-border-bottom-left-radius: 4px; + -webkit-border-bottom-right-radius: 4px; + -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); +} + +.SelectItem { + font: 8pt Arial, Verdana, sans-serif; + padding-left: 2px; + padding-right: 12px; + border: 0px; +} + +span.SelectionMark { + margin-right: 4px; + font-family: monospace; + outline-style: none; + text-decoration: none; +} + +a.SelectItem { + display: block; + outline-style: none; + color: #000000; + text-decoration: none; + padding-left: 6px; + padding-right: 12px; +} + +a.SelectItem:focus, +a.SelectItem:active { + color: #000000; + outline-style: none; + text-decoration: none; +} + +a.SelectItem:hover { + color: #FFFFFF; + background-color: #3D578C; + outline-style: none; + text-decoration: none; + cursor: pointer; + display: block; +} + +/*---------------- Search results window */ + +iframe#MSearchResults { + width: 60ex; + height: 15em; +} + +#MSearchResultsWindow { + display: none; + position: absolute; + left: 0; top: 0; + border: 1px solid #000; + background-color: #EEF1F7; + z-index:10000; +} + +/* ----------------------------------- */ + + +#SRIndex { + clear:both; + padding-bottom: 15px; +} + +.SREntry { + font-size: 10pt; + padding-left: 1ex; +} + +.SRPage .SREntry { + font-size: 8pt; + padding: 1px 5px; +} + +body.SRPage { + margin: 5px 2px; +} + +.SRChildren { + padding-left: 3ex; padding-bottom: .5em +} + +.SRPage .SRChildren { + display: none; +} + +.SRSymbol { + font-weight: bold; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRScope { + display: block; + color: #425E97; + font-family: Arial, Verdana, sans-serif; + text-decoration: none; + outline: none; +} + +a.SRSymbol:focus, a.SRSymbol:active, +a.SRScope:focus, a.SRScope:active { + text-decoration: underline; +} + +span.SRScope { + padding-left: 4px; +} + +.SRPage .SRStatus { + padding: 2px 5px; + font-size: 8pt; + font-style: italic; +} + +.SRResult { + display: none; +} + +DIV.searchresults { + margin-left: 10px; + margin-right: 10px; +} + +/*---------------- External search page results */ + +.searchresult { + background-color: #F0F3F8; +} + +.pages b { + color: white; + padding: 5px 5px 3px 5px; + background-image: url("../tab_a.png"); + background-repeat: repeat-x; + text-shadow: 0 1px 1px #000000; +} + +.pages { + line-height: 17px; + margin-left: 4px; + text-decoration: none; +} + +.hl { + font-weight: bold; +} + +#searchresults { + margin-bottom: 20px; +} + +.searchpages { + margin-top: 10px; +} + diff --git a/docs/manual/search/search.js b/docs/manual/search/search.js new file mode 100644 index 0000000..ff2b8c8 --- /dev/null +++ b/docs/manual/search/search.js @@ -0,0 +1,814 @@ +/* + @licstart The following is the entire license notice for the JavaScript code in this file. + + The MIT License (MIT) + + Copyright (C) 1997-2020 by Dimitri van Heesch + + Permission is hereby granted, free of charge, to any person obtaining a copy of this software + and associated documentation files (the "Software"), to deal in the Software without restriction, + including without limitation the rights to use, copy, modify, merge, publish, distribute, + sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice shall be included in all copies or + substantial portions of the Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + @licend The above is the entire license notice for the JavaScript code in this file + */ +function convertToId(search) +{ + var result = ''; + for (i=0;i do a search + { + this.Search(); + } + } + + this.OnSearchSelectKey = function(evt) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==40 && this.searchIndex0) // Up + { + this.searchIndex--; + this.OnSelectItem(this.searchIndex); + } + else if (e.keyCode==13 || e.keyCode==27) + { + this.OnSelectItem(this.searchIndex); + this.CloseSelectionWindow(); + this.DOMSearchField().focus(); + } + return false; + } + + // --------- Actions + + // Closes the results window. + this.CloseResultsWindow = function() + { + this.DOMPopupSearchResultsWindow().style.display = 'none'; + this.DOMSearchClose().style.display = 'none'; + this.Activate(false); + } + + this.CloseSelectionWindow = function() + { + this.DOMSearchSelectWindow().style.display = 'none'; + } + + // Performs a search. + this.Search = function() + { + this.keyTimeout = 0; + + // strip leading whitespace + var searchValue = this.DOMSearchField().value.replace(/^ +/, ""); + + var code = searchValue.toLowerCase().charCodeAt(0); + var idxChar = searchValue.substr(0, 1).toLowerCase(); + if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1) // surrogate pair + { + idxChar = searchValue.substr(0, 2); + } + + var resultsPage; + var resultsPageWithSearch; + var hasResultsPage; + + var idx = indexSectionsWithContent[this.searchIndex].indexOf(idxChar); + if (idx!=-1) + { + var hexCode=idx.toString(16); + resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html'; + resultsPageWithSearch = resultsPage+'?'+escape(searchValue); + hasResultsPage = true; + } + else // nothing available for this search term + { + resultsPage = this.resultsPath + '/nomatches.html'; + resultsPageWithSearch = resultsPage; + hasResultsPage = false; + } + + window.frames.MSearchResults.location = resultsPageWithSearch; + var domPopupSearchResultsWindow = this.DOMPopupSearchResultsWindow(); + + if (domPopupSearchResultsWindow.style.display!='block') + { + var domSearchBox = this.DOMSearchBox(); + this.DOMSearchClose().style.display = 'inline'; + if (this.insideFrame) + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + domPopupSearchResultsWindow.style.position = 'relative'; + domPopupSearchResultsWindow.style.display = 'block'; + var width = document.body.clientWidth - 8; // the -8 is for IE :-( + domPopupSearchResultsWindow.style.width = width + 'px'; + domPopupSearchResults.style.width = width + 'px'; + } + else + { + var domPopupSearchResults = this.DOMPopupSearchResults(); + var left = getXPos(domSearchBox) + 150; // domSearchBox.offsetWidth; + var top = getYPos(domSearchBox) + 20; // domSearchBox.offsetHeight + 1; + domPopupSearchResultsWindow.style.display = 'block'; + left -= domPopupSearchResults.offsetWidth; + domPopupSearchResultsWindow.style.top = top + 'px'; + domPopupSearchResultsWindow.style.left = left + 'px'; + } + } + + this.lastSearchValue = searchValue; + this.lastResultsPage = resultsPage; + } + + // -------- Activation Functions + + // Activates or deactivates the search panel, resetting things to + // their default values if necessary. + this.Activate = function(isActive) + { + if (isActive || // open it + this.DOMPopupSearchResultsWindow().style.display == 'block' + ) + { + this.DOMSearchBox().className = 'MSearchBoxActive'; + + var searchField = this.DOMSearchField(); + + if (searchField.value == this.searchLabel) // clear "Search" term upon entry + { + searchField.value = ''; + this.searchActive = true; + } + } + else if (!isActive) // directly remove the panel + { + this.DOMSearchBox().className = 'MSearchBoxInactive'; + this.DOMSearchField().value = this.searchLabel; + this.searchActive = false; + this.lastSearchValue = '' + this.lastResultsPage = ''; + } + } +} + +// ----------------------------------------------------------------------- + +// The class that handles everything on the search results page. +function SearchResults(name) +{ + // The number of matches from the last run of . + this.lastMatchCount = 0; + this.lastKey = 0; + this.repeatOn = false; + + // Toggles the visibility of the passed element ID. + this.FindChildElement = function(id) + { + var parentElement = document.getElementById(id); + var element = parentElement.firstChild; + + while (element && element!=parentElement) + { + if (element.nodeName == 'DIV' && element.className == 'SRChildren') + { + return element; + } + + if (element.nodeName == 'DIV' && element.hasChildNodes()) + { + element = element.firstChild; + } + else if (element.nextSibling) + { + element = element.nextSibling; + } + else + { + do + { + element = element.parentNode; + } + while (element && element!=parentElement && !element.nextSibling); + + if (element && element!=parentElement) + { + element = element.nextSibling; + } + } + } + } + + this.Toggle = function(id) + { + var element = this.FindChildElement(id); + if (element) + { + if (element.style.display == 'block') + { + element.style.display = 'none'; + } + else + { + element.style.display = 'block'; + } + } + } + + // Searches for the passed string. If there is no parameter, + // it takes it from the URL query. + // + // Always returns true, since other documents may try to call it + // and that may or may not be possible. + this.Search = function(search) + { + if (!search) // get search word from URL + { + search = window.location.search; + search = search.substring(1); // Remove the leading '?' + search = unescape(search); + } + + search = search.replace(/^ +/, ""); // strip leading spaces + search = search.replace(/ +$/, ""); // strip trailing spaces + search = search.toLowerCase(); + search = convertToId(search); + + var resultRows = document.getElementsByTagName("div"); + var matches = 0; + + var i = 0; + while (i < resultRows.length) + { + var row = resultRows.item(i); + if (row.className == "SRResult") + { + var rowMatchName = row.id.toLowerCase(); + rowMatchName = rowMatchName.replace(/^sr\d*_/, ''); // strip 'sr123_' + + if (search.length<=rowMatchName.length && + rowMatchName.substr(0, search.length)==search) + { + row.style.display = 'block'; + matches++; + } + else + { + row.style.display = 'none'; + } + } + i++; + } + document.getElementById("Searching").style.display='none'; + if (matches == 0) // no results + { + document.getElementById("NoMatches").style.display='block'; + } + else // at least one result + { + document.getElementById("NoMatches").style.display='none'; + } + this.lastMatchCount = matches; + return true; + } + + // return the first item with index index or higher that is visible + this.NavNext = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index++; + } + return focusItem; + } + + this.NavPrev = function(index) + { + var focusItem; + while (1) + { + var focusName = 'Item'+index; + focusItem = document.getElementById(focusName); + if (focusItem && focusItem.parentNode.parentNode.style.display=='block') + { + break; + } + else if (!focusItem) // last element + { + break; + } + focusItem=null; + index--; + } + return focusItem; + } + + this.ProcessKeys = function(e) + { + if (e.type == "keydown") + { + this.repeatOn = false; + this.lastKey = e.keyCode; + } + else if (e.type == "keypress") + { + if (!this.repeatOn) + { + if (this.lastKey) this.repeatOn = true; + return false; // ignore first keypress after keydown + } + } + else if (e.type == "keyup") + { + this.lastKey = 0; + this.repeatOn = false; + } + return this.lastKey!=0; + } + + this.Nav = function(evt,itemIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + var newIndex = itemIndex-1; + var focusItem = this.NavPrev(newIndex); + if (focusItem) + { + var child = this.FindChildElement(focusItem.parentNode.parentNode.id); + if (child && child.style.display == 'block') // children visible + { + var n=0; + var tmpElem; + while (1) // search for last child + { + tmpElem = document.getElementById('Item'+newIndex+'_c'+n); + if (tmpElem) + { + focusItem = tmpElem; + } + else // found it! + { + break; + } + n++; + } + } + } + if (focusItem) + { + focusItem.focus(); + } + else // return focus to search field + { + parent.document.getElementById("MSearchField").focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = itemIndex+1; + var focusItem; + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem && elem.style.display == 'block') // children visible + { + focusItem = document.getElementById('Item'+itemIndex+'_c0'); + } + if (!focusItem) focusItem = this.NavNext(newIndex); + if (focusItem) focusItem.focus(); + } + else if (this.lastKey==39) // Right + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'block'; + } + else if (this.lastKey==37) // Left + { + var item = document.getElementById('Item'+itemIndex); + var elem = this.FindChildElement(item.parentNode.parentNode.id); + if (elem) elem.style.display = 'none'; + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } + + this.NavChild = function(evt,itemIndex,childIndex) + { + var e = (evt) ? evt : window.event; // for IE + if (e.keyCode==13) return true; + if (!this.ProcessKeys(e)) return false; + + if (this.lastKey==38) // Up + { + if (childIndex>0) + { + var newIndex = childIndex-1; + document.getElementById('Item'+itemIndex+'_c'+newIndex).focus(); + } + else // already at first child, jump to parent + { + document.getElementById('Item'+itemIndex).focus(); + } + } + else if (this.lastKey==40) // Down + { + var newIndex = childIndex+1; + var elem = document.getElementById('Item'+itemIndex+'_c'+newIndex); + if (!elem) // last child, jump to parent next parent + { + elem = this.NavNext(itemIndex+1); + } + if (elem) + { + elem.focus(); + } + } + else if (this.lastKey==27) // Escape + { + parent.searchBox.CloseResultsWindow(); + parent.document.getElementById("MSearchField").focus(); + } + else if (this.lastKey==13) // Enter + { + return true; + } + return false; + } +} + +function setKeyActions(elem,action) +{ + elem.setAttribute('onkeydown',action); + elem.setAttribute('onkeypress',action); + elem.setAttribute('onkeyup',action); +} + +function setClassAttr(elem,attr) +{ + elem.setAttribute('class',attr); + elem.setAttribute('className',attr); +} + +function createResults() +{ + var results = document.getElementById("SRResults"); + for (var e=0; e + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/typedefs_0.js b/docs/manual/search/typedefs_0.js new file mode 100644 index 0000000..7d7d01e --- /dev/null +++ b/docs/manual/search/typedefs_0.js @@ -0,0 +1,24 @@ +var searchData= +[ + ['asallocfunc_5ft_1259',['asALLOCFUNC_t',['../angelscript_8h.html#ac69a827822c73771cd972bff270cefc7',1,'angelscript.h']]], + ['asbyte_1260',['asBYTE',['../angelscript_8h.html#a48b3da7121b3abb56bff63b3beb0df63',1,'angelscript.h']]], + ['ascircularreffunc_5ft_1261',['asCIRCULARREFFUNC_t',['../angelscript_8h.html#ad39eb868abeebf44bb67fd3965f8bc5f',1,'angelscript.h']]], + ['ascleancontextfunc_5ft_1262',['asCLEANCONTEXTFUNC_t',['../angelscript_8h.html#a761b892984e5af51e0f6e37c27dfadb6',1,'angelscript.h']]], + ['ascleanenginefunc_5ft_1263',['asCLEANENGINEFUNC_t',['../angelscript_8h.html#aa3dd561bcccb3d5e4966966d7eb2715c',1,'angelscript.h']]], + ['ascleanfunctionfunc_5ft_1264',['asCLEANFUNCTIONFUNC_t',['../angelscript_8h.html#a6c0fcc7fee72733c9feb03c0bbf8f5d6',1,'angelscript.h']]], + ['ascleanmodulefunc_5ft_1265',['asCLEANMODULEFUNC_t',['../angelscript_8h.html#a5a01d6871440c3b6261da54a8308c452',1,'angelscript.h']]], + ['ascleanscriptobjectfunc_5ft_1266',['asCLEANSCRIPTOBJECTFUNC_t',['../angelscript_8h.html#ab89ff127aa05aef3793646b377e9c724',1,'angelscript.h']]], + ['ascleantypeinfofunc_5ft_1267',['asCLEANTYPEINFOFUNC_t',['../angelscript_8h.html#aca9bfb1e5a93426df269bd10d88e5cb3',1,'angelscript.h']]], + ['asdword_1268',['asDWORD',['../angelscript_8h.html#a5428f0c940201e5f3bbb28304aeb81bc',1,'angelscript.h']]], + ['asfreefunc_5ft_1269',['asFREEFUNC_t',['../angelscript_8h.html#adeecc934971e695fc4441a47694860fb',1,'angelscript.h']]], + ['asint16_1270',['asINT16',['../angelscript_8h.html#afd9f62d6b3a975d02b22432f7a923f83',1,'angelscript.h']]], + ['asint64_1271',['asINT64',['../angelscript_8h.html#aa8044b56ee56e2350b06f1e7207b43df',1,'angelscript.h']]], + ['asint8_1272',['asINT8',['../angelscript_8h.html#a2b6922ec0cb3785c6c2328afa7bd9a9b',1,'angelscript.h']]], + ['asjitfunction_1273',['asJITFunction',['../angelscript_8h.html#af9d3986a33c1bda5c4f82a7aaa0dfeeb',1,'angelscript.h']]], + ['aspword_1274',['asPWORD',['../angelscript_8h.html#a76fc6994aba7ff6c685a62c273c057e3',1,'angelscript.h']]], + ['asqword_1275',['asQWORD',['../angelscript_8h.html#a10aea5de212e440ffd6ec8fc0b17563d',1,'angelscript.h']]], + ['asrequestcontextfunc_5ft_1276',['asREQUESTCONTEXTFUNC_t',['../angelscript_8h.html#a2925360becae92319e68abb23a61fd56',1,'angelscript.h']]], + ['asreturncontextfunc_5ft_1277',['asRETURNCONTEXTFUNC_t',['../angelscript_8h.html#a3ffcfca5bd3be4f4c633408a6b209476',1,'angelscript.h']]], + ['asuint_1278',['asUINT',['../angelscript_8h.html#ac8186f029686800b7ce36bde4a55c815',1,'angelscript.h']]], + ['asword_1279',['asWORD',['../angelscript_8h.html#a340da175136fbe283932fa3c3442cea0',1,'angelscript.h']]] +]; diff --git a/docs/manual/search/variables_0.html b/docs/manual/search/variables_0.html new file mode 100644 index 0000000..9ce246b --- /dev/null +++ b/docs/manual/search/variables_0.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_0.js b/docs/manual/search/variables_0.js new file mode 100644 index 0000000..e69677c --- /dev/null +++ b/docs/manual/search/variables_0.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['asbcinfo_1241',['asBCInfo',['../angelscript_8h.html#ac58d23b688ddd6d6e788b034daf25df7',1,'angelscript.h']]], + ['asbctypesize_1242',['asBCTypeSize',['../angelscript_8h.html#a9f93754a6f4d43118cd0d2b3896875a5',1,'angelscript.h']]] +]; diff --git a/docs/manual/search/variables_1.html b/docs/manual/search/variables_1.html new file mode 100644 index 0000000..5802cec --- /dev/null +++ b/docs/manual/search/variables_1.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_1.js b/docs/manual/search/variables_1.js new file mode 100644 index 0000000..1d59934 --- /dev/null +++ b/docs/manual/search/variables_1.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['bc_1243',['bc',['../structas_s_b_c_info.html#a44543d80233f6d2158b300e7049e23ab',1,'asSBCInfo']]] +]; diff --git a/docs/manual/search/variables_2.html b/docs/manual/search/variables_2.html new file mode 100644 index 0000000..00291e5 --- /dev/null +++ b/docs/manual/search/variables_2.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_2.js b/docs/manual/search/variables_2.js new file mode 100644 index 0000000..41756dd --- /dev/null +++ b/docs/manual/search/variables_2.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['col_1244',['col',['../structas_s_message_info.html#a08b23a360ac52110323bbf4aad553d9d',1,'asSMessageInfo']]], + ['ctx_1245',['ctx',['../structas_s_v_m_registers.html#aaaf2063a2786459281f9426f5083f8d1',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/search/variables_3.html b/docs/manual/search/variables_3.html new file mode 100644 index 0000000..0e5389b --- /dev/null +++ b/docs/manual/search/variables_3.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_3.js b/docs/manual/search/variables_3.js new file mode 100644 index 0000000..29d7903 --- /dev/null +++ b/docs/manual/search/variables_3.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['doprocesssuspend_1246',['doProcessSuspend',['../structas_s_v_m_registers.html#ae1fe3cb6cbcf870cfde3364e66909e4f',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/search/variables_4.html b/docs/manual/search/variables_4.html new file mode 100644 index 0000000..789a86b --- /dev/null +++ b/docs/manual/search/variables_4.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_4.js b/docs/manual/search/variables_4.js new file mode 100644 index 0000000..eec967a --- /dev/null +++ b/docs/manual/search/variables_4.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['message_1247',['message',['../structas_s_message_info.html#af76694c6342dd82ef6aca0dff42072f5',1,'asSMessageInfo']]] +]; diff --git a/docs/manual/search/variables_5.html b/docs/manual/search/variables_5.html new file mode 100644 index 0000000..c7873eb --- /dev/null +++ b/docs/manual/search/variables_5.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_5.js b/docs/manual/search/variables_5.js new file mode 100644 index 0000000..cfe73c3 --- /dev/null +++ b/docs/manual/search/variables_5.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['name_1248',['name',['../structas_s_b_c_info.html#a0fec180d222e297a574000aa64bd3af5',1,'asSBCInfo']]] +]; diff --git a/docs/manual/search/variables_6.html b/docs/manual/search/variables_6.html new file mode 100644 index 0000000..a588588 --- /dev/null +++ b/docs/manual/search/variables_6.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_6.js b/docs/manual/search/variables_6.js new file mode 100644 index 0000000..075237c --- /dev/null +++ b/docs/manual/search/variables_6.js @@ -0,0 +1,5 @@ +var searchData= +[ + ['objectregister_1249',['objectRegister',['../structas_s_v_m_registers.html#a12e6c46db50443d8f7faeec71abf42f7',1,'asSVMRegisters']]], + ['objecttype_1250',['objectType',['../structas_s_v_m_registers.html#a6b6463e377e4f83bb8bd7b9afb3abb02',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/search/variables_7.html b/docs/manual/search/variables_7.html new file mode 100644 index 0000000..b09b295 --- /dev/null +++ b/docs/manual/search/variables_7.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_7.js b/docs/manual/search/variables_7.js new file mode 100644 index 0000000..0710e21 --- /dev/null +++ b/docs/manual/search/variables_7.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['programpointer_1251',['programPointer',['../structas_s_v_m_registers.html#abacce81d44b2387a2b66549bcba47643',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/search/variables_8.html b/docs/manual/search/variables_8.html new file mode 100644 index 0000000..a479f8e --- /dev/null +++ b/docs/manual/search/variables_8.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_8.js b/docs/manual/search/variables_8.js new file mode 100644 index 0000000..d2f07f9 --- /dev/null +++ b/docs/manual/search/variables_8.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['row_1252',['row',['../structas_s_message_info.html#a21ef80321436f229a547411a6598ea21',1,'asSMessageInfo']]] +]; diff --git a/docs/manual/search/variables_9.html b/docs/manual/search/variables_9.html new file mode 100644 index 0000000..97cc440 --- /dev/null +++ b/docs/manual/search/variables_9.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_9.js b/docs/manual/search/variables_9.js new file mode 100644 index 0000000..92027e4 --- /dev/null +++ b/docs/manual/search/variables_9.js @@ -0,0 +1,7 @@ +var searchData= +[ + ['section_1253',['section',['../structas_s_message_info.html#aeca6368be12c84b62ed8c659b1e4615c',1,'asSMessageInfo']]], + ['stackframepointer_1254',['stackFramePointer',['../structas_s_v_m_registers.html#ab1d0ebdb2e9b1b57320ade00beaf229b',1,'asSVMRegisters']]], + ['stackinc_1255',['stackInc',['../structas_s_b_c_info.html#afa46372104c863ec52c4f6c5e33eba89',1,'asSBCInfo']]], + ['stackpointer_1256',['stackPointer',['../structas_s_v_m_registers.html#abb79cddcc4d38d286f221f2b4d323ab6',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/search/variables_a.html b/docs/manual/search/variables_a.html new file mode 100644 index 0000000..0107448 --- /dev/null +++ b/docs/manual/search/variables_a.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_a.js b/docs/manual/search/variables_a.js new file mode 100644 index 0000000..e0f72b2 --- /dev/null +++ b/docs/manual/search/variables_a.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['type_1257',['type',['../structas_s_message_info.html#a6aa9231534b8aea2a3099cdc3206bcc8',1,'asSMessageInfo::type()'],['../structas_s_b_c_info.html#aa0579956f325760177250e0eddd52ab4',1,'asSBCInfo::type()']]] +]; diff --git a/docs/manual/search/variables_b.html b/docs/manual/search/variables_b.html new file mode 100644 index 0000000..e5b2fd9 --- /dev/null +++ b/docs/manual/search/variables_b.html @@ -0,0 +1,36 @@ + + + + + + + + + +
+
Loading...
+
+ +
Searching...
+
No Matches
+ +
+ + diff --git a/docs/manual/search/variables_b.js b/docs/manual/search/variables_b.js new file mode 100644 index 0000000..d0065f9 --- /dev/null +++ b/docs/manual/search/variables_b.js @@ -0,0 +1,4 @@ +var searchData= +[ + ['valueregister_1258',['valueRegister',['../structas_s_v_m_registers.html#aa87c457f97ce8e49fd808c8b6fd8e9d8',1,'asSVMRegisters']]] +]; diff --git a/docs/manual/splitbar.png b/docs/manual/splitbar.png new file mode 100644 index 0000000..fe895f2 Binary files /dev/null and b/docs/manual/splitbar.png differ diff --git a/docs/manual/structas_s_b_c_info-members.html b/docs/manual/structas_s_b_c_info-members.html new file mode 100644 index 0000000..883617d --- /dev/null +++ b/docs/manual/structas_s_b_c_info-members.html @@ -0,0 +1,117 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asSBCInfo Member List
+
+
+ +

This is the complete list of members for asSBCInfo, including all inherited members.

+ + + + + +
bcasSBCInfo
nameasSBCInfo
stackIncasSBCInfo
typeasSBCInfo
+
+ + + + diff --git a/docs/manual/structas_s_b_c_info.html b/docs/manual/structas_s_b_c_info.html new file mode 100644 index 0000000..c7b12a2 --- /dev/null +++ b/docs/manual/structas_s_b_c_info.html @@ -0,0 +1,144 @@ + + + + + + + +AngelScript: asSBCInfo Struct Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asSBCInfo Struct Reference
+
+
+ +

Information on a bytecode instruction. + More...

+ + + + + + + + + + + + + + +

+Public Attributes

+asEBCInstr bc
 Bytecode instruction id.
 
+asEBCType type
 Instruction argument layout.
 
+int stackInc
 How much this argument increments the stack pointer. 0xFFFF if it depends on the arguments.
 
+const char * name
 Name of the instruction for debugging.
 
+

Detailed Description

+

This structure can be obtained for each bytecode instruction by looking it up in the asBCInfo array.

+

The size of the instruction can be obtained by looking up the type in the asBCTypeSize array.

+
See also
How to build a JIT compiler
+

The documentation for this struct was generated from the following file: +
+
+ + + + diff --git a/docs/manual/structas_s_func_ptr-members.html b/docs/manual/structas_s_func_ptr-members.html new file mode 100644 index 0000000..31d618f --- /dev/null +++ b/docs/manual/structas_s_func_ptr-members.html @@ -0,0 +1,112 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asSFuncPtr Member List
+
+
+ +

This is the complete list of members for asSFuncPtr, including all inherited members.

+
+
+ + + + diff --git a/docs/manual/structas_s_func_ptr.html b/docs/manual/structas_s_func_ptr.html new file mode 100644 index 0000000..34550d1 --- /dev/null +++ b/docs/manual/structas_s_func_ptr.html @@ -0,0 +1,119 @@ + + + + + + + +AngelScript: asSFuncPtr Struct Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asSFuncPtr Struct Reference
+
+
+ +

Represents a function or method pointer. +

+
The documentation for this struct was generated from the following file: +
+
+ + + + diff --git a/docs/manual/structas_s_message_info-members.html b/docs/manual/structas_s_message_info-members.html new file mode 100644 index 0000000..d5cd384 --- /dev/null +++ b/docs/manual/structas_s_message_info-members.html @@ -0,0 +1,118 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asSMessageInfo Member List
+
+
+ +

This is the complete list of members for asSMessageInfo, including all inherited members.

+ + + + + + +
colasSMessageInfo
messageasSMessageInfo
rowasSMessageInfo
sectionasSMessageInfo
typeasSMessageInfo
+
+ + + + diff --git a/docs/manual/structas_s_message_info.html b/docs/manual/structas_s_message_info.html new file mode 100644 index 0000000..e869cf7 --- /dev/null +++ b/docs/manual/structas_s_message_info.html @@ -0,0 +1,144 @@ + + + + + + + +AngelScript: asSMessageInfo Struct Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asSMessageInfo Struct Reference
+
+
+ +

Represents a compiler message. +

+ + + + + + + + + + + + + + + + + +

+Public Attributes

+const char * section
 The script section where the message is raised.
 
+int row
 The row number.
 
+int col
 The column.
 
+asEMsgType type
 The type of message.
 
+const char * message
 The message text.
 
+
The documentation for this struct was generated from the following file: +
+
+ + + + diff --git a/docs/manual/structas_s_v_m_registers-members.html b/docs/manual/structas_s_v_m_registers-members.html new file mode 100644 index 0000000..737537d --- /dev/null +++ b/docs/manual/structas_s_v_m_registers-members.html @@ -0,0 +1,121 @@ + + + + + + + +AngelScript: Member List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
asSVMRegisters Member List
+
+ +
+ + + + diff --git a/docs/manual/structas_s_v_m_registers.html b/docs/manual/structas_s_v_m_registers.html new file mode 100644 index 0000000..438cf28 --- /dev/null +++ b/docs/manual/structas_s_v_m_registers.html @@ -0,0 +1,159 @@ + + + + + + + +AngelScript: asSVMRegisters Struct Reference + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+ +
+
asSVMRegisters Struct Reference
+
+
+ +

A struct with registers from the VM sent to a JIT compiled function. + More...

+ + + + + + + + + + + + + + + + + + + + + + + + + + +

+Public Attributes

+asDWORDprogramPointer
 Points to the current bytecode instruction.
 
+asDWORDstackFramePointer
 Function stack frame. This doesn't change during the function execution.
 
+asDWORDstackPointer
 Top of the stack (grows downward)
 
+asQWORD valueRegister
 Temporary register for primitives and unmanaged references.
 
+void * objectRegister
 Temporary register for managed object references/handles.
 
+asITypeInfoobjectType
 Type of the object held in the object register.
 
+bool doProcessSuspend
 Set to true if the SUSPEND instruction should be processed. Do not update this value.
 
+asIScriptContextctx
 The context to which the registers belong.
 
+

Detailed Description

+

The JIT compiled function will receive a pointer to this structure when called. It is the responsibility of the JIT compiled function to make sure these values are updated correctly before control is returned to the VM.

+
See also
How to build a JIT compiler
+

The documentation for this struct was generated from the following file: +
+
+ + + + diff --git a/docs/manual/sync_off.png b/docs/manual/sync_off.png new file mode 100644 index 0000000..3b443fc Binary files /dev/null and b/docs/manual/sync_off.png differ diff --git a/docs/manual/sync_on.png b/docs/manual/sync_on.png new file mode 100644 index 0000000..e08320f Binary files /dev/null and b/docs/manual/sync_on.png differ diff --git a/docs/manual/tab_a.png b/docs/manual/tab_a.png new file mode 100644 index 0000000..3b725c4 Binary files /dev/null and b/docs/manual/tab_a.png differ diff --git a/docs/manual/tab_b.png b/docs/manual/tab_b.png new file mode 100644 index 0000000..e2b4a86 Binary files /dev/null and b/docs/manual/tab_b.png differ diff --git a/docs/manual/tab_h.png b/docs/manual/tab_h.png new file mode 100644 index 0000000..fd5cb70 Binary files /dev/null and b/docs/manual/tab_h.png differ diff --git a/docs/manual/tab_s.png b/docs/manual/tab_s.png new file mode 100644 index 0000000..ab478c9 Binary files /dev/null and b/docs/manual/tab_s.png differ diff --git a/docs/manual/tabs.css b/docs/manual/tabs.css new file mode 100644 index 0000000..85a0cd5 --- /dev/null +++ b/docs/manual/tabs.css @@ -0,0 +1 @@ +.sm{position:relative;z-index:9999}.sm,.sm ul,.sm li{display:block;list-style:none;margin:0;padding:0;line-height:normal;direction:ltr;text-align:left;-webkit-tap-highlight-color:rgba(0,0,0,0)}.sm-rtl,.sm-rtl ul,.sm-rtl li{direction:rtl;text-align:right}.sm>li>h1,.sm>li>h2,.sm>li>h3,.sm>li>h4,.sm>li>h5,.sm>li>h6{margin:0;padding:0}.sm ul{display:none}.sm li,.sm a{position:relative}.sm a{display:block}.sm a.disabled{cursor:not-allowed}.sm:after{content:"\00a0";display:block;height:0;font:0/0 serif;clear:both;visibility:hidden;overflow:hidden}.sm,.sm *,.sm *:before,.sm *:after{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.sm-dox{background-image:url("tab_b.png")}.sm-dox a,.sm-dox a:focus,.sm-dox a:hover,.sm-dox a:active{padding:0 12px;padding-right:43px;font-family:"Lucida Grande","Geneva","Helvetica",Arial,sans-serif;font-size:13px;font-weight:bold;line-height:36px;text-decoration:none;text-shadow:0 1px 1px rgba(255,255,255,0.9);color:#283a5d;outline:0}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a.current{color:#d23600}.sm-dox a.disabled{color:#bbb}.sm-dox a span.sub-arrow{position:absolute;top:50%;margin-top:-14px;left:auto;right:3px;width:28px;height:28px;overflow:hidden;font:bold 12px/28px monospace!important;text-align:center;text-shadow:none;background:rgba(255,255,255,0.5);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox a.highlighted span.sub-arrow:before{display:block;content:'-'}.sm-dox>li:first-child>a,.sm-dox>li:first-child>:not(ul) a{-moz-border-radius:5px 5px 0 0;-webkit-border-radius:5px;border-radius:5px 5px 0 0}.sm-dox>li:last-child>a,.sm-dox>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul{-moz-border-radius:0 0 5px 5px;-webkit-border-radius:0;border-radius:0 0 5px 5px}.sm-dox>li:last-child>a.highlighted,.sm-dox>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>a.highlighted,.sm-dox>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>ul>li:last-child>*:not(ul) a.highlighted{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox ul{background:rgba(162,162,162,0.1)}.sm-dox ul a,.sm-dox ul a:focus,.sm-dox ul a:hover,.sm-dox ul a:active{font-size:12px;border-left:8px solid transparent;line-height:36px;text-shadow:none;background-color:white;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul ul a,.sm-dox ul ul a:hover,.sm-dox ul ul a:focus,.sm-dox ul ul a:active{border-left:16px solid transparent}.sm-dox ul ul ul a,.sm-dox ul ul ul a:hover,.sm-dox ul ul ul a:focus,.sm-dox ul ul ul a:active{border-left:24px solid transparent}.sm-dox ul ul ul ul a,.sm-dox ul ul ul ul a:hover,.sm-dox ul ul ul ul a:focus,.sm-dox ul ul ul ul a:active{border-left:32px solid transparent}.sm-dox ul ul ul ul ul a,.sm-dox ul ul ul ul ul a:hover,.sm-dox ul ul ul ul ul a:focus,.sm-dox ul ul ul ul ul a:active{border-left:40px solid transparent}@media(min-width:768px){.sm-dox ul{position:absolute;width:12em}.sm-dox li{float:left}.sm-dox.sm-rtl li{float:right}.sm-dox ul li,.sm-dox.sm-rtl ul li,.sm-dox.sm-vertical li{float:none}.sm-dox a{white-space:nowrap}.sm-dox ul a,.sm-dox.sm-vertical a{white-space:normal}.sm-dox .sm-nowrap>li>a,.sm-dox .sm-nowrap>li>:not(ul) a{white-space:nowrap}.sm-dox{padding:0 10px;background-image:url("tab_b.png");line-height:36px}.sm-dox a span.sub-arrow{top:50%;margin-top:-2px;right:12px;width:0;height:0;border-width:4px;border-style:solid dashed dashed dashed;border-color:#283a5d transparent transparent transparent;background:transparent;-moz-border-radius:0;-webkit-border-radius:0;border-radius:0}.sm-dox a,.sm-dox a:focus,.sm-dox a:active,.sm-dox a:hover,.sm-dox a.highlighted{padding:0 12px;background-image:url("tab_s.png");background-repeat:no-repeat;background-position:right;-moz-border-radius:0!important;-webkit-border-radius:0;border-radius:0!important}.sm-dox a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox a:hover span.sub-arrow{border-color:white transparent transparent transparent}.sm-dox a.has-submenu{padding-right:24px}.sm-dox li{border-top:0}.sm-dox>li>ul:before,.sm-dox>li>ul:after{content:'';position:absolute;top:-18px;left:30px;width:0;height:0;overflow:hidden;border-width:9px;border-style:dashed dashed solid dashed;border-color:transparent transparent #bbb transparent}.sm-dox>li>ul:after{top:-16px;left:31px;border-width:8px;border-color:transparent transparent #fff transparent}.sm-dox ul{border:1px solid #bbb;padding:5px 0;background:#fff;-moz-border-radius:5px!important;-webkit-border-radius:5px;border-radius:5px!important;-moz-box-shadow:0 5px 9px rgba(0,0,0,0.2);-webkit-box-shadow:0 5px 9px rgba(0,0,0,0.2);box-shadow:0 5px 9px rgba(0,0,0,0.2)}.sm-dox ul a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-color:transparent transparent transparent #555;border-style:dashed dashed dashed solid}.sm-dox ul a,.sm-dox ul a:hover,.sm-dox ul a:focus,.sm-dox ul a:active,.sm-dox ul a.highlighted{color:#555;background-image:none;border:0!important;color:#555;background-image:none}.sm-dox ul a:hover{background-image:url("tab_a.png");background-repeat:repeat-x;color:white;text-shadow:0 1px 1px black}.sm-dox ul a:hover span.sub-arrow{border-color:transparent transparent transparent white}.sm-dox span.scroll-up,.sm-dox span.scroll-down{position:absolute;display:none;visibility:hidden;overflow:hidden;background:#fff;height:36px}.sm-dox span.scroll-up:hover,.sm-dox span.scroll-down:hover{background:#eee}.sm-dox span.scroll-up:hover span.scroll-up-arrow,.sm-dox span.scroll-up:hover span.scroll-down-arrow{border-color:transparent transparent #d23600 transparent}.sm-dox span.scroll-down:hover span.scroll-down-arrow{border-color:#d23600 transparent transparent transparent}.sm-dox span.scroll-up-arrow,.sm-dox span.scroll-down-arrow{position:absolute;top:0;left:50%;margin-left:-6px;width:0;height:0;overflow:hidden;border-width:6px;border-style:dashed dashed solid dashed;border-color:transparent transparent #555 transparent}.sm-dox span.scroll-down-arrow{top:8px;border-style:solid dashed dashed dashed;border-color:#555 transparent transparent transparent}.sm-dox.sm-rtl a.has-submenu{padding-right:12px;padding-left:24px}.sm-dox.sm-rtl a span.sub-arrow{right:auto;left:12px}.sm-dox.sm-rtl.sm-vertical a.has-submenu{padding:10px 20px}.sm-dox.sm-rtl.sm-vertical a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-rtl>li>ul:before{left:auto;right:30px}.sm-dox.sm-rtl>li>ul:after{left:auto;right:31px}.sm-dox.sm-rtl ul a.has-submenu{padding:10px 20px!important}.sm-dox.sm-rtl ul a span.sub-arrow{right:auto;left:8px;border-style:dashed solid dashed dashed;border-color:transparent #555 transparent transparent}.sm-dox.sm-vertical{padding:10px 0;-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px}.sm-dox.sm-vertical a{padding:10px 20px}.sm-dox.sm-vertical a:hover,.sm-dox.sm-vertical a:focus,.sm-dox.sm-vertical a:active,.sm-dox.sm-vertical a.highlighted{background:#fff}.sm-dox.sm-vertical a.disabled{background-image:url("tab_b.png")}.sm-dox.sm-vertical a span.sub-arrow{right:8px;top:50%;margin-top:-5px;border-width:5px;border-style:dashed dashed dashed solid;border-color:transparent transparent transparent #555}.sm-dox.sm-vertical>li>ul:before,.sm-dox.sm-vertical>li>ul:after{display:none}.sm-dox.sm-vertical ul a{padding:10px 20px}.sm-dox.sm-vertical ul a:hover,.sm-dox.sm-vertical ul a:focus,.sm-dox.sm-vertical ul a:active,.sm-dox.sm-vertical ul a.highlighted{background:#eee}.sm-dox.sm-vertical ul a.disabled{background:#fff}} \ No newline at end of file diff --git a/docs/manual/todo.html b/docs/manual/todo.html new file mode 100644 index 0000000..b9c7c2a --- /dev/null +++ b/docs/manual/todo.html @@ -0,0 +1,124 @@ + + + + + + + +AngelScript: Todo List + + + + + + + + + + + + + + +
+
+ + + + + + + + +
+
AngelScript +
+
+ + + + + + +
+
+
+ + + +
+
+ +
+
+
+ +
+ +
+
+ + +
+ +
+ +
+
+
Todo List
+
+
+
+
Page Serializer
+

Show how to serialize extra objects too. And explain about memory management for restored objects

+

Explain that handles to registered types without factories will be kept as-is

+

Registered pod-types do not need a special user type as the serializer will simply keep a bitwise copy

+
+
Page Advanced topics
+
Add page about imports and function binding
+
Page Understanding AngelScript
+

Add article on the calling conventions used by AngelScript

+

Add article on sandboxing

+
+
+
+
+
+ + + + diff --git a/samples/asbuild/bin/config.txt b/samples/asbuild/bin/config.txt new file mode 100644 index 0000000..33df71d --- /dev/null +++ b/samples/asbuild/bin/config.txt @@ -0,0 +1,229 @@ +// Configuration for AngelScript asrun sample +// Generated with WriteConfigToFile after configuring the engine in asrun + +// Engine properties +ep 0 0 +ep 1 0 +ep 2 1 +ep 3 1 +ep 4 0 +ep 5 0 +ep 6 0 +ep 7 0 +ep 8 0 +ep 9 1 +ep 10 0 +ep 11 1 +ep 12 0 +ep 13 0 +ep 14 2 +ep 15 0 +ep 16 1 +ep 17 0 +ep 18 0 +ep 19 1 +ep 20 0 +ep 21 0 +ep 22 0 +ep 23 0 +ep 24 0 +ep 25 0 +ep 26 1 +ep 27 100 + +// Enums + +// Types +access ffffffff +objtype "string" 7938 +objtype "array" 69 +objtype "dictionaryValue" 1922 +objtype "dictionary" 5 +objtype "file" 1 +objtype "filesystem" 1 +objtype "datetime" 6922 +funcdef "bool array::less(const T&in, const T&in)" +funcdef "void coroutine(dictionary@)" + +// Template type members +objbeh "array" 3 "array@ array(int&in)" +objbeh "array" 3 "array@ array(int&in, uint)" +objbeh "array" 3 "array@ array(int&in, uint, const T&in)" +objbeh "array" 5 "void $beh5()" +objbeh "array" 6 "void $beh6()" +objbeh "array" 9 "int $beh9()" +objbeh "array" 10 "void $beh10()" +objbeh "array" 11 "bool $beh11()" +objbeh "array" 12 "void $beh12(int&in)" +objbeh "array" 13 "void $beh13(int&in)" +//objbeh "array" 8 "bool $beh8(int&in, bool&out)" +objbeh "array" 4 "array@ $beh4(int&in, int&in) { repeat T }" +objmthd "array" "T& opIndex(uint)" +objmthd "array" "const T& opIndex(uint) const" +objmthd "array" "array& opAssign(const array&in)" +objmthd "array" "void insertAt(uint, const T&in)" +objmthd "array" "void insertAt(uint, const array&inout)" +objmthd "array" "void insertLast(const T&in)" +objmthd "array" "void removeAt(uint)" +objmthd "array" "void removeLast()" +objmthd "array" "void removeRange(uint, uint)" +objmthd "array" "uint length() const" +objmthd "array" "void reserve(uint)" +objmthd "array" "void resize(uint)" +objmthd "array" "void sortAsc()" +objmthd "array" "void sortAsc(uint, uint)" +objmthd "array" "void sortDesc()" +objmthd "array" "void sortDesc(uint, uint)" +objmthd "array" "void reverse()" +objmthd "array" "int find(const T&in) const" +objmthd "array" "int find(uint, const T&in) const" +objmthd "array" "int findByRef(const T&in) const" +objmthd "array" "int findByRef(uint, const T&in) const" +objmthd "array" "bool opEquals(const array&in) const" +objmthd "array" "bool isEmpty() const" +objmthd "array" "void sort(array::less&in, uint = 0, uint = uint ( - 1 ))" +objmthd "array" "uint get_length() const" +objmthd "array" "void set_length(uint)" + +// Type members +objbeh "string" 2 "void string()" +objbeh "string" 0 "void string()" +objbeh "string" 0 "void string(const string&in)" +objmthd "string" "string& opAssign(const string&in)" +objmthd "string" "string& opAddAssign(const string&in)" +objmthd "string" "bool opEquals(const string&in) const" +objmthd "string" "int opCmp(const string&in) const" +objmthd "string" "string opAdd(const string&in) const" +objmthd "string" "uint length() const" +objmthd "string" "void resize(uint)" +objmthd "string" "uint get_length() const" +objmthd "string" "void set_length(uint)" +objmthd "string" "bool isEmpty() const" +objmthd "string" "uint8& opIndex(uint)" +objmthd "string" "const uint8& opIndex(uint) const" +objmthd "string" "string& opAssign(double)" +objmthd "string" "string& opAddAssign(double)" +objmthd "string" "string opAdd(double) const" +objmthd "string" "string opAdd_r(double) const" +objmthd "string" "string& opAssign(float)" +objmthd "string" "string& opAddAssign(float)" +objmthd "string" "string opAdd(float) const" +objmthd "string" "string opAdd_r(float) const" +objmthd "string" "string& opAssign(int64)" +objmthd "string" "string& opAddAssign(int64)" +objmthd "string" "string opAdd(int64) const" +objmthd "string" "string opAdd_r(int64) const" +objmthd "string" "string& opAssign(uint64)" +objmthd "string" "string& opAddAssign(uint64)" +objmthd "string" "string opAdd(uint64) const" +objmthd "string" "string opAdd_r(uint64) const" +objmthd "string" "string& opAssign(bool)" +objmthd "string" "string& opAddAssign(bool)" +objmthd "string" "string opAdd(bool) const" +objmthd "string" "string opAdd_r(bool) const" +objmthd "string" "string substr(uint = 0, int = - 1) const" +objmthd "string" "int findFirst(const string&in, uint = 0) const" +objmthd "string" "int findFirstOf(const string&in, uint = 0) const" +objmthd "string" "int findFirstNotOf(const string&in, uint = 0) const" +objmthd "string" "int findLast(const string&in, int = - 1) const" +objmthd "string" "int findLastOf(const string&in, int = - 1) const" +objmthd "string" "int findLastNotOf(const string&in, int = - 1) const" +objmthd "string" "void insert(uint, const string&in)" +objmthd "string" "void erase(uint, int = - 1)" +objmthd "string" "array@ split(const string&in) const" +objbeh "dictionaryValue" 2 "void dictionaryValue()" +objbeh "dictionaryValue" 0 "void dictionaryValue()" +objmthd "dictionaryValue" "dictionaryValue& opAssign(const dictionaryValue&in)" +objmthd "dictionaryValue" "dictionaryValue& opHndlAssign(const ?&in)" +objmthd "dictionaryValue" "dictionaryValue& opAssign(const ?&in)" +objmthd "dictionaryValue" "dictionaryValue& opAssign(double)" +objmthd "dictionaryValue" "dictionaryValue& opAssign(int64)" +objmthd "dictionaryValue" "void opCast(?&out)" +objmthd "dictionaryValue" "void opConv(?&out)" +objmthd "dictionaryValue" "int64 opConv()" +objmthd "dictionaryValue" "double opConv()" +objbeh "dictionary" 3 "dictionary@ dictionary()" +objbeh "dictionary" 5 "void $beh5()" +objbeh "dictionary" 6 "void $beh6()" +objbeh "dictionary" 9 "int $beh9()" +objbeh "dictionary" 10 "void $beh10()" +objbeh "dictionary" 11 "bool $beh11()" +objbeh "dictionary" 12 "void $beh12(int&in)" +objbeh "dictionary" 13 "void $beh13(int&in)" +objbeh "dictionary" 4 "dictionary@ $beh4(int&in) { repeat { string, ? } }" +objmthd "dictionary" "dictionary& opAssign(const dictionary&in)" +objmthd "dictionary" "void set(const string&in, const ?&in)" +objmthd "dictionary" "bool get(const string&in, ?&out) const" +objmthd "dictionary" "void set(const string&in, const int64&in)" +objmthd "dictionary" "bool get(const string&in, int64&out) const" +objmthd "dictionary" "void set(const string&in, const double&in)" +objmthd "dictionary" "bool get(const string&in, double&out) const" +objmthd "dictionary" "bool exists(const string&in) const" +objmthd "dictionary" "bool isEmpty() const" +objmthd "dictionary" "uint getSize() const" +objmthd "dictionary" "bool delete(const string&in)" +objmthd "dictionary" "void deleteAll()" +objmthd "dictionary" "array@ getKeys() const" +objmthd "dictionary" "dictionaryValue& opIndex(const string&in)" +objmthd "dictionary" "const dictionaryValue& opIndex(const string&in) const" +objbeh "file" 3 "file@ file()" +objbeh "file" 5 "void $beh5()" +objbeh "file" 6 "void $beh6()" +objmthd "file" "int open(const string&in, const string&in)" +objmthd "file" "int close()" +objmthd "file" "int getSize() const" +objmthd "file" "bool isEndOfFile() const" +objmthd "file" "string readString(uint)" +objmthd "file" "string readLine()" +objmthd "file" "int64 readInt(uint)" +objmthd "file" "uint64 readUInt(uint)" +objmthd "file" "float readFloat()" +objmthd "file" "double readDouble()" +objmthd "file" "int writeString(const string&in)" +objmthd "file" "int writeInt(int64, uint)" +objmthd "file" "int writeUInt(uint64, uint)" +objmthd "file" "int writeFloat(float)" +objmthd "file" "int writeDouble(double)" +objmthd "file" "int getPos() const" +objmthd "file" "int setPos(int)" +objmthd "file" "int movePos(int)" +objprop "file" "bool mostSignificantByteFirst" +objbeh "filesystem" 3 "filesystem@ filesystem()" +objbeh "filesystem" 5 "void $beh5()" +objbeh "filesystem" 6 "void $beh6()" +objmthd "filesystem" "bool changeCurrentPath(const string&in)" +objmthd "filesystem" "string getCurrentPath() const" +objmthd "filesystem" "array@ getDirs()" +objmthd "filesystem" "array@ getFiles()" +objmthd "filesystem" "bool isDir(const string&in)" +objbeh "datetime" 0 "void datetime()" +objbeh "datetime" 0 "void datetime(const datetime&in)" +objmthd "datetime" "datetime& opAssign(const datetime&in)" +objmthd "datetime" "uint get_year() const" +objmthd "datetime" "uint get_month() const" +objmthd "datetime" "uint get_day() const" +objmthd "datetime" "uint get_hour() const" +objmthd "datetime" "uint get_minute() const" +objmthd "datetime" "uint get_second() const" + +// Functions +func "string formatInt(int64, const string&in = \"\", uint = 0)" +func "string formatUInt(uint64, const string&in = \"\", uint = 0)" +func "string formatFloat(double, const string&in = \"\", uint = 0, uint = 0)" +func "int64 parseInt(const string&in, uint = 10, uint&out = 0)" +func "uint64 parseUInt(const string&in, uint = 10, uint&out = 0)" +func "double parseFloat(const string&in, uint&out = 0)" +func "string join(const array&in, const string&in)" +func "void print(const string&in)" +func "string getInput()" +func "array@ getCommandLineArgs()" +func "int exec(const string&in)" +func "void yield()" +func "void createCoRoutine(coroutine@, dictionary@)" + +// Properties + +// String factory +strfactory "string" + +// Default array type diff --git a/samples/asbuild/bin/script.as b/samples/asbuild/bin/script.as new file mode 100644 index 0000000..0b8f68c --- /dev/null +++ b/samples/asbuild/bin/script.as @@ -0,0 +1,5 @@ +void main() +{ + string str = "hello world"; + print(str); +} \ No newline at end of file diff --git a/samples/asbuild/projects/gnuc/makefile b/samples/asbuild/projects/gnuc/makefile new file mode 100644 index 0000000..bc38627 --- /dev/null +++ b/samples/asbuild/projects/gnuc/makefile @@ -0,0 +1,30 @@ +# GCC Makefile +CXX = g++ +CXXFLAGS = -g -I../../../../angelscript/include -D_LINUX_ +SRCDIR = ../../source +OBJDIR = obj + +SRCNAMES = \ + main.cpp + +OBJ = $(addprefix $(OBJDIR)/, $(notdir $(SRCNAMES:.cpp=.o))) obj/asbuild.o +BIN = ../../bin/asbuild +DELETER = rm -f + +all: $(BIN) + +$(BIN): $(OBJ) + $(CXX) -o $(BIN) $(OBJ) -langelscript -lpthread -L ../../../../angelscript/lib + @echo ------------------------------------------------------------------- + @echo Done. + +$(OBJDIR)/%.o: $(SRCDIR)/%.cpp + $(CXX) $(CXXFLAGS) -o $@ -c $< + +obj/asbuild.o: ../../../../add_on/scriptbuilder/scriptbuilder.cpp + $(CXX) $(CXXFLAGS) -o $@ -c $< + +clean: + $(DELETER) $(OBJ) $(BIN) + +.PHONY: all clean diff --git a/samples/asbuild/projects/gnuc/obj/delete.me b/samples/asbuild/projects/gnuc/obj/delete.me new file mode 100644 index 0000000..945c9b4 --- /dev/null +++ b/samples/asbuild/projects/gnuc/obj/delete.me @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/samples/asbuild/projects/msvc2012/asbuild.sln b/samples/asbuild/projects/msvc2012/asbuild.sln new file mode 100644 index 0000000..64184f9 --- /dev/null +++ b/samples/asbuild/projects/msvc2012/asbuild.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asbuild", "asbuild.vcxproj", "{1454C75F-8CE0-450D-A520-D9D487A37ACD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.Build.0 = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.ActiveCfg = Release|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/asbuild/projects/msvc2012/asbuild.vcxproj b/samples/asbuild/projects/msvc2012/asbuild.vcxproj new file mode 100644 index 0000000..c33f161 --- /dev/null +++ b/samples/asbuild/projects/msvc2012/asbuild.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {1454C75F-8CE0-450D-A520-D9D487A37ACD} + asbuild + Win32Proj + + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + true + + + Application + v110 + Unicode + + + Application + v110 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60315.1 + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + true + + + true + $(Platform)\$(Configuration)\ + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + false + + + false + $(Platform)\$(Configuration)\ + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + + + ../../../../angelscript/lib/angelscriptd.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + MachineX86 + + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64d.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/asbuild/projects/msvc2015/asbuild.sln b/samples/asbuild/projects/msvc2015/asbuild.sln new file mode 100644 index 0000000..64184f9 --- /dev/null +++ b/samples/asbuild/projects/msvc2015/asbuild.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asbuild", "asbuild.vcxproj", "{1454C75F-8CE0-450D-A520-D9D487A37ACD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.Build.0 = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.ActiveCfg = Release|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/asbuild/projects/msvc2015/asbuild.vcxproj b/samples/asbuild/projects/msvc2015/asbuild.vcxproj new file mode 100644 index 0000000..f1c6cad --- /dev/null +++ b/samples/asbuild/projects/msvc2015/asbuild.vcxproj @@ -0,0 +1,182 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {1454C75F-8CE0-450D-A520-D9D487A37ACD} + asbuild + Win32Proj + + + + Application + v140 + Unicode + true + + + Application + v140 + Unicode + true + + + Application + v140 + Unicode + + + Application + v140 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60315.1 + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + true + + + true + $(Platform)\$(Configuration)\ + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + false + + + false + $(Platform)\$(Configuration)\ + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + + + ../../../../angelscript/lib/angelscriptd.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + MachineX86 + + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64d.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/asbuild/projects/msvc2017/asbuild.sln b/samples/asbuild/projects/msvc2017/asbuild.sln new file mode 100644 index 0000000..64184f9 --- /dev/null +++ b/samples/asbuild/projects/msvc2017/asbuild.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asbuild", "asbuild.vcxproj", "{1454C75F-8CE0-450D-A520-D9D487A37ACD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.Build.0 = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.ActiveCfg = Release|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/asbuild/projects/msvc2017/asbuild.vcxproj b/samples/asbuild/projects/msvc2017/asbuild.vcxproj new file mode 100644 index 0000000..bd3b582 --- /dev/null +++ b/samples/asbuild/projects/msvc2017/asbuild.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {1454C75F-8CE0-450D-A520-D9D487A37ACD} + asbuild + Win32Proj + 10.0.16299.0 + + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + true + + + Application + v141 + Unicode + + + Application + v141 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60315.1 + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + true + + + true + $(Platform)\$(Configuration)\ + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + false + + + false + $(Platform)\$(Configuration)\ + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + + + ../../../../angelscript/lib/angelscriptd.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + MachineX86 + + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64d.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/asbuild/projects/msvc2019/asbuild.sln b/samples/asbuild/projects/msvc2019/asbuild.sln new file mode 100644 index 0000000..64184f9 --- /dev/null +++ b/samples/asbuild/projects/msvc2019/asbuild.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Express 2012 for Windows Desktop +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asbuild", "asbuild.vcxproj", "{1454C75F-8CE0-450D-A520-D9D487A37ACD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.Build.0 = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.ActiveCfg = Release|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/asbuild/projects/msvc2019/asbuild.vcxproj b/samples/asbuild/projects/msvc2019/asbuild.vcxproj new file mode 100644 index 0000000..9c40874 --- /dev/null +++ b/samples/asbuild/projects/msvc2019/asbuild.vcxproj @@ -0,0 +1,183 @@ + + + + + Debug + Win32 + + + Debug + x64 + + + Release + Win32 + + + Release + x64 + + + + {1454C75F-8CE0-450D-A520-D9D487A37ACD} + asbuild + Win32Proj + 10.0 + + + + Application + v142 + Unicode + true + + + Application + v142 + Unicode + true + + + Application + v142 + Unicode + + + Application + v142 + Unicode + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>11.0.60315.1 + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + true + + + true + $(Platform)\$(Configuration)\ + + + ..\..\bin\ + $(Platform)\$(Configuration)\ + false + + + false + $(Platform)\$(Configuration)\ + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + true + EnableFastChecks + MultiThreadedDebug + + Level3 + EditAndContinue + + + ../../../../angelscript/lib/angelscriptd.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + MachineX86 + + + + + Disabled + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) + EnableFastChecks + MultiThreadedDebug + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64d.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + MachineX86 + + + + + MaxSpeed + true + ..\..\..\..\angelscript\include;%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) + MultiThreaded + true + + + Level3 + ProgramDatabase + + + ../../../../angelscript/lib/angelscript64.lib;%(AdditionalDependencies) + $(OutDir)$(ProjectName).exe + true + Console + true + true + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/samples/asbuild/projects/msvc9/asbuild.sln b/samples/asbuild/projects/msvc9/asbuild.sln new file mode 100644 index 0000000..ac45c8c --- /dev/null +++ b/samples/asbuild/projects/msvc9/asbuild.sln @@ -0,0 +1,20 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual C++ Express 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "asbuild", "asbuild.vcproj", "{1454C75F-8CE0-450D-A520-D9D487A37ACD}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.ActiveCfg = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Debug|Win32.Build.0 = Debug|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.ActiveCfg = Release|Win32 + {1454C75F-8CE0-450D-A520-D9D487A37ACD}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/samples/asbuild/projects/msvc9/asbuild.vcproj b/samples/asbuild/projects/msvc9/asbuild.vcproj new file mode 100644 index 0000000..c1f3dad --- /dev/null +++ b/samples/asbuild/projects/msvc9/asbuild.vcproj @@ -0,0 +1,211 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/asbuild/source/main.cpp b/samples/asbuild/source/main.cpp new file mode 100644 index 0000000..dc93f96 --- /dev/null +++ b/samples/asbuild/source/main.cpp @@ -0,0 +1,321 @@ +#include // cout +#include // assert() +#include // strstr() +#include +#include "../../../add_on/scriptbuilder/scriptbuilder.h" +#include "../../../add_on/scripthelper/scripthelper.h" +#include +#include +#include +#include +#if defined(_MSC_VER) && !defined(_WIN32_WCE) +#include +#include +#endif +#ifdef _WIN32_WCE +#include // For GetModuleFileName +#endif + +using namespace std; + +// Function prototypes +int ConfigureEngine(asIScriptEngine *engine, const char *configFile); +int CompileScript(asIScriptEngine *engine, const char *scriptFile); +int SaveBytecode(asIScriptEngine *engine, const char *outputFile); +static const char *GetCurrentDir(char *buf, size_t size); + +void MessageCallback(const asSMessageInfo *msg, void *param) +{ + const char *type = "ERR "; + if( msg->type == asMSGTYPE_WARNING ) + type = "WARN"; + else if( msg->type == asMSGTYPE_INFORMATION ) + type = "INFO"; + + printf("%s (%d, %d) : %s : %s\n", msg->section, msg->row, msg->col, type, msg->message); +} + +int main(int argc, char **argv) +{ +#if defined(_MSC_VER) + // Turn on memory leak detection (use _CrtSetBreakAlloc to break at specific allocation) + _CrtSetDbgFlag(_CRTDBG_LEAK_CHECK_DF|_CRTDBG_ALLOC_MEM_DF); + _CrtSetReportMode(_CRT_ASSERT,_CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT,_CRTDBG_FILE_STDERR); + + //_CrtSetBreakAlloc(6150); +#endif + + int r; + + if( argc < 4 ) + { + cout << "Usage: " << endl; + cout << "asbuild