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