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 14const CtorNumArgsErrorf = "expected %v argument%v to %v constructor, but %v received" 15 16// Transition functions for recognizing object constructors. 17// Adapted from encoding/json/scanner.go. 18 19// stateConstructor is the state after reading a constructor name. 20func stateConstructor(s *scanner, c int) int { 21 if c <= ' ' && isSpace(rune(c)) { 22 return scanSkipSpace 23 } 24 if c == '(' { 25 s.step = stateBeginCtorOrEmpty 26 s.pushParseState(parseCtorArg) 27 return scanBeginCtor 28 } 29 return s.error(c, "expected '('") 30} 31 32// stateBeginCtorOrEmpty is the state after reading `(`. 33func stateBeginCtorOrEmpty(s *scanner, c int) int { 34 if c <= ' ' && isSpace(rune(c)) { 35 return scanSkipSpace 36 } 37 if c == ')' { 38 return stateEndValue(s, c) 39 } 40 return stateBeginValue(s, c) 41} 42 43// ctor consumes a constructor from d.data[d.off-1:], given a type specification t. 44// the first byte of the constructor ('(') has been read already. 45func (d *decodeState) ctor(name string, t []reflect.Type) ([]reflect.Value, error) { 46 result := make([]reflect.Value, 0, len(t)) 47 48 i := 0 49 for { 50 // Look ahead for ) - can only happen on first iteration. 51 op := d.scanWhile(scanSkipSpace) 52 if op == scanEndCtor { 53 break 54 } 55 56 // Back up so d.value can have the byte we just read. 57 d.off-- 58 d.scan.undo(op) 59 60 if i < len(t) { 61 v := reflect.New(t[i]).Elem() 62 63 // Get argument of constructor 64 d.value(v) 65 66 result = append(result, v) 67 i++ 68 } 69 70 // Next token must be , or ). 71 op = d.scanWhile(scanSkipSpace) 72 if op == scanEndCtor { 73 break 74 } 75 if op != scanCtorArg { 76 d.error(errPhase) 77 } 78 } 79 80 return result, ctorNumArgsMismatch(name, len(t), i) 81} 82 83// ctorInterface is like ctor but returns []interface{}. 84func (d *decodeState) ctorInterface() []interface{} { 85 var v = make([]interface{}, 0) 86 for { 87 // Look ahead for ) - can only happen on first iteration. 88 op := d.scanWhile(scanSkipSpace) 89 if op == scanEndCtor { 90 break 91 } 92 93 // Back up so d.value can have the byte we just read. 94 d.off-- 95 d.scan.undo(op) 96 97 v = append(v, d.valueInterface(false)) 98 99 // Next token must be , or ). 100 op = d.scanWhile(scanSkipSpace) 101 if op == scanEndCtor { 102 break 103 } 104 if op != scanCtorArg { 105 d.error(errPhase) 106 } 107 } 108 return v 109} 110 111// Returns a descriptive error message if the number of arguments given 112// to the constructor do not match what is expected. 113func ctorNumArgsMismatch(name string, expected, actual int) error { 114 if expected == actual { 115 return nil 116 } 117 118 quantifier := "" 119 if expected > 1 { 120 quantifier = "s" 121 } 122 return fmt.Errorf(CtorNumArgsErrorf, expected, quantifier, name, actual) 123} 124