netscape-revival
mocha/src/mochaapi.c
/*
** Mocha API.
**
** Brendan Eich, 6/21/95
*/
#include <setjmp.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "prarena.h"
#include "prlog.h"
#include "prmem.h"
#include "prprf.h"
#include "mo_atom.h"
#include "mo_cntxt.h"
#include "mo_emit.h"
#include "mo_parse.h"
#include "mo_scan.h"
#include "mo_scope.h"
#include "mocha.h"
#include "mochaapi.h"
#include "mochalib.h"
uint16 (*mocha_MixTaint)(MochaContext *mc, uint16 accum, uint16 taint);
MochaDatum MOCHA_void = {0,MOCHA_UNDEF, MDF_TRACEBITS,MOCHA_TAINT_IDENTITY};
MochaDatum MOCHA_null = {0,MOCHA_OBJECT, MDF_TRACEBITS,MOCHA_TAINT_IDENTITY};
MochaDatum MOCHA_zero = {0,MOCHA_NUMBER, MDF_TRACEBITS,MOCHA_TAINT_IDENTITY};
MochaDatum MOCHA_NaN = {0,MOCHA_NUMBER, MDF_TRACEBITS,MOCHA_TAINT_IDENTITY};
MochaDatum MOCHA_false = {0,MOCHA_BOOLEAN,MDF_TRACEBITS,MOCHA_TAINT_IDENTITY};
MochaDatum MOCHA_true = {0,MOCHA_BOOLEAN,MDF_TRACEBITS,MOCHA_TAINT_IDENTITY};
MochaDatum MOCHA_empty = {0,MOCHA_STRING, MDF_TRACEBITS,MOCHA_TAINT_IDENTITY};
/*
** Do first things first, at most once.
*/
static void
mocha_StaticInit(MochaContext *mc)
{
if (MOCHA_true.u.bval)
return;
MOCHA_true.u.bval = MOCHA_TRUE;
MOCHA_empty.u.atom = mocha_Atomize(mc, "", ATOM_HELD | ATOM_STRING);
}
void
MOCHA_HoldRef(MochaContext *mc, MochaDatum *dp)
{
mocha_HoldRef(mc, dp);
}
void
MOCHA_DropRef(MochaContext *mc, MochaDatum *dp)
{
mocha_DropRef(mc, dp);
}
void
MOCHA_WeakenRef(MochaContext *mc, MochaDatum *dp)
{
switch (dp->tag) {
case MOCHA_ATOM:
case MOCHA_STRING:
dp->u.atom->nrefs--;
break;
case MOCHA_FUNCTION:
dp->u.fun->object.nrefs--;
break;
case MOCHA_OBJECT:
case MOCHA_SYMBOL:
if (dp->u.obj)
dp->u.obj->nrefs--;
break;
default:;
}
}
MochaBoolean
MOCHA_ConvertDatum(MochaContext *mc, MochaDatum d, MochaTag tag,
MochaDatum *dp)
{
MochaFunction *fun;
MochaObject *obj;
MochaFloat fval;
MochaBoolean bval;
MochaAtom *atom;
switch (tag) {
case MOCHA_FUNCTION:
if (!mocha_DatumToFunction(mc, d, &fun))
return MOCHA_FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_FUNCTION, u.fun, fun);
break;
case MOCHA_OBJECT:
if (!mocha_DatumToObject(mc, d, &obj))
return MOCHA_FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_OBJECT, u.obj, obj);
break;
case MOCHA_NUMBER:
if (!mocha_DatumToNumber(mc, d, &fval))
return MOCHA_FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_NUMBER, u.fval, fval);
break;
case MOCHA_BOOLEAN:
if (!mocha_DatumToBoolean(mc, d, &bval))
return MOCHA_FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_BOOLEAN, u.bval, bval);
break;
case MOCHA_STRING:
if (!mocha_DatumToString(mc, d, &atom))
return MOCHA_FALSE;
MOCHA_INIT_DATUM(mc, dp, MOCHA_STRING, u.atom, atom);
break;
default:
if ((unsigned)tag >= (unsigned)MOCHA_NTYPES) {
MOCHA_ReportError(mc, "illegal type tag %d", tag);
} else if (mocha_RawDatumToString(mc, d, &atom)) {
MOCHA_ReportError(mc, "can't convert %s to %s",
atom_name(atom), mocha_typeStr[tag]);
mocha_DropAtom(mc, atom);
}
return MOCHA_FALSE;
}
MOCHA_WeakenRef(mc, dp);
return MOCHA_TRUE;
}
MochaBoolean
MOCHA_DatumToFunction(MochaContext *mc, MochaDatum d, MochaFunction **funp)
{
return mocha_DatumToFunction(mc, d, funp);
}
MochaBoolean
MOCHA_DatumToObject(MochaContext *mc, MochaDatum d, MochaObject **objp)
{
return mocha_DatumToObject(mc, d, objp);
}
MochaBoolean
MOCHA_DatumToNumber(MochaContext *mc, MochaDatum d, MochaFloat *fvalp)
{
return mocha_DatumToNumber(mc, d, fvalp);
}
MochaBoolean
MOCHA_DatumToBoolean(MochaContext *mc, MochaDatum d, MochaBoolean *bvalp)
{
return mocha_DatumToBoolean(mc, d, bvalp);
}
MochaBoolean
MOCHA_DatumToString(MochaContext *mc, MochaDatum d, MochaAtom **atomp)
{
return mocha_DatumToString(mc, d, atomp);
}
const char *
MOCHA_TypeOfDatum(MochaContext *mc, MochaDatum d)
{
MochaAtom *atom;
if (!mocha_TypeOfDatum(mc, d, &atom))
return 0;
return atom_name(atom);
}
MochaContext *
MOCHA_NewContext(size_t stackSize)
{
MochaContext *mc;
mc = mocha_NewContext(stackSize);
if (mc) {
/* Can't initialize trailing union arms, so do this here. */
mocha_StaticInit(mc);
}
return mc;
}
void
MOCHA_DestroyContext(MochaContext *mc)
{
mocha_DestroyContext(mc);
}
MochaContext *
MOCHA_ContextIterator(MochaContext **iterp)
{
return mocha_ContextIterator(iterp);
}
/* XXX comment me */
MochaObject *
MOCHA_GetGlobalObject(MochaContext *mc)
{
return mc->globalObject;
}
/* XXX comment me */
MochaBoolean
MOCHA_SetGlobalObject(MochaContext *mc, MochaObject *obj)
{
if (obj->parent) {
MOCHA_ReportError(mc, "illegal global object %s", obj->clazz->name);
return MOCHA_FALSE;
}
mc->globalObject = obj; /* XXX weak link */
return mocha_InitStandardLibrary(mc, obj);
}
MochaObject *
MOCHA_GetStaticLink(MochaContext *mc)
{
return mc->staticLink;
}
void *
MOCHA_malloc(MochaContext *mc, size_t nbytes)
{
void *p = malloc(nbytes);
if (!p)
MOCHA_ReportOutOfMemory(mc);
return p;
}
char *
MOCHA_strdup(MochaContext *mc, const char *s)
{
char *p = MOCHA_malloc(mc, strlen(s) + 1);
if (!p)
return 0;
return strcpy(p, s);
}
void
MOCHA_free(MochaContext *mc, void *p)
{
free(p);
}
MochaBoolean
MOCHA_PropertyStub(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp)
{
return MOCHA_TRUE;
}
MochaBoolean
MOCHA_ListPropStub(MochaContext *mc, MochaObject *obj)
{
return MOCHA_TRUE;
}
MochaBoolean
MOCHA_ResolveStub(MochaContext *mc, MochaObject *obj, const char *name)
{
return MOCHA_TRUE;
}
MochaBoolean
MOCHA_ConvertStub(MochaContext *mc, MochaObject *obj, MochaTag tag,
MochaDatum *dp)
{
return MOCHA_TRUE;
}
void
MOCHA_FinalizeStub(MochaContext *mc, MochaObject *obj)
{
}
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)
{
MochaAtom *atom;
MochaObject *prototype;
MochaFunction *fun;
MochaDatum d;
atom = mocha_Atomize(mc, clazz->name, ATOM_HELD | ATOM_NAME);
if (!atom)
return 0;
/* Define the constructor function in a mutable scope for obj. */
prototype = 0;
if (!mocha_GetMutableScope(mc, obj))
goto out;
fun = mocha_DefineFunction(mc, obj, atom, constructor, nargs, 0);
if (!fun)
goto out;
/* Construct a prototype object for this class. */
prototype = mocha_NewObject(mc, clazz, data, 0, &fun->object);
if (!prototype)
goto out;
d = MOCHA_void;
if (!(*constructor)(mc, prototype, 0, 0, &d)) {
prototype->clazz = &mocha_ObjectClass;
mocha_DestroyObject(mc, prototype);
prototype = 0;
goto out;
}
if (d.tag == MOCHA_OBJECT && d.u.obj && d.u.obj != prototype) {
prototype->clazz = &mocha_ObjectClass;
mocha_DestroyObject(mc, prototype);
prototype = d.u.obj;
}
/* Bootstrap Function.prototype (XXX see mochalib.c for crucial order). */
if (!fun->object.prototype && fun->object.clazz == clazz) {
PR_ASSERT(fun->object.scope->object == &fun->object);
mocha_DropScope(mc, fun->object.scope);
fun->object.scope = mocha_HoldScope(mc, prototype->scope);
fun->object.prototype = MOCHA_HoldObject(mc, prototype);
}
/* Add properties and methods to the prototype and the constructor. */
if ((ps && !MOCHA_SetProperties(mc, prototype, ps)) ||
(fs && !MOCHA_DefineFunctions(mc, prototype, fs)) ||
(static_ps && !MOCHA_SetProperties(mc, &fun->object, static_ps)) ||
(static_fs && !MOCHA_DefineFunctions(mc, &fun->object, static_fs)) ||
!mocha_SetPrototype(mc, fun, prototype)) {
mocha_DestroyObject(mc, prototype);
prototype = 0;
goto out;
}
out:
if (!prototype)
mocha_RemoveSymbol(mc, obj->scope, atom);
mocha_DropAtom(mc, atom);
return prototype;
}
MochaBoolean
MOCHA_InstanceOf(MochaContext *mc, MochaObject *obj, MochaClass *clazz,
MochaFunction *fun)
{
if (obj->clazz != clazz) {
MOCHA_ReportError(mc, "method %s.%s called on incompatible %s",
clazz->name, atom_name(fun->atom), obj->clazz->name);
return MOCHA_FALSE;
}
return MOCHA_TRUE;
}
MochaObject *
MOCHA_DefineNewObject(MochaContext *mc, MochaObject *obj, const char *name,
MochaClass *clazz, void *data,
MochaObject *prototype, unsigned flags,
MochaPropertySpec *ps, MochaFunctionSpec *fs)
{
MochaObject *nobj;
nobj = MOCHA_NewObject(mc, clazz, data, prototype, obj, ps, fs);
if (!nobj)
return 0;
if (!MOCHA_DefineObject(mc, obj, name, nobj, flags)) {
MOCHA_DestroyObject(mc, nobj);
return 0;
}
return nobj;
}
MochaObject *
MOCHA_NewObject(MochaContext *mc, MochaClass *clazz, void *data,
MochaObject *prototype, MochaObject *parent,
MochaPropertySpec *ps, MochaFunctionSpec *fs)
{
MochaObject *obj;
obj = mocha_NewObject(mc, clazz, data, prototype, parent);
if (!obj)
return 0;
if ((ps && !MOCHA_SetProperties(mc, obj, ps)) ||
(fs && !MOCHA_DefineFunctions(mc, obj, fs))) {
mocha_DestroyObject(mc, obj);
return 0;
}
return obj;
}
MochaBoolean
MOCHA_DefineObject(MochaContext *mc, MochaObject *obj, const char *name,
MochaObject *nobj, unsigned flags)
{
MochaAtom *atom;
MochaDatum od;
MochaSymbol *sym;
if (!mocha_GetMutableScope(mc, obj))
return MOCHA_FALSE;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return MOCHA_FALSE;
MOCHA_INIT_FULL_DATUM(mc, &od, MOCHA_OBJECT, flags, MOCHA_TAINT_IDENTITY,
u.obj, nobj);
sym = mocha_SetProperty(mc, obj->scope, atom, obj->scope->minslot-1, od);
mocha_DropAtom(mc, atom);
return sym != 0;
}
static MochaSymbol *
SetProperty(MochaContext *mc, MochaObject *obj, const char *name,
MochaSlot slot, MochaDatum datum)
{
MochaAtom *atom;
MochaSymbol *sym;
if (!name) {
atom = 0;
} else {
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return MOCHA_FALSE;
}
sym = mocha_SetProperty(mc, obj->scope, atom, slot, datum);
if (atom)
mocha_DropAtom(mc, atom);
return sym;
}
MochaBoolean
MOCHA_SetProperties(MochaContext *mc, MochaObject *obj, MochaPropertySpec *ps)
{
MochaDatum d;
MochaSymbol *sym;
MochaProperty *prop;
if (!mocha_GetMutableScope(mc, obj))
return MOCHA_FALSE;
for (; ps->name; ps++) {
MOCHA_INIT_FULL_DATUM(mc, &d, MOCHA_OBJECT,
ps->flags, MOCHA_TAINT_IDENTITY,
u.obj, 0);
sym = SetProperty(mc, obj, ps->name, ps->slot, d);
if (!sym)
return MOCHA_FALSE;
prop = sym_property(sym);
if (ps->getter)
prop->getter = ps->getter;
if (ps->setter)
prop->setter = ps->setter;
}
return MOCHA_TRUE;
}
void
MOCHA_DestroyObject(MochaContext *mc, MochaObject *obj)
{
mocha_DestroyObject(mc, obj);
}
MochaBoolean
MOCHA_SetProperty(MochaContext *mc, MochaObject *obj, const char *name,
MochaSlot slot, MochaDatum datum)
{
if (!mocha_GetMutableScope(mc, obj))
return MOCHA_FALSE;
return (SetProperty(mc, obj, name, slot, datum) != 0);
}
void
MOCHA_RemoveProperty(MochaContext *mc, MochaObject *obj, const char *name)
{
MochaAtom *atom;
if (!mocha_GetMutableScope(mc, obj))
return; /* XXX */
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return;
mocha_RemoveProperty(mc, obj->scope, atom);
mocha_DropAtom(mc, atom);
}
MochaBoolean
MOCHA_GetSlot(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum *dp)
{
char buf[20];
MochaAtom *atom;
MochaBoolean ok;
MochaPair pair;
PR_snprintf(buf, sizeof buf, "%d", slot);
atom = mocha_Atomize(mc, buf, ATOM_HELD | ATOM_NAME);
if (!atom)
return MOCHA_FALSE;
ok = mocha_LookupSymbol(mc, obj->scope, atom, MLF_GET, &pair.sym);
if (ok && !pair.sym) {
ok = mocha_GetMutableScope(mc, obj);
if (ok) {
pair.sym = mocha_SetProperty(mc, obj->scope, atom, slot,
MOCHA_null);
ok = (pair.sym != 0);
}
}
mocha_DropAtom(mc, atom);
if (!ok)
return MOCHA_FALSE;
pair.obj = obj;
MOCHA_INIT_FULL_DATUM(mc, dp, MOCHA_SYMBOL, 0, MOCHA_TAINT_IDENTITY,
u.pair, pair);
return mocha_ResolveValue(mc, dp);
}
/* XXX this does not call OBJ_SET_PROPERTY; should distinguish Init from Set */
MochaBoolean
MOCHA_SetSlot(MochaContext *mc, MochaObject *obj, MochaSlot slot,
MochaDatum datum)
{
if (!mocha_GetMutableScope(mc, obj))
return MOCHA_FALSE;
return mocha_SetProperty(mc, obj->scope, 0, slot, datum) != 0;
}
void
MOCHA_RemoveSlot(MochaContext *mc, MochaObject *obj, MochaSlot slot)
{
char buf[20];
PR_snprintf(buf, sizeof buf, "%d", slot);
MOCHA_RemoveProperty(mc, obj, buf);
}
MochaAtom *
MOCHA_Atomize(MochaContext *mc, const char *name)
{
if (!name)
return MOCHA_empty.u.atom;
return mocha_Atomize(mc, name, ATOM_STRING);
}
const char *
MOCHA_GetAtomName(MochaContext *mc, MochaAtom *atom)
{
if (!atom)
return 0;
return atom_name(atom);
}
MochaAtom *
MOCHA_HoldAtom(MochaContext *mc, MochaAtom *atom)
{
if (!atom)
return 0;
return mocha_HoldAtom(mc, atom);
}
MochaAtom *
MOCHA_DropAtom(MochaContext *mc, MochaAtom *atom)
{
if (!atom)
return 0;
return mocha_DropAtom(mc, atom);
}
MochaFunction *
MOCHA_NewFunction(MochaContext *mc, MochaObject *obj, MochaNativeCall call,
unsigned nargs)
{
return mocha_NewFunction(mc, call, nargs, obj, mocha_anonymousAtom);
}
void
MOCHA_DestroyFunction(MochaContext *mc, MochaFunction *fun)
{
mocha_DestroyFunction(mc, fun);
}
static MochaFunction *
DefineFunction(MochaContext *mc, MochaObject *obj, const char *name,
MochaNativeCall call, unsigned nargs, unsigned flags)
{
MochaAtom *atom;
MochaFunction *fun;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return 0;
fun = mocha_DefineFunction(mc, obj, atom, call, nargs, flags);
mocha_DropAtom(mc, atom);
return fun;
}
MochaFunction *
MOCHA_DefineFunction(MochaContext *mc, MochaObject *obj, const char *name,
MochaNativeCall call, unsigned nargs, unsigned flags)
{
if (!mocha_GetMutableScope(mc, obj))
return 0;
return DefineFunction(mc, obj, name, call, nargs, flags);
}
MochaBoolean
MOCHA_DefineFunctions(MochaContext *mc, MochaObject *obj, MochaFunctionSpec *fs)
{
MochaFunction *fun;
MochaDatum fd;
MochaSymbol *sym;
if (!mocha_GetMutableScope(mc, obj))
return MOCHA_FALSE;
for (; fs->name; fs++) {
if (!fs->fun) {
fun = DefineFunction(mc, obj, fs->name, fs->call, fs->nargs,
fs->flags);
if (!fun)
return MOCHA_FALSE;
fs->fun = (MochaFunction *)MOCHA_HoldObject(mc, &fun->object);
} else {
MOCHA_INIT_FULL_DATUM(mc, &fd, MOCHA_FUNCTION,
fs->flags, MOCHA_TAINT_IDENTITY,
u.fun, fs->fun);
sym = SetProperty(mc, obj, fs->name, obj->scope->minslot-1, fd);
if (!sym)
return MOCHA_FALSE;
}
}
return MOCHA_TRUE;
}
MochaObject *
MOCHA_HoldObject(MochaContext *mc, MochaObject *obj)
{
if (!obj)
return 0;
PR_ASSERT(obj->nrefs == MOCHA_FINALIZING || obj->nrefs >= 0);
if (obj->nrefs != MOCHA_FINALIZING)
obj->nrefs++;
return obj;
}
MochaObject *
MOCHA_DropObject(MochaContext *mc, MochaObject *obj)
{
if (!obj)
return 0;
PR_ASSERT(obj->nrefs == MOCHA_FINALIZING || obj->nrefs > 0);
if (obj->nrefs != MOCHA_FINALIZING && --obj->nrefs == 0) {
mocha_DestroyObject(mc, obj);
return 0;
}
if (obj->parent && obj->parent->nrefs == MOCHA_FINALIZING)
obj->parent = 0;
return obj;
}
MochaBoolean
MOCHA_LookupName(MochaContext *mc, MochaObject *obj, const char *name,
MochaDatum *dp)
{
MochaAtom *atom;
MochaPair pair;
MochaBoolean ok;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return MOCHA_FALSE;
ok = mocha_LookupSymbol(mc, obj->scope, atom, MLF_GET, &pair.sym);
mocha_DropAtom(mc, atom);
if (!ok)
return MOCHA_FALSE;
if (!pair.sym || pair.sym->type == SYM_UNDEF) {
*dp = MOCHA_void;
return MOCHA_TRUE;
}
pair.obj = obj;
MOCHA_INIT_FULL_DATUM(mc, dp, MOCHA_SYMBOL, 0, MOCHA_TAINT_IDENTITY,
u.pair, pair);
return mocha_ResolveValue(mc, dp);
}
MochaBoolean
MOCHA_ResolveName(MochaContext *mc, MochaObject *obj, const char *name,
MochaDatum *dp)
{
MochaAtom *atom;
MochaObject *oldslink;
MochaBoolean ok;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return MOCHA_FALSE;
MOCHA_INIT_FULL_DATUM(mc, dp, MOCHA_ATOM, 0, MOCHA_TAINT_IDENTITY,
u.atom, atom);
oldslink = mc->staticLink;
mc->staticLink = obj;
ok = mocha_ResolveSymbol(mc, dp, MLF_GET);
mc->staticLink = oldslink;
mocha_DropAtom(mc, atom);
if (!ok)
return MOCHA_FALSE;
if (dp->tag != MOCHA_SYMBOL) {
*dp = MOCHA_void;
return MOCHA_TRUE;
}
return mocha_ResolveValue(mc, dp);
}
void
MOCHA_UndefineName(MochaContext *mc, MochaObject *obj, const char *name)
{
MochaAtom *atom;
if (!mocha_GetMutableScope(mc, obj))
return;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return;
mocha_RemoveSymbol(mc, obj->scope, atom);
mocha_DropAtom(mc, atom);
}
void
MOCHA_ClearScope(MochaContext *mc, MochaObject *obj)
{
mocha_ClearScope(mc, obj->scope);
}
static MochaScript *
CompileTokenStream(MochaContext *mc, MochaObject *obj, MochaTokenStream *ts,
void *tempMark)
{
void *codeMark;
CodeGenerator cg;
unsigned lineno;
MochaScript *script;
codeMark = PR_ARENA_MARK(&mc->codePool);
if (!mocha_InitCodeGenerator(mc, &cg, &mc->codePool))
return 0;
lineno = ts->lineno;
if (mocha_Parse(mc, obj, ts, &cg))
script = mocha_NewScript(mc, &cg, ts->filename, lineno);
else
script = 0;
if (!mocha_CloseTokenStream(ts) && script) {
mocha_DestroyScript(mc, script);
script = 0;
}
PR_ARENA_RELEASE(&mc->codePool, codeMark);
PR_ARENA_RELEASE(&mc->tempPool, tempMark);
return script;
}
MochaScript *
MOCHA_CompileBuffer(MochaContext *mc, MochaObject *obj,
const char *base, size_t length,
const char *filename, unsigned lineno)
{
void *mark;
MochaTokenStream *ts;
mark = PR_ARENA_MARK(&mc->tempPool);
ts = mocha_NewTokenStream(mc, base, length, filename, lineno);
if (!ts)
return MOCHA_FALSE;
return CompileTokenStream(mc, obj, ts, mark);
}
#ifdef MOCHAFILE
MochaScript *
MOCHA_CompileFile(MochaContext *mc, MochaObject *obj, const char *filename)
{
void *mark;
MochaTokenStream *ts;
mark = PR_ARENA_MARK(&mc->tempPool);
if (filename && strcmp(filename, "-") != 0) {
ts = mocha_NewFileTokenStream(mc, filename);
if (!ts) return MOCHA_FALSE;
} else {
ts = mocha_NewBufferTokenStream(mc, 0, 0);
if (!ts) return MOCHA_FALSE;
ts->file = stdin;
}
return CompileTokenStream(mc, obj, ts, mark);
}
#endif
MochaBoolean
MOCHA_CompileMethod(MochaContext *mc, MochaObject *obj,
const char *name, unsigned nargs,
const char *base, size_t length,
const char *filename, unsigned lineno)
{
void *mark;
MochaTokenStream *ts;
MochaAtom *atom;
MochaFunction *fun;
MochaBoolean ok;
mark = PR_ARENA_MARK(&mc->tempPool);
ts = mocha_NewTokenStream(mc, base, length, filename, lineno);
if (!ts)
return MOCHA_FALSE;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
ok = (atom != 0);
if (ok) {
if (!mocha_GetMutableScope(mc, obj)) {
ok = MOCHA_FALSE;
} else {
fun = mocha_DefineFunction(mc, obj, atom, 0, nargs, 0);
if (!fun)
ok = MOCHA_FALSE;
}
mocha_DropAtom(mc, atom);
if (ok) {
ok = mocha_ParseFunctionBody(mc, ts, fun);
if (!ok)
mocha_RemoveSymbol(mc, obj->scope, atom);
}
}
PR_ARENA_RELEASE(&mc->tempPool, mark);
return ok;
}
MochaBoolean
MOCHA_DecompileScript(MochaContext *mc, MochaScript *script, const char *name,
unsigned indent, char **sp)
{
MochaPrinter *mp;
MochaBoolean ok;
mp = mocha_NewPrinter(mc, name, indent);
if (!mp)
return MOCHA_FALSE;
ok = mocha_DecompileScript(script, mp);
if (ok)
ok = mocha_GetPrinterOutput(mp, sp);
mocha_DestroyPrinter(mp);
return ok;
}
MochaBoolean
MOCHA_DecompileFunctionBody(MochaContext *mc, MochaFunction *fun,
unsigned indent, char **sp)
{
return MOCHA_DecompileScript(mc, fun->script, atom_name(fun->atom),
indent, sp);
}
MochaBoolean
MOCHA_ExecuteScript(MochaContext *mc, MochaObject *obj, MochaScript *script,
MochaDatum *result)
{
return mocha_Interpret(mc, obj, script, result);
}
void
MOCHA_DestroyScript(MochaContext *mc, MochaScript *script)
{
mocha_DestroyScript(mc, script);
}
MochaBoolean
MOCHA_EvaluateBuffer(MochaContext *mc, MochaObject *obj,
const char *base, size_t length,
const char *filename, unsigned lineno,
MochaDatum *result)
{
MochaScript *script;
MochaBoolean ok;
script = MOCHA_CompileBuffer(mc, obj, base, length, filename, lineno);
if (!script)
return MOCHA_FALSE;
ok = MOCHA_ExecuteScript(mc, obj, script, result);
MOCHA_DestroyScript(mc, script);
return ok;
}
MochaBoolean
MOCHA_CallMethod(MochaContext *mc, MochaObject *obj, const char *name,
unsigned argc, MochaDatum *argv, MochaDatum *result)
{
MochaAtom *atom;
MochaPair pair;
MochaDatum fd;
MochaBoolean ok;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return MOCHA_FALSE;
if (!mocha_LookupSymbol(mc, obj->scope, atom, MLF_GET, &pair.sym))
return MOCHA_FALSE;
if (!pair.sym) {
*result = MOCHA_void;
return MOCHA_TRUE;
}
pair.obj = obj;
MOCHA_INIT_FULL_DATUM(mc, &fd, MOCHA_SYMBOL, 0, MOCHA_TAINT_IDENTITY,
u.pair, pair);
ok = mocha_Call(mc, fd, argc, argv, result);
mocha_DropAtom(mc, atom);
return ok;
}
MochaBranchCallback
MOCHA_SetBranchCallback(MochaContext *mc, MochaBranchCallback cb)
{
MochaBranchCallback oldcb;
oldcb = mc->branchCallback;
mc->branchCallback = cb;
return oldcb;
}
MochaBoolean
MOCHA_IsRunning(MochaContext *mc)
{
return mc->script != 0;
}
void
MOCHA_ReportError(MochaContext *mc, const char *format, ...)
{
va_list ap;
va_start(ap, format);
mocha_ReportErrorVA(mc, format, ap);
va_end(ap);
}
void
MOCHA_ReportOutOfMemory(MochaContext *mc)
{
MOCHA_ReportError(mc, "out of memory");
}
MochaErrorReporter
MOCHA_SetErrorReporter(MochaContext *mc, MochaErrorReporter er)
{
MochaErrorReporter older;
older = mc->errorReporter;
mc->errorReporter = er;
return older;
}
void
MOCHA_SetTaintCallbacks(MochaTaintCounter hold, MochaTaintCounter drop,
MochaTaintMixer mix)
{
mocha_HoldTaint = hold;
mocha_DropTaint = drop;
mocha_MixTaint = mix;
}
MochaTaintInfo *
MOCHA_GetTaintInfo(MochaContext *mc)
{
return mc->taintInfo;
}
void
MOCHA_SetTaintInfo(MochaContext *mc, MochaTaintInfo *info)
{
if (!info)
mocha_InitTaintInfo(mc);
else
mc->taintInfo = info;
}
MochaBoolean
MOCHA_SetPropertyTaint(MochaContext *mc, MochaObject *obj, const char *name,
uint16 taint)
{
MochaAtom *atom;
MochaBoolean ok;
MochaSymbol *sym;
atom = mocha_Atomize(mc, name, ATOM_HELD | ATOM_NAME);
if (!atom)
return MOCHA_FALSE;
ok = mocha_LookupSymbol(mc, obj->scope, atom, MLF_GET, &sym);
mocha_DropAtom(mc, atom);
if (!ok)
return MOCHA_FALSE;
if (sym && sym->type == SYM_PROPERTY)
sym_property(sym)->datum.taint = taint;
return MOCHA_TRUE;
}
void
MOCHA_SetCharFilter(MochaContext *mc, MochaCharFilter filter, void *arg)
{
mc->charFilter = filter;
mc->charFilterArg = arg;
}