include/keima.h
author Asher Baker <asherkin@gmail.com>
Mon Jun 10 15:52:44 2013 +0100 (2013-06-10)
changeset 265 3a903b89a514
parent 251 ca99a81745fe
permissions -rw-r--r--
Fixed type checking for multidimensional arrays.
     1 /* vim: set ts=4 sw=4 tw=99 et:
     2  *
     3  * Copyright (C) 2004-2012 David Anderson
     4  *
     5  * This file is part of SourcePawn.
     6  *
     7  * SourcePawn is free software: you can redistribute it and/or modify it under
     8  * the terms of the GNU General Public License as published by the Free
     9  * Software Foundation, either version 3 of the License, or (at your option)
    10  * any later version.
    11  * 
    12  * SourcePawn is distributed in the hope that it will be useful, but WITHOUT ANY
    13  * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    14  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
    15  *
    16  * You should have received a copy of the GNU General Public License along with
    17  * SourcePawn. If not, see http://www.gnu.org/licenses/.
    18  */
    19 #ifndef _include_sourcepawn2_api_h_
    20 #define _include_sourcepawn2_api_h_
    21 
    22 #include <assert.h>
    23 #include <stddef.h>
    24 #include "../include/keima_util.h"
    25 
    26 namespace ke {
    27 
    28 class Zone;
    29 class Object;
    30 class HandleScope;
    31 class HeapRoot;
    32 
    33 }
    34 
    35 namespace Ke {
    36 
    37 class Function;
    38 class Package;
    39 
    40 /*
    41  * A Handle is a safe pointer that holds an object reference, such that it
    42  * can be scanned and potentially moved by the garbage collector.
    43  */
    44 template <typename T>
    45 class Handle
    46 {
    47     template <typename S> friend class Root;
    48   protected:
    49     template <typename S> void typeCheck() {
    50         while (false) {
    51             T *v1 = NULL;
    52             S *v2 = NULL;
    53             v1 = v2;
    54             (void)v1;
    55         }
    56     }
    57 
    58   public:
    59     Handle()
    60       : obj_(NULL)
    61     {
    62     }
    63 
    64     template <typename S> Handle(Handle<S> other)
    65       : obj_(reinterpret_cast<S *>(*other))
    66     {
    67         typeCheck<S>();
    68     }
    69  
    70     explicit Handle(T *obj)
    71       : obj_(obj)
    72     {
    73     }
    74 
    75     T *operator ->() const {
    76         return obj_;
    77     }
    78     T *operator *() const {
    79         return obj_;
    80     }
    81     operator bool () const {
    82         return !!obj_;
    83     }
    84 
    85   protected:
    86     T *obj_;
    87 };
    88 
    89 /*
    90  * A local variable that roots an object. Locals are owned by the nearest
    91  * HandleScope, and as soon as that HandleScope dies, all its Locals are
    92  * no longer available.
    93  */
    94 template <typename T>
    95 class Local : public Handle<T>
    96 {
    97   public:
    98     Local()
    99       : Handle<T>()
   100     {
   101     }
   102 
   103     template <typename S> Local(Local<S> other)
   104       : Handle<T>(reinterpret_cast<T *>(*other))
   105     {
   106         this->template typeCheck<S>();
   107     }
   108 
   109     template <typename S> Local(S *other)
   110       : Handle<T>(other)
   111     {
   112     }
   113 };
   114 
   115 /*
   116  * A non-local variable that outlives HandleScopes. Unlike Local, a Root
   117  * actually represents a rooted location. Roots must be allocated and
   118  * disposed, and assignment to a root changes its contained object, not
   119  * the location of the object.
   120  */
   121 template <typename T>
   122 class Root
   123 {
   124   public:
   125     Root()
   126       : root_(NULL)
   127     {
   128     }
   129 
   130     Root(Handle<T> other)
   131       : root_(NULL)
   132     {
   133         set(other);
   134     }
   135 
   136     inline ~Root();
   137 
   138     operator const Handle<T>() const {
   139         return obj_;
   140     }
   141 
   142     bool operator ==(Handle<T> other) {
   143         return Handle<T>(*this) == other;
   144     }
   145     Root<T> &operator =(Handle<T> other) {
   146         set(other);
   147         return *this;
   148     }
   149 
   150   private:
   151     void set(Handle<T> other);
   152 
   153     ke::HeapRoot *root_;
   154     Handle<T> obj_;
   155 };
   156 
   157 /*
   158  * A HandleScope is where Local roots are allcoated. When the HandleScope
   159  * is destroyed, all Handles created under it are also destroyed. HandleScopes
   160  * may only be allocated on the stack, in LIFO order.
   161  */
   162 class HandleScope
   163 {
   164   protected:
   165     ke::Zone *zone_;
   166     ke::Object **position_;
   167     HandleScope *prev_;
   168 
   169     HandleScope(ke::Zone *zone, ke::Object **position, HandleScope *prev)
   170       : zone_(zone),
   171         position_(position),
   172         prev_(prev)
   173     {
   174     }
   175 
   176   public:
   177     HandleScope();
   178     ~HandleScope();
   179 
   180     static ke::Object **CreateHandle(ke::Object *obj);
   181 
   182   private:
   183     // Disallow silly stuff.
   184     HandleScope(const HandleScope &);
   185     void operator =(const HandleScope &);
   186     void *operator new (size_t size);
   187     void operator delete(void *, size_t);
   188 };
   189 
   190 class Parameter;
   191 
   192 // Error messages are pumped through this interface.
   193 class IMessageReporter
   194 {
   195   public:
   196     virtual void onOutOfMemory() {
   197     }
   198     virtual void onUncaughtException(const char *message) {
   199     }
   200     virtual void beginCompilationErrors(const char *file) {
   201     }
   202     virtual void reportCompilationError(const char *message, unsigned line, unsigned col) {
   203     }
   204     virtual void endCompilationErrors() {
   205     }
   206 };
   207 
   208 // For the purposes of error reporting, very basic information can be queried
   209 // about the stack frame. This structure may be used to retrieve such
   210 // information. During iteration, it is illegal to re-enter any scripted code
   211 // or call any Keima functions that may cause garbage collection.
   212 class IStackFrameIterator
   213 {
   214   public:
   215     virtual ~IStackFrameIterator() {
   216     }
   217 
   218     // Returns true if there are more frames, false otherwise.
   219     virtual bool done() = 0;
   220 
   221     // Returns the name of the current function. This may be NULL if the
   222     // function is anonymous.
   223     virtual const char *function() = 0;
   224 
   225     // Returns the file of the current function. This will return an invalid
   226     // path for C++ functions (for example, "<native>").
   227     virtual const char *source() = 0;
   228 
   229     // Returns the line number currently executing on this frame. For C++
   230     // functions, this is always 0.
   231     virtual unsigned lineNumber() = 0;
   232 
   233     // Advance to the previous frame in the call stack.
   234     virtual void prev() = 0;
   235 };
   236 
   237 // Listener interface for when public functions are registered or unregisted.
   238 class IPublicFunctionListener
   239 {
   240   public:
   241     virtual ~IPublicFunctionListener() {
   242     }
   243 
   244     // Called when a public function becomes available to the runtime.
   245     virtual void registerPublic(Handle<Function> fun) = 0;
   246 
   247     // Called when a public is no longer available to the runtime.
   248     virtual void unregisterPublic(Handle<Function> fun) = 0;
   249 };
   250 
   251 // A string is an immutable UTF8 buffer.
   252 class KE_EXPORT String
   253 {
   254   public:
   255     static Local<String> NewAscii(const char *str);
   256 
   257     // Returns the length of the string, in bytes.
   258     unsigned length();
   259 
   260     // Returns the character buffer of the string, or NULL on failure. If the
   261     // string is interned, chars() is guaranteed to succeed.
   262     const char *chars();
   263 };
   264 
   265 // A function is an executable unit of code.
   266 class KE_EXPORT Function
   267 {
   268   public:
   269     // Returns the name of a function, which may be NULL. If not NULL, the
   270     // string is guaranteed to be interned.
   271     Local<String> name();
   272 
   273     // Returns the package the function was created in.
   274     Local<Package> package();
   275 };
   276 
   277 // A pubvar is an ISourcePawnEngine-compatible structure that holds information
   278 // about public variables.
   279 class KE_EXPORT Pubvar
   280 {
   281   public:
   282     // Returns the name of a pubvar, which is never NULL. The string is
   283     // guaranteed to be interned.
   284     Local<String> name();
   285 };
   286 
   287 // A package is a collection of compiled files and possibly sub-packages.
   288 // Internally, packages are used to implement the "import" statement. However,
   289 // the host application can also create packages to organize related files,
   290 // restrict import visibility, or implement hot swapping of loaded modules.
   291 class KE_EXPORT Package
   292 {
   293   public:
   294     enum {
   295         Normal = 0,
   296 
   297         // The package cannot be accessed from any import statement.
   298         Hidden = (1 << 0),
   299 
   300         // Source files compiled in this package cannot import names in the
   301         // package.
   302         Jailed = (1 << 1)
   303     };
   304 
   305     // Creates a package. The parent package may be NULL. The name can be NULL
   306     // as well. |path| must be a filesystem path, which will be normalized 
   307     // according to OS-specific rules.
   308     static Local<Package> New(Handle<Package> parent,
   309                               Handle<String> name,
   310                               const char *path,
   311                               unsigned flags);
   312 
   313     // Returns the name of the package, which may be NULL. The string is
   314     // guaranteed to be interned.
   315     Local<String> name();
   316 
   317     // Returns the full path of the package. The string is guaranteed to be
   318     // interned.
   319     Local<String> path();
   320 
   321     // Sets the package's native identity. This is a host-application defined
   322     // value that is passed to native callbacks.  Packages created under this
   323     // one will automatically inherit this native identity.
   324     void setNativeIdentity(void *identity);
   325 
   326     // Returns the package's native identity, or NULL if none was set.
   327     void *getNativeIdentity();
   328 };
   329 
   330 class Keima
   331 {
   332   public:
   333     /*
   334      * Initializes the Keima engine. This must be called exactly once before any
   335      * other Keima functions are called. After this, it is safe to use Keima
   336      * on the calling thread only. It is not safe to race on calling this.
   337      */
   338     static bool Initialize();
   339 
   340     /*
   341      * Shuts down the Keima engine and frees data structures on all threads.
   342      */
   343     static void Shutdown();
   344 
   345     /*
   346      * Searches the call stack and returns true if the given package has any
   347      * active code running. This is an O(n) algorithm.
   348      */
   349     static bool IsInCallStack(Handle<Package> package);
   350 
   351     /*
   352      * Reclaim as much memory as possible. This pauses the calling thread
   353      * until garbage collection completes.
   354      */
   355     static void CollectGarbage();
   356 
   357     /*
   358      * Clear any pending exception.
   359      */
   360     static void ClearPendingException();
   361 
   362     /*
   363      * Executes a function with the given parameters. This interface is
   364      * intended for compatibility with SourceMod's ISourcePawnEngine2 and
   365      * should not be used otherwise, since it is intended to support only
   366      * a small subset of the core language.
   367      */
   368     static bool Invoke(Handle<Function> fun, const Parameter *params, unsigned nparams,
   369                        bool checkTypes, int *result);
   370 
   371     /*
   372      * Sets the global message handler through which errors will be reported
   373      */
   374     static void InstallMessageReporter(IMessageReporter *reporter);
   375 
   376     /* Returns a new stack frame iterator object. */
   377     static IStackFrameIterator *NewStackFrameIterator();
   378 
   379     /*
   380      * Binds a native, by name, to an address. Natives are an ISPE1 concept
   381      * (originally from Pawn/Small's AMX API). In SourceMod 1, natives were
   382      * registered globally, but bound to plugins individually. We roughly
   383      * preserve that functionality here, by allowing host applications to
   384      * give us the name -> address mappings.
   385      *
   386      * Natives can be rebound or unbound any number of times. This function
   387      * fails if there is not enough memory.
   388      */
   389     static bool BindNative(const char *name, void *address);
   390 
   391     /* Sets the object that will listen for public functions. */
   392     static void SetPublicFunctionListener(IPublicFunctionListener *listener);
   393 
   394     /*
   395      * Installs a system root folder. When an attempt to import locally fails,
   396      * the list of system roots are searched in the order they were installed.
   397      *
   398      * The given path must be absolute. It may contain a trailing slash.
   399      *
   400      * The name is an arbitrary, optional identifier that can be used to
   401      * build fully-qualified package identifiers.
   402      */
   403     static bool InstallSystemRoot(const char *path, const char *name);
   404 
   405     /*
   406      * Compiles a source file into a package and runs any initializers it has.
   407      * The file name must be a file name only, rather than a path. It may
   408      * optionally end in ".sp". If no ".sp" is provided, it is added
   409      * automatically.
   410      *
   411      * Note that if the file name (sans ".sp" extension) does not match the
   412      * regular expression /^[A-Za-z_][A-Za-z0-9_]+$/ then it will not be
   413      * importable from other files.
   414      */
   415     static bool Compile(Handle<Package> package, const char *name);
   416 };
   417 
   418 /*
   419  * Suppresses exceptions. This is useful for calling API functions. When this
   420  * in scope, errors will be reported, but the exception will be cleared after.
   421  */
   422 class AutoClearExceptions
   423 {
   424   public:
   425     ~AutoClearExceptions()
   426     {
   427         Keima::ClearPendingException();
   428     }
   429 };
   430 
   431 // Argument-passing interface for Invoke().
   432 class Parameter
   433 {
   434   public:
   435     enum Type {
   436         Int,
   437         Float,
   438         IntRef,
   439         FloatRef,
   440         Array,
   441         CharArray
   442     };
   443 
   444     Parameter()
   445     {
   446     }
   447 
   448     Parameter(int i)
   449       : type_(Int)
   450     {
   451         u.i = i;
   452     }
   453 
   454     Parameter(int *i, bool writeback)
   455       : type_(IntRef),
   456         writeback_(writeback)
   457     {
   458         u.ip = i;
   459     }
   460 
   461     Parameter(float f)
   462       : type_(Float)
   463     {
   464         u.f = f;
   465     }
   466 
   467     Parameter(float *f, bool writeback)
   468       : type_(FloatRef),
   469         writeback_(writeback)
   470     {
   471         u.fp = f;
   472     }
   473 
   474     Parameter(Type type, void *buffer, size_t length, bool writeback)
   475       : type_(type),
   476         writeback_(writeback),
   477         length_(length)
   478     {
   479         assert(type == Array || type == CharArray);
   480         u.buffer = buffer;
   481     }
   482 
   483     Type type() const {
   484         return type_;
   485     }
   486 
   487     int i32() const {
   488         assert(type() == Int);
   489         return u.i;
   490     }
   491     float f() const {
   492         assert(type() == Float);
   493         return u.f;
   494     }
   495     int *i32p() const {
   496         assert(type() == IntRef);
   497         return u.ip;
   498     }
   499     float *fp() const {
   500         assert(type() == FloatRef);
   501         return u.fp;
   502     }
   503     bool writeback() const {
   504         assert(type() >= IntRef && type() <= CharArray);
   505         return writeback_;
   506     }
   507     size_t length() const {
   508         return length_;
   509     }
   510     void *buffer() const {
   511         assert(type() == Array || type() == CharArray);
   512         return u.buffer;
   513     }
   514 
   515   private:
   516     Type type_;
   517     bool writeback_;
   518     size_t length_;
   519 
   520     union {
   521         int i;
   522         float f;
   523         int *ip;
   524         float *fp;
   525         void *buffer;
   526     } u;
   527 };
   528 
   529 class Internals
   530 {
   531     template <typename T> friend class Root;
   532 
   533   private:
   534     static ke::HeapRoot *NewHeapRoot();
   535     static void Destroy(ke::HeapRoot *root);
   536 };
   537 
   538 template <typename T> void
   539 Root<T>::set(Handle<T> other)
   540 {
   541     if (!other) {
   542         obj_ = other;
   543         return;
   544     }
   545 
   546     ke::Object **ptr = reinterpret_cast<ke::Object **>(*other);
   547     if (!root_) {
   548         root_ = Internals::NewHeapRoot();
   549         if (!root_)
   550             return;
   551     }
   552 
   553     *reinterpret_cast<ke::Object **>(root_) = *ptr;
   554     obj_.obj_ = reinterpret_cast<T *>(root_);
   555 }
   556 
   557 template <typename T>
   558 Root<T>::~Root()
   559 {
   560     if (!root_)
   561         return;
   562     Internals::Destroy(root_);
   563 }
   564 
   565 
   566 }
   567 
   568 #endif // _include_sourcepawn2_api_h_