Changeset 15149 in webkit for trunk/JavaScriptCore/API


Ignore:
Timestamp:
Jul 3, 2006, 7:35:09 PM (19 years ago)
Author:
ggaren
Message:

Reviewed by Darin.


  • Refined value conversions in the API:
    • failed toNumber returns NaN
    • failed toObject returns NULL
    • failed toString returns empty string


  • Refined excpetion handling in the API:
    • failed value conversions do not throw exceptions
    • uncaught exceptions in JSEvaluate, JSObjectCallAsFunction, and JSObjectCallAsConstructor are returned through a JSValueRef* exception argument
    • removed JSContextHasException, because JSContextGetException does the same job


  • API/JSBase.h:
  • API/JSCharBufferRef.cpp: (JSValueCopyStringValue):
  • API/JSContextRef.cpp: (JSEvaluate):
  • API/JSContextRef.h:
  • API/JSNodeList.c: Added test code demonstrating how you would use toNumber, and why you probably don't need toUInt32, etc. (JSNodeListPrototype_item): (JSNodeList_getProperty):
  • API/JSObjectRef.cpp: (JSValueToObject): (JSObjectCallAsFunction): (JSObjectCallAsConstructor):
  • API/JSObjectRef.h:
  • API/JSValueRef.cpp: (JSValueToNumber):
  • API/JSValueRef.h:
  • API/minidom.c: (main):
  • API/testapi.c: (main): Added tests for new rules, and call to JSGCProtect to fix Intel crash
  • JavaScriptCore.exp:
Location:
trunk/JavaScriptCore/API
Files:
11 edited

Legend:

Unmodified
Added
Removed
  • trunk/JavaScriptCore/API/JSBase.h

    r15133 r15149  
    4444#endif
    4545
    46 // Returns true for successful execution, false for uncaught exception.
    47 // returnValue will contain value of last evaluated statement or exception value.
     46// Evaluation
    4847/*!
    4948  @function JSEvaluate
    50   Evaluates a string of JavaScript code
     49  Evaluates a string of JavaScript
    5150  @param context            execution context to use
    52   @param thisValue          object to use as the "this" value, or NULL to use the global object as "this"
    53   @param script             a string containing the script source code
    54   @param sourceURL          URL to the file containing the source, or NULL - this is only used for error reporting
    55   @param startingLineNumber starting line number in the source at sourceURL - this is only used for error reporting
    56   @param returnValue        result of evaluation if successful, or value of exception
    57   @result                   true if evaluation succeeded, false if an uncaught exception or error occured
     51  @param script             a character buffer containing the JavaScript to evaluate
     52  @param thisValue          object to use as "this," or NULL to use the global object as "this"
     53  @param sourceURL          URL to the file containing the JavaScript, or NULL - this is only used for error reporting
     54  @param startingLineNumber the JavaScript's starting line number in the file located at sourceURL - this is only used for error reporting
     55  @param exception          pointer to a JSValueRef in which to store an uncaught exception, or NULL
     56  @result                   result of evaluation, or NULL if an uncaught exception was thrown
    5857*/
    59 bool JSEvaluate(JSContextRef context, JSValueRef thisValue, JSCharBufferRef script, JSCharBufferRef sourceURL, int startingLineNumber, JSValueRef* returnValue);
     58JSValueRef JSEvaluate(JSContextRef context, JSCharBufferRef script, JSValueRef thisValue, JSCharBufferRef sourceURL, int startingLineNumber, JSValueRef* exception);
    6059
    6160/*!
  • trunk/JavaScriptCore/API/JSCharBufferRef.cpp

    r15133 r15149  
    7878
    7979    JSCharBufferRef charBufferRef = toRef(jsValue->toString(exec).rep()->ref());
    80     // FIXME: What should we do with this exception?
    8180    if (exec->hadException())
    8281        exec->clearException();
  • trunk/JavaScriptCore/API/JSContextRef.cpp

    r15133 r15149  
    7272}
    7373
    74 bool JSEvaluate(JSContextRef context, JSValueRef thisValue, JSCharBufferRef script, JSCharBufferRef sourceURL, int startingLineNumber, JSValueRef* returnValue)
     74JSValueRef JSEvaluate(JSContextRef context, JSCharBufferRef script, JSValueRef thisValue, JSCharBufferRef sourceURL, int startingLineNumber, JSValueRef* exception)
    7575{
    7676    JSLock lock;
     
    7979    UString::Rep* scriptRep = toJS(script);
    8080    UString::Rep* sourceURLRep = toJS(sourceURL);
     81    // Interpreter::evaluate sets thisValue to the global object if it is NULL
    8182    Completion completion = exec->dynamicInterpreter()->evaluate(UString(sourceURLRep), startingLineNumber, UString(scriptRep), jsThisValue);
    8283
    83     if (returnValue)
    84         *returnValue = completion.value() ? toRef(completion.value()) : toRef(jsUndefined());
    85 
    86     return completion.complType() != Throw;
     84    if (completion.complType() == Throw) {
     85        if (exception)
     86            *exception = completion.value();
     87        return NULL;
     88    }
     89   
     90    if (completion.value())
     91        return toRef(completion.value());
     92   
     93    // happens, for example, when the only statement is an empty (';') statement
     94    return toRef(jsUndefined());
    8795}
    8896
     
    93101    UString::Rep* rep = toJS(script);
    94102    return exec->dynamicInterpreter()->checkSyntax(UString(rep));
    95 }
    96 
    97 bool JSContextHasException(JSContextRef context)
    98 {
    99     ExecState* exec = toJS(context);
    100     return exec->hadException();
    101103}
    102104
  • trunk/JavaScriptCore/API/JSContextRef.h

    r15133 r15149  
    4040JSObjectRef JSContextGetGlobalObject(JSContextRef context);
    4141
    42 /* FIXME: These probably aren't useful. The exception is sometimes set
    43    as a throw completion, other times as a value in the exec state.
    44    There's no unified notion of the interpreter's "exception state."
    45  */
    46 bool JSContextHasException(JSContextRef context);
    47 JSValueRef JSContextGetException(JSContextRef context);
     42JSValueRef JSContextGetException(JSContextRef context); // NULL if there is no exception
     43void JSContextSetException(JSContextRef context, JSValueRef value);
    4844void JSContextClearException(JSContextRef context);
    49 void JSContextSetException(JSContextRef context, JSValueRef value);
    5045   
    5146#ifdef __cplusplus
  • trunk/JavaScriptCore/API/JSNodeList.c

    r15133 r15149  
    3434        NodeList* nodeList = JSObjectGetPrivate(thisObject);
    3535        assert(nodeList);
    36         // FIXME: check for integer value
    37         double index = JSValueToNumber(context, argv[0]);
    38         Node* node = NodeList_item(nodeList, (unsigned)index);
     36        Node* node = NodeList_item(nodeList, JSValueToNumber(context, argv[0]));
    3937        if (node)
    4038            return JSNode_new(context, node);
     
    7876    NodeList* nodeList = JSObjectGetPrivate(thisObject);
    7977    assert(nodeList);
    80     // FIXME: check for integer value
    8178    double index = JSValueToNumber(context, JSStringMake(propertyName));
    82     Node* node = NodeList_item(nodeList, (unsigned)index);
    83     if (node) {
    84         *returnValue = JSNode_new(context, node);
    85         return true;
     79    unsigned uindex = index;
     80    if (uindex == index) { // false for NaN
     81        Node* node = NodeList_item(nodeList, uindex);
     82        if (node) {
     83            *returnValue = JSNode_new(context, node);
     84            return true;
     85        }
    8686    }
    8787   
  • trunk/JavaScriptCore/API/JSObjectRef.cpp

    r15133 r15149  
    4646
    4747    JSObjectRef objectRef = toRef(jsValue->toObject(exec));
    48     // FIXME: What should we do with this exception?
    49     if (exec->hadException())
     48    if (exec->hadException()) {
    5049        exec->clearException();
     50        objectRef = NULL;
     51    }
    5152    return objectRef;
    5253}   
     
    177178}
    178179
    179 bool JSObjectCallAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argc, JSValueRef argv[], JSValueRef* returnValue)
     180JSValueRef JSObjectCallAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argc, JSValueRef argv[], JSValueRef* exception)
    180181{
    181182    JSLock lock;
     
    188189        argList.append(toJS(argv[i]));
    189190   
    190     *returnValue = jsObject->call(exec, jsThisObject, argList);
     191    JSValueRef result = toRef(jsObject->call(exec, jsThisObject, argList));
    191192    if (exec->hadException()) {
     193        if (exception)
     194            *exception = exec->exception();
     195        result = NULL;
    192196        exec->clearException();
    193         return false;
    194     }
    195     return true;
     197    }
     198    return result;
    196199}
    197200
     
    202205}
    203206
    204 bool JSObjectCallAsConstructor(JSContextRef context, JSObjectRef object, size_t argc, JSValueRef argv[], JSValueRef* returnValue)
     207JSObjectRef JSObjectCallAsConstructor(JSContextRef context, JSObjectRef object, size_t argc, JSValueRef argv[], JSValueRef* exception)
    205208{
    206209    JSLock lock;
     
    212215        argList.append(toJS(argv[i]));
    213216   
    214     *returnValue = jsObject->construct(exec, argList);
     217    JSObjectRef result = toRef(jsObject->construct(exec, argList));
    215218    if (exec->hadException()) {
     219        if (exception)
     220            *exception = exec->exception();
     221        result = NULL;
    216222        exec->clearException();
    217         return false;
    218     }
    219     return true;
     223    }
     224    return result;
    220225}
    221226
  • trunk/JavaScriptCore/API/JSObjectRef.h

    r15133 r15149  
    128128
    129129bool JSObjectIsFunction(JSObjectRef object);
    130 bool JSObjectCallAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argc, JSValueRef argv[], JSValueRef* returnValue);
     130JSValueRef JSObjectCallAsFunction(JSContextRef context, JSObjectRef object, JSObjectRef thisObject, size_t argc, JSValueRef argv[], JSValueRef* exception);
    131131bool JSObjectIsConstructor(JSObjectRef object);
    132 bool JSObjectCallAsConstructor(JSContextRef context, JSObjectRef object, size_t argc, JSValueRef argv[], JSValueRef* returnValue);
     132JSObjectRef JSObjectCallAsConstructor(JSContextRef context, JSObjectRef object, size_t argc, JSValueRef argv[], JSValueRef* exception);
    133133
    134134// Used for enumerating the names of an object's properties like a for...in loop would
  • trunk/JavaScriptCore/API/JSValueRef.cpp

    r15133 r15149  
    189189
    190190    double number = jsValue->toNumber(exec);
    191     // FIXME: What should we do with this exception?
    192     if (exec->hadException())
    193         exec->clearException();
     191    if (exec->hadException()) {
     192        exec->clearException();
     193        number = NaN;
     194    }
    194195    return number;
    195196}
  • trunk/JavaScriptCore/API/JSValueRef.h

    r15133 r15149  
    188188/*!
    189189  @function JSValueToBoolean
    190   Convert a JavaScript value to boolean and get the boolean value
    191   @param context the execution context to use
    192   @param value   the value to convert to boolean
     190  Convert a JavaScript value to boolean and return the resulting boolean
     191  @param context the execution context to use
     192  @param value   the value to convert
    193193  @result        the boolean result of conversion
    194194*/
     
    197197/*!
    198198  @function JSValueToNumber
    199   Convert a JavaScript value to number and get the numeric value
    200   @param context the execution context to use
    201   @param value   the value to convert to number
    202   @result        the boolean result of conversion, or 0 on failure
     199  Convert a JavaScript value to number and return the resulting number
     200  @param context the execution context to use
     201  @param value   the value to convert
     202  @result        the numeric result of conversion, or NaN if conversion fails
    203203*/
    204204double JSValueToNumber(JSContextRef context, JSValueRef value);
     
    206206/*!
    207207  @function JSValueCopyStringValue
    208   Convert a JavaScript value to string and get the value as a string
    209   @param context the execution context to use 
    210   @param value   the value to convert to string
    211   @result        the string result of conversion, or empty string on failure
     208  Convert a JavaScript value to string and copy the resulting string into a newly allocated character buffer
     209  @param context the execution context to use
     210  @param value   the value to convert
     211  @result        a character buffer containing the result of conversion, or an empty character buffer if conversion fails
    212212*/
    213213JSCharBufferRef JSValueCopyStringValue(JSContextRef context, JSValueRef value);
     
    217217  Convert a JavaScript value to object and return the resulting object
    218218  @param context the execution context to use
    219   @param value   the value to convert to string
    220   @result        the string result of conversion, or error object on failure
     219  @param value   the value to convert
     220  @result        the object result of conversion, or NULL if conversion fails
    221221*/
    222222JSObjectRef JSValueToObject(JSContextRef context, JSValueRef value);
  • trunk/JavaScriptCore/API/minidom.c

    r15133 r15149  
    5050    char* script = createStringWithContentsOfFile("minidom.js");
    5151    JSCharBufferRef scriptBuf = JSCharBufferCreateUTF8(script);
    52     JSValueRef result;
    53     JSEvaluate(context, globalObject, scriptBuf, NULL, 0, &result);
    54 
    55     if (JSValueIsUndefined(result))
     52    JSValueRef exception;
     53    JSValueRef result = JSEvaluate(context, scriptBuf, NULL, NULL, 0, &exception);
     54    if (result)
    5655        printf("PASS: Test script executed successfully.\n");
    5756    else {
    58         printf("FAIL: Test script returned unexcpected value:\n");
    59         JSCharBufferRef resultBuf = JSValueCopyStringValue(context, result);
    60         CFStringRef resultCF = CFStringCreateWithJSCharBuffer(kCFAllocatorDefault, resultBuf);
    61         CFShow(resultCF);
    62         CFRelease(resultCF);
    63         JSCharBufferRelease(resultBuf);
     57        printf("FAIL: Test script threw exception:\n");
     58        JSCharBufferRef exceptionBuf = JSValueCopyStringValue(context, exception);
     59        CFStringRef exceptionCF = CFStringCreateWithJSCharBuffer(kCFAllocatorDefault, exceptionBuf);
     60        CFShow(exceptionCF);
     61        CFRelease(exceptionCF);
     62        JSCharBufferRelease(exceptionBuf);
    6463    }
    6564    JSCharBufferRelease(scriptBuf);
  • trunk/JavaScriptCore/API/testapi.c

    r15133 r15149  
    321321    JSValueRef jsOne = JSNumberMake(1);
    322322    JSValueRef jsOneThird = JSNumberMake(1.0 / 3.0);
     323    JSObjectRef jsObjectNoProto = JSObjectMake(context, NULL, JSNullMake());
     324
    323325    // FIXME: test funny utf8 characters
    324326    JSCharBufferRef jsEmptyStringBuf = JSCharBufferCreateUTF8("");
     
    373375#endif // __APPLE__
    374376
     377    // Conversions that throw exceptions
     378    assert(NULL == JSValueToObject(context, jsNull));
     379    assert(!JSContextGetException(context));
     380    assert(isnan(JSValueToNumber(context, jsObjectNoProto)));
     381    assert(!JSContextGetException(context));
     382    assertEqualsAsCharactersPtr(jsObjectNoProto, "");
     383    assert(!JSContextGetException(context));
     384
    375385    assertEqualsAsBoolean(jsUndefined, false);
    376386    assertEqualsAsBoolean(jsNull, false);
     
    472482#endif // __APPLE__
    473483   
    474     // GDB says jsGlobalValue actually ends up being marked by the stack crawl, so this
    475     // exercise is a bit academic. Not sure why that happens, or how to avoid it.
    476     jsGlobalValue = JSObjectMake(context, NULL, 0);
     484    jsGlobalValue = JSObjectMake(context, NULL, NULL);
     485    JSGCProtect(jsGlobalValue);
    477486    JSGCCollect();
    478487    assert(JSValueIsObject(jsGlobalValue));
     
    490499
    491500    JSValueRef result;
    492     assert(JSEvaluate(context, globalObject, goodSyntaxBuf, jsEmptyString, 0, &result));
     501    JSValueRef exception;
     502
     503    result = JSEvaluate(context, goodSyntaxBuf, NULL, NULL, 0, NULL);
     504    assert(result);
    493505    assert(JSValueIsEqual(context, result, jsOne));
    494506   
    495     assert(!JSEvaluate(context, globalObject, badSyntaxBuf, jsEmptyString, 0, &result));
    496     assert(JSValueIsObject(result));
     507    result = JSEvaluate(context, badSyntaxBuf, NULL, NULL, 0, &exception);
     508    assert(!result);
     509    assert(!JSContextGetException(context));
     510    assert(JSValueIsObject(exception));
    497511   
    498512    JSContextSetException(context, JSNumberMake(1));
    499     assert(JSContextHasException(context));
     513    assert(JSContextGetException(context));
    500514    assert(JSValueIsEqual(context, jsOne, JSContextGetException(context)));
    501515    JSContextClearException(context);
    502     assert(!JSContextHasException(context));
     516    assert(!JSContextGetException(context));
    503517
    504518    JSCharBufferRelease(jsEmptyStringBuf);
     
    518532    JSObjectRef arrayConstructor = JSValueToObject(context, v);
    519533    JSCharBufferRelease(arrayBuf);
    520     JSValueRef arrayObject;
    521     assert(JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, &arrayObject));
    522     assert(JSValueIsInstanceOf(context, arrayObject, arrayConstructor));
     534    result = JSObjectCallAsConstructor(context, arrayConstructor, 0, NULL, NULL);
     535    assert(result);
     536    assert(JSValueIsInstanceOf(context, result, arrayConstructor));
    523537    assert(!JSValueIsInstanceOf(context, JSNullMake(), arrayConstructor));
    524538   
     
    539553    char* script = createStringWithContentsOfFile("testapi.js");
    540554    JSCharBufferRef scriptBuf = JSCharBufferCreateUTF8(script);
    541     JSEvaluate(context, globalObject, scriptBuf, jsEmptyString, 0, &result);
     555    result = JSEvaluate(context, scriptBuf, NULL, NULL, 0, &exception);
    542556    if (JSValueIsUndefined(result))
    543557        printf("PASS: Test script executed successfully.\n");
    544558    else {
    545559        printf("FAIL: Test script returned unexcpected value:\n");
    546         JSCharBufferRef resultBuf = JSValueCopyStringValue(context, result);
    547         CFStringRef resultCF = CFStringCreateWithJSCharBuffer(kCFAllocatorDefault, resultBuf);
    548         CFShow(resultCF);
    549         CFRelease(resultCF);
    550         JSCharBufferRelease(resultBuf);
     560        JSCharBufferRef exceptionBuf = JSValueCopyStringValue(context, exception);
     561        CFStringRef exceptionCF = CFStringCreateWithJSCharBuffer(kCFAllocatorDefault, exceptionBuf);
     562        CFShow(exceptionCF);
     563        CFRelease(exceptionCF);
     564        JSCharBufferRelease(exceptionBuf);
    551565    }
    552566    JSCharBufferRelease(scriptBuf);
Note: See TracChangeset for help on using the changeset viewer.