danderson@91: /* vim: set ts=4 sw=4 tw=99 et: danderson@91: * dvander@60: * Copyright (C) 2004-2012 David Anderson dvander@60: * dvander@60: * This file is part of SourcePawn. dvander@60: * dvander@60: * SourcePawn is free software: you can redistribute it and/or modify it under dvander@60: * the terms of the GNU General Public License as published by the Free dvander@60: * Software Foundation, either version 3 of the License, or (at your option) dvander@60: * any later version. dvander@60: * dvander@60: * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY dvander@60: * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS dvander@60: * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. dvander@60: * dvander@60: * You should have received a copy of the GNU General Public License along with dvander@60: * SourcePawn. If not, see http://www.gnu.org/licenses/. dvander@60: */ dvander@60: #ifndef _include_sourcepawn3_api_h_ dvander@60: #define _include_sourcepawn3_api_h_ dvander@60: dvander@65: #include dvander@60: #include dvander@64: #include "../include/keima_util.h" dvander@60: dvander@60: namespace ke { dvander@60: dvander@60: class Zone; dvander@60: class Object; dvander@60: class HandleScope; dvander@60: class HeapRoot; dvander@60: dvander@60: } dvander@60: dvander@60: namespace Ke { dvander@60: dvander@64: class Function; dvander@64: dvander@60: /* dvander@60: * A Handle is a safe pointer that holds an object reference, such that it dvander@60: * can be scanned and potentially moved by the garbage collector. dvander@60: */ dvander@60: template dvander@60: class Handle dvander@60: { dvander@60: protected: dvander@60: template void typeCheck() { dvander@60: while (false) { dvander@60: T *v1 = NULL; dvander@60: S *v2 = NULL; dvander@60: v1 = v2; dvander@60: (void)v1; dvander@60: } dvander@60: } dvander@60: dvander@60: public: dvander@60: Handle() dvander@60: : obj_(NULL) dvander@60: { dvander@60: } dvander@60: dvander@60: template Handle(Handle other) dvander@60: : obj_(reinterpret_cast(*other)) dvander@60: { dvander@60: typeCheck(); dvander@60: } dvander@60: dvander@60: explicit Handle(T *obj) dvander@60: : obj_(obj) dvander@60: { dvander@60: } dvander@60: dvander@60: T *operator ->() const { dvander@60: return obj_; dvander@60: } dvander@60: T *operator *() const { dvander@60: return obj_; dvander@60: } dvander@60: operator bool () const { dvander@60: return !!obj_; dvander@60: } dvander@60: dvander@65: protected: dvander@60: T *obj_; dvander@60: }; dvander@60: dvander@60: /* dvander@60: * A local variable that roots an object. Locals are owned by the nearest dvander@60: * HandleScope, and as soon as that HandleScope dies, all its Locals are dvander@60: * no longer available. dvander@60: */ dvander@60: template dvander@60: class Local : public Handle dvander@60: { dvander@60: public: dvander@60: Local() dvander@60: : Handle() dvander@60: { dvander@60: } dvander@60: dvander@60: template Local(Local other) dvander@60: : Handle(reinterpret_cast(*other)) dvander@60: { danderson@91: this->template typeCheck(); dvander@60: } dvander@60: dvander@60: template Local(S *other) dvander@60: : Handle(other) dvander@60: { dvander@60: } dvander@60: }; dvander@60: dvander@60: /* dvander@60: * A non-local variable that outlives HandleScopes. A Root is reference- dvander@60: * counted. When its reference count reaches 0, the Root is removed. dvander@60: */ dvander@60: template dvander@60: class Root : public Handle dvander@60: { dvander@60: public: dvander@65: Root() dvander@60: : Handle() dvander@60: { dvander@60: } dvander@60: dvander@65: Root(const Root &other) dvander@60: : Handle(reinterpret_cast(*other)) dvander@60: { dvander@60: incref(); dvander@60: } dvander@60: dvander@61: explicit Root(ke::HeapRoot *obj) dvander@60: : Handle(reinterpret_cast(obj)) dvander@60: { danderson@91: incref(); dvander@60: } dvander@60: dvander@61: static inline Root New(Handle other); dvander@60: dvander@60: ~Root() { dvander@60: decref(); dvander@60: } dvander@60: dvander@65: Root &operator =(const Root &other) { dvander@60: decref(); danderson@91: this->obj_ = other.obj_; danderson@91: incref(); dvander@60: return *this; dvander@60: } dvander@60: dvander@60: private: dvander@60: void incref(); dvander@60: void decref(); dvander@60: }; dvander@60: dvander@60: /* dvander@60: * A HandleScope is where Local roots are allcoated. When the HandleScope dvander@60: * is destroyed, all Handles created under it are also destroyed. HandleScopes dvander@60: * may only be allocated on the stack, in LIFO order. dvander@60: */ dvander@60: class HandleScope dvander@60: { dvander@60: protected: dvander@60: ke::Zone *zone_; dvander@60: ke::Object **position_; dvander@60: HandleScope *prev_; dvander@60: dvander@60: HandleScope(ke::Zone *zone, ke::Object **position, HandleScope *prev) dvander@60: : zone_(zone), dvander@60: position_(position), dvander@60: prev_(prev) dvander@60: { dvander@60: } dvander@60: dvander@60: public: dvander@60: HandleScope(); dvander@60: ~HandleScope(); dvander@60: dvander@60: static ke::Object **CreateHandle(ke::Object *obj); dvander@60: dvander@60: private: dvander@60: // Disallow silly stuff. dvander@60: HandleScope(const HandleScope &); dvander@60: void operator =(const HandleScope &); dvander@60: void *operator new (size_t size); dvander@60: void operator delete(void *, size_t); dvander@60: }; dvander@60: dvander@65: class Parameter; dvander@65: dvander@69: // Error messages are pumped through this interface. dvander@69: class IMessageReporter dvander@69: { dvander@69: public: dvander@69: virtual void onOutOfMemory() { dvander@69: } dvander@69: virtual void onUncaughtException(const char *message) { dvander@69: } dvander@69: virtual void beginCompilationErrors(const char *file) { dvander@69: } dvander@69: virtual void reportCompilationError(const char *message, unsigned line, unsigned col) { dvander@69: } dvander@69: virtual void endCompilationErrors() { dvander@69: } dvander@69: }; dvander@69: dvander@69: // For the purposes of error reporting, very basic information can be queried dvander@69: // about the stack frame. This structure may be used to retrieve such dvander@69: // information. During iteration, it is illegal to re-enter any scripted code dvander@69: // or call any Keima functions that may cause garbage collection. dvander@69: class IStackFrameIterator dvander@69: { dvander@69: public: dvander@69: virtual ~IStackFrameIterator() { } dvander@69: dvander@69: // Returns true if there are more frames, false otherwise. dvander@69: virtual bool done() = 0; dvander@69: dvander@69: // Returns the name of the current function. This may be NULL if the dvander@69: // function is anonymous. dvander@69: virtual const char *function() = 0; dvander@69: dvander@69: // Returns the file of the current function. This will return an invalid dvander@69: // path for C++ functions (for example, ""). dvander@69: virtual const char *source() = 0; dvander@69: dvander@69: // Returns the line number currently executing on this frame. For C++ dvander@69: // functions, this is always 0. dvander@69: virtual unsigned lineNumber() = 0; dvander@69: dvander@69: // Advance to the previous frame in the call stack. dvander@69: virtual void prev() = 0; dvander@69: }; dvander@69: dvander@64: // A string is an immutable UTF8 buffer. dvander@64: class KE_EXPORT String dvander@64: { dvander@64: public: dvander@64: // Returns the length of the string, in bytes. dvander@64: unsigned length(); dvander@64: dvander@64: // Returns the character buffer of the string, or NULL on failure. If the dvander@64: // string is interned, chars() is guaranteed to succeed. dvander@64: const char *chars(); dvander@64: }; dvander@64: dvander@64: // A function is an executable unit of code. dvander@64: class KE_EXPORT Function dvander@64: { dvander@64: public: dvander@64: // Returns the name of a function, which may be NULL. If not NULL, the dvander@68: // string is guaranteed to be interned. dvander@64: Local name(); dvander@64: }; dvander@64: dvander@68: // A native is an ISourcePawnEngine-compatible function provided by C++. dvander@68: class KE_EXPORT Native dvander@68: { dvander@68: public: dvander@68: // Returns the name of a native, which is never NULL. The string is dvander@68: // guaranteed to be interned. dvander@68: Local name(); dvander@68: dvander@68: // Returns the function pointer of the native. dvander@68: void *function(); dvander@68: dvander@68: // Sets the function pointer of the native. dvander@68: void bind(void *function); dvander@68: }; dvander@68: dvander@62: // A module represents a single compiled file, and contains functions and dvander@62: // global variables for that file (as well as exported types). dvander@64: class KE_EXPORT Module dvander@62: { dvander@62: public: dvander@64: // Returns publics that are based on forwards. dvander@64: unsigned numPublics(); dvander@64: Local getPublic(unsigned index); dvander@68: dvander@68: // Returns natives. dvander@68: unsigned numNatives(); dvander@68: Local getNative(unsigned index); dvander@68: dvander@68: // Sets the native identity pointer, which is passed as the first argument dvander@68: // to natives. dvander@68: void setNativeIdentity(void *ptr); dvander@62: }; dvander@62: dvander@62: class Keima dvander@62: { dvander@62: public: dvander@62: /* dvander@62: * Initializes the Keima engine. This must be called exactly once before any dvander@62: * other Keima functions are called. After this, it is safe to use Keima dvander@62: * on the calling thread. dvander@62: */ dvander@62: static bool Initialize(); dvander@60: dvander@62: /* dvander@62: * Shuts down the Keima engine and frees data structures on all threads. dvander@62: */ dvander@62: static void Shutdown(); dvander@60: dvander@62: /* dvander@62: * Searches the call stack and returns true if the given module has any dvander@62: * active code running. This is an O(n) algorithm. dvander@62: */ dvander@62: static bool IsInCallStack(Handle module); dvander@62: dvander@62: /* dvander@62: * Reclaim as much memory as possible. This pauses the calling thread dvander@62: * until garbage collection completes. dvander@62: */ dvander@62: static void CollectGarbage(); dvander@64: dvander@64: /* dvander@64: * Clear any pending exception. dvander@64: */ dvander@64: static void ClearPendingException(); dvander@65: dvander@65: /* dvander@65: * Type checks a function against given parameters. dvander@65: */ dvander@65: static bool CheckInvokeTypes(Handle fun, const Parameter *params, unsigned nparams); dvander@65: dvander@65: /* dvander@65: * Executes a function with the given parameters. This interface is dvander@65: * intended for compatibility with SourceMod's ISourcePawnEngine2 and dvander@65: * should not be used otherwise, since it is intended to support only dvander@65: * a small subset of the core language. dvander@65: */ dvander@65: static bool Invoke(Handle fun, const Parameter *params, unsigned nparams, int *result); dvander@69: dvander@69: /* dvander@69: * Sets the global message handler through which errors will be reported dvander@69: */ dvander@69: static void InstallMessageReporter(IMessageReporter *reporter); dvander@69: dvander@69: static IStackFrameIterator *NewStackFrameIterator(); dvander@62: }; dvander@60: dvander@60: /* dvander@64: * Suppresses exceptions. This is useful for calling API functions. When this dvander@64: * in scope, errors will be reported, but the exception will be cleared after. dvander@64: */ dvander@64: class AutoClearExceptions dvander@64: { dvander@64: public: dvander@64: ~AutoClearExceptions() dvander@64: { dvander@64: Keima::ClearPendingException(); dvander@64: } dvander@64: }; dvander@64: dvander@65: // Argument-passing interface for Invoke(). dvander@65: class Parameter dvander@65: { dvander@65: public: dvander@65: enum Type { dvander@65: Int, dvander@65: Float, dvander@65: IntRef, dvander@65: FloatRef, dvander@65: Array, dvander@65: CharArray dvander@65: }; dvander@65: dvander@65: Parameter() dvander@65: { dvander@65: } dvander@65: dvander@65: Parameter(int i) dvander@65: : type_(Int) dvander@65: { dvander@65: u.i = i; dvander@65: } dvander@65: dvander@65: Parameter(int *i, bool writeback) dvander@65: : type_(IntRef), dvander@65: writeback_(writeback) dvander@65: { dvander@65: u.ip = i; dvander@65: } dvander@65: dvander@65: Parameter(float f) dvander@65: : type_(Float) dvander@65: { dvander@65: u.f = f; dvander@65: } dvander@65: dvander@65: Parameter(float *f, bool writeback) dvander@65: : type_(FloatRef), dvander@65: writeback_(writeback) dvander@65: { dvander@65: u.fp = f; dvander@65: } dvander@65: dvander@65: Parameter(Type type, void *buffer, size_t length, bool writeback) dvander@65: : type_(type), dvander@65: writeback_(writeback), dvander@65: length_(length) dvander@65: { dvander@65: assert(type == Array || type == CharArray); dvander@65: u.buffer = buffer; dvander@65: } dvander@65: dvander@65: Type type() const { dvander@65: return type_; dvander@65: } dvander@65: dvander@65: int i32() const { dvander@65: assert(type() == Int); dvander@65: return u.i; dvander@65: } dvander@65: float f() const { dvander@65: assert(type() == Float); dvander@65: return u.f; dvander@65: } dvander@65: int *i32p() const { dvander@65: assert(type() == IntRef); dvander@65: return u.ip; dvander@65: } dvander@65: float *fp() const { dvander@65: assert(type() == FloatRef); dvander@65: return u.fp; dvander@65: } dvander@65: bool writeback() const { dvander@65: assert(type() >= IntRef && type() <= CharArray); dvander@65: return writeback_; dvander@65: } dvander@65: size_t length() const { dvander@65: return length_; dvander@65: } dvander@65: void *buffer() const { dvander@65: assert(type() == Array || type() == CharArray); dvander@65: return u.buffer; dvander@65: } dvander@65: dvander@65: private: dvander@65: Type type_; dvander@65: bool writeback_; dvander@65: size_t length_; dvander@65: dvander@65: union { dvander@65: int i; dvander@65: float f; dvander@65: int *ip; dvander@65: float *fp; dvander@65: void *buffer; dvander@65: } u; dvander@65: }; dvander@64: dvander@64: /* dvander@60: * Compiles a file and returns a Module. dvander@60: */ dvander@60: extern Local Compile(const char *path); dvander@60: dvander@61: class Internals dvander@61: { dvander@61: template friend class Root; dvander@61: dvander@61: private: dvander@61: static ke::HeapRoot *NewHeapRoot(ke::Object **objp); dvander@61: static void IncRef(ke::HeapRoot *root); dvander@61: static void DecRef(ke::HeapRoot *root); dvander@61: }; dvander@61: dvander@61: template Root dvander@61: Root::New(Handle other) dvander@61: { dvander@61: if (!other) dvander@65: return Root(); dvander@61: ke::Object **ptr = reinterpret_cast(*other); dvander@61: return Root(Internals::NewHeapRoot(ptr)); dvander@61: } dvander@61: dvander@61: template void dvander@61: Root::incref() dvander@61: { dvander@61: if (!*this) dvander@61: return; dvander@61: ke::HeapRoot *ptr = reinterpret_cast(**this); dvander@61: Internals::IncRef(ptr); dvander@61: } dvander@61: dvander@61: template void dvander@61: Root::decref() dvander@61: { dvander@61: if (!*this) dvander@61: return; dvander@61: ke::HeapRoot *ptr = reinterpret_cast(**this); dvander@61: Internals::DecRef(ptr); dvander@61: } dvander@61: dvander@60: } dvander@60: dvander@60: #endif // _include_sourcepawn3_api_h_