Milán Major

netscape-revival

1 branch
Code

mocha/include/mochaapi.h

#ifndef _mochaapi_h_
#define _mochaapi_h_
/*
** Mocha API.
**
** Brendan Eich, 6/21/95
*/
#include <stddef.h>
#include "prmacros.h"
#include "mo_pubtd.h"                   /* public typedefs */

NSPR_BEGIN_EXTERN_C

/*
** Mocha stack datum type.
**
** API clients should use only MOCHA_UNDEF, MOCHA_FUNCTION, MOCHA_OBJECT,
** MOCHA_NUMBER, MOCHA_BOOLEAN, and MOCHA_STRING.  Further, MochaFunction and
** MochaObject are mostly-opaque struct types, and the only method for getting
** valid pointers to instances of these types is to call MOCHA_DefineFunction()
** or MOCHA_NewObject(), e.g.
*/
typedef enum MochaTag {
    MOCHA_UNDEF,                        /* undefined value (void) */
    MOCHA_INTERNAL,                     /* internal handle (void *) */
    MOCHA_ATOM,                         /* unresolved identifier */
    MOCHA_SYMBOL,                       /* resolved symbol (lvalue) */
    MOCHA_FUNCTION,                     /* function pointer (rvalue) */
    MOCHA_OBJECT,                       /* object reference (rvalue) */
    MOCHA_NUMBER,                       /* floating point number (rvalue) */
    MOCHA_BOOLEAN,                      /* Boolean (rvalue) */
    MOCHA_STRING,                       /* character string (rvalue) */
    MOCHA_NTYPES
} MochaTag;

typedef struct MochaPair {
    MochaObject         *obj;           /* object containing this symbol */
    MochaSymbol         *sym;           /* member symbol in object scope */
} MochaPair;

/*
** API clients should not set or use nrefs.  All MochaDatum instances visible
** through this API are stack-allocated, either on the Mocha virtual machine
** interpreter's stack or on the client's C runtime stack.
**
** In other words, if you need to make a MochaDatum to return from a native
** function (see below for more), just declare it as a local variable in the
** function, set its members using MOCHA_INIT_DATUM, and return it.
*/
struct MochaDatum {
    MochaRefCount       nrefs;          /* reference count, must be first */
    uint8               tag;            /* union discriminant */
    uint8               flags;          /* flags, see below */
    uint16              taint;          /* taint code */
    union {
        void            *ptr;           /* internal pointer */
        MochaAtom       *atom;          /* literal */
        MochaPair       pair;           /* object/symbol pair */
        MochaFunction   *fun;           /* function pointer */
        MochaObject     *obj;           /* object pointer */
        MochaFloat      fval;           /* number */
        MochaBoolean    bval;           /* boolean */
    } u;
};

#define MDF_BACKEDGE    0x01            /* graph back-edge: do not refcount */
#define MDF_ENUMERATE   0x02            /* property is visible to for-in loop */
#define MDF_READONLY    0x04            /* set when property is read-only */
#define MDF_VISITED     0x08            /* visited bit for depth-first search */
#define MDF_TAINTED     0x10            /* for private/secret data tainting */
#define MDF_ALLFLAGS    0x1f            /* bit-set of all valid datum flags */

#ifdef DEBUG_brendan
#define MDF_TRACEBITS   0xa0            /* make sure these two bits propagate */
#else
#define MDF_TRACEBITS   0
#endif

#define MOCHA_ASSERT_VALID_DATUM_FLAGS(DP) \
    PR_ASSERT(((DP)->flags & ~MDF_ALLFLAGS) == MDF_TRACEBITS)

/* Well-known data tainting code values. */
#define MOCHA_TAINT_IDENTITY    0
#define MOCHA_TAINT_SHIST       ((uint16)0xfffd)
#define MOCHA_TAINT_JAVA        ((uint16)0xfffe)
#define MOCHA_TAINT_MAX         ((uint16)0xffff)

#define MOCHA_MIX_TAINT(MC, ACCUM, TAINT)                                     \
    NSPR_BEGIN_MACRO                                                          \
        uint16 _ACCUM = (ACCUM), _TAINT = (TAINT);                            \
        if (_ACCUM != _TAINT) {                                               \
            if (_ACCUM == MOCHA_TAINT_IDENTITY) {                             \
                (ACCUM) = _TAINT;                                             \
            } else if (_TAINT != MOCHA_TAINT_IDENTITY) {                      \
                if (mocha_MixTaint)                                           \
                    (ACCUM) = (*mocha_MixTaint)(MC, _ACCUM, _TAINT);          \
                else                                                          \
                    (ACCUM) = MOCHA_TAINT_MAX;                                \
            }                                                                 \
        }                                                                     \
    NSPR_END_MACRO

extern MochaTaintMixer mocha_MixTaint;

/*
** Call MOCHA_INIT_DATUM to initialize a datum passed by reference from the
** runtime into an object operation like OBJ_GET_PROPERTY, or as a result param
** in a native method (rval).
**
** Call MOCHA_INIT_FULL_DATUM to initialize an auto storage class temporary
** datum that's passed to MOCHA_SetProperty(), MOCHA_ConvertDatum(), etc.
*/
#define MOCHA_INIT_DATUM(MC,DP,TAG,ARM,VAL)                                   \
    NSPR_BEGIN_MACRO                                                          \
        (DP)->tag = TAG;                                                      \
        (DP)->ARM = VAL;                                                      \
    NSPR_END_MACRO

#define MOCHA_INIT_FULL_DATUM(MC,DP,TAG,FLAGS,TAINT,ARM,VAL)                  \
    NSPR_BEGIN_MACRO                                                          \
        MOCHA_INIT_DATUM(MC,DP,TAG,ARM,VAL);                                  \
        (DP)->flags = MDF_TRACEBITS | ((FLAGS) & MDF_ALLFLAGS);               \
        (DP)->taint = TAINT;                                                  \
    NSPR_END_MACRO

#define MOCHA_DATUM_IS_NULL(D)  ((D).tag == MOCHA_OBJECT && (D).u.obj == 0)

/* XXX should use macros from prdtoa.c, exported via a header... */
#include "prcpucfg.h"

#ifdef IS_LITTLE_ENDIAN
#define _word0(x) (((uint32 *)&(x))[1])
#define _word1(x) (((uint32 *)&(x))[0])
#else
#define _word0(x) (((uint32 *)&(x))[0])
#define _word1(x) (((uint32 *)&(x))[1])
#endif
#define _expmask  0x7ff00000

#define MOCHA_FLOAT_IS_NaN(x) ((_word0(x) & _expmask) == _expmask &&          \
			       (_word1(x) || (_word0(x) & 0x000fffff)))

/*
** Well-known global Mocha data.  Use these instead of making your own if
** your native function returns void or 0.
*/
extern MochaDatum MOCHA_void;
extern MochaDatum MOCHA_null;
extern MochaDatum MOCHA_zero;
extern MochaDatum MOCHA_NaN;
extern MochaDatum MOCHA_false;
extern MochaDatum MOCHA_true;
extern MochaDatum MOCHA_empty;          /* the empty string */

/*
** Hold any reference from *dp to an atom, function, or object.  If *dp is not
** of reference type (i.e., it's a number or boolean), do nothing.
*/
extern void
MOCHA_HoldRef(MochaContext *mc, MochaDatum *dp);

/*
** Drop any reference from *dp to an atom, function, or object.  If *dp is not
** of reference type (i.e., it's a number or boolean), do nothing.
*/
extern void
MOCHA_DropRef(MochaContext *mc, MochaDatum *dp);

/*
** Lower any reference count held by dp, but don't destroy the referenced
** object if it goes to zero.  Used to make weak links that are strengthened
** by the runtime, e.g., the dp value/result parameter of OBJ_GET_PROPERTY.
*/
extern void
MOCHA_WeakenRef(MochaContext *mc, MochaDatum *dp);

/*
** Convert d to the type indicated by tag and return the result in dp.
*/
MochaBoolean
MOCHA_ConvertDatum(MochaContext *mc, MochaDatum d, MochaTag tag,
                   MochaDatum *dp);

/*
** Convert d to a function reference.  Return true on success with *funp
** pointing to the held function, which the caller must release by calling
** MOCHA_DropObject().  Return false on error, implying MOCHA_ReportError()
** has been called.
*/
extern MochaBoolean
MOCHA_DatumToFunction(MochaContext *mc, MochaDatum d, MochaFunction **funp);

/*
** Convert d to an object reference.  Report the error and return false if
** there's no valid conversion.  Return true with *objp pointing to the held
** object on success.  It is up to the user to call MOCHA_DropObject() after
** using the returned object.
*/
extern MochaBoolean
MOCHA_DatumToObject(MochaContext *mc, MochaDatum d, MochaObject **objp);

/*
** Convert d to a number.  Report the error and return false if there's no
** valid conversion.  Return true with the number in *fvalp on success.
*/
extern MochaBoolean
MOCHA_DatumToNumber(MochaContext *mc, MochaDatum d, MochaFloat *fvalp);

/*
** Convert d to a Boolean.  Report the error and return false if there's no
** valid conversion.  Return true with the boolean in *bvalp on success.
*/
extern MochaBoolean
MOCHA_DatumToBoolean(MochaContext *mc, MochaDatum d, MochaBoolean *bvalp);

/*
** Convert d to a string representation.  Report the error and return null
** if out of memory.  Return a pointer to an internalized string structure,
** MochaAtom, which must be released via mocha_DropAtom().
*/
extern MochaBoolean
MOCHA_DatumToString(MochaContext *mc, MochaDatum d, MochaAtom **atomp);

/*
** XXX comment me
*/
extern const char *
MOCHA_TypeOfDatum(MochaContext *mc, MochaDatum d);

/*
** Initialize Mocha by calling MOCHA_NewContext(), which creates a new
** execution context for compiling and running Mocha scripts and functions.
** Its return value is an opaque pointer to the new Mocha context.
**
** When you're all through doing Mocha, you may call MOCHA_DestroyContext().
*/
extern MochaContext *
MOCHA_NewContext(size_t stackSize);

extern void
MOCHA_DestroyContext(MochaContext *mc);

extern MochaContext *
MOCHA_ContextIterator(MochaContext **iterp);

/* XXX comment me */
extern MochaObject *
MOCHA_GetGlobalObject(MochaContext *mc);

/* XXX comment me */
extern MochaBoolean
MOCHA_SetGlobalObject(MochaContext *mc, MochaObject *obj);

/* XXX comment me */
extern MochaObject *
MOCHA_GetStaticLink(MochaContext *mc);

/*
** Wrapper function that calls malloc but reports errors via mc.
*/
extern void *
MOCHA_malloc(MochaContext *mc, size_t nbytes);

extern char *
MOCHA_strdup(MochaContext *mc, const char *s);

extern void
MOCHA_free(MochaContext *mc, void *p);

/*
** Mocha Object structure.
** XXX eliminate nrefs via gc, make data a symbol in scope
*/
struct MochaObject {
    MochaRefCount       nrefs;          /* reference count, must be first */
    MochaClass          *clazz;         /* class pointer */
    void                *data;          /* private data */
    MochaScope          *scope;         /* symbol table and public data */
    MochaObject         *prototype;     /* prototype object; strong link */
    MochaObject         *parent;        /* parent scope's object; weak link */
};

/*
** Mocha object operations.  Mocha API clients may stub these with functions
** prototyped below, or provide their own specific implementations.
**
** The getProperty and setProperty functions allow clients to intercept gets
** and sets, and to modify the nominal property value being fetched or stored
** (the MochaDatum pointed at by dp).  Mocha properties are numbered by slot,
** which the API client defines (see below for more on this).  So for objects
** with fixed properties, the easiest way to implement getProperty/setProperty
** is with 'switch (slot) {...}' statements.
**
** The listProperties function is called just before an object's properties
** are enumerated by a for-in loop.  If an object reflects properties lazily,
** it should provide this method rather than a stub, and the function should
** eagerly add all unreflected properties to obj.
**
** The resolveName entry point should be used by objects to reflect properties
** lazily from their native source into Mocha (e.g., HTML page elements, which
** should only be reflected into Mocha if an embedded script mentions them).
** resolveName takes a name and adds a property or defines a symbol for it in
** the object's scope if name is resolvable.
**
** The dp value/result parameter to get/setProperty and convert need not be set
** by these methods: it is preset by the runtime to hold a nominal value: the
** current property value for get, the value to store for set, and MOCHA_void
** for convert.  Any new object reference returned via dp must be weak (as are
** refs returned by MOCHA_NewObject(), etc.).  The runtime will strengthen dp
** after a successful return from one of these methods.
**
** get/setProperty, listProperties, resolveName, and convert use the same error
** reporting convention as native functions: return MOCHA_FALSE after reporting
** the error with MOCHA_ReportError() or MOCHA_ReportOutOfMemory() on failure,
** return MOCHA_TRUE on success.
*/
struct MochaClass {
    const char      *name;
    MochaPropertyOp getProperty;
    MochaPropertyOp setProperty;
    MochaBoolean    (*listProperties)(MochaContext *mc, MochaObject *obj);
    MochaBoolean    (*resolveName)(MochaContext *mc, MochaObject *obj,
                                   const char *name);
    MochaBoolean    (*convert)(MochaContext *mc, MochaObject *obj,
                               MochaTag tag, MochaDatum *dp);
    void            (*finalize)(MochaContext *mc, MochaObject *obj);
};

/* Helper macros that take MochaObject * and call object operations. */
#define OBJ_GET_PROPERTY(mc, obj, slot, dp) \
        ((*(obj)->clazz->getProperty)(mc, obj, slot, dp))
#define OBJ_SET_PROPERTY(mc, obj, slot, dp) \
        ((*(obj)->clazz->setProperty)(mc, obj, slot, dp))
#define OBJ_LIST_PROPERTIES(mc, obj) \
        ((*(obj)->clazz->listProperties)(mc, obj))
#define OBJ_RESOLVE_NAME(mc, obj, name) \
        ((*(obj)->clazz->resolveName)(mc, obj, name))
#define OBJ_CONVERT(mc, obj, tag, dp) \
        ((*(obj)->clazz->convert)(mc, obj, tag, dp))
#define OBJ_FINALIZE(mc, obj) \
        ((*(obj)->clazz->finalize)(mc, obj))

/*
** Do-nothing stub for getProperty and setProperty, in case the object obj
** doesn't care about setProperty calls, and doesn't need to compute new
** values to satisfy getProperty calls.
*/
extern MochaBoolean
MOCHA_PropertyStub(MochaContext *mc, MochaObject *obj, MochaSlot slot,
                   MochaDatum *dp);

/*
** Do-nothing stub for MochaClass.listProperties.
*/
extern MochaBoolean
MOCHA_ListPropStub(MochaContext *mc, MochaObject *obj);

/*
** Do-nothing stub for MochaClass.resolveName.
*/
extern MochaBoolean
MOCHA_ResolveStub(MochaContext *mc, MochaObject *obj, const char *name);

/*
** Do-nothing stub for MochaClass.convert.
*/
extern MochaBoolean
MOCHA_ConvertStub(MochaContext *mc, MochaObject *obj, MochaTag tag,
                  MochaDatum *dp);

/*
** Do-nothing stub for MochaClass.finalize.
*/
extern void
MOCHA_FinalizeStub(MochaContext *mc, MochaObject *obj);

/*
** Mocha property specifier.
**
** A native object typically allocates property specifiers statically in an
** initialized array, passing the array to MOCHA_DefineObject() in the native
** object module's initialization function.  The array must be terminated with
** a specifier whose name is null.
**
** Example use, for a gauge widget written in C that exposes 3 properties to
** Mocha scripts:
**
**  enum gauge_slot { INITIAL_VALUE, REFRESH_RATE, REFRESH_URL };
**
**  static MochaPropertySpec gauge_props[] = {
**      {"initialValue",        INITIAL_VALUE},
**      {"refreshRate",         REFRESH_RATE},
**      {"refreshURL",          REFRESH_URL},
**      {0}
**  };
*/
struct MochaPropertySpec {
    char            *name;
    int16           slot;
    uint16          flags;
    MochaPropertyOp getter;
    MochaPropertyOp setter;
};

/*
** Mocha native function specifier.  Tells Mocha how to call a hand-written
** C function that may bridge to another language, like Java, or implement a
** low-level OS-specific function.  The call function pointer points to this
** user-supplied native function.  The function may return a MochaDatum via
** its *rval result parameter, but the default result is MOCHA_void.
**
** nargs is the minimum number of arguments to expect.  If fewer arguments
** are passed the rest will be passed as MOCHA_void.
**
** The fun member should not be set by the API client -- it should be left
** statically-initialized by default to 0.  After the first call that passes
** a vector of MochaFunctionSpec structs to MOCHA_DefineFunctions(), each vector
** element's fun pointer will point to a shared MochaFunction to be added to
** subsequent objects' scopes by reference.
*/
struct MochaFunctionSpec {
    char                *name;
    MochaNativeCall     call;
    uint8               nargs;
    uint8               flags;
    uint16              spare;
    MochaFunction       *fun;
};

/*
** Initialize clazz, defining a constructor named clazz->name in obj's scope.
** Construct the prototype object for clazz, giving it data, properties spec'd
** in ps, and methods in fs.  Add static properties and methods in static_ps
** and static_fs to the constructor's scope, so Number.MAX_VALUE and Date.UTC
** can be used.  Any of the final four arguments may be null.
**
** Return a pointer to the prototype, or null on error.
*/
extern MochaObject *
MOCHA_InitClass(MochaContext *mc, MochaObject *obj, MochaClass *clazz,
                void *data, MochaNativeCall constructor, unsigned nargs,
                MochaPropertySpec *ps, MochaFunctionSpec *fs,
                MochaPropertySpec *static_ps, MochaFunctionSpec *static_fs);

/*
** Return true with iff obj->clazz == clazz; return false otherwise, reporting
** the class error using the fun argument, which should be argv[-1].u.fun when
** in a native function.
*/
extern MochaBoolean
MOCHA_InstanceOf(MochaContext *mc, MochaObject *obj, MochaClass *clazz,
                 MochaFunction *fun);

/*
** Mocha native object constructor, which defines a name for the new object.
** Example call, in gauge initialization code:
**
**  obj = MOCHA_DefineNewObject(mc, obj, "gauge", &gauge_class, gauge_data,
**                              0, 0, gauge_props, gauge_methods);
**
** Note that gauge_data is the "void *data" member of the (MochaObject *)
** argument.  It should contain object private data, plus any (pointers to)
** allocation bookkeeping required by alloc and freeMemory.
*/
extern MochaObject *
MOCHA_DefineNewObject(MochaContext *mc, MochaObject *obj, const char *name,
                      MochaClass *clazz, void *data,
                      MochaObject *prototype, unsigned flags,
                      MochaPropertySpec *ps, MochaFunctionSpec *fs);

/*
** Sometimes it is useful to create an anonymous object.  Anonymous objects
** are destroyed automatically on last dereference, unless there are cycles
** from object to object, in which case a direct call to MOCHA_DestroyObject()
** is required somewhere.
*/
extern MochaObject *
MOCHA_NewObject(MochaContext *mc, MochaClass *clazz, void *data,
                MochaObject *prototype, MochaObject *parent,
                MochaPropertySpec *ps, MochaFunctionSpec *fs);

/*
** Bind nobj to the name given by atom in obj's scope, using a Mocha property.
** The flags argument should contain MochaDatum flags such as MDF_READONLY.
*/
extern MochaBoolean
MOCHA_DefineObject(MochaContext *mc, MochaObject *obj, const char *name,
                   MochaObject *nobj, unsigned flags);

/*
** Add the properties specified by the all-zeroes terminated array at ps to
** obj's scope.
*/
extern MochaBoolean
MOCHA_SetProperties(MochaContext *mc, MochaObject *obj, MochaPropertySpec *ps);

/*
** Named objects, those created via MOCHA_DefineObject(), must be destroyed
** with MOCHA_UndefineName(), not MOCHA_DestroyObject().  Reference-counted
** objects should be held with MOCHA_HoldObject() and destroyed on the last
** dereference with MOCHA_DropObject(), not by calling MOCHA_DestroyObject().
**
** The Mocha runtime takes care of holding and dropping objects created with
** zero reference count by a native or getProperty function.  Native code
** should just return the pointer returned by MOCHA_NewObject(), and not use
** MOCHA_HoldObject().
*/
extern void
MOCHA_DestroyObject(MochaContext *mc, MochaObject *obj);

/*
** Add a property with the given name and slot to an object.  Use this to
** create dynamic properties, and then be prepared to handle new slot numbers
** in your getProperty and setProperty object ops.  If name is null, add the
** property indexed by slot.
**
** Returns MOCHA_FALSE if out of memory, MOCHA_TRUE otherwise.
*/
extern MochaBoolean
MOCHA_SetProperty(MochaContext *mc, MochaObject *obj, const char *name,
                  MochaSlot slot, MochaDatum datum);

/*
** Remove a named property from an object.
** XXX need to take MochaDatum for number/boolean/string key
*/
extern void
MOCHA_RemoveProperty(MochaContext *mc, MochaObject *obj, const char *name);

/*
** Get, set (add), and remove property by slot instead of by name.
*/
extern MochaBoolean
MOCHA_GetSlot(MochaContext *mc, MochaObject *obj, MochaSlot slot,
              MochaDatum *dp);

extern MochaBoolean
MOCHA_SetSlot(MochaContext *mc, MochaObject *obj, MochaSlot slot,
              MochaDatum datum);

extern void
MOCHA_RemoveSlot(MochaContext *mc, MochaObject *obj, MochaSlot slot);

/*
** XXX comment me
*/
MochaAtom *
MOCHA_Atomize(MochaContext *mc, const char *name);

/*
** XXX comment me
*/
const char *
MOCHA_GetAtomName(MochaContext *mc, MochaAtom *atom);

/*
** XXX comment me
*/
MochaAtom *
MOCHA_HoldAtom(MochaContext *mc, MochaAtom *atom);

/*
** XXX comment me
*/
MochaAtom *
MOCHA_DropAtom(MochaContext *mc, MochaAtom *atom);

/*
** Create a native function with the given callback and number of arguments.
** Don't associate it with a name in any scope.  It is up to the caller to
** free the returned structure via MOCHA_DestroyFunction() when no references
** remain.
**
** MochaFunction derives from MochaObject, so it's safe to cast up.
*/
extern MochaFunction *
MOCHA_NewFunction(MochaContext *mc, MochaObject *obj, MochaNativeCall call,
                  unsigned nargs);

extern void
MOCHA_DestroyFunction(MochaContext *mc, MochaFunction *fun);

/*
** Define a native function with the given name in obj's scope, and with the
** given C callback and number of arguments.  The call arguments points to a
** function of the following form:
**
**  MochaBoolean
**  call(MochaContext *mc, MochaObject *obj, unsigned argc,
**       MochaDatum *argv, MochaDatum *rval);
**
** The flags argument should contain MochaDatum flags such as MDF_READONLY.
*/
extern MochaFunction *
MOCHA_DefineFunction(MochaContext *mc, MochaObject *obj, const char *name,
                     MochaNativeCall call, unsigned nargs, unsigned flags);

extern MochaBoolean
MOCHA_DefineFunctions(MochaContext *mc, MochaObject *obj,
                      MochaFunctionSpec *fs);

/*
** Increment obj's reference count.  Use this before a MOCHA_DefineObject()
** or MOCHA_UndefineName() call that will decrement obj's reference count, so
** you can detach obj from its name and keep hold of it anonymously.
*/
extern MochaObject *
MOCHA_HoldObject(MochaContext *mc, MochaObject *obj);

/*
** Decrement obj's reference count, destroying it and returning null if the
** count goes to zero.  Return obj otherwise.
**
** If the reference count goes to zero, obj must not be named in any scope.
** You must call MOCHA_UndefineName() to drop a named object reference.
*/
extern MochaObject *
MOCHA_DropObject(MochaContext *mc, MochaObject *obj);

/*
** Lookup a name in obj's scope, returning MOCHA_FALSE only on error, else
** MOCHA_TRUE with *dp initialized to describe name's value, or MOCHA_UNDEF
** if name is not bound in obj.
*/
extern MochaBoolean
MOCHA_LookupName(MochaContext *mc, MochaObject *obj, const char *name,
                 MochaDatum *dp);

/*
** Like MOCHA_LookupName, but resolve undefined names via OBJ_RESOLVE_NAME.
*/
extern MochaBoolean
MOCHA_ResolveName(MochaContext *mc, MochaObject *obj, const char *name,
                  MochaDatum *dp);

/*
** Remove a name from the given object's scope.
*/
extern void
MOCHA_UndefineName(MochaContext *mc, MochaObject *obj, const char *name);

/*
** Remove all names from the given object's scope.
*/
extern void
MOCHA_ClearScope(MochaContext *mc, MochaObject *obj);

/*
** Compile Mocha source in the input buffer starting at base and continuing
** for length bytes, returning MOCHA_TRUE on success with the code member of
** script pointing at the generated bytecode.  Return MOCHA_FALSE on failure.
** On failure, the error-reporting function set by MOCHA_SetErrorReporter()
** (see below) will be called with details about the failure.
**
** NB: the buffer does not need to be a '\0'-terminated string.
*/
extern MochaScript *
MOCHA_CompileBuffer(MochaContext *mc, MochaObject *obj,
                    const char *base, size_t length,
                    const char *filename, unsigned lineno);

#ifdef MOCHAFILE
/*
** Like MOCHA_CompileBuffer, but opens filename readonly and reads it.
*/
extern MochaScript *
MOCHA_CompileFile(MochaContext *mc, MochaObject *obj, const char *filename);
#endif

/*
** Compile the source (base,length) into an object method for the given name
** and number of arguments.  Return MOCHA_TRUE on success, else MOCHA_FALSE.
** On failure, the error-reporting function set by MOCHA_SetErrorReporter()
** (see below) will be called with details about the failure.
*/
extern MochaBoolean
MOCHA_CompileMethod(MochaContext *mc, MochaObject *obj,
                    const char *name, unsigned nargs,
                    const char *base, size_t length,
                    const char *filename, unsigned lineno);

/*
** XXX comment me
*/
MochaBoolean
MOCHA_DecompileScript(MochaContext *mc, MochaScript *script, const char *name,
                      unsigned indent, char **sp);

/*
** XXX comment me
*/
MochaBoolean
MOCHA_DecompileFunctionBody(MochaContext *mc, MochaFunction *fun,
                            unsigned indent, char **sp);

/*
** Execute Mocha script compiled from MOCHA_Compile*().  Return MOCHA_TRUE
** on success with the last stack datum stored via result.  Return MOCHA_FALSE
** on failure, which means an error was reported (see mocha_SetErrorReporter(),
** below, for more on error reporting).
*/
extern MochaBoolean
MOCHA_ExecuteScript(MochaContext *mc, MochaObject *obj, MochaScript *script,
                    MochaDatum *result);

/*
** Destroy the given script, which must have been constructed by an earlier
** successful call to MOCHA_CompileBuffer().
*/
extern void
MOCHA_DestroyScript(MochaContext *mc, MochaScript *script);

/*
** A composite MOCHA_CompileBuffer/MOCHA_ExecuteScript utility function.
*/
extern MochaBoolean
MOCHA_EvaluateBuffer(MochaContext *mc, MochaObject *obj,
                     const char *base, size_t length,
                     const char *filename, unsigned lineno,
                     MochaDatum *result);

/*
** Call the named method (function or function-valued property) in obj with
** the given arguments.  Return true on success with *result set.  On error
** of any kind, return false.
*/
extern MochaBoolean
MOCHA_CallMethod(MochaContext *mc, MochaObject *obj, const char *name,
                 unsigned argc, MochaDatum *argv, MochaDatum *result);

/*
** Arrange for a function to be called on every branch, in order to schedule
** other threads, police infinite loops, etc.  The function pointed to by cb
** has the following prototype:
**
**  MochaBoolean
**  myMochaBranchCallback(MochaContext *mc, MochaScript *script);
**
** If it returns MOCHA_FALSE, the currently running script aborts.  Otherwise
** the script continues to execute.
*/
extern MochaBranchCallback
MOCHA_SetBranchCallback(MochaContext *mc, MochaBranchCallback cb);

/*
** Predicate telling whether the Mocha interpreter is currently running.
*/
extern MochaBoolean
MOCHA_IsRunning(MochaContext *mc);

/*
** Report an exception represented by the sprintf-like conversion of format
** and its arguments.  This exception message string is passed to a pre-set
** MochaErrorReporter function (see immediately below).
*/
extern void
MOCHA_ReportError(MochaContext *mc, const char *format, ...);

/*
** Complain when out of memory.
*/
extern void
MOCHA_ReportOutOfMemory(MochaContext *mc);

/*
** Register a function for reporting diagnostics.  The message string passed
** to the reporter may contain newlines, but will not end in a newline.
**
**  void
**  myErrorReporter(MochaContext *context, const char *message,
**                  MochaErrorReport *report);
**
** The final report argument is either null or a pointer to the following
** structure.  NB: the linebuf member points to a source line without the
** final newline.  If the source line is overlong, only the first buffer's
** worth is passed by reference.
*/
struct MochaErrorReport {
    const char  *filename;      /* source file name, URL, etc., or null */
    unsigned    lineno;         /* source line number */
    const char  *linebuf;       /* offending source line without final '\n' */
    const char  *tokenptr;      /* pointer to error token in linebuf */
};

/*
** Register a per-context error-reporter function.
*/
extern MochaErrorReporter
MOCHA_SetErrorReporter(MochaContext *mc, MochaErrorReporter reporter);

/*
** Data tainting structure and routines.
*/
struct MochaTaintInfo {
    uint16              taint;          /* a context's taint identifier */
    uint16              accum;          /* and its taint accumulator */
    void                *data;          /* private data pointer */
};

extern void
MOCHA_SetTaintCallbacks(MochaTaintCounter hold, MochaTaintCounter drop,
                        MochaTaintMixer mix);

extern MochaTaintInfo *
MOCHA_GetTaintInfo(MochaContext *mc);

extern void
MOCHA_SetTaintInfo(MochaContext *mc, MochaTaintInfo *info);

extern MochaBoolean
MOCHA_SetPropertyTaint(MochaContext *mc, MochaObject *obj, const char *name,
                       uint16 taint);

typedef int (*MochaCharFilter)(void *, char);

extern void
MOCHA_SetCharFilter(MochaContext *mc, MochaCharFilter filter, void *arg);

NSPR_END_EXTERN_C

#endif /* _mochaapi_h_ */