tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

JSONParser.h (22570B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
      2 * vim: set ts=8 sts=2 et sw=2 tw=80:
      3 * This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #ifndef vm_JSONParser_h
      8 #define vm_JSONParser_h
      9 
     10 #include "mozilla/Assertions.h"  // MOZ_ASSERT
     11 #include "mozilla/Attributes.h"  // MOZ_STACK_CLASS
     12 #include "mozilla/Maybe.h"       // mozilla::{Maybe,Some}
     13 #include "mozilla/Range.h"       // mozilla::Range
     14 #include "mozilla/RangedPtr.h"   // mozilla::RangedPtr
     15 
     16 #include <stddef.h>  // size_t
     17 #include <stdint.h>  // uint32_t
     18 #include <utility>   // std::move
     19 
     20 #include "builtin/ParseRecordObject.h"  // js::ParseRecordObject
     21 #include "ds/IdValuePair.h"             // IdValuePair
     22 #include "gc/GC.h"                      // AutoSelectGCHeap
     23 #include "js/GCVector.h"                // JS::GCVector
     24 #include "js/RootingAPI.h"  // JS::Handle, JS::MutableHandle, MutableWrappedPtrOperations
     25 #include "js/Value.h"            // JS::Value, JS::BooleanValue, JS::NullValue
     26 #include "js/Vector.h"           // Vector
     27 #include "util/StringBuilder.h"  // JSStringBuilder
     28 #include "vm/StringType.h"       // JSString, JSAtom
     29 
     30 struct JSContext;
     31 class JSTracer;
     32 
     33 namespace js {
     34 
     35 class FrontendContext;
     36 
     37 enum class JSONToken {
     38  String,
     39  Number,
     40  True,
     41  False,
     42  Null,
     43  ArrayOpen,
     44  ArrayClose,
     45  ObjectOpen,
     46  ObjectClose,
     47  Colon,
     48  Comma,
     49  OOM,
     50  Error
     51 };
     52 
     53 enum class JSONStringType { PropertyName, LiteralValue };
     54 
     55 template <typename CharT, typename ParserT>
     56 class MOZ_STACK_CLASS JSONTokenizer {
     57 public:
     58  using CharPtr = mozilla::RangedPtr<const CharT>;
     59 
     60  using JSONStringBuilder = typename ParserT::JSONStringBuilder;
     61 
     62 protected:
     63  CharPtr sourceStart;
     64  CharPtr current;
     65  const CharPtr begin, end;
     66 
     67  ParserT* parser = nullptr;
     68 
     69  JSONTokenizer(CharPtr sourceStart, CharPtr current, const CharPtr begin,
     70                const CharPtr end, ParserT* parser)
     71      : sourceStart(sourceStart),
     72        current(current),
     73        begin(begin),
     74        end(end),
     75        parser(parser) {
     76    MOZ_ASSERT(current <= end);
     77    MOZ_ASSERT(parser);
     78  }
     79 
     80 public:
     81  JSONTokenizer(CharPtr current, const CharPtr begin, const CharPtr end,
     82                ParserT* parser)
     83      : JSONTokenizer(current, current, begin, end, parser) {}
     84 
     85  explicit JSONTokenizer(mozilla::Range<const CharT> data, ParserT* parser)
     86      : JSONTokenizer(data.begin(), data.begin(), data.end(), parser) {}
     87 
     88  JSONTokenizer(JSONTokenizer<CharT, ParserT>&& other) noexcept
     89      : JSONTokenizer(other.sourceStart, other.current, other.begin, other.end,
     90                      other.parser) {}
     91 
     92  JSONTokenizer(const JSONTokenizer<CharT, ParserT>& other) = delete;
     93  void operator=(const JSONTokenizer<CharT, ParserT>& other) = delete;
     94 
     95  void fixupParser(ParserT* newParser) { parser = newParser; }
     96 
     97  void getTextPosition(uint32_t* column, uint32_t* line);
     98 
     99  bool consumeTrailingWhitespaces();
    100 
    101  JSONToken advance();
    102  JSONToken advancePropertyName();
    103  JSONToken advancePropertyColon();
    104  JSONToken advanceAfterProperty();
    105  JSONToken advanceAfterObjectOpen();
    106  JSONToken advanceAfterArrayElement();
    107 
    108  void unget() { --current; }
    109 
    110 #ifdef DEBUG
    111  bool finished() { return end == current; }
    112 #endif
    113 
    114  JSONToken token(JSONToken t) {
    115    MOZ_ASSERT(t != JSONToken::String);
    116    MOZ_ASSERT(t != JSONToken::Number);
    117    return t;
    118  }
    119 
    120  template <JSONStringType ST>
    121  JSONToken stringToken(const CharPtr start, size_t length);
    122  template <JSONStringType ST>
    123  JSONToken stringToken(JSONStringBuilder& builder);
    124 
    125  JSONToken numberToken(double d);
    126 
    127  template <JSONStringType ST>
    128  JSONToken readString();
    129 
    130  JSONToken readNumber();
    131 
    132  void error(const char* msg);
    133 
    134 protected:
    135  inline mozilla::Span<const CharT> getSource() const {
    136    return mozilla::Span<const CharT>(sourceStart.get(), current.get());
    137  }
    138 };
    139 
    140 // Possible states the parser can be in between values.
    141 enum class JSONParserState {
    142  // An array element has just being parsed.
    143  FinishArrayElement,
    144 
    145  // An object property has just been parsed.
    146  FinishObjectMember,
    147 
    148  // At the start of the parse, before any values have been processed.
    149  JSONValue
    150 };
    151 
    152 // Character-type-agnostic base class for JSONFullParseHandler.
    153 // JSONParser is templatized to work on either Latin1
    154 // or TwoByte input strings, JSONFullParseHandlerAnyChar holds all state and
    155 // methods that can be shared between the two encodings.
    156 class MOZ_STACK_CLASS JSONFullParseHandlerAnyChar {
    157 public:
    158  // State related to the parser's current position. At all points in the
    159  // parse this keeps track of the stack of arrays and objects which have
    160  // been started but not finished yet. The actual JS object is not
    161  // allocated until the literal is closed, so that the result can be sized
    162  // according to its contents and have its type and shape filled in using
    163  // caches.
    164 
    165  // State for an array that is currently being parsed. This includes all
    166  // elements that have been seen so far.
    167  using ElementVector = JS::GCVector<JS::Value, 20>;
    168 
    169  // State for an object that is currently being parsed. This includes all
    170  // the key/value pairs that have been seen so far.
    171  using PropertyVector = IdValueVector;
    172 
    173  enum class ParseType {
    174    // Parsing a string as if by JSON.parse.
    175    JSONParse,
    176    // Parsing what may or may not be JSON in a string of eval code.
    177    // In this case, a failure to parse indicates either syntax that isn't JSON,
    178    // or syntax that has different semantics in eval code than in JSON.
    179    AttemptForEval,
    180  };
    181 
    182  // Stack element for an in progress array or object.
    183  struct StackEntry {
    184    ElementVector& elements() {
    185      MOZ_ASSERT(state == JSONParserState::FinishArrayElement);
    186      return *static_cast<ElementVector*>(vector);
    187    }
    188 
    189    PropertyVector& properties() {
    190      MOZ_ASSERT(state == JSONParserState::FinishObjectMember);
    191      return *static_cast<PropertyVector*>(vector);
    192    }
    193 
    194    explicit StackEntry(JSContext* cx, ElementVector* elements)
    195        : state(JSONParserState::FinishArrayElement), vector(elements) {}
    196 
    197    explicit StackEntry(JSContext* cx, PropertyVector* properties)
    198        : state(JSONParserState::FinishObjectMember), vector(properties) {}
    199 
    200    JSONParserState state;
    201 
    202   private:
    203    void* vector;
    204  };
    205 
    206 public:
    207  /* Data members */
    208 
    209  JSContext* cx;
    210 
    211  bool reportLineNumbersFromParsedData = false;
    212 
    213  mozilla::Maybe<JS::ConstUTF8CharsZ> filename;
    214 
    215  JS::Value v;
    216 
    217  ParseType parseType = ParseType::JSONParse;
    218 
    219  AutoSelectGCHeap gcHeap;
    220 
    221 private:
    222  // Unused element and property vectors for previous in progress arrays and
    223  // objects. These vectors are not freed until the end of the parse to avoid
    224  // unnecessary freeing and allocation.
    225  Vector<ElementVector*, 5> freeElements;
    226  Vector<PropertyVector*, 5> freeProperties;
    227 
    228 public:
    229  explicit JSONFullParseHandlerAnyChar(JSContext* cx);
    230  ~JSONFullParseHandlerAnyChar();
    231 
    232  // Allow move construction for use with Rooted.
    233  JSONFullParseHandlerAnyChar(JSONFullParseHandlerAnyChar&& other) noexcept;
    234 
    235  JSONFullParseHandlerAnyChar(const JSONFullParseHandlerAnyChar& other) =
    236      delete;
    237  void operator=(const JSONFullParseHandlerAnyChar& other) = delete;
    238 
    239  JSContext* context() { return cx; }
    240 
    241  JS::Value numberValue() const {
    242    MOZ_ASSERT(v.isNumber());
    243    return v;
    244  }
    245 
    246  JS::Value stringValue() const {
    247    MOZ_ASSERT(v.isString());
    248    return v;
    249  }
    250 
    251  JSAtom* atomValue() const {
    252    JS::Value strval = stringValue();
    253    return &strval.toString()->asAtom();
    254  }
    255 
    256  inline JS::Value booleanValue(bool value) { return JS::BooleanValue(value); }
    257  inline JS::Value nullValue() { return JS::NullValue(); }
    258 
    259  inline bool objectOpen(Vector<StackEntry, 10>& stack,
    260                         PropertyVector** properties);
    261  inline bool objectPropertyName(Vector<StackEntry, 10>& stack,
    262                                 bool* isProtoInEval);
    263  inline bool finishObjectMember(Vector<StackEntry, 10>& stack,
    264                                 JS::Handle<JS::Value> value,
    265                                 PropertyVector** properties);
    266  inline bool finishObject(Vector<StackEntry, 10>& stack,
    267                           JS::MutableHandle<JS::Value> vp,
    268                           PropertyVector* properties);
    269 
    270  inline bool arrayOpen(Vector<StackEntry, 10>& stack,
    271                        ElementVector** elements);
    272  inline bool arrayElement(Vector<StackEntry, 10>& stack,
    273                           JS::Handle<JS::Value> value,
    274                           ElementVector** elements);
    275  inline bool finishArray(Vector<StackEntry, 10>& stack,
    276                          JS::MutableHandle<JS::Value> vp,
    277                          ElementVector* elements);
    278 
    279  inline bool errorReturn() const {
    280    return parseType == ParseType::AttemptForEval;
    281  }
    282 
    283  inline bool ignoreError() const {
    284    return parseType == ParseType::AttemptForEval;
    285  }
    286 
    287  inline void freeStackEntry(StackEntry& entry);
    288 
    289  void trace(JSTracer* trc);
    290 };
    291 
    292 template <typename CharT>
    293 class MOZ_STACK_CLASS JSONFullParseHandler
    294    : public JSONFullParseHandlerAnyChar {
    295  using Base = JSONFullParseHandlerAnyChar;
    296  using CharPtr = mozilla::RangedPtr<const CharT>;
    297 
    298 public:
    299  using ContextT = JSContext;
    300 
    301  class JSONStringBuilder {
    302   public:
    303    JSStringBuilder buffer;
    304 
    305    explicit JSONStringBuilder(JSContext* cx) : buffer(cx) {}
    306 
    307    bool append(char16_t c);
    308    bool append(const CharT* begin, const CharT* end);
    309  };
    310 
    311  explicit JSONFullParseHandler(JSContext* cx) : Base(cx) {}
    312 
    313  JSONFullParseHandler(JSONFullParseHandler&& other) noexcept
    314      : Base(std::move(other)) {}
    315 
    316  JSONFullParseHandler(const JSONFullParseHandler& other) = delete;
    317  void operator=(const JSONFullParseHandler& other) = delete;
    318 
    319  template <JSONStringType ST>
    320  inline bool setStringValue(CharPtr start, size_t length,
    321                             mozilla::Span<const CharT>&& source);
    322  template <JSONStringType ST>
    323  inline bool setStringValue(JSONStringBuilder& builder,
    324                             mozilla::Span<const CharT>&& source);
    325  inline bool setNumberValue(double d, mozilla::Span<const CharT>&& source);
    326  inline bool setBooleanValue(bool value, mozilla::Span<const CharT>&& source);
    327  inline bool setNullValue(mozilla::Span<const CharT>&& source);
    328 
    329  void reportError(const char* msg, uint32_t line, uint32_t column);
    330 };
    331 
    332 template <typename CharT>
    333 class MOZ_STACK_CLASS JSONReviveHandler : public JSONFullParseHandler<CharT> {
    334  using CharPtr = mozilla::RangedPtr<const CharT>;
    335  using Base = JSONFullParseHandler<CharT>;
    336 
    337 public:
    338  using SourceT = mozilla::Span<const CharT>;
    339 
    340  using JSONStringBuilder = typename Base::JSONStringBuilder;
    341  using StackEntry = typename Base::StackEntry;
    342  using PropertyVector = typename Base::PropertyVector;
    343  using ElementVector = typename Base::ElementVector;
    344 
    345 public:
    346  explicit JSONReviveHandler(JSContext* cx) : Base(cx), parseRecordStack(cx) {}
    347 
    348  JSONReviveHandler(JSONReviveHandler&& other) noexcept
    349      : Base(std::move(other)),
    350        parseRecordStack(std::move(other.parseRecordStack)) {}
    351 
    352  JSONReviveHandler(const JSONReviveHandler& other) = delete;
    353  void operator=(const JSONReviveHandler& other) = delete;
    354 
    355  JSContext* context() { return this->cx; }
    356 
    357  template <JSONStringType ST>
    358  inline bool setStringValue(CharPtr start, size_t length, SourceT&& source) {
    359    if (!Base::template setStringValue<ST>(start, length,
    360                                           std::forward<SourceT&&>(source))) {
    361      return false;
    362    }
    363    return finishPrimitiveParseRecord(this->v, source);
    364  }
    365 
    366  template <JSONStringType ST>
    367  inline bool setStringValue(JSONStringBuilder& builder, SourceT&& source) {
    368    if (!Base::template setStringValue<ST>(builder,
    369                                           std::forward<SourceT&&>(source))) {
    370      return false;
    371    }
    372    return finishPrimitiveParseRecord(this->v, source);
    373  }
    374 
    375  inline bool setNumberValue(double d, SourceT&& source) {
    376    if (!Base::setNumberValue(d, std::forward<SourceT&&>(source))) {
    377      return false;
    378    }
    379    return finishPrimitiveParseRecord(this->v, source);
    380  }
    381 
    382  inline bool setBooleanValue(bool value, SourceT&& source) {
    383    return finishPrimitiveParseRecord(JS::BooleanValue(value), source);
    384  }
    385  inline bool setNullValue(SourceT&& source) {
    386    return finishPrimitiveParseRecord(JS::NullValue(), source);
    387  }
    388 
    389  inline bool objectOpen(Vector<StackEntry, 10>& stack,
    390                         PropertyVector** properties);
    391  inline bool finishObjectMember(Vector<StackEntry, 10>& stack,
    392                                 JS::Handle<JS::Value> value,
    393                                 PropertyVector** properties);
    394  inline bool finishObject(Vector<StackEntry, 10>& stack,
    395                           JS::MutableHandle<JS::Value> vp,
    396                           PropertyVector* properties);
    397 
    398  inline bool arrayOpen(Vector<StackEntry, 10>& stack,
    399                        ElementVector** elements);
    400  inline bool arrayElement(Vector<StackEntry, 10>& stack,
    401                           JS::Handle<JS::Value> value,
    402                           ElementVector** elements);
    403  inline bool finishArray(Vector<StackEntry, 10>& stack,
    404                          JS::MutableHandle<JS::Value> vp,
    405                          ElementVector* elements);
    406 
    407  void trace(JSTracer* trc);
    408 
    409  inline ParseRecordObject* getParseRecordObject() {
    410    return parseRecordStack.back();
    411  };
    412 
    413 private:
    414  inline bool finishPrimitiveParseRecord(const Value& value, SourceT source);
    415 
    416  GCVector<ParseRecordObject*, 10> parseRecordStack;
    417 };
    418 
    419 template <typename CharT>
    420 class MOZ_STACK_CLASS JSONSyntaxParseHandler {
    421 private:
    422  using CharPtr = mozilla::RangedPtr<const CharT>;
    423 
    424 public:
    425  /* Types for templatized parser. */
    426 
    427  using ContextT = FrontendContext;
    428 
    429  class DummyValue {};
    430 
    431  struct ElementVector {};
    432  struct PropertyVector {};
    433 
    434  class JSONStringBuilder {
    435   public:
    436    explicit JSONStringBuilder(FrontendContext* fc) {}
    437 
    438    bool append(char16_t c) { return true; }
    439    bool append(const CharT* begin, const CharT* end) { return true; }
    440  };
    441 
    442  struct StackEntry {
    443    JSONParserState state;
    444  };
    445 
    446 public:
    447  FrontendContext* fc;
    448 
    449  /* Public API */
    450 
    451  /* Create a parser for the provided JSON data. */
    452  explicit JSONSyntaxParseHandler(FrontendContext* fc) : fc(fc) {}
    453 
    454  JSONSyntaxParseHandler(JSONSyntaxParseHandler&& other) noexcept
    455      : fc(other.fc) {}
    456 
    457  JSONSyntaxParseHandler(const JSONSyntaxParseHandler& other) = delete;
    458  void operator=(const JSONSyntaxParseHandler& other) = delete;
    459 
    460  FrontendContext* context() { return fc; }
    461 
    462  template <JSONStringType ST>
    463  inline bool setStringValue(CharPtr start, size_t length,
    464                             mozilla::Span<const CharT>&& source) {
    465    return true;
    466  }
    467 
    468  template <JSONStringType ST>
    469  inline bool setStringValue(JSONStringBuilder& builder,
    470                             mozilla::Span<const CharT>&& source) {
    471    return true;
    472  }
    473 
    474  inline bool setNumberValue(double d, mozilla::Span<const CharT>&& source) {
    475    return true;
    476  }
    477  inline bool setBooleanValue(bool value, mozilla::Span<const CharT>&& source) {
    478    return true;
    479  }
    480  inline bool setNullValue(mozilla::Span<const CharT>&& source) { return true; }
    481 
    482  inline DummyValue numberValue() const { return DummyValue(); }
    483 
    484  inline DummyValue stringValue() const { return DummyValue(); }
    485 
    486  inline DummyValue booleanValue(bool value) { return DummyValue(); }
    487  inline DummyValue nullValue() { return DummyValue(); }
    488 
    489  inline bool objectOpen(Vector<StackEntry, 10>& stack,
    490                         PropertyVector** properties);
    491  inline bool objectPropertyName(Vector<StackEntry, 10>& stack,
    492                                 bool* isProtoInEval) {
    493    *isProtoInEval = false;
    494    return true;
    495  }
    496  inline bool finishObjectMember(Vector<StackEntry, 10>& stack,
    497                                 DummyValue& value,
    498                                 PropertyVector** properties) {
    499    return true;
    500  }
    501  inline bool finishObject(Vector<StackEntry, 10>& stack, DummyValue* vp,
    502                           PropertyVector* properties);
    503 
    504  inline bool arrayOpen(Vector<StackEntry, 10>& stack,
    505                        ElementVector** elements);
    506  inline bool arrayElement(Vector<StackEntry, 10>& stack, DummyValue& value,
    507                           ElementVector** elements) {
    508    return true;
    509  }
    510  inline bool finishArray(Vector<StackEntry, 10>& stack, DummyValue* vp,
    511                          ElementVector* elements);
    512 
    513  inline bool errorReturn() const { return false; }
    514 
    515  inline bool ignoreError() const { return false; }
    516 
    517  inline void freeStackEntry(StackEntry& entry) {}
    518 
    519  void reportError(const char* msg, uint32_t line, uint32_t column);
    520 };
    521 
    522 template <typename CharT, typename HandlerT>
    523 class MOZ_STACK_CLASS JSONPerHandlerParser {
    524  using ContextT = typename HandlerT::ContextT;
    525 
    526  using Tokenizer = JSONTokenizer<CharT, JSONPerHandlerParser<CharT, HandlerT>>;
    527 
    528 public:
    529  using JSONStringBuilder = typename HandlerT::JSONStringBuilder;
    530 
    531 public:
    532  HandlerT handler;
    533  Tokenizer tokenizer;
    534 
    535  // All in progress arrays and objects being parsed, in order from outermost
    536  // to innermost.
    537  Vector<typename HandlerT::StackEntry, 10> stack;
    538 
    539 public:
    540  JSONPerHandlerParser(ContextT* context, mozilla::Range<const CharT> data)
    541      : handler(context), tokenizer(data, this), stack(context) {}
    542 
    543  JSONPerHandlerParser(JSONPerHandlerParser&& other) noexcept
    544      : handler(std::move(other.handler)),
    545        tokenizer(std::move(other.tokenizer)),
    546        stack(handler.context()) {
    547    tokenizer.fixupParser(this);
    548  }
    549 
    550  ~JSONPerHandlerParser();
    551 
    552  JSONPerHandlerParser(const JSONPerHandlerParser<CharT, HandlerT>& other) =
    553      delete;
    554  void operator=(const JSONPerHandlerParser<CharT, HandlerT>& other) = delete;
    555 
    556  template <typename TempValueT, typename ResultSetter>
    557  inline bool parseImpl(TempValueT& value, ResultSetter setResult);
    558 
    559  void outOfMemory();
    560 
    561  void error(const char* msg);
    562 };
    563 
    564 template <typename CharT>
    565 class MOZ_STACK_CLASS JSONParser
    566    : JSONPerHandlerParser<CharT, JSONFullParseHandler<CharT>> {
    567  using Base = JSONPerHandlerParser<CharT, JSONFullParseHandler<CharT>>;
    568 
    569 public:
    570  using ParseType = JSONFullParseHandlerAnyChar::ParseType;
    571 
    572  /* Public API */
    573 
    574  /* Create a parser for the provided JSON data. */
    575  JSONParser(JSContext* cx, mozilla::Range<const CharT> data,
    576             ParseType parseType)
    577      : Base(cx, data) {
    578    this->handler.parseType = parseType;
    579  }
    580 
    581  /* Allow move construction for use with Rooted. */
    582  JSONParser(JSONParser&& other) noexcept : Base(std::move(other)) {}
    583 
    584  JSONParser(const JSONParser& other) = delete;
    585  void operator=(const JSONParser& other) = delete;
    586 
    587  /*
    588   * Parse the JSON data specified at construction time.  If it parses
    589   * successfully, store the prescribed value in *vp and return true.  If an
    590   * internal error (e.g. OOM) occurs during parsing, return false.
    591   * Otherwise, if invalid input was specifed but no internal error occurred,
    592   * behavior depends upon the error handling specified at construction: if
    593   * error handling is RaiseError then throw a SyntaxError and return false,
    594   * otherwise return true and set *vp to |undefined|.  (JSON syntax can't
    595   * represent |undefined|, so the JSON data couldn't have specified it.)
    596   */
    597  bool parse(JS::MutableHandle<JS::Value> vp);
    598 
    599  void reportLineNumbersFromParsedData(bool b) {
    600    this->handler.reportLineNumbersFromParsedData = b;
    601  }
    602 
    603  /**
    604   * Set a filename to be used in error messages.
    605   * This is optional and only used for error reporting.
    606   */
    607  void setFilename(JS::ConstUTF8CharsZ filename) {
    608    this->handler.filename = mozilla::Some(filename);
    609  }
    610 
    611  void trace(JSTracer* trc);
    612 };
    613 
    614 template <typename CharT>
    615 class MOZ_STACK_CLASS JSONReviveParser
    616    : JSONPerHandlerParser<CharT, JSONReviveHandler<CharT>> {
    617  using Base = JSONPerHandlerParser<CharT, JSONReviveHandler<CharT>>;
    618 
    619 public:
    620  using ParseType = JSONFullParseHandlerAnyChar::ParseType;
    621 
    622  /* Public API */
    623 
    624  /* Create a parser for the provided JSON data. */
    625  JSONReviveParser(JSContext* cx, mozilla::Range<const CharT> data)
    626      : Base(cx, data) {}
    627 
    628  /* Allow move construction for use with Rooted. */
    629  JSONReviveParser(JSONReviveParser&& other) noexcept
    630      : Base(std::move(other)) {}
    631 
    632  JSONReviveParser(const JSONReviveParser& other) = delete;
    633  void operator=(const JSONReviveParser& other) = delete;
    634 
    635  /*
    636   * Parse the JSON data specified at construction time.  If it parses
    637   * successfully, store the prescribed value in *vp and return true.  If an
    638   * internal error (e.g. OOM) occurs during parsing, return false.
    639   * Otherwise, if invalid input was specifed but no internal error occurred,
    640   * behavior depends upon the error handling specified at construction: if
    641   * error handling is RaiseError then throw a SyntaxError and return false,
    642   * otherwise return true and set *vp to |undefined|.  (JSON syntax can't
    643   * represent |undefined|, so the JSON data couldn't have specified it.)
    644   *
    645   * If it parses successfully, parse information for calling the reviver
    646   * function is stored in *pro. If this function returns false, *pro will be
    647   * set to |undefined|.
    648   */
    649  bool parse(JS::MutableHandle<JS::Value> vp,
    650             JS::MutableHandle<ParseRecordObject*> pro);
    651 
    652  void trace(JSTracer* trc);
    653 };
    654 
    655 template <typename CharT, typename Wrapper>
    656 class MutableWrappedPtrOperations<JSONParser<CharT>, Wrapper>
    657    : public WrappedPtrOperations<JSONParser<CharT>, Wrapper> {
    658 public:
    659  bool parse(JS::MutableHandle<JS::Value> vp) {
    660    return static_cast<Wrapper*>(this)->get().parse(vp);
    661  }
    662  void setFilename(JS::ConstUTF8CharsZ filename) {
    663    static_cast<Wrapper*>(this)->get().setFilename(filename);
    664  }
    665  void reportLineNumbersFromParsedData(bool b) {
    666    static_cast<Wrapper*>(this)->get().reportLineNumbersFromParsedData(b);
    667  }
    668 };
    669 
    670 template <typename CharT>
    671 class MOZ_STACK_CLASS JSONSyntaxParser
    672    : JSONPerHandlerParser<CharT, JSONSyntaxParseHandler<CharT>> {
    673  using HandlerT = JSONSyntaxParseHandler<CharT>;
    674  using Base = JSONPerHandlerParser<CharT, HandlerT>;
    675 
    676 public:
    677  JSONSyntaxParser(FrontendContext* fc, mozilla::Range<const CharT> data)
    678      : Base(fc, data) {}
    679 
    680  JSONSyntaxParser(JSONSyntaxParser<CharT>&& other) noexcept
    681      : Base(std::move(other)) {}
    682 
    683  JSONSyntaxParser(const JSONSyntaxParser& other) = delete;
    684  void operator=(const JSONSyntaxParser& other) = delete;
    685 
    686  bool parse();
    687 };
    688 
    689 } /* namespace js */
    690 
    691 #endif /* vm_JSONParser_h */