js/src/jsonparser.h

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

     1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
     2  * vim: set ts=8 sts=4 et sw=4 tw=99:
     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/. */
     7 #ifndef jsonparser_h
     8 #define jsonparser_h
    10 #include "mozilla/Attributes.h"
    12 #include "ds/IdValuePair.h"
    13 #include "vm/String.h"
    15 namespace js {
    17 class MOZ_STACK_CLASS JSONParser : private AutoGCRooter
    18 {
    19   public:
    20     enum ErrorHandling { RaiseError, NoError };
    22   private:
    23     /* Data members */
    25     JSContext * const cx;
    26     JS::ConstTwoByteChars current;
    27     const JS::ConstTwoByteChars begin, end;
    29     Value v;
    31     const ErrorHandling errorHandling;
    33     enum Token { String, Number, True, False, Null,
    34                  ArrayOpen, ArrayClose,
    35                  ObjectOpen, ObjectClose,
    36                  Colon, Comma,
    37                  OOM, Error };
    39     // State related to the parser's current position. At all points in the
    40     // parse this keeps track of the stack of arrays and objects which have
    41     // been started but not finished yet. The actual JS object is not
    42     // allocated until the literal is closed, so that the result can be sized
    43     // according to its contents and have its type and shape filled in using
    44     // caches.
    46     // State for an array that is currently being parsed. This includes all
    47     // elements that have been seen so far.
    48     typedef Vector<Value, 20> ElementVector;
    50     // State for an object that is currently being parsed. This includes all
    51     // the key/value pairs that have been seen so far.
    52     typedef Vector<IdValuePair, 10> PropertyVector;
    54     // Possible states the parser can be in between values.
    55     enum ParserState {
    56         // An array element has just being parsed.
    57         FinishArrayElement,
    59         // An object property has just been parsed.
    60         FinishObjectMember,
    62         // At the start of the parse, before any values have been processed.
    63         JSONValue
    64     };
    66     // Stack element for an in progress array or object.
    67     struct StackEntry {
    68         ElementVector &elements() {
    69             JS_ASSERT(state == FinishArrayElement);
    70             return * static_cast<ElementVector *>(vector);
    71         }
    73         PropertyVector &properties() {
    74             JS_ASSERT(state == FinishObjectMember);
    75             return * static_cast<PropertyVector *>(vector);
    76         }
    78         StackEntry(ElementVector *elements)
    79           : state(FinishArrayElement), vector(elements)
    80         {}
    82         StackEntry(PropertyVector *properties)
    83           : state(FinishObjectMember), vector(properties)
    84         {}
    86         ParserState state;
    88       private:
    89         void *vector;
    90     };
    92     // All in progress arrays and objects being parsed, in order from outermost
    93     // to innermost.
    94     Vector<StackEntry, 10> stack;
    96     // Unused element and property vectors for previous in progress arrays and
    97     // objects. These vectors are not freed until the end of the parse to avoid
    98     // unnecessary freeing and allocation.
    99     Vector<ElementVector*, 5> freeElements;
   100     Vector<PropertyVector*, 5> freeProperties;
   102 #ifdef DEBUG
   103     Token lastToken;
   104 #endif
   106   public:
   107     /* Public API */
   109     /* Create a parser for the provided JSON data. */
   110     JSONParser(JSContext *cx, JS::ConstTwoByteChars data, size_t length,
   111                ErrorHandling errorHandling = RaiseError)
   112       : AutoGCRooter(cx, JSONPARSER),
   113         cx(cx),
   114         current(data),
   115         begin(data),
   116         end((data + length).get(), data.get(), length),
   117         errorHandling(errorHandling),
   118         stack(cx),
   119         freeElements(cx),
   120         freeProperties(cx)
   121 #ifdef DEBUG
   122       , lastToken(Error)
   123 #endif
   124     {
   125         JS_ASSERT(current <= end);
   126     }
   128     ~JSONParser();
   130     /*
   131      * Parse the JSON data specified at construction time.  If it parses
   132      * successfully, store the prescribed value in *vp and return true.  If an
   133      * internal error (e.g. OOM) occurs during parsing, return false.
   134      * Otherwise, if invalid input was specifed but no internal error occurred,
   135      * behavior depends upon the error handling specified at construction: if
   136      * error handling is RaiseError then throw a SyntaxError and return false,
   137      * otherwise return true and set *vp to |undefined|.  (JSON syntax can't
   138      * represent |undefined|, so the JSON data couldn't have specified it.)
   139      */
   140     bool parse(MutableHandleValue vp);
   142   private:
   143     Value numberValue() const {
   144         JS_ASSERT(lastToken == Number);
   145         JS_ASSERT(v.isNumber());
   146         return v;
   147     }
   149     Value stringValue() const {
   150         JS_ASSERT(lastToken == String);
   151         JS_ASSERT(v.isString());
   152         return v;
   153     }
   155     JSAtom *atomValue() const {
   156         Value strval = stringValue();
   157         return &strval.toString()->asAtom();
   158     }
   160     Token token(Token t) {
   161         JS_ASSERT(t != String);
   162         JS_ASSERT(t != Number);
   163 #ifdef DEBUG
   164         lastToken = t;
   165 #endif
   166         return t;
   167     }
   169     Token stringToken(JSString *str) {
   170         this->v = StringValue(str);
   171 #ifdef DEBUG
   172         lastToken = String;
   173 #endif
   174         return String;
   175     }
   177     Token numberToken(double d) {
   178         this->v = NumberValue(d);
   179 #ifdef DEBUG
   180         lastToken = Number;
   181 #endif
   182         return Number;
   183     }
   185     enum StringType { PropertyName, LiteralValue };
   186     template<StringType ST> Token readString();
   188     Token readNumber();
   190     Token advance();
   191     Token advancePropertyName();
   192     Token advancePropertyColon();
   193     Token advanceAfterProperty();
   194     Token advanceAfterObjectOpen();
   195     Token advanceAfterArrayElement();
   197     void error(const char *msg);
   198     bool errorReturn();
   200     JSObject *createFinishedObject(PropertyVector &properties);
   201     bool finishObject(MutableHandleValue vp, PropertyVector &properties);
   202     bool finishArray(MutableHandleValue vp, ElementVector &elements);
   204     void getTextPosition(uint32_t *column, uint32_t *line);
   206     friend void AutoGCRooter::trace(JSTracer *trc);
   207     void trace(JSTracer *trc);
   209   private:
   210     JSONParser(const JSONParser &other) MOZ_DELETE;
   211     void operator=(const JSONParser &other) MOZ_DELETE;
   212 };
   214 } /* namespace js */
   216 #endif /* jsonparser_h */

mercurial