Coverage Report

Created: 2025-08-28 06:48

/src/hermes/include/hermes/Parser/JSONParser.h
Line
Count
Source (jump to first uncovered line)
1
/*
2
 * Copyright (c) Meta Platforms, Inc. and affiliates.
3
 *
4
 * This source code is licensed under the MIT license found in the
5
 * LICENSE file in the root directory of this source tree.
6
 */
7
8
#ifndef HERMES_PARSER_JSONPARSER_H
9
#define HERMES_PARSER_JSONPARSER_H
10
11
#include <algorithm>
12
#include <cstddef>
13
#include <functional>
14
#include <iterator>
15
#include <map>
16
#include <memory>
17
#include <utility>
18
19
#include "hermes/Parser/JSLexer.h"
20
#include "hermes/Parser/pack.h"
21
#include "hermes/Support/Conversions.h"
22
#include "hermes/Support/JSONEmitter.h"
23
24
#include "llvh/ADT/DenseMap.h"
25
#include "llvh/ADT/FoldingSet.h"
26
#include "llvh/ADT/Optional.h"
27
#include "llvh/ADT/StringRef.h"
28
#include "llvh/Support/Casting.h"
29
30
namespace hermes {
31
namespace parser {
32
33
class JSONFactory;
34
class JSONParser;
35
36
enum class JSONKind {
37
  Object,
38
  Array,
39
  String,
40
  Number,
41
  Boolean,
42
  Null,
43
};
44
45
/// Converts JSONKind to a char*.
46
const char *JSONKindToString(JSONKind kind);
47
48
/// The base type for all values that can be represented in JSON.
49
class JSONValue {
50
  JSONKind const kind_;
51
52
  JSONValue(const JSONValue &) = delete;
53
  JSONValue &operator=(const JSONValue &) = delete;
54
55
 public:
56
0
  explicit constexpr JSONValue(JSONKind kind) : kind_(kind){};
57
58
0
  JSONKind getKind() const {
59
0
    return kind_;
60
0
  }
61
62
  /// Writes this JSON value into \p emitter.
63
  void emitInto(JSONEmitter &emitter) const;
64
};
65
66
/// The base type for all values except arrays and objects.
67
class JSONScalar : public JSONValue {
68
 public:
69
0
  explicit constexpr JSONScalar(JSONKind kind) : JSONValue(kind) {}
70
71
0
  static bool classof(const JSONValue *v) {
72
0
    return v->getKind() >= JSONKind::String;
73
0
  }
74
};
75
76
class JSONNull : public JSONScalar {
77
0
  constexpr JSONNull() : JSONScalar(JSONKind::Null){};
78
79
  static JSONNull instance_;
80
81
 public:
82
0
  static JSONNull *getInstance() {
83
0
    return &instance_;
84
0
  }
85
86
0
  static bool classof(const JSONValue *v) {
87
0
    return v->getKind() == JSONKind::Null;
88
0
  }
89
};
90
91
class JSONBoolean : public JSONScalar {
92
  bool const value_;
93
94
  explicit constexpr JSONBoolean(bool value)
95
0
      : JSONScalar(JSONKind::Boolean), value_(value){};
96
97
  static JSONBoolean true_;
98
  static JSONBoolean false_;
99
100
 public:
101
0
  static JSONBoolean *getInstance(bool v) {
102
0
    return v ? &true_ : &false_;
103
0
  };
104
105
0
  bool getValue() const {
106
0
    return value_;
107
0
  }
108
0
  explicit operator bool() const {
109
0
    return getValue();
110
0
  }
111
112
0
  static bool classof(const JSONValue *v) {
113
0
    return v->getKind() == JSONKind::Boolean;
114
0
  }
115
};
116
117
class JSONString : public JSONScalar, public llvh::FoldingSetNode {
118
  UniqueString *const value_;
119
120
 public:
121
  explicit JSONString(UniqueString *value)
122
0
      : JSONScalar(JSONKind::String), value_(value) {}
123
124
0
  UniqueString *stringBase() const {
125
0
    return value_;
126
0
  }
127
128
0
  const llvh::StringRef &str() const {
129
0
    return value_->str();
130
0
  }
131
0
  explicit operator llvh::StringRef() const {
132
0
    return value_->str();
133
0
  }
134
0
  const char *c_str() const {
135
0
    return value_->c_str();
136
0
  }
137
138
0
  static void Profile(llvh::FoldingSetNodeID &id, UniqueString *str) {
139
0
    id.AddPointer(str);
140
0
  }
141
142
0
  void Profile(llvh::FoldingSetNodeID &id) {
143
0
    JSONString::Profile(id, value_);
144
0
  }
145
146
0
  static bool classof(const JSONValue *v) {
147
0
    return v->getKind() == JSONKind::String;
148
0
  }
149
};
150
151
class JSONNumber : public JSONScalar, public llvh::FoldingSetNode {
152
  double const value_;
153
154
 public:
155
  explicit JSONNumber(double value)
156
0
      : JSONScalar(JSONKind::Number), value_(value) {}
157
158
0
  double getValue() const {
159
0
    return value_;
160
0
  }
161
0
  explicit operator double() const {
162
0
    return getValue();
163
0
  }
164
165
0
  static void Profile(llvh::FoldingSetNodeID &id, double value) {
166
0
    id.AddInteger(llvh::DoubleToBits(value));
167
0
  }
168
169
0
  void Profile(llvh::FoldingSetNodeID &id) {
170
0
    JSONNumber::Profile(id, value_);
171
0
  }
172
173
0
  static bool classof(const JSONValue *v) {
174
0
    return v->getKind() == JSONKind::Number;
175
0
  }
176
};
177
178
/// A descriptor containing a sorted list of names. A JSON object contains
179
/// an array of values and a pointer to this descriptor.
180
class JSONHiddenClass {
181
  size_t size_;
182
  JSONString *keys_[];
183
184
  struct NameComparator {
185
0
    bool operator()(llvh::StringRef a, JSONString *b) const {
186
0
      return a < b->str();
187
0
    }
188
0
    bool operator()(JSONString *a, llvh::StringRef b) const {
189
0
      return a->str() < b;
190
0
    }
191
  };
192
193
  JSONHiddenClass(const JSONHiddenClass &) = delete;
194
  JSONHiddenClass &operator=(const JSONHiddenClass &) = delete;
195
196
  template <typename FwIt>
197
0
  JSONHiddenClass(size_t size, FwIt b, FwIt e) : size_(size) {
198
0
    std::copy(b, e, keys_);
199
0
  }
200
201
  // Allocator
202
  //
203
  template <class Allocator>
204
0
  static void *operator new(size_t size, Allocator &alloc, size_t count) {
205
0
    return alloc.Allocate(
206
0
        offsetof(JSONHiddenClass, keys_) + sizeof(keys_[0]) * count,
207
0
        alignof(JSONHiddenClass));
208
0
  }
209
210
  friend class JSONFactory;
211
212
 public:
213
  using iterator = hermes::parser::JSONString *const *;
214
215
0
  size_t size() const {
216
0
    return size_;
217
0
  }
218
0
  iterator begin() const {
219
0
    return keys_;
220
0
  }
221
0
  iterator end() const {
222
0
    return keys_ + size_;
223
0
  }
224
225
0
  llvh::Optional<size_t> find(llvh::StringRef name) {
226
0
    auto e = end();
227
0
    auto it = std::lower_bound(begin(), e, name, NameComparator{});
228
0
    if (it != e && (*it)->str() == name)
229
0
      return it - begin();
230
0
    else
231
0
      return llvh::None;
232
0
  }
233
};
234
235
/// A JSON object, which is a map from a string name to a JSONValue* value.
236
/// The names are stored in a separate JSONHiddenClass object. Multiple
237
/// instances of JSONObject which happen to have the same keys share one
238
/// JSONHiddenClass.
239
class JSONObject : public JSONValue {
240
  JSONHiddenClass *const hiddenClass_;
241
242
0
  inline JSONValue **values() {
243
0
    return Pack<JSONObject, JSONValue *>::values(this);
244
0
  }
245
246
0
  inline JSONValue *const *values() const {
247
0
    return Pack<JSONObject, JSONValue *>::values(this);
248
0
  }
249
250
  /// Initialize the object with a sequence of values, one value per member of
251
  /// the
252
  /// hidden class.
253
  template <typename FwId>
254
  JSONObject(JSONHiddenClass *hiddenClass, FwId b, FwId e)
255
0
      : JSONValue(JSONKind::Object), hiddenClass_(hiddenClass) {
256
0
    JSONValue *const *oe = std::copy(b, e, values());
257
0
    assert(oe - values() == (ptrdiff_t)hiddenClass_->size());
258
0
    (void)oe;
259
0
  }
260
261
  /// Initialize all members of the object with the same value.
262
  JSONObject(JSONHiddenClass *hiddenClass, JSONValue *fillValue)
263
0
      : JSONValue(JSONKind::Object), hiddenClass_(hiddenClass) {
264
0
    JSONValue **v = values();
265
0
    std::fill(v, v + hiddenClass->size(), fillValue);
266
0
  }
267
268
  // Allocator
269
270
  template <class Allocator>
271
0
  void *operator new(size_t size, Allocator &alloc, size_t count) {
272
0
    return Pack<JSONObject, JSONValue *>::allocate(alloc, count);
273
0
  }
274
275
  friend class JSONFactory;
276
277
 public:
278
0
  JSONHiddenClass *getHiddenClass() const {
279
0
    return hiddenClass_;
280
0
  }
281
0
  size_t size() const {
282
0
    return hiddenClass_->size();
283
0
  }
284
285
  /// Obtain a value, or return nullptr if not found.
286
0
  JSONValue *get(llvh::StringRef name) const {
287
0
    if (auto res = hiddenClass_->find(name))
288
0
      return values()[res.getValue()];
289
0
    else
290
0
      return nullptr;
291
0
  }
292
293
  /// Obtain a value. If the value is not found, debug builds assert; in release
294
  /// builds the behavior is undefined.
295
0
  JSONValue *at(llvh::StringRef name) const {
296
0
    if (auto res = hiddenClass_->find(name))
297
0
      return values()[res.getValue()];
298
0
299
0
    assert(false && "name not found");
300
0
    return nullptr;
301
0
  }
302
303
  /// Obtain a value by name, Behavior is undefined if the name is not found.
304
0
  JSONValue *operator[](llvh::StringRef name) const {
305
0
    return values()[hiddenClass_->find(name).getValue()];
306
0
  }
307
  /// Obtain a value by name, Behavior is undefined if the name is not found.
308
0
  JSONValue *&operator[](llvh::StringRef name) {
309
0
    return values()[hiddenClass_->find(name).getValue()];
310
0
  }
311
  /// Obtain a value by index.
312
0
  JSONValue *operator[](size_t index) const {
313
0
    assert(index < size());
314
0
    return values()[index];
315
0
  }
316
  /// Obtain a value by index.
317
0
  JSONValue *&operator[](size_t index) {
318
0
    assert(index < size());
319
0
    return values()[index];
320
0
  }
321
322
  /// Check for the presence of a key.
323
0
  size_t count(llvh::StringRef name) const {
324
0
    return hiddenClass_->find(name) ? 1 : 0;
325
0
  }
326
327
  /// Iterator creating the impression that we are storing key/value pairs.
328
  /// The illusion is not complete as "it->first" doesn't work, but it is better
329
  /// than nothing.
330
  class iterator {
331
    JSONObject *obj_;
332
    size_t index_;
333
334
0
    iterator(JSONObject *obj, size_t index) : obj_(obj), index_(index) {}
335
    friend class JSONObject;
336
    friend class const_iterator;
337
338
   public:
339
    using iterator_category = std::bidirectional_iterator_tag;
340
    using value_type = std::pair<JSONString *, JSONValue *&>;
341
    using difference_type = std::ptrdiff_t;
342
    using pointer = value_type *;
343
    using reference = value_type &;
344
345
    iterator(const iterator &) = default;
346
    iterator &operator=(const iterator &) = default;
347
348
0
    value_type operator*() const {
349
0
      return value_type{obj_->hiddenClass_->begin()[index_], (*obj_)[index_]};
350
0
    }
351
352
0
    iterator &operator++() {
353
0
      ++index_;
354
0
      return *this;
355
0
    }
356
357
0
    iterator &operator--() {
358
0
      --index_;
359
0
      return *this;
360
0
    }
361
362
0
    difference_type operator-(const iterator &x) const {
363
0
      assert(obj_ == x.obj_);
364
0
      return (difference_type)(index_ - x.index_);
365
0
    }
366
367
0
    bool operator==(const iterator &it) const {
368
0
      return obj_ == it.obj_ && index_ == it.index_;
369
0
    }
370
0
    bool operator!=(const iterator &it) const {
371
0
      return obj_ != it.obj_ || index_ != it.index_;
372
0
    }
373
  };
374
  class const_iterator {
375
    const JSONObject *obj_;
376
    size_t index_;
377
378
    const_iterator(const JSONObject *obj, size_t index)
379
0
        : obj_(obj), index_(index) {}
380
    friend class JSONObject;
381
382
   public:
383
    using iterator_category = std::bidirectional_iterator_tag;
384
    using value_type = std::pair<JSONString *, JSONValue *>;
385
    using difference_type = std::ptrdiff_t;
386
    using pointer = value_type *;
387
    using reference = value_type &;
388
389
    const_iterator(const const_iterator &) = default;
390
    const_iterator &operator=(const const_iterator &) = default;
391
392
    explicit const_iterator(const JSONObject::iterator &it)
393
0
        : obj_(it.obj_), index_(it.index_) {}
394
0
    const_iterator &operator=(const JSONObject::iterator &it) {
395
0
      obj_ = it.obj_;
396
0
      index_ = it.index_;
397
0
      return *this;
398
0
    }
399
400
0
    value_type operator*() const {
401
0
      return value_type{obj_->hiddenClass_->begin()[index_], (*obj_)[index_]};
402
0
    }
403
404
0
    const_iterator &operator++() {
405
0
      ++index_;
406
0
      return *this;
407
0
    }
408
409
0
    const_iterator &operator--() {
410
0
      --index_;
411
0
      return *this;
412
0
    }
413
414
0
    difference_type operator-(const const_iterator &x) const {
415
0
      assert(obj_ == x.obj_);
416
0
      return (difference_type)(index_ - x.index_);
417
0
    }
418
419
0
    bool operator==(const const_iterator &it) const {
420
0
      return obj_ == it.obj_ && index_ == it.index_;
421
0
    }
422
0
    bool operator!=(const const_iterator &it) const {
423
0
      return obj_ != it.obj_ || index_ != it.index_;
424
0
    }
425
  };
426
427
0
  iterator begin() {
428
0
    return iterator(this, 0);
429
0
  }
430
0
  iterator end() {
431
0
    return iterator(this, size());
432
0
  }
433
0
  const_iterator begin() const {
434
0
    return const_iterator(this, 0);
435
0
  }
436
0
  const_iterator end() const {
437
0
    return const_iterator(this, size());
438
0
  }
439
440
0
  iterator find(llvh::StringRef name) {
441
0
    if (auto res = hiddenClass_->find(name))
442
0
      return iterator(this, res.getValue());
443
0
    else
444
0
      return end();
445
0
  }
446
0
  const_iterator find(llvh::StringRef name) const {
447
0
    if (auto res = hiddenClass_->find(name))
448
0
      return const_iterator(this, res.getValue());
449
0
    else
450
0
      return end();
451
0
  }
452
453
0
  static bool classof(const JSONValue *v) {
454
0
    return v->getKind() == JSONKind::Object;
455
0
  }
456
};
457
458
class JSONArray : public JSONValue {
459
  size_t const size_;
460
461
0
  inline JSONValue **values() {
462
0
    return Pack<JSONArray, JSONValue *>::values(this);
463
0
  }
464
465
0
  inline JSONValue *const *values() const {
466
0
    return Pack<JSONArray, JSONValue *>::values(this);
467
0
  }
468
469
  /// Initialize the array with a sequence of values.
470
  template <class FwdIt>
471
  JSONArray(size_t size, FwdIt b, FwdIt e)
472
0
      : JSONValue(JSONKind::Array), size_(size) {
473
0
    std::copy(b, e, values());
474
0
  }
475
476
  /// Initialize all elements of the array with the same value.
477
  JSONArray(size_t size, JSONValue *fillValue)
478
0
      : JSONValue(JSONKind::Array), size_(size) {
479
0
    JSONValue **v = values();
480
0
    std::fill(v, v + size_, fillValue);
481
0
  }
482
483
  // Allocator
484
485
  template <class Allocator>
486
0
  inline void *operator new(size_t size, Allocator &alloc, size_t count) {
487
0
    return Pack<JSONArray, JSONValue *>::allocate(alloc, count);
488
0
  }
489
490
  friend class JSONFactory;
491
492
 public:
493
  using iterator = const hermes::parser::JSONValue *const *;
494
495
0
  size_t size() const {
496
0
    return size_;
497
0
  }
498
499
0
  iterator begin() const {
500
0
    return values();
501
0
  };
502
0
  iterator end() const {
503
0
    return values() + size_;
504
0
  }
505
506
0
  const JSONValue *at(size_t pos) const {
507
0
    assert(pos < size_);
508
0
    return values()[pos];
509
0
  };
510
511
0
  const JSONValue *operator[](size_t pos) const {
512
0
    assert(pos < size_);
513
0
    return values()[pos];
514
0
  }
515
516
0
  static bool classof(const JSONValue *v) {
517
0
    return v->getKind() == JSONKind::Array;
518
0
  }
519
};
520
521
/// This class owns all the objects, takes care of uniquing, and so on.
522
/// It needs to be configured with a function for creating unique string
523
/// literals (which usually comes from JSLexer).
524
class JSONFactory {
525
 public:
526
  using Allocator = hermes::BumpPtrAllocator;
527
528
  /// Uniquely identifies a hidden class. The first element of the pair is the
529
  /// number
530
  /// of hidden class members while the second element is a pointer to an
531
  /// alphabetically
532
  /// sorted array of their names.
533
  using HiddenClassKey = std::pair<size_t, JSONString *const *>;
534
535
  /// A single property.
536
  using Prop = std::pair<JSONString *, JSONValue *>;
537
538
  struct LessHiddenClassKey {
539
    bool operator()(const HiddenClassKey &a, const HiddenClassKey &b) const;
540
  };
541
542
 private:
543
  Allocator &allocator_;
544
545
  /// If a StringTable was not supplied to us from outside, store our own
546
  /// table here.
547
  std::unique_ptr<StringTable> ownStrTab_;
548
  /// The StringLIteralTable to use: either supplied to us, or points to our own
549
  /// copy.
550
  StringTable &strTab_;
551
552
  // Unique the strings and numbers as there are likely to be many duplicates.
553
  llvh::FoldingSet<JSONString> strings_;
554
  llvh::FoldingSet<JSONNumber> numbers_;
555
556
  std::map<HiddenClassKey, JSONHiddenClass *, LessHiddenClassKey>
557
      hiddenClasses_;
558
559
 public:
560
  explicit JSONFactory(Allocator &allocator, StringTable *strTab = nullptr);
561
562
0
  Allocator &getAllocator() {
563
0
    return allocator_;
564
0
  }
565
0
  StringTable &getStringTable() {
566
0
    return strTab_;
567
0
  }
568
569
  // Methods for creating JSON objects. Numbers, strings and hidden classes are
570
  // "uniqued" - creating the same value multiple times returns a pointer to the
571
  // same object.
572
573
  JSONString *getString(UniqueString *lit);
574
  JSONString *getString(llvh::StringRef str);
575
  JSONNumber *getNumber(double value);
576
0
  static JSONBoolean *getBoolean(bool v) {
577
0
    return JSONBoolean::getInstance(v);
578
0
  }
579
0
  static JSONNull *getNull() {
580
0
    return JSONNull::getInstance();
581
0
  }
582
583
  /// Lookup or create a hidden class identified by the key \p key.
584
  JSONHiddenClass *getHiddenClass(const HiddenClassKey &key);
585
586
  /// Sort a sequence of properties in-place, so they can be passed directly
587
  /// to \c newObject(). If there are duplicates, return a pointer to the first
588
  /// duplicate name, otherwise return null.
589
  static JSONString *sortProps(Prop *from, Prop *to);
590
591
  /// Create an object described by the sequence of properties. The properties
592
  /// are sorted first, and if there are duplicates the operation aborts and
593
  /// returns nullptr.
594
  /// \param propsAreSorted indicates that the properties are already sorted
595
  ///   and checked for duplicates, so it doesn't need to be done again.
596
  JSONObject *newObject(Prop *from, Prop *to, bool propsAreSorted = false);
597
598
  /// Create a new object of a particular hidden class, initializing it with a
599
  /// sequence of values. The values must be in the same order as the elements
600
  /// of the hidden class, which are sorted alphabetically.
601
  template <typename FwIt>
602
0
  JSONObject *newObject(JSONHiddenClass *hiddenClass, FwIt b, FwIt e) const {
603
0
    return new (allocator_, hiddenClass->size()) JSONObject(hiddenClass, b, e);
604
0
  }
605
  /// Create a new object of a particular hidden class, setting all elements to
606
  /// the same value.
607
  JSONObject *newObject(
608
      JSONHiddenClass *hiddenClass,
609
0
      JSONValue *fillValue = JSONNull::getInstance()) const {
610
0
    return new (allocator_, hiddenClass->size())
611
0
        JSONObject(hiddenClass, fillValue);
612
0
  }
613
614
  /// Create a new array of given size, initializing it with a sequence of
615
  /// values. The number of values provided must be the same as the size of the
616
  /// array.
617
  template <class FwIt>
618
0
  JSONArray *newArray(size_t size, FwIt b, FwIt e) const {
619
0
    return new (allocator_, size) JSONArray(size, b, e);
620
0
  }
621
  /// Create a new array of given size, initializing all elements with the same
622
  /// value.
623
  JSONArray *newArray(
624
      size_t size,
625
0
      JSONValue *fillValue = JSONNull::getInstance()) const {
626
0
    return new (allocator_, size) JSONArray(size, fillValue);
627
0
  }
628
};
629
630
class JSONParser {
631
 private:
632
  JSONFactory &factory_;
633
  JSLexer lexer_;
634
  SourceErrorManager &sm_;
635
636
 public:
637
  JSONParser(
638
      JSONFactory &factory,
639
      std::unique_ptr<llvh::MemoryBuffer> input,
640
      SourceErrorManager &sm,
641
      bool convertSurrogates = false);
642
643
  JSONParser(
644
      JSONFactory &factory,
645
      llvh::StringRef input,
646
      SourceErrorManager &sm,
647
      bool convertSurrogates = false)
648
      : JSONParser(
649
            factory,
650
            llvh::MemoryBuffer::getMemBuffer(input, "json"),
651
            sm,
652
0
            convertSurrogates) {}
653
654
  JSONParser(
655
      JSONFactory &factory,
656
      llvh::MemoryBufferRef input,
657
      SourceErrorManager &sm,
658
      bool showColors = true,
659
      bool convertSurrogates = false)
660
0
      : JSONParser(factory, llvh::MemoryBuffer::getMemBuffer(input), sm) {}
661
662
  /// Parse the supplied input. On error the result will be empty and the error
663
  /// would have been reported to the SourceMgr.
664
  llvh::Optional<JSONValue *> parse();
665
666
0
  void error(const llvh::Twine &msg) {
667
0
    sm_.error(lexer_.getCurToken()->getSourceRange(), msg, Subsystem::Parser);
668
0
  }
669
670
 private:
671
  llvh::Optional<JSONValue *> parseValue();
672
  llvh::Optional<JSONValue *> parseArray();
673
  llvh::Optional<JSONValue *> parseObject();
674
};
675
676
/// A holder class for a JSONValue backed by a shared allocator.
677
class JSONSharedValue {
678
 public:
679
  using Allocator = hermes::BumpPtrAllocator;
680
681
 private:
682
  const JSONValue *value_;
683
  std::shared_ptr<const Allocator> allocator_;
684
685
 public:
686
  JSONSharedValue(
687
      const JSONValue *value,
688
      std::shared_ptr<const Allocator> allocator)
689
0
      : value_(value), allocator_(std::move(allocator)) {}
690
691
0
  const JSONValue *operator*() const {
692
0
    return value_;
693
0
  }
694
695
0
  const JSONValue *operator->() const {
696
0
    return value_;
697
0
  }
698
};
699
700
} // namespace parser
701
} // namespace hermes
702
703
#endif // HERMES_PARSER_JSONPARSER_H