1// Copyright (C) MongoDB, Inc. 2014-present.
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may
4// not use this file except in compliance with the License. You may obtain
5// a copy of the License at http://www.apache.org/licenses/LICENSE-2.0
6
7package json
8
9import (
10	"fmt"
11	"reflect"
12)
13
14// Transition functions for recognizing new.
15// Adapted from encoding/json/scanner.go.
16
17// stateNe is the state after reading `ne`.
18func stateNe(s *scanner, c int) int {
19	if c == 'w' {
20		s.step = stateNew
21		return scanContinue
22	}
23	return s.error(c, "in literal new (expecting 'w')")
24}
25
26// stateNew is the state after reading `new`.
27// Ensures that there is a space after the new keyword.
28func stateNew(s *scanner, c int) int {
29	if c <= ' ' && isSpace(rune(c)) {
30		s.step = stateBeginObjectValue
31		return scanContinue
32	}
33	return s.error(c, "expected space after new keyword")
34}
35
36// stateBeginObjectValue is the state after reading `new`.
37func stateBeginObjectValue(s *scanner, c int) int {
38	if c <= ' ' && isSpace(rune(c)) {
39		return scanSkipSpace
40	}
41	switch c {
42	case 'B': // beginning of BinData or Boolean
43		s.step = stateB
44	case 'D': // beginning of Date
45		s.step = stateD
46	case 'N': // beginning of NumberInt or NumberLong
47		s.step = stateNumberUpperN
48	case 'O': // beginning of ObjectId
49		s.step = stateO
50	case 'R': // beginning of RegExp
51		s.step = stateR
52	case 'T': // beginning of Timestamp
53		s.step = stateUpperT
54	default:
55		return s.error(c, "looking for beginning of value")
56	}
57
58	return scanBeginLiteral
59}
60
61// stateNumberUpperN is the state after reading `N`.
62func stateNumberUpperN(s *scanner, c int) int {
63	if c == 'u' {
64		s.step = stateUpperNu
65		return scanContinue
66	}
67	return s.error(c, "in literal NumberInt or NumberLong (expecting 'u')")
68}
69
70// Decodes a literal stored in the underlying byte data into v.
71func (d *decodeState) storeNewLiteral(v reflect.Value, fromQuoted bool) {
72	op := d.scanWhile(scanSkipSpace)
73	if op != scanBeginLiteral {
74		d.error(fmt.Errorf("expected beginning of constructor"))
75	}
76
77	// Read constructor identifier
78	start := d.off - 1
79	op = d.scanWhile(scanContinue)
80	if op != scanBeginCtor {
81		d.error(fmt.Errorf("expected beginning of constructor"))
82	}
83
84	// Back up so d.ctor can have the byte we just read.
85	d.off--
86	d.scan.undo(op)
87
88	d.literalStore(d.data[start:d.off-1], v, fromQuoted)
89}
90
91// Returns a literal from the underlying byte data.
92func (d *decodeState) getNewLiteral() interface{} {
93	op := d.scanWhile(scanSkipSpace)
94	if op != scanBeginLiteral {
95		d.error(fmt.Errorf("expected beginning of constructor"))
96	}
97	return d.literalInterface()
98}
99