Title: [233911] trunk
Revision
233911
Author
[email protected]
Date
2018-07-18 05:54:38 -0700 (Wed, 18 Jul 2018)

Log Message

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

Reviewed by Yusuke Suzuki.

Source/_javascript_Core:

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/_javascript_Core/glib/TestJSC.cpp:
(testJSCCheckSyntax):
(main):

Modified Paths

Diff

Modified: trunk/Source/_javascript_Core/API/glib/JSCContext.cpp (233910 => 233911)


--- trunk/Source/_javascript_Core/API/glib/JSCContext.cpp	2018-07-18 10:22:15 UTC (rev 233910)
+++ trunk/Source/_javascript_Core/API/glib/JSCContext.cpp	2018-07-18 12:54:38 UTC (rev 233911)
@@ -30,6 +30,7 @@
 #include "JSRetainPtr.h"
 #include "JSWithScope.h"
 #include "OpaqueJSString.h"
+#include "Parser.h"
 #include <wtf/glib/GUniquePtr.h>
 #include <wtf/glib/WTFGType.h>
 
@@ -828,6 +829,114 @@
 }
 
 /**
+ * JSCCheckSyntaxMode:
+ * @JSC_CHECK_SYNTAX_MODE_SCRIPT: mode to check syntax of a script
+ * @JSC_CHECK_SYNTAX_MODE_MODULE: mode to check syntax of a module
+ *
+ * Enum values to specify a mode to check for syntax errors in jsc_context_check_syntax().
+ */
+
+/**
+ * JSCCheckSyntaxResult:
+ * @JSC_CHECK_SYNTAX_RESULT_SUCCESS: no errors
+ * @JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR: recoverable syntax error
+ * @JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR: irrecoverable syntax error
+ * @JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR: unterminated literal error
+ * @JSC_CHECK_SYNTAX_RESULT_OUT_OF_MEMORY_ERROR: out of memory error
+ * @JSC_CHECK_SYNTAX_RESULT_STACK_OVERFLOW_ERROR: stack overflow error
+ *
+ * Enum values to specify the result of jsc_context_check_syntax().
+ */
+
+/**
+ * jsc_context_check_syntax:
+ * @context: a #JSCContext
+ * @code: a _javascript_ script to check
+ * @length: length of @code, or -1 if @code is a nul-terminated string
+ * @mode: a #JSCCheckSyntaxMode
+ * @uri: the source URI
+ * @line_number: the starting line number
+ * @exception: (out) (optional) (transfer full): return location for a #JSCException, or %NULL to ignore
+ *
+ * Check the given @code in @context for syntax errors. The @line_number is the starting line number in @uri;
+ * the value is one-based so the first line is 1. @uri and @line_number are only used to fill the @exception.
+ * In case of errors @exception will be set to a new #JSCException with the details. You can pass %NULL to
+ * @exception to ignore the error details.
+ *
+ * Returns: a #JSCCheckSyntaxResult
+ */
+JSCCheckSyntaxResult jsc_context_check_syntax(JSCContext* context, const char* code, gssize length, JSCCheckSyntaxMode mode, const char* uri, unsigned lineNumber, JSCException **exception)
+{
+    g_return_val_if_fail(JSC_IS_CONTEXT(context), JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
+    g_return_val_if_fail(code, JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
+    g_return_val_if_fail(!exception || !*exception, JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR);
+
+    lineNumber = std::max<unsigned>(1, lineNumber);
+
+    auto* jsContext = context->priv->jsContext.get();
+    JSC::ExecState* exec = toJS(jsContext);
+    JSC::VM& vm = exec->vm();
+    JSC::JSLockHolder locker(vm);
+
+    String sourceURLString = uri ? String::fromUTF8(uri) : String();
+    JSC::SourceCode source = JSC::makeSource(String::fromUTF8(code, length < 0 ? strlen(code) : length), JSC::SourceOrigin { sourceURLString },
+        sourceURLString, TextPosition(OrdinalNumber::fromOneBasedInt(lineNumber), OrdinalNumber()));
+    bool success = false;
+    JSC::ParserError error;
+    switch (mode) {
+    case JSC_CHECK_SYNTAX_MODE_SCRIPT:
+        success = !!JSC::parse<JSC::ProgramNode>(&vm, source, JSC::Identifier(), JSC::JSParserBuiltinMode::NotBuiltin,
+            JSC::JSParserStrictMode::NotStrict, JSC::JSParserScriptMode::Classic, JSC::SourceParseMode::ProgramMode, JSC::SuperBinding::NotNeeded, error);
+        break;
+    case JSC_CHECK_SYNTAX_MODE_MODULE:
+        success = !!JSC::parse<JSC::ModuleProgramNode>(&vm, source, JSC::Identifier(), JSC::JSParserBuiltinMode::NotBuiltin,
+            JSC::JSParserStrictMode::Strict, JSC::JSParserScriptMode::Module, JSC::SourceParseMode::ModuleAnalyzeMode, JSC::SuperBinding::NotNeeded, error);
+        break;
+    }
+
+    JSCCheckSyntaxResult result = JSC_CHECK_SYNTAX_RESULT_SUCCESS;
+    if (success)
+        return result;
+
+    switch (error.type()) {
+    case JSC::ParserError::ErrorType::SyntaxError: {
+        switch (error.syntaxErrorType()) {
+        case JSC::ParserError::SyntaxErrorType::SyntaxErrorIrrecoverable:
+            result = JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR;
+            break;
+        case JSC::ParserError::SyntaxErrorType::SyntaxErrorUnterminatedLiteral:
+            result = JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR;
+            break;
+        case JSC::ParserError::SyntaxErrorType::SyntaxErrorRecoverable:
+            result = JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR;
+            break;
+        case JSC::ParserError::SyntaxErrorType::SyntaxErrorNone:
+            ASSERT_NOT_REACHED();
+            break;
+        }
+        break;
+    }
+    case JSC::ParserError::ErrorType::StackOverflow:
+        result = JSC_CHECK_SYNTAX_RESULT_STACK_OVERFLOW_ERROR;
+        break;
+    case JSC::ParserError::ErrorType::OutOfMemory:
+        result = JSC_CHECK_SYNTAX_RESULT_OUT_OF_MEMORY_ERROR;
+        break;
+    case JSC::ParserError::ErrorType::EvalError:
+    case JSC::ParserError::ErrorType::ErrorNone:
+        ASSERT_NOT_REACHED();
+        break;
+    }
+
+    if (exception) {
+        auto* jsError = error.toErrorObject(exec->lexicalGlobalObject(), source);
+        *exception = jscExceptionCreate(context, toRef(exec, jsError)).leakRef();
+    }
+
+    return result;
+}
+
+/**
  * jsc_context_get_global_object:
  * @context: a #JSCContext
  *

Modified: trunk/Source/_javascript_Core/API/glib/JSCContext.h (233910 => 233911)


--- trunk/Source/_javascript_Core/API/glib/JSCContext.h	2018-07-18 10:22:15 UTC (rev 233910)
+++ trunk/Source/_javascript_Core/API/glib/JSCContext.h	2018-07-18 12:54:38 UTC (rev 233911)
@@ -48,6 +48,20 @@
                                       JSCException *exception,
                                       gpointer      user_data);
 
+typedef enum {
+    JSC_CHECK_SYNTAX_MODE_SCRIPT,
+    JSC_CHECK_SYNTAX_MODE_MODULE
+} JSCCheckSyntaxMode;
+
+typedef enum {
+    JSC_CHECK_SYNTAX_RESULT_SUCCESS,
+    JSC_CHECK_SYNTAX_RESULT_RECOVERABLE_ERROR,
+    JSC_CHECK_SYNTAX_RESULT_IRRECOVERABLE_ERROR,
+    JSC_CHECK_SYNTAX_RESULT_UNTERMINATED_LITERAL_ERROR,
+    JSC_CHECK_SYNTAX_RESULT_OUT_OF_MEMORY_ERROR,
+    JSC_CHECK_SYNTAX_RESULT_STACK_OVERFLOW_ERROR,
+} JSCCheckSyntaxResult;
+
 struct _JSCContext {
     GObject parent;
 
@@ -123,6 +137,15 @@
                                       guint               line_number,
                                       JSCValue          **object);
 
+JSC_API JSCCheckSyntaxResult
+jsc_context_check_syntax             (JSCContext         *context,
+                                      const char         *code,
+                                      gssize              length,
+                                      JSCCheckSyntaxMode  mode,
+                                      const char         *uri,
+                                      unsigned            line_number,
+                                      JSCException      **exception);
+
 JSC_API JSCValue *
 jsc_context_get_global_object        (JSCContext         *context);
 

Modified: trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt (233910 => 233911)


--- trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt	2018-07-18 10:22:15 UTC (rev 233910)
+++ trunk/Source/_javascript_Core/API/glib/docs/jsc-glib-4.0-sections.txt	2018-07-18 12:54:38 UTC (rev 233911)
@@ -26,6 +26,8 @@
 <TITLE>JSCContext</TITLE>
 JSCContext
 JSCExceptionHandler
+JSCCheckSyntaxMode
+JSCCheckSyntaxResult
 jsc_context_new
 jsc_context_new_with_virtual_machine
 jsc_context_get_virtual_machine
@@ -39,6 +41,7 @@
 jsc_context_evaluate
 jsc_context_evaluate_with_source_uri
 jsc_context_evaluate_in_object
+jsc_context_check_syntax
 jsc_context_get_global_object
 jsc_context_set_value
 jsc_context_get_value

Modified: trunk/Source/_javascript_Core/ChangeLog (233910 => 233911)


--- trunk/Source/_javascript_Core/ChangeLog	2018-07-18 10:22:15 UTC (rev 233910)
+++ trunk/Source/_javascript_Core/ChangeLog	2018-07-18 12:54:38 UTC (rev 233911)
@@ -1,3 +1,17 @@
+2018-07-18  Carlos Garcia Campos  <[email protected]>
+
+        [GLIB] Add jsc_context_check_syntax() to GLib API
+        https://bugs.webkit.org/show_bug.cgi?id=187694
+
+        Reviewed by Yusuke Suzuki.
+
+        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:
+
 2018-07-17  Keith Miller  <[email protected]>
 
         Revert r233630 since it broke internal wasm benchmarks

Modified: trunk/Tools/ChangeLog (233910 => 233911)


--- trunk/Tools/ChangeLog	2018-07-18 10:22:15 UTC (rev 233910)
+++ trunk/Tools/ChangeLog	2018-07-18 12:54:38 UTC (rev 233911)
@@ -1,3 +1,16 @@
+2018-07-18  Carlos Garcia Campos  <[email protected]>
+
+        [GLIB] Add jsc_context_check_syntax() to GLib API
+        https://bugs.webkit.org/show_bug.cgi?id=187694
+
+        Reviewed by Yusuke Suzuki.
+
+        Add a new test case.
+
+        * TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp:
+        (testJSCCheckSyntax):
+        (main):
+
 2018-07-17  Sihui Liu  <[email protected]>
 
         REGRESSION: [macOS Sierra] TestWebKitAPI.WebKit.WebsiteDataStoreCustomPaths is a flaky failure

Modified: trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp (233910 => 233911)


--- trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp	2018-07-18 10:22:15 UTC (rev 233910)
+++ trunk/Tools/TestWebKitAPI/Tests/_javascript_Core/glib/TestJSC.cpp	2018-07-18 12:54:38 UTC (rev 233911)
@@ -719,6 +719,52 @@
     g_assert_true(jsc_value_is_undefined(moduleInWk.get()));
 }
 
+static void testJSCCheckSyntax()
+{
+    LeakChecker checker;
+    GRefPtr<JSCContext> context = adoptGRef(jsc_context_new());
+    checker.watch(context.get());
+    ExceptionHandler exceptionHandler(context.get());
+
+    GRefPtr<JSCException> exception;
+    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);
+    g_assert_null(exception.get());
+
+    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);
+    checker.watch(exception.get());
+    g_assert_true(JSC_IS_EXCEPTION(exception.get()));
+    g_assert_cmpstr(jsc_exception_get_message(exception.get()), ==, "Unexpected end of script");
+    g_assert_cmpuint(jsc_exception_get_line_number(exception.get()), ==, 1);
+    g_assert_false(jsc_exception_get_source_uri(exception.get()));
+    GRefPtr<JSCValue> globalObject = adoptGRef(jsc_context_get_global_object(context.get()));
+    checker.watch(globalObject.get());
+    g_assert_false(jsc_value_object_has_property(globalObject.get(), "f"));
+    exception = nullptr;
+
+    // Only syntax errors are checked.
+    bool didThrow = false;
+    g_assert_throw_begin(exceptionHandler, didThrow);
+    GRefPtr<JSCValue> value = adoptGRef(jsc_context_evaluate(context.get(), "f", -1));
+    checker.watch(value.get());
+    g_assert_true(jsc_value_is_undefined(value.get()));
+    g_assert_did_throw(exceptionHandler, didThrow);
+    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);
+    g_assert_null(exception.get());
+
+    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);
+    checker.watch(exception.get());
+    g_assert_true(JSC_IS_EXCEPTION(exception.get()));
+    g_assert_cmpstr(jsc_exception_get_message(exception.get()), ==, "Unexpected token '='");
+    g_assert_cmpuint(jsc_exception_get_line_number(exception.get()), ==, 2);
+    g_assert_cmpstr(jsc_exception_get_source_uri(exception.get()), ==, "file:///foo/script.js");
+
+    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);
+    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);
+
+    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);
+    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);
+}
+
 static int foo(int n)
 {
     return n * 2;
@@ -2998,6 +3044,7 @@
     g_test_add_func("/jsc/types", testJSCTypes);
     g_test_add_func("/jsc/global-object", testJSCGlobalObject);
     g_test_add_func("/jsc/evaluate-in-object", testJSCEvaluateInObject);
+    g_test_add_func("/jsc/check-syntax", testJSCCheckSyntax);
     g_test_add_func("/jsc/function", testJSCFunction);
     g_test_add_func("/jsc/object", testJSCObject);
     g_test_add_func("/jsc/class", testJSCClass);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to