Changeset 233911 in webkit


Ignore:
Timestamp:
Jul 18, 2018 5:54:38 AM (6 years ago)
Author:
Carlos Garcia Campos
Message:

[GLIB] Add jsc_context_check_syntax() to GLib API
https://bugs.webkit.org/show_bug.cgi?id=187694

Reviewed by Yusuke Suzuki.

Source/JavaScriptCore:

A new function to be able to check for syntax errors without actually evaluating the code.

  • API/glib/JSCContext.cpp:

(jsc_context_check_syntax):

  • API/glib/JSCContext.h:
  • API/glib/docs/jsc-glib-4.0-sections.txt:

Tools:

Add a new test case.

  • TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:

(testJSCCheckSyntax):
(main):

Location:
trunk
Files:
6 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/JavaScriptCore/API/glib/JSCContext.cpp

    r233844 r233911  
    3131#include "JSWithScope.h"
    3232#include "OpaqueJSString.h"
     33#include "Parser.h"
    3334#include <wtf/glib/GUniquePtr.h>
    3435#include <wtf/glib/WTFGType.h>
     
    829830
    830831/**
     832 * JSCCheckSyntaxMode:
     833 * @JSC_CHECK_SYNTAX_MODE_SCRIPT: mode to check syntax of a script
     834 * @JSC_CHECK_SYNTAX_MODE_MODULE: mode to check syntax of a module
     835 *
     836 * Enum values to specify a mode to check for syntax errors in jsc_context_check_syntax().
     837 */
     838
     839/**
     840 * JSCCheckSyntaxResult:
     841 * @JSC_CHECK_SYNTAX_RESULT_SUCCESS: no errors
     842 * @JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR: recoverable syntax error
     843 * @JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR: irrecoverable syntax error
     844 * @JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR: unterminated literal error
     845 * @JSC_CHECK_SYNTAX_RESULT_OUT_OF_MEMORY_ERROR: out of memory error
     846 * @JSC_CHECK_SYNTAX_RESULT_STACK_OVERFLOW_ERROR: stack overflow error
     847 *
     848 * Enum values to specify the result of jsc_context_check_syntax().
     849 */
     850
     851/**
     852 * jsc_context_check_syntax:
     853 * @context: a #JSCContext
     854 * @code: a JavaScript script to check
     855 * @length: length of @code, or -1 if @code is a nul-terminated string
     856 * @mode: a #JSCCheckSyntaxMode
     857 * @uri: the source URI
     858 * @line_number: the starting line number
     859 * @exception: (out) (optional) (transfer full): return location for a #JSCException, or %NULL to ignore
     860 *
     861 * Check the given @code in @context for syntax errors. The @line_number is the starting line number in @uri;
     862 * the value is one-based so the first line is 1. @uri and @line_number are only used to fill the @exception.
     863 * In case of errors @exception will be set to a new #JSCException with the details. You can pass %NULL to
     864 * @exception to ignore the error details.
     865 *
     866 * Returns: a #JSCCheckSyntaxResult
     867 */
     868JSCCheckSyntaxResult jsc_context_check_syntax(JSCContext* context, const char* code, gssize length, JSCCheckSyntaxMode mode, const char* uri, unsigned lineNumber, JSCException **exception)
     869{
     870    g_return_val_if_fail(JSC_IS_CONTEXT(context), JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
     871    g_return_val_if_fail(code, JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
     872    g_return_val_if_fail(!exception || !*exception, JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
     873
     874    lineNumber = std::max<unsigned>(1, lineNumber);
     875
     876    auto* jsContext = context->priv->jsContext.get();
     877    JSC::ExecState* exec = toJS(jsContext);
     878    JSC::VM& vm = exec->vm();
     879    JSC::JSLockHolder locker(vm);
     880
     881    String sourceURLString = uri ? String::fromUTF8(uri) : String();
     882    JSC::SourceCode source = JSC::makeSource(String::fromUTF8(code, length < 0 ? strlen(code) : length), JSC::SourceOrigin { sourceURLString },
     883        sourceURLString, TextPosition(OrdinalNumber::fromOneBasedInt(lineNumber), OrdinalNumber()));
     884    bool success = false;
     885    JSC::ParserError error;
     886    switch (mode) {
     887    case JSC_CHECK_SYNTAX_MODE_SCRIPT:
     888        success = !!JSC::parse<JSC::ProgramNode>(&vm, source, JSC::Identifier(), JSC::JSParserBuiltinMode::NotBuiltin,
     889            JSC::JSParserStrictMode::NotStrict, JSC::JSParserScriptMode::Classic, JSC::SourceParseMode::ProgramMode, JSC::SuperBinding::NotNeeded, error);
     890        break;
     891    case JSC_CHECK_SYNTAX_MODE_MODULE:
     892        success = !!JSC::parse<JSC::ModuleProgramNode>(&vm, source, JSC::Identifier(), JSC::JSParserBuiltinMode::NotBuiltin,
     893            JSC::JSParserStrictMode::Strict, JSC::JSParserScriptMode::Module, JSC::SourceParseMode::ModuleAnalyzeMode, JSC::SuperBinding::NotNeeded, error);
     894        break;
     895    }
     896
     897    JSCCheckSyntaxResult result = JSC_CHECK_SYNTAX_RESULT_SUCCESS;
     898    if (success)
     899        return result;
     900
     901    switch (error.type()) {
     902    case JSC::ParserError::ErrorType::SyntaxError: {
     903        switch (error.syntaxErrorType()) {
     904        case JSC::ParserError::SyntaxErrorType::SyntaxErrorIrrecoverable:
     905            result = JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR;
     906            break;
     907        case JSC::ParserError::SyntaxErrorType::SyntaxErrorUnterminatedLiteral:
     908            result = JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR;
     909            break;
     910        case JSC::ParserError::SyntaxErrorType::SyntaxErrorRecoverable:
     911            result = JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR;
     912            break;
     913        case JSC::ParserError::SyntaxErrorType::SyntaxErrorNone:
     914            ASSERT_NOT_REACHED();
     915            break;
     916        }
     917        break;
     918    }
     919    case JSC::ParserError::ErrorType::StackOverflow:
     920        result = JSC_CHECK_SYNTAX_RESULT_STACK_OVERFLOW_ERROR;
     921        break;
     922    case JSC::ParserError::ErrorType::OutOfMemory:
     923        result = JSC_CHECK_SYNTAX_RESULT_OUT_OF_MEMORY_ERROR;
     924        break;
     925    case JSC::ParserError::ErrorType::EvalError:
     926    case JSC::ParserError::ErrorType::ErrorNone:
     927        ASSERT_NOT_REACHED();
     928        break;
     929    }
     930
     931    if (exception) {
     932        auto* jsError = error.toErrorObject(exec->lexicalGlobalObject(), source);
     933        *exception = jscExceptionCreate(context, toRef(exec, jsError)).leakRef();
     934    }
     935
     936    return result;
     937}
     938
     939/**
    831940 * jsc_context_get_global_object:
    832941 * @context: a #JSCContext
  • trunk/Source/JavaScriptCore/API/glib/JSCContext.h

    r233844 r233911  
    4848                                      JSCException *exception,
    4949                                      gpointer      user_data);
     50
     51typedef enum {
     52    JSC_CHECK_SYNTAX_MODE_SCRIPT,
     53    JSC_CHECK_SYNTAX_MODE_MODULE
     54} JSCCheckSyntaxMode;
     55
     56typedef enum {
     57    JSC_CHECK_SYNTAX_RESULT_SUCCESS,
     58    JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR,
     59    JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR,
     60    JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR,
     61    JSC_CHECK_SYNTAX_RESULT_OUT_OF_MEMORY_ERROR,
     62    JSC_CHECK_SYNTAX_RESULT_STACK_OVERFLOW_ERROR,
     63} JSCCheckSyntaxResult;
    5064
    5165struct _JSCContext {
     
    124138                                      JSCValue          **object);
    125139
     140JSC_API JSCCheckSyntaxResult
     141jsc_context_check_syntax             (JSCContext         *context,
     142                                      const char         *code,
     143                                      gssize              length,
     144                                      JSCCheckSyntaxMode  mode,
     145                                      const char         *uri,
     146                                      unsigned            line_number,
     147                                      JSCException      **exception);
     148
    126149JSC_API JSCValue *
    127150jsc_context_get_global_object        (JSCContext         *context);
  • trunk/Source/JavaScriptCore/API/glib/docs/jsc-glib-4.0-sections.txt

    r233844 r233911  
    2727JSCContext
    2828JSCExceptionHandler
     29JSCCheckSyntaxMode
     30JSCCheckSyntaxResult
    2931jsc_context_new
    3032jsc_context_new_with_virtual_machine
     
    4042jsc_context_evaluate_with_source_uri
    4143jsc_context_evaluate_in_object
     44jsc_context_check_syntax
    4245jsc_context_get_global_object
    4346jsc_context_set_value
  • trunk/Source/JavaScriptCore/ChangeLog

    r233906 r233911  
     12018-07-18  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GLIB] Add jsc_context_check_syntax() to GLib API
     4        https://bugs.webkit.org/show_bug.cgi?id=187694
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        A new function to be able to check for syntax errors without actually evaluating the code.
     9
     10        * API/glib/JSCContext.cpp:
     11        (jsc_context_check_syntax):
     12        * API/glib/JSCContext.h:
     13        * API/glib/docs/jsc-glib-4.0-sections.txt:
     14
    1152018-07-17  Keith Miller  <keith_miller@apple.com>
    216
  • trunk/Tools/ChangeLog

    r233899 r233911  
     12018-07-18  Carlos Garcia Campos  <cgarcia@igalia.com>
     2
     3        [GLIB] Add jsc_context_check_syntax() to GLib API
     4        https://bugs.webkit.org/show_bug.cgi?id=187694
     5
     6        Reviewed by Yusuke Suzuki.
     7
     8        Add a new test case.
     9
     10        * TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp:
     11        (testJSCCheckSyntax):
     12        (main):
     13
    1142018-07-17  Sihui Liu  <sihui_liu@apple.com>
    215
  • trunk/Tools/TestWebKitAPI/Tests/JavaScriptCore/glib/TestJSC.cpp

    r233844 r233911  
    720720}
    721721
     722static void testJSCCheckSyntax()
     723{
     724    LeakChecker checker;
     725    GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
     726    checker.watch(context.get());
     727    ExceptionHandler exceptionHandler(context.get());
     728
     729    GRefPtr<JSCException> exception;
     730    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "f = 42", -1, JSC_CHECK_SYNTAX_MODE_SCRIPT, nullptr, 0, &exception.outPtr()), ==, JSC_CHECK_SYNTAX_RESULT_SUCCESS);
     731    g_assert_null(exception.get());
     732
     733    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "f = 42; b =", -1, JSC_CHECK_SYNTAX_MODE_SCRIPT, nullptr, 0, &exception.outPtr()), ==, JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR);
     734    checker.watch(exception.get());
     735    g_assert_true(JSC_IS_EXCEPTION(exception.get()));
     736    g_assert_cmpstr(jsc_exception_get_message(exception.get()), ==, "Unexpected end of script");
     737    g_assert_cmpuint(jsc_exception_get_line_number(exception.get()), ==, 1);
     738    g_assert_false(jsc_exception_get_source_uri(exception.get()));
     739    GRefPtr<JSCValue> globalObject = adoptGRef(jsc_context_get_global_object(context.get()));
     740    checker.watch(globalObject.get());
     741    g_assert_false(jsc_value_object_has_property(globalObject.get(), "f"));
     742    exception = nullptr;
     743
     744    // Only syntax errors are checked.
     745    bool didThrow = false;
     746    g_assert_throw_begin(exceptionHandler, didThrow);
     747    GRefPtr<JSCValue> value = adoptGRef(jsc_context_evaluate(context.get(), "f", -1));
     748    checker.watch(value.get());
     749    g_assert_true(jsc_value_is_undefined(value.get()));
     750    g_assert_did_throw(exceptionHandler, didThrow);
     751    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "f", -1, JSC_CHECK_SYNTAX_MODE_SCRIPT, nullptr, 0, &exception.outPtr()), ==, JSC_CHECK_SYNTAX_RESULT_SUCCESS);
     752    g_assert_null(exception.get());
     753
     754    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "f ==== 42", -1, JSC_CHECK_SYNTAX_MODE_SCRIPT, "file:///foo/script.js", 2, &exception.outPtr()), ==, JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
     755    checker.watch(exception.get());
     756    g_assert_true(JSC_IS_EXCEPTION(exception.get()));
     757    g_assert_cmpstr(jsc_exception_get_message(exception.get()), ==, "Unexpected token '='");
     758    g_assert_cmpuint(jsc_exception_get_line_number(exception.get()), ==, 2);
     759    g_assert_cmpstr(jsc_exception_get_source_uri(exception.get()), ==, "file:///foo/script.js");
     760
     761    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "f := 42", -1, JSC_CHECK_SYNTAX_MODE_SCRIPT, nullptr, 0, nullptr), ==, JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
     762    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "f '42;", -1, JSC_CHECK_SYNTAX_MODE_SCRIPT, nullptr, 0, nullptr), ==, JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR);
     763
     764    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "import foo from '/foo.js'", -1, JSC_CHECK_SYNTAX_MODE_SCRIPT, nullptr, 0, nullptr), ==, JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
     765    g_assert_cmpuint(jsc_context_check_syntax(context.get(), "import foo from '/foo.js'", -1, JSC_CHECK_SYNTAX_MODE_MODULE, nullptr, 0, nullptr), ==, JSC_CHECK_SYNTAX_RESULT_SUCCESS);
     766}
     767
    722768static int foo(int n)
    723769{
     
    29993045    g_test_add_func("/jsc/global-object", testJSCGlobalObject);
    30003046    g_test_add_func("/jsc/evaluate-in-object", testJSCEvaluateInObject);
     3047    g_test_add_func("/jsc/check-syntax", testJSCCheckSyntax);
    30013048    g_test_add_func("/jsc/function", testJSCFunction);
    30023049    g_test_add_func("/jsc/object", testJSCObject);
Note: See TracChangeset for help on using the changeset viewer.