Bug 1439855 - Extend JS shell binParse with ability to pick a tokenizer;r?arai draft
authorDavid Teller <dteller@mozilla.com>
Thu, 05 Apr 2018 14:31:39 +0200
changeset 784329 f4f5fc2fbbb94df0068104cfd7dd53e88833831e
parent 784328 ec1dd6feef68f7d8fa55683cd9a5d72b24b1d44d
child 784330 1edc11d533e2a882f3f0fc845c388e44b2768c6f
push id106893
push userdteller@mozilla.com
push dateWed, 18 Apr 2018 11:19:13 +0000
reviewersarai
bugs1439855
milestone61.0a1
Bug 1439855 - Extend JS shell binParse with ability to pick a tokenizer;r?arai MozReview-Commit-ID: 9EQY36O9wQo
js/src/shell/js.cpp
--- a/js/src/shell/js.cpp
+++ b/js/src/shell/js.cpp
@@ -4279,54 +4279,117 @@ BinParse(JSContext* cx, unsigned argc, V
 
     CallArgs args = CallArgsFromVp(argc, vp);
 
     if (args.length() < 1) {
         JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr, JSMSG_MORE_ARGS_NEEDED,
                                   "parse", "0", "s");
         return false;
     }
+
+    // Extract argument 1: ArrayBuffer.
+
     if (!args[0].isObject()) {
         const char* typeName = InformalValueTypeName(args[0]);
         JS_ReportErrorASCII(cx, "expected object (ArrayBuffer) to parse, got %s", typeName);
         return false;
     }
 
-    RootedObject obj(cx, &args[0].toObject());
-    if (!JS_IsArrayBufferObject(obj)) {
+    RootedObject objBuf(cx, &args[0].toObject());
+    if (!JS_IsArrayBufferObject(objBuf)) {
         const char* typeName = InformalValueTypeName(args[0]);
         JS_ReportErrorASCII(cx, "expected ArrayBuffer to parse, got %s", typeName);
         return false;
     }
 
     uint32_t buf_length = 0;
     bool buf_isSharedMemory = false;
     uint8_t* buf_data = nullptr;
-    GetArrayBufferViewLengthAndData(obj, &buf_length, &buf_isSharedMemory, &buf_data);
+    GetArrayBufferLengthAndData(objBuf, &buf_length, &buf_isSharedMemory, &buf_data);
     MOZ_ASSERT(buf_data);
 
+    // Extract argument 2: Options.
+
+    bool useMultipart = true;
+
+    if (args.length() >= 2) {
+        if (!args[1].isObject()) {
+            const char* typeName = InformalValueTypeName(args[1]);
+            JS_ReportErrorASCII(cx, "expected object (options) to parse, got %s", typeName);
+            return false;
+        }
+        RootedObject objOptions(cx, &args[1].toObject());
+
+        RootedValue optionFormat(cx);
+        if (!JS_GetProperty(cx, objOptions, "format", &optionFormat))
+            return false;
+
+        if (optionFormat.isUndefined()) {
+            // By default, `useMultipart` is `true`.
+            useMultipart = true;
+        } else if (optionFormat.isString()) {
+            RootedString stringFormat(cx);
+            stringFormat = optionFormat.toString();
+            JS::Rooted<JSLinearString*> linearFormat(cx);
+            linearFormat = stringFormat->ensureLinear(cx);
+            if (StringEqualsAscii(linearFormat, "multipart")) {
+                useMultipart = true;
+            } else if (StringEqualsAscii(linearFormat, "simple")) {
+                useMultipart = false;
+            } else {
+                JSAutoByteString printable;
+                JS_ReportErrorASCII(cx, "Unknown value for option `format`, expected 'multipart' or 'simple', got %s", ValueToPrintableUTF8(cx, optionFormat, &printable));
+                return false;
+            }
+        } else {
+            const char* typeName = InformalValueTypeName(optionFormat);
+            JS_ReportErrorASCII(cx, "option `format` should be a string, got %s", typeName);
+            return false;
+        }
+    }
+
+
     CompileOptions options(cx);
     options.setIntroductionType("js shell bin parse")
            .setFileAndLine("<ArrayBuffer>", 1);
 
     UsedNameTracker usedNames(cx);
     if (!usedNames.init())
         return false;
 
-    BinASTParser reader(cx, cx->tempLifoAlloc(), usedNames, options);
-
-    JS::Result<ParseNode*> parsed = reader.parse(buf_data, buf_length);
-    if (parsed.isErr())
-        return false;
+    JS::Result<ParseNode*> parsed(nullptr);
+    if (useMultipart) {
+        // Note: We need to keep `reader` alive as long as we can use `parsed`.
+        BinASTParser<BinTokenReaderMultipart> reader(cx, cx->tempLifoAlloc(), usedNames, options);
+
+        parsed = reader.parse(buf_data, buf_length);
+
+        if (parsed.isErr())
+            return false;
 
 #ifdef DEBUG
-    Fprinter out(stderr);
-    DumpParseTree(parsed.unwrap(), out);
+        Fprinter out(stderr);
+        DumpParseTree(parsed.unwrap(), out);
 #endif
 
+    } else {
+        // Note: We need to keep `reader` alive as long as we can use `parsed`.
+        BinASTParser<BinTokenReaderTester> reader(cx, cx->tempLifoAlloc(), usedNames, options);
+
+        parsed = reader.parse(buf_data, buf_length);
+
+        if (parsed.isErr())
+            return false;
+
+#ifdef DEBUG
+        Fprinter out(stderr);
+        DumpParseTree(parsed.unwrap(), out);
+#endif
+    }
+
     args.rval().setUndefined();
     return true;
 }
 
 #endif // defined(JS_BUILD_BINAST)
 
 static bool
 Parse(JSContext* cx, unsigned argc, Value* vp)