/*
 * The contents of this file are subject to the Netscape Public
 * License Version 1.1 (the "License"); you may not use this file
 * except in compliance with the License. You may obtain a copy of
 * the License at http://www.mozilla.org/NPL/

 * Software distributed under the License is distributed on an "AS
 * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * rights and limitations under the License.

 * The Original Code is Rhino code, released
 * May 6, 1999.

 * The Initial Developer of the Original Code is Netscape
 * Communications Corporation.  Portions created by Netscape are
 * Copyright (C) 1997-1999 Netscape Communications Corporation. All
 * Rights Reserved.

 * Contributor(s): 

 * Alternatively, the contents of this file may be used under the
 * terms of the GNU Public License (the "GPL"), in which case the
 * provisions of the GPL are applicable instead of those above.
 * If you wish to allow use of your version of this file only
 * under the terms of the GPL and not to allow others to use your
 * version of this file under the NPL, indicate your decision by
 * deleting the provisions above and replace them with the notice
 * and other provisions required by the GPL.  If you do not delete
 * the provisions above, a recipient may use your version of this
 * file under either the NPL or the GPL.
 */
/* Header file */
#include <stdio.h>
#include <ctype.h>
#include <float.h>
#include <math.h>
#ifdef VX
#include <private/mathP.h>
#endif
#ifdef SUNOS5
#include <strings.h>
#include <ieeefp.h>
#endif
#include "js-scriptruntime.h"
#include "js-evaluatorexception.h"
#include "js-exceptionhandler.h"
#include "js-tokenstream.h"
#include "js-ctorfunction.h"
#include "js-exceptionhandler.h"
#include "js-stringreader.h"
#include "js-stringbuffer.h"
#include "js-utils.h"
#include "js-ecmaerror.h"
#include "js-propertyexception.h"
#include "js-javascriptexception.h"
#include "js-notafunctionexception.h"
#include "js-interpretedscript.h"
#include "js-nativefunction.h"
#if defined(USE_UTF8) || defined(USE_SJIS)
#include "js-stringruntime.h"
#endif
#include "js-nativeglobal.h"
#ifndef SHELL
extern "C" {
# include "ewb-trace.h"
}
#endif

/* Internal data */
const jsString_t	JSNativeGlobal::className = "NativeGlobal";
const jsString_t	JSNativeGlobal::uriReservedPlusPound = ";/?:@&=+$,#";
const jsString_t	JSNativeGlobal::uriUnescaped = 
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";
const jsString_t	JSNativeGlobal::uriReservedPlusPoundPlusUriUnescaped = 
    ";/?:@&=+$,#"
    "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz-_.!~*'()";

/* Procedures */
int
JSNativeGlobal::unHex(jsChar_t c)
{
    if (c >= '0' && c <= '9') {
	return c - '0';
    } else {
	if (c >= 'a' && c <= 'f') {
	    return c - 'a' + 10;
	} else {
	    return c - 'A' +10;
	}
    }
}
/*
 *   ECMA 3, 15.1.3 URI Handling Function Properties
 *
 *   The following are implementations of the algorithms
 *   given in the ECMA specification for the hidden functions
 *   'Encode' and 'Decode'.
 */
jsVal_t
JSNativeGlobal::encode(JSContext *cx, jsString_t str, jsString_t unescapedSet)
{
    int k;
    jsChar_t C;
    JSStringBuffer R(cx);

    int length = strlen(str);

    k = 0;
    while (k < length) {
	C = str[k];
	if (index(unescapedSet, C) != NULL) {
	    R.append(C);
	} else {
	    cx->exceptionHandler->throwEx(
                    cx,
                    JSContext::reportRuntimeError(cx,
				JSContext::getMessage(cx, "msg.bad.uri")));
	}
	k++;
    }
    return JS_STRING_TO_VAL(JS_NewGCString(cx, R.toString()));
}
jsVal_t
JSNativeGlobal::decode(JSContext *cx, jsString_t str, jsString_t reservedSet)
{
    int start, k = 0;
    jsChar_t C;
    int B;
    JSStringBuffer R(cx);

    int length = strlen(str);

    while (k < length) {
	C = str[k];
	if (C == '%') {
	    start = k;
	    if ((k + 2) >= length) {
		cx->exceptionHandler->throwEx(
                        cx,
			JSContext::reportRuntimeError(cx,
				JSContext::getMessage(cx, "msg.bad.uri")));
	    }
	    if (!isxdigit(str[k + 1]) || !isxdigit(str[k + 2])) {
		cx->exceptionHandler->throwEx(
                        cx,
			JSContext::reportRuntimeError(cx,
				JSContext::getMessage(cx, "msg.bad.uri")));
	    }
	    B = unHex(str[k + 1]) * 16 + unHex(str[k + 2]);
	    k += 2;
	    if ((B & 0x80) == 0) {
		C = (jsChar_t) B;
	    } else {
		cx->exceptionHandler->throwEx(
                        cx,
			JSContext::reportRuntimeError(cx,
				JSContext::getMessage(cx, "msg.bad.uri")));
	    }
	    if (index(reservedSet, C) != NULL) {
		for (int x = 0; x < (k - start + 1); x++) {
		    R.append(str[start + x]);
		}
	    } else {
		R.append(C);
	    }
	} else {
	    R.append(C);
	}
	k++;
    }
    return JS_STRING_TO_VAL(JS_NewGCString(cx, R.toString()));
}
jsVal_t  
JSNativeGlobal::eval(JSContext *cx, JSScriptable *thisArg, int numArgs,
			jsVal_t *args, JSFunction *funObj)
{
    jsString_t m = JSScriptRuntime::getMessage(cx, "msg.cant.call.indirect %s",
					"eval");

    cx->exceptionHandler->throwEx(
            cx,
            JSNativeGlobal::constructError(cx, "EvalError", m,
		(JSNativeFunction *) funObj));
    /* NOT REACHED */
    return JS_VAL_VOID;
}
/**
  * The global method parseFloat, as per ECMA-262 15.1.2.3.
  */  
jsVal_t
JSNativeGlobal::parseFloat(JSContext *cx, JSScriptable *thisObj, int numArgs,
			jsVal_t *args, JSFunction *funObj)
{
    if (numArgs < 1) {
	return JSScriptRuntime::NaNobj(cx);
    }
    jsString_t s = JSScriptRuntime::toString(cx, args[0]);
    int len = strlen(s);

    if (len == 0) {
	JS_DeleteZoneObj(cx, s);
	return JSScriptRuntime::NaNobj(cx);
    }

    int i;
    jsChar_t c;

    // Scan forward to the first digit or .
    for (i = 0; JSTokenStream::isJSSpace(c = s[i]) && (i + 1) < len; i++) {
	/* empty */
	;
    }

    int start = i;

    if (c == '+' || c == '-') {
	c = s[++i];
    }

    if (c == 'I') {
	// check for "Infinity"
	double d;
	jsChar_t substring[9];

	if ((i + 8) <= len) {
	    memcpy(substring, s + i, sizeof (*substring) * 8);
	    substring[8] = '\0';
	}
	if ((i + 8) <= len && strcmp(substring, "Infinity") == 0) {
	    d = s[start] == '-' ? NEGATIVE_INFINITY : POSITIVE_INFINITY;
	} else {
	    JS_DeleteZoneObj(cx, s);
	    return JSScriptRuntime::NaNobj(cx);
	}
	JS_DeleteZoneObj(cx, s);
	return  JS_DOUBLE_TO_VAL(JS_NewGCDouble(cx, d));
    }

    // Find the end of the legal bit
    int decimal = -1;
    int exponent = -1;
    for (; i < len; i++) {
	switch (s[i]) {
	  case '.':
	    if (decimal != -1) {// Only allow a single decimal point.
		break;
	    }
	    decimal = i;
	    continue;

	  case 'e':
	  case 'E':
	    if (exponent != -1) {
		break;
	    }
	    exponent = i;
	    continue;

	  case '+':
	  case '-':
	     // Only allow '+' or '-' after 'e' or 'E'
	    if (exponent != i - 1) {
		break;
	    }
	    continue;

	  case '0': case '1': case '2': case '3': case '4':
	  case '5': case '6': case '7': case '8': case '9':
	    continue;

	  default:
	    break;
	}
	break;
    }
    jsString_t substring;
    double d;

    substring = (jsString_t) JS_Substring(cx, s, start, i);
    if (sscanf(substring, "%lf", &d) > 0) {
	JS_DeleteZoneObj(cx, substring);
	JS_DeleteZoneObj(cx, s);
	return JS_DOUBLE_TO_VAL(JS_NewGCDouble(cx, d));
    }
    JS_DeleteZoneObj(cx, substring);
    JS_DeleteZoneObj(cx, s);
    return JSScriptRuntime::NaNobj(cx);
}
/**
  * The global method escape, as per ECMA-262 15.1.2.4.

  * Includes code for the 'mask' argument supported by the C escape
  * method, which used to be part of the browser imbedding.  Blame
  * for the strange constant names should be directed there.
  */  
jsVal_t
JSNativeGlobal::escape(JSContext *cx, JSScriptable *thisObj, int numArgs,
			jsVal_t *args, JSFunction *funObj)
{
    static jsChar_t digits[] = {
	'0', '1', '2', '3', '4', '5', '6', '7',
	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
    };
    const int	URL_XALPHAS = 1,
		URL_XPALPHAS = 2,
		URL_PATH = 4;
    jsVal_t *padArgs;
    
    if (numArgs < 1) {
	args = padArgs = JSScriptRuntime::padArguments(cx, numArgs, args, 1);
	numArgs = 1;
    } else {
	padArgs = NULL;
    }

    jsString_t s = JSScriptRuntime::toString(cx, args[0]);

    int mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
    if (numArgs > 1) { // the 'mask' argument.  Non-ECMA.
	double d = JSScriptRuntime::toNumber(cx, args[1]);

	if (d != d || ((mask = (int) d) != d) ||
	    0 != (mask & ~(URL_XALPHAS | URL_XPALPHAS | URL_PATH))) {
	    jsString_t message = JSContext::getMessage(cx, "msg.bad.esc.mask");

	    JSContext::reportError(cx, message);
	    // do the ecma thing, in case reportError returns.
	    mask = URL_XALPHAS | URL_XPALPHAS | URL_PATH;
	}
    }
    JSStringBuffer R(cx);
    int length = strlen(s);

#if defined(USE_UTF8) || defined(USE_SJIS)
    int n;

    for (int k = 0; k < length; k += n) {
	wchar_t c;

	n = JSStringRuntime::mbtowc(&c, s + k, JSStringRuntime::_MB_CUR_MAX);
#else
    for (int k = 0; k < length; k++) {
	jsChar_t c = s[k];
#endif

	if (mask != 0 && ((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z')
	    || (c >= 'a' && c <= 'z') || c == '@' || c == '*' || c == '_'
	    || c == '-' || c == '.' || ((c == '/' || c == '+') && mask > 3))) {
	    R.append((jsChar_t) c);
#if defined(USE_UTF8) || defined(USE_SJIS)
	} else if (c < 256) {
	    if (c == ' ' && mask == URL_XPALPHAS) {
		R.append('+');
	    } else {
		R.append('%');
		R.append(digits[c >> 4]);
		R.append(digits[c & 0xF]);
	    }
	} else {
	    R.append('%');
	    R.append('u');
	    R.append(digits[c >> 12]);
	    R.append(digits[(c & 0xF00) >> 8]);
	    R.append(digits[(c & 0xF0) >> 4]);
	    R.append(digits[c & 0xF]);
	}
#else 
	} else {
	    if (c == ' ' && mask == URL_XPALPHAS) {
		R.append('+');
	    } else {
		R.append('%');
		R.append(digits[c >> 4]);
		R.append(digits[c & 0xF]);
	    }
	}
#endif
    }
    JS_DeleteZoneObj(cx, s);
    if (padArgs != NULL) {
	JS_DeleteZoneObj(cx, padArgs);
    } 

    return JS_STRING_TO_VAL(JS_NewGCString(cx, R.toString()));
}
/**
  * The global unescape method, as per ECMA-262 15.1.2.5.
 */  
jsVal_t
JSNativeGlobal::unescape(JSContext *cx, JSScriptable *thisObj, int numArgs,
			jsVal_t *args, JSFunction *funObj)
{
    jsVal_t *padArgs;
    
    if (numArgs < 1) {
	args = padArgs = JSScriptRuntime::padArguments(cx, numArgs, args, 1);
	numArgs = 1;
    } else {
	padArgs = NULL;
    }

    jsString_t s = JSScriptRuntime::toString(cx, args[0]);
    JSStringBuffer R(cx);
    int length = strlen(s);

#if defined(USE_UTF8) || defined(USE_SJIS)
    int n;

    for (int k = 0; k < length; k += n) {
	wchar_t c;

	n = JSStringRuntime::mbtowc(&c, s + k, JSStringRuntime::_MB_CUR_MAX);
#else
    for (int k = 0; k < length; k++) {
	jsChar_t c = s[k];
#endif

	if (c != '%' || k == length - 1) {
#if defined(USE_UTF8) || defined(USE_SJIS)
	    R.append(s, k, n);
#else

	    R.append(c);
#endif
	    continue;
	}
	jsString_t hex;
	int end, start;

	if (s[k + 1] == 'u') {
	    start = k + 2;
	    end = k + 6;
	} else {
	    start = k + 1;
	    end = k + 3;
	}
	if (end > length) {
	    R.append('%');
	    continue;
	}
	hex = JS_Substring(cx, s, start, end);
	for (int i = 0; i < (end - start); i++) {
	    if (!JSTokenStream::isXDigit(hex[i])) {
		if (i >= 2) {
		    end -= 2;
		    hex[2] = '\0';
		    break;
		}
		R.append('%');
		goto stringIter;
	    }
	}
	k = end - 1;
#if defined(USE_UTF8) || defined(USE_SJIS)
	n = 1;
#endif

	int ival;

	sscanf(hex, "%x", &ival);
#if defined(USE_UTF8) || defined(USE_SJIS)
	if (ival < 0x80) {
	    R.append((jsChar_t) ival);
	} else {
	    jsChar_t mb[JSStringRuntime::_MB_CUR_MAX];
	    int l;

	    l = JSStringRuntime::wctomb(mb, ival);
	    R.append(mb, 0, l);
	}
#else
	R.append((jsChar_t) ival);
#endif
stringIter:
	JS_DeleteZoneObj(cx, hex);
    }
    JS_DeleteZoneObj(cx, s);
    if (padArgs != NULL) {
	JS_DeleteZoneObj(cx, padArgs);
    } 

    return JS_STRING_TO_VAL(JS_NewGCString(cx, R.toString()));
}
/**
 * The global method isNaN, as per ECMA-262 15.1.2.6.
 */  
jsVal_t
JSNativeGlobal::isNaN(JSContext *cx, JSScriptable *thisObj, int numArgs,
			jsVal_t *args, JSFunction *funObj)
{
    if (numArgs < 1) {
	return JS_VAL_TRUE;
    }
    double d = JSScriptRuntime::toNumber(cx, args[0]);

#ifdef VX
    return (isNan(d) ? JS_VAL_TRUE : JS_VAL_FALSE);
#else
    return (isnan(d) ? JS_VAL_TRUE : JS_VAL_FALSE);
#endif
}
jsVal_t
JSNativeGlobal::isFinite(JSContext *cx, JSScriptable *thisObj, int numArgs,
			jsVal_t *args, JSFunction *funObj)
{
    if (numArgs < 1) {
	return JS_VAL_FALSE;
    }
    double d = JSScriptRuntime::toNumber(cx, args[0]);
#ifdef VX
    return (isNan(d) || isInf(d)) ? JS_VAL_FALSE : JS_VAL_TRUE;
#else
    return (finite(d) ? JS_VAL_TRUE : JS_VAL_FALSE);
#endif
}
jsVal_t
JSNativeGlobal::decodeURI(JSContext *cx, JSScriptable *thisObj,
			int numArgs, jsVal_t *args, JSFunction *funObj)
{
    jsString_t str = JSScriptRuntime::toString(cx, args[0]);
    jsVal_t val = decode(cx, str, uriReservedPlusPound);

    JS_DeleteZoneObj(cx, str);
    return val;
}	
jsVal_t
JSNativeGlobal::decodeURIComponent(JSContext *cx, JSScriptable *thisObj,
			int numArgs, jsVal_t *args, JSFunction *funObj)
{
    jsString_t str = JSScriptRuntime::toString(cx, args[0]);
    jsVal_t val = decode(cx, str, "");

    JS_DeleteZoneObj(cx, str);
    return val;
}	
jsVal_t
JSNativeGlobal::encodeURI(JSContext *cx, JSScriptable *thisObj,
			int numArgs, jsVal_t *args, JSFunction *funObj)
{
    jsString_t str = JSScriptRuntime::toString(cx, args[0]);
    jsVal_t val = encode(cx, str, uriReservedPlusPoundPlusUriUnescaped);

    JS_DeleteZoneObj(cx, str);
    return val;
}	
jsVal_t
JSNativeGlobal::encodeURIComponent(JSContext *cx, JSScriptable *thisObj,
			int numArgs, jsVal_t *args, JSFunction *funObj)

{
    jsString_t str = JSScriptRuntime::toString(cx, args[0]);
    jsVal_t val  = encode(cx, str, uriUnescaped);

    JS_DeleteZoneObj(cx, str);
    return val;
}	
/**
 * The implementation of all the ECMA error constructors (SyntaxError,
 * TypeError, etc.)
 */  
jsVal_t
JSNativeGlobal::CommonError(JSContext *cx, int numArgs, jsVal_t *args,
			JSFunction *ctorObj, jsBool_t inNewExpr)
{
    JSScriptable *newInstance = new (cx) JSNativeError();
    jsVal_t val;

    (void) ((JSNativeFunction *) ctorObj)->get(cx, "prototype",
					(JSNativeFunction *) ctorObj, &val);
    newInstance->setPrototype(cx, JS_VAL_TO_OBJECT(val));
    newInstance->setParentScope(cx, cx->ctorScope);
    if (numArgs > 0) {
	newInstance->put(cx, "message", newInstance, args[0]);
    }
    return JS_OBJECT_TO_VAL(newInstance);
}


void
JSNativeGlobal::defineClass(JSContext *cx, JSScriptable *scope) 
{
    class GlobalAdapter {
  	public:
	    static jsVal_t	jsFunction_parseInt(JSContext *cx,
					JSScriptable *thisObj, int numArgs,
					jsVal_t *args, JSFunction *funObj) {
		int radix;

		if (args[1] != JS_VAL_VOID) {
		    radix = JSScriptRuntime::toInt32(cx, args[1]);
		    if (radix < 0) {
		        return JSScriptRuntime::NaNobj(cx);
		    }
		} else {
		    radix = 0;
		}
		return JSNativeGlobal::parseInt(cx, 
				JSScriptRuntime::toString(cx, args[0]),
				radix);
	    }
    } ;
    static JSScriptableObject::jsFunction_t functions[] = {
#define Item(name, length)      { #name,  name, length }
#define ItemAdapter(name, clazz, length)	\
				{ #name,  &clazz::jsFunction_##name, length }
	Item(eval, -1),
	ItemAdapter(parseInt, GlobalAdapter, 2),  Item(parseFloat, -1),
	Item(escape, -1),   	Item(unescape, -1),
	Item(isNaN, -1),   	Item(isFinite, -1),
	Item(decodeURI, -1),   	Item(decodeURIComponent, -1),
	Item(encodeURI, -1),   	Item(encodeURIComponent, -1),
#undef	ItemAdapter
#undef  Item
    } ;

    JSScriptableObject *global = (JSScriptableObject *) scope;

    global->defineFunctionProperties(cx, className,
				TableSize(functions), functions,
				JS_PA_DontEnum);

    global->defineProperty(cx, "NaN", JSScriptRuntime::NaNobj(cx),
			JS_PA_DontEnum);

    double *d = (double *) JS_NewGCDouble(cx, POSITIVE_INFINITY);
    global->defineProperty(cx, "Infinity", JS_DOUBLE_TO_VAL(d), JS_PA_DontEnum);
    global->defineProperty(cx, "undefined", JS_VAL_VOID, JS_PA_DontEnum);
 
    static const jsString_t errorMethods[] = {
	"ConversionError",	"EvalError",
	"RangeError",		"ReferenceError",
	"SyntaxError",		"TypeError",
	"URIError"
    };

    for (int i = 0; i < (int) TableSize(errorMethods); ++i) {
	jsString_t name = errorMethods[i];

	JSFunctionObject *ctor
			= new (cx) JSCtorFunction(cx, name, className,
						CommonError, global);

	global->defineProperty(cx, name, JS_OBJECT_TO_VAL(ctor),
			JS_PA_DontEnum);

	JSScriptable *errorProto = cx->newObject(scope, "Error");

	errorProto->put(cx, "name", errorProto,
			JS_STRING_TO_VAL(JS_NewGCString(cx, name)));
	ctor->put(cx, "prototype", ctor, JS_OBJECT_TO_VAL(errorProto));
    }
}
/**
 * The global method parseInt, as per ECMA-262 15.1.2.2.
 */  
jsVal_t
JSNativeGlobal::parseInt(JSContext *cx, jsString_t s, int radix)
{
    int len = strlen(s);

    if (len == 0) {
	return JSScriptRuntime::NaNobj(cx);
    }

    jsBool_t negative = FALSE;
    int start = 0;
    jsChar_t c;
    do {
	c = s[start];
	if (!isspace(c)) {
	    break;
	}
	start++;
    } while (start < len);

    if (c == '+' || (negative = (c == '-'))) {
	start++;
    }

    const int NO_RADIX = -1;
    if (radix == 0) {
	radix = NO_RADIX;
    } else if (radix < 2 || radix > 36) {
	return JSScriptRuntime::NaNobj(cx);
    } else if (radix == 16 && len - start > 1 && s[start] == '0') {
	c = s[start+1];
	if (c == 'x' || c == 'X') {
	    start += 2;
	}
    }

    if (radix == NO_RADIX) {
	radix = 10;
	if (len - start > 1 && s[start] == '0') {
	    c = s[start + 1];
	    if (c == 'x' || c == 'X') {
		radix = 16;
		start += 2;
	    } else if (c != '.') {
		radix = 8;
		start++;
	    }
	}
    }

    double d = JSScriptRuntime::stringToNumber(s, start, radix);
 
    return JS_DOUBLE_TO_VAL(JS_NewGCDouble(cx, negative ? -d : d));
}
/**
 * The eval function property of the global object.
 *   
 * See ECMA 15.1.2.1
 */  
jsVal_t
JSNativeGlobal::evalSpecial(JSContext *cx, JSScriptable *scope,
			JSScriptable *thisArg, int numArgs, jsVal_t *args,
			jsString_t filename, int lineNumber)
{
    if (numArgs < 1) {
	return JS_VAL_VOID;
    }
    jsVal_t x = args[0];

    if (!JS_VAL_IS_STRING(x)) {
	jsString_t message = JSContext::getMessage(cx, "msg.eval.nonstring");

	JSContext::reportWarning(cx, message);
	return x;
    }
    int linep = lineNumber;

    if (filename == NULL) {
	filename = JSContext::getSourcePosition(cx, &linep);
        if (filename == NULL) {
            filename = "<eval'ed string>";
            linep = 1;
        }
    }
    JSException *ex;
    int n = 0;

    if ((ex = enterTry(cx)) == NULL) {
	JSStringReader in(JS_VAL_TO_STRING(x));

        //20040531 ichino
        cx->setSourceInfo( in.str, filename, linep);
	
#ifndef SHELL
EWBTPENT(12,"JsEval");
#endif

	// Compile the reader with opt level of -1 to force interpreter
	// mode.
	int oldOptLevel = cx->getOptimizationLevel();
	cx->setOptimizationLevel(-1);
	JSScript *script = cx->compileReader(scope, &in, filename, linep);
	cx->setOptimizationLevel(oldOptLevel);
	
	// if the compile fails, an error has been reported by the
	// compiler, but we need to stop execution to avoid
	// infinite looping on while(true) { eval('foo bar') } -
	// so we throw an EvaluatorException.
	if (script == NULL) {
	    jsString_t message = JSContext::getMessage(cx, "msg.syntax");

	    cx->exceptionHandler->throwEx(
                    cx,
                    new (cx) JSEvaluatorException(message));
	}

	JSInterpretedScript *is = (JSInterpretedScript *) script;
	is->itsData->itsFromEvalCode = TRUE;

	cx->pushLocalVal(JS_OBJECT_TO_VAL(is)); // gc safe

	jsVal_t result = is->call(cx, scope, thisArg, 0, NULL);

	cx->popLocalVals(1);
        n += 1;
			 
	cx->exceptionHandler->exitTry();
#ifndef SHELL
EWBTPEXT(12);
#endif
	cx->clearSourceInfo();
	return result;
    } else {
	cx->popLocalVals(1);
	cx->clearSourceInfo();
	cx->exceptionHandler->throwEx(cx, ex);
    }
    /* NOT REACHED */
    return JS_VAL_VOID;
}
/**
 * The NativeError functions
 *   
 * See ECMA 15.11.6
 */  
JSEcmaError *
JSNativeGlobal::constructError(JSContext *cx, jsString_t error,
			jsString_t message, JSScriptable *scope)
{
    int linep;
    jsString_t filename = JSContext::getSourcePosition(cx, &linep);

    return constructError(cx, error, message, scope, filename, linep, 0, NULL);
}
/**
 * The NativeError functions
 *   
 * See ECMA 15.11.6
 */  
JSEcmaError *
JSNativeGlobal::constructError(JSContext *cx, jsString_t error,
			jsString_t message, JSScriptable *scope,
			jsString_t sourceName, int lineNumber,
			int columnNumber, jsString_t lineSource)
{
    jsVal_t args[1] = { JS_STRING_TO_VAL(JS_NewGCString(cx, message)) };
    int numArgs = 1;

    JSException *ex;

    if ((ex = enterTry(cx)) == NULL) {
	JSScriptable *errorObject = cx->newObject(scope, error, numArgs, args);

	cx->exceptionHandler->exitTry();
	return new (cx) JSEcmaError((JSNativeError *) errorObject, sourceName,
			     lineNumber, columnNumber, lineSource);
    } else if(ex->isInstanceOf(JSPropertyException::className)) {
	cx->exceptionHandler->throwEx(
                cx,
                new (cx) JSRuntimeException(ex->toString(cx)));
    } else if(ex->isInstanceOf(JSJavaScriptException::className)) {
	cx->exceptionHandler->throwEx(
                cx,
                new (cx) JSRuntimeException(ex->toString(cx)));
    } else if(ex->isInstanceOf(JSNotAFunctionException::className)) {
	cx->exceptionHandler->throwEx(
                cx,
                new (cx) JSRuntimeException(ex->toString(cx)));
    }
    return NULL;
}
