diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 14:29:10 +0000 |
commit | 2aa4a82499d4becd2284cdb482213d541b8804dd (patch) | |
tree | b80bf8bf13c3766139fbacc530efd0dd9d54394c /js/src/vm/JSONParser.h | |
parent | Initial commit. (diff) | |
download | firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.tar.xz firefox-2aa4a82499d4becd2284cdb482213d541b8804dd.zip |
Adding upstream version 86.0.1.upstream/86.0.1upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r-- | js/src/vm/JSONParser.h | 284 |
1 files changed, 284 insertions, 0 deletions
diff --git a/js/src/vm/JSONParser.h b/js/src/vm/JSONParser.h new file mode 100644 index 0000000000..a88980b382 --- /dev/null +++ b/js/src/vm/JSONParser.h @@ -0,0 +1,284 @@ +/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim: set ts=8 sts=2 et sw=2 tw=80: + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef vm_JSONParser_h +#define vm_JSONParser_h + +#include "mozilla/Attributes.h" +#include "mozilla/Range.h" + +#include "jspubtd.h" + +#include "ds/IdValuePair.h" +#include "vm/StringType.h" + +namespace js { + +// JSONParser base class. JSONParser is templatized to work on either Latin1 +// or TwoByte input strings, JSONParserBase holds all state and methods that +// can be shared between the two encodings. +class MOZ_STACK_CLASS JSONParserBase { + public: + enum class ParseType { + // Parsing a string as if by JSON.parse. + JSONParse, + // Parsing what may or may not be JSON in a string of eval code. + // In this case, a failure to parse indicates either syntax that isn't JSON, + // or syntax that has different semantics in eval code than in JSON. + AttemptForEval, + }; + + private: + /* Data members */ + Value v; + + protected: + JSContext* const cx; + + const ParseType parseType; + + enum Token { + String, + Number, + True, + False, + Null, + ArrayOpen, + ArrayClose, + ObjectOpen, + ObjectClose, + Colon, + Comma, + OOM, + Error + }; + + // State related to the parser's current position. At all points in the + // parse this keeps track of the stack of arrays and objects which have + // been started but not finished yet. The actual JS object is not + // allocated until the literal is closed, so that the result can be sized + // according to its contents and have its type and shape filled in using + // caches. + + // State for an array that is currently being parsed. This includes all + // elements that have been seen so far. + typedef GCVector<Value, 20> ElementVector; + + // State for an object that is currently being parsed. This includes all + // the key/value pairs that have been seen so far. + typedef GCVector<IdValuePair, 10> PropertyVector; + + // Possible states the parser can be in between values. + enum ParserState { + // An array element has just being parsed. + FinishArrayElement, + + // An object property has just been parsed. + FinishObjectMember, + + // At the start of the parse, before any values have been processed. + JSONValue + }; + + // Stack element for an in progress array or object. + struct StackEntry { + ElementVector& elements() { + MOZ_ASSERT(state == FinishArrayElement); + return *static_cast<ElementVector*>(vector); + } + + PropertyVector& properties() { + MOZ_ASSERT(state == FinishObjectMember); + return *static_cast<PropertyVector*>(vector); + } + + explicit StackEntry(ElementVector* elements) + : state(FinishArrayElement), vector(elements) {} + + explicit StackEntry(PropertyVector* properties) + : state(FinishObjectMember), vector(properties) {} + + ParserState state; + + private: + void* vector; + }; + + // All in progress arrays and objects being parsed, in order from outermost + // to innermost. + Vector<StackEntry, 10> stack; + + // Unused element and property vectors for previous in progress arrays and + // objects. These vectors are not freed until the end of the parse to avoid + // unnecessary freeing and allocation. + Vector<ElementVector*, 5> freeElements; + Vector<PropertyVector*, 5> freeProperties; + +#ifdef DEBUG + Token lastToken; +#endif + + JSONParserBase(JSContext* cx, ParseType parseType) + : cx(cx), + parseType(parseType), + stack(cx), + freeElements(cx), + freeProperties(cx) +#ifdef DEBUG + , + lastToken(Error) +#endif + { + } + ~JSONParserBase(); + + // Allow move construction for use with Rooted. + JSONParserBase(JSONParserBase&& other) + : v(other.v), + cx(other.cx), + parseType(other.parseType), + stack(std::move(other.stack)), + freeElements(std::move(other.freeElements)), + freeProperties(std::move(other.freeProperties)) +#ifdef DEBUG + , + lastToken(std::move(other.lastToken)) +#endif + { + } + + Value numberValue() const { + MOZ_ASSERT(lastToken == Number); + MOZ_ASSERT(v.isNumber()); + return v; + } + + Value stringValue() const { + MOZ_ASSERT(lastToken == String); + MOZ_ASSERT(v.isString()); + return v; + } + + JSAtom* atomValue() const { + Value strval = stringValue(); + return &strval.toString()->asAtom(); + } + + Token token(Token t) { + MOZ_ASSERT(t != String); + MOZ_ASSERT(t != Number); +#ifdef DEBUG + lastToken = t; +#endif + return t; + } + + Token stringToken(JSString* str) { + this->v = StringValue(str); +#ifdef DEBUG + lastToken = String; +#endif + return String; + } + + Token numberToken(double d) { + this->v = NumberValue(d); +#ifdef DEBUG + lastToken = Number; +#endif + return Number; + } + + enum StringType { PropertyName, LiteralValue }; + + bool errorReturn(); + + bool finishObject(MutableHandleValue vp, PropertyVector& properties); + bool finishArray(MutableHandleValue vp, ElementVector& elements); + + void trace(JSTracer* trc); + + private: + JSONParserBase(const JSONParserBase& other) = delete; + void operator=(const JSONParserBase& other) = delete; +}; + +template <typename CharT> +class MOZ_STACK_CLASS JSONParser : public JSONParserBase { + private: + using CharPtr = mozilla::RangedPtr<const CharT>; + + CharPtr current; + const CharPtr begin, end; + + public: + /* Public API */ + + /* Create a parser for the provided JSON data. */ + JSONParser(JSContext* cx, mozilla::Range<const CharT> data, + ParseType parseType) + : JSONParserBase(cx, parseType), + current(data.begin()), + begin(current), + end(data.end()) { + MOZ_ASSERT(current <= end); + } + + /* Allow move construction for use with Rooted. */ + JSONParser(JSONParser&& other) + : JSONParserBase(std::move(other)), + current(other.current), + begin(other.begin), + end(other.end) {} + + /* + * Parse the JSON data specified at construction time. If it parses + * successfully, store the prescribed value in *vp and return true. If an + * internal error (e.g. OOM) occurs during parsing, return false. + * Otherwise, if invalid input was specifed but no internal error occurred, + * behavior depends upon the error handling specified at construction: if + * error handling is RaiseError then throw a SyntaxError and return false, + * otherwise return true and set *vp to |undefined|. (JSON syntax can't + * represent |undefined|, so the JSON data couldn't have specified it.) + */ + bool parse(MutableHandleValue vp); + + void trace(JSTracer* trc) { JSONParserBase::trace(trc); } + + private: + template <StringType ST> + Token readString(); + + Token readNumber(); + + Token advance(); + Token advancePropertyName(); + Token advancePropertyColon(); + Token advanceAfterProperty(); + Token advanceAfterObjectOpen(); + Token advanceAfterArrayElement(); + + void error(const char* msg); + + void getTextPosition(uint32_t* column, uint32_t* line); + + private: + JSONParser(const JSONParser& other) = delete; + void operator=(const JSONParser& other) = delete; +}; + +template <typename CharT, typename Wrapper> +class MutableWrappedPtrOperations<JSONParser<CharT>, Wrapper> + : public WrappedPtrOperations<JSONParser<CharT>, Wrapper> { + public: + bool parse(MutableHandleValue vp) { + return static_cast<Wrapper*>(this)->get().parse(vp); + } +}; + +} /* namespace js */ + +#endif /* vm_JSONParser_h */ |