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: */ danderson@96: #ifndef _include_sourcepawn2_api_h_ danderson@96: #define _include_sourcepawn2_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@195: template friend class Root; 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@195: * A non-local variable that outlives HandleScopes. Unlike Local, a Root dvander@195: * actually represents a rooted location. Roots must be allocated and dvander@195: * disposed, and assignment to a root changes its contained object, not dvander@195: * the location of the object. dvander@60: */ dvander@60: template dvander@195: class Root dvander@60: { dvander@60: public: dvander@195: Root() dvander@195: : root_(NULL) dvander@60: { dvander@60: } dvander@60: dvander@195: Root(Handle other) dvander@195: : root_(NULL) dvander@60: { dvander@195: set(other); dvander@60: } dvander@60: dvander@195: inline ~Root(); dvander@195: dvander@195: operator const Handle() const { dvander@195: return obj_; dvander@60: } dvander@60: dvander@195: bool operator ==(Handle other) { dvander@195: return Handle(*this) == other; dvander@60: } dvander@195: Root &operator =(Handle other) { dvander@195: set(other); dvander@60: return *this; dvander@60: } dvander@60: dvander@60: private: dvander@195: void set(Handle other); dvander@195: dvander@195: ke::HeapRoot *root_; dvander@195: Handle obj_; 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@195: virtual ~IStackFrameIterator() { dvander@195: } 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@195: // Listener interface for when public functions are registered or unregisted. dvander@195: class IPublicFunctionListener dvander@195: { dvander@195: public: dvander@195: virtual ~IPublicFunctionListener() { dvander@195: } dvander@195: dvander@195: // Called when a public function becomes available to the runtime. dvander@195: virtual void registerPublic(Handle fun) = 0; dvander@195: dvander@195: // Called when a public is no longer available to the runtime. dvander@195: virtual void unregisterPublic(Handle fun) = 0; dvander@195: }; dvander@195: 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@170: // A pubvar is an ISourcePawnEngine-compatible structure that holds information dvander@170: // about public variables. dvander@170: class KE_EXPORT Pubvar dvander@170: { dvander@170: public: dvander@170: // Returns the name of a pubvar, which is never NULL. The string is dvander@170: // guaranteed to be interned. dvander@170: Local name(); dvander@170: }; dvander@170: 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@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: * 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@129: static bool Invoke(Handle fun, const Parameter *params, unsigned nparams, dvander@129: bool checkTypes, 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@195: /* Returns a new stack frame iterator object. */ dvander@69: static IStackFrameIterator *NewStackFrameIterator(); dvander@195: dvander@195: /* dvander@195: * Binds a native, by name, to an address. Natives are an ISPE1 concept dvander@195: * (originally from Pawn/Small's AMX API). In SourceMod 1, natives were dvander@195: * registered globally, but bound to plugins individually. We roughly dvander@195: * preserve that functionality here, by allowing host applications to dvander@195: * give us the name -> address mappings. dvander@195: * dvander@195: * Natives can be rebound or unbound any number of times. This function dvander@195: * fails if there is not enough memory. dvander@195: */ dvander@195: static bool BindNative(const char *name, void *address); dvander@195: dvander@195: /* Sets the object that will listen for public functions. */ dvander@195: static void SetPublicFunctionListener(IPublicFunctionListener *listener); 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@232: extern bool Compile(const char *path); dvander@60: dvander@61: class Internals dvander@61: { dvander@61: template friend class Root; dvander@61: dvander@61: private: dvander@195: static ke::HeapRoot *NewHeapRoot(); dvander@195: static void Destroy(ke::HeapRoot *root); dvander@61: }; dvander@61: dvander@61: template void dvander@195: Root::set(Handle other) dvander@61: { dvander@195: if (!other) { dvander@195: obj_ = other; dvander@61: return; dvander@195: } dvander@195: dvander@195: ke::Object **ptr = reinterpret_cast(*other); dvander@195: if (!root_) { dvander@195: root_ = Internals::NewHeapRoot(); dvander@195: if (!root_) dvander@195: return; dvander@195: } dvander@195: dvander@195: *reinterpret_cast(root_) = *ptr; dvander@195: obj_.obj_ = reinterpret_cast(root_); dvander@61: } dvander@61: dvander@195: template dvander@195: Root::~Root() dvander@61: { dvander@195: if (!root_) dvander@61: return; dvander@195: Internals::Destroy(root_); dvander@61: } dvander@61: dvander@195: dvander@60: } dvander@60: danderson@96: #endif // _include_sourcepawn2_api_h_