/*
 * 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"
/* #include "ewb-trace.h" */
#include "js-trace.h"

/* 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(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(JSContext::reportRuntimeError(cx, JSContext::getMessage(cx, "msg.bad.uri")));
            }
            if (!isxdigit(str[k + 1]) || !isxdigit(str[k + 2])) {
                cx->exceptionHandler->throwEx(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(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(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;

    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(new(cx) JSEvaluatorException(message));
            return JS_VAL_VOID;
        }

        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);

        cx->exceptionHandler->exitTry();
#ifndef SHELL
        EWBTPEXT(12);
#endif
        return result;
    }
    else {
        cx->popLocalVals(1);
        cx->exceptionHandler->throwEx(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(new(cx) JSRuntimeException(ex->toString(cx)));
    }
    else if (ex->isInstanceOf(JSJavaScriptException::className)) {
        cx->exceptionHandler->throwEx(new(cx) JSRuntimeException(ex->toString(cx)));
    }
    else if (ex->isInstanceOf(JSNotAFunctionException::className)) {
        cx->exceptionHandler->throwEx(new(cx) JSRuntimeException(ex->toString(cx)));
    }
    return NULL;
}
