Initial commit
This commit is contained in:
0
vendor/github.com/hjson/hjson-go/.gitignore
generated
vendored
Normal file
0
vendor/github.com/hjson/hjson-go/.gitignore
generated
vendored
Normal file
21
vendor/github.com/hjson/hjson-go/LICENSE
generated
vendored
Normal file
21
vendor/github.com/hjson/hjson-go/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2016, 2017 Christian Zangl
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
181
vendor/github.com/hjson/hjson-go/README.md
generated
vendored
Normal file
181
vendor/github.com/hjson/hjson-go/README.md
generated
vendored
Normal file
@@ -0,0 +1,181 @@
|
||||
# hjson-go
|
||||
|
||||
[](https://github.com/hjson/hjson-go/actions)
|
||||
[](https://github.com/hjson/hjson-go/releases)
|
||||
[](https://goreportcard.com/report/github.com/hjson/hjson-go)
|
||||
[](http://gocover.io/github.com/hjson/hjson-go/)
|
||||
[](https://godoc.org/github.com/hjson/hjson-go)
|
||||
|
||||

|
||||
|
||||
```
|
||||
{
|
||||
# specify rate in requests/second (because comments are helpful!)
|
||||
rate: 1000
|
||||
|
||||
// prefer c-style comments?
|
||||
/* feeling old fashioned? */
|
||||
|
||||
# did you notice that rate doesn't need quotes?
|
||||
hey: look ma, no quotes for strings either!
|
||||
|
||||
# best of all
|
||||
notice: []
|
||||
anything: ?
|
||||
|
||||
# yes, commas are optional!
|
||||
}
|
||||
```
|
||||
|
||||
The Go implementation of Hjson is based on [hjson-js](https://github.com/hjson/hjson-js). For other platforms see [hjson.github.io](https://hjson.github.io).
|
||||
|
||||
# Install
|
||||
|
||||
Make sure you have a working Go environment. See the [install instructions](http://golang.org/doc/install.html).
|
||||
|
||||
1. Get the sources
|
||||
```bash
|
||||
$ go get -u github.com/hjson/hjson-go
|
||||
```
|
||||
2. Build the **hjson-cli** commandline tool (optional)
|
||||
```bash
|
||||
$ cd $(go env GOPATH)/src/github.com/hjson/hjson-go/hjson-cli && go install
|
||||
$ hjson-cli --version
|
||||
```
|
||||
# Usage as command line tool
|
||||
```
|
||||
usage: hjson-cli [OPTIONS] [INPUT]
|
||||
hjson can be used to convert JSON from/to Hjson.
|
||||
|
||||
hjson will read the given JSON/Hjson input file or read from stdin.
|
||||
|
||||
Options:
|
||||
-allowMinusZero
|
||||
Allow -0.
|
||||
-bracesSameLine
|
||||
Print braces on the same line.
|
||||
-c Output as JSON.
|
||||
-h Show this screen.
|
||||
-indentBy string
|
||||
The indent string. (default " ")
|
||||
-j Output as formatted JSON.
|
||||
-omitRootBraces
|
||||
Omit braces at the root.
|
||||
-quoteAlways
|
||||
Always quote string values.
|
||||
```
|
||||
|
||||
Sample:
|
||||
- run `hjson-cli test.json > test.hjson` to convert to Hjson
|
||||
- run `hjson-cli -j test.hjson > test.json` to convert to JSON
|
||||
|
||||
# Usage as a GO library
|
||||
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hjson/hjson-go"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Now let's look at decoding Hjson data into Go
|
||||
// values.
|
||||
sampleText := []byte(`
|
||||
{
|
||||
# specify rate in requests/second
|
||||
rate: 1000
|
||||
array:
|
||||
[
|
||||
foo
|
||||
bar
|
||||
]
|
||||
}`)
|
||||
|
||||
// We need to provide a variable where Hjson
|
||||
// can put the decoded data.
|
||||
var dat map[string]interface{}
|
||||
|
||||
// Decode and a check for errors.
|
||||
if err := hjson.Unmarshal(sampleText, &dat); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(dat)
|
||||
|
||||
// In order to use the values in the decoded map,
|
||||
// we'll need to cast them to their appropriate type.
|
||||
|
||||
rate := dat["rate"].(float64)
|
||||
fmt.Println(rate)
|
||||
|
||||
array := dat["array"].([]interface{})
|
||||
str1 := array[0].(string)
|
||||
fmt.Println(str1)
|
||||
|
||||
|
||||
// To encode to Hjson with default options:
|
||||
sampleMap := map[string]int{"apple": 5, "lettuce": 7}
|
||||
hjson, _ := hjson.Marshal(sampleMap)
|
||||
// this is short for:
|
||||
// options := hjson.DefaultOptions()
|
||||
// hjson, _ := hjson.MarshalWithOptions(sampleMap, options)
|
||||
fmt.Println(string(hjson))
|
||||
}
|
||||
```
|
||||
|
||||
If you prefer, you can also unmarshal to Go objects by converting to JSON:
|
||||
|
||||
```go
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/hjson/hjson-go"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
type Sample struct {
|
||||
Rate int
|
||||
Array []string
|
||||
}
|
||||
|
||||
func main() {
|
||||
|
||||
sampleText := []byte(`
|
||||
{
|
||||
# specify rate in requests/second
|
||||
rate: 1000
|
||||
array:
|
||||
[
|
||||
foo
|
||||
bar
|
||||
]
|
||||
}`)
|
||||
|
||||
// read Hjson
|
||||
var dat map[string]interface{}
|
||||
hjson.Unmarshal(sampleText, &dat)
|
||||
|
||||
// convert to JSON
|
||||
b, _ := json.Marshal(dat)
|
||||
|
||||
// unmarshal
|
||||
var sample Sample
|
||||
json.Unmarshal(b, &sample)
|
||||
|
||||
fmt.Println(sample.Rate)
|
||||
fmt.Println(sample.Array)
|
||||
}
|
||||
```
|
||||
|
||||
# API
|
||||
|
||||
[](http://godoc.org/github.com/hjson/hjson-go)
|
||||
|
||||
# History
|
||||
|
||||
[see releases](https://github.com/hjson/hjson-go/releases)
|
||||
58
vendor/github.com/hjson/hjson-go/build_release.sh
generated
vendored
Normal file
58
vendor/github.com/hjson/hjson-go/build_release.sh
generated
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
#!/bin/bash
|
||||
|
||||
cd `dirname $0`
|
||||
ROOT=$PWD/_dist
|
||||
|
||||
if [ -d "$ROOT" ]; then rm -rf $ROOT; fi
|
||||
|
||||
mkdir $ROOT
|
||||
|
||||
function build() {
|
||||
export GOOS=$1
|
||||
export GOARCH=$2
|
||||
|
||||
echo build $GOOS $GOARCH
|
||||
OUT=$ROOT/${GOOS}_${GOARCH}
|
||||
mkdir $OUT
|
||||
cd $OUT
|
||||
go build github.com/hjson/hjson-go/hjson-cli
|
||||
if [[ $3 == "zip" ]]; then
|
||||
mv $OUT/hjson-cli.exe $OUT/hjson.exe
|
||||
zip -j ${OUT}.zip $OUT/*
|
||||
else
|
||||
mv $OUT/hjson-cli $OUT/hjson
|
||||
tar -czf ${OUT}.tar.gz -C $OUT .
|
||||
fi
|
||||
|
||||
}
|
||||
|
||||
# not all targets can be built on travis
|
||||
|
||||
# build android arm
|
||||
build darwin 386
|
||||
build darwin amd64
|
||||
# build darwin arm
|
||||
# build darwin arm64
|
||||
build dragonfly amd64
|
||||
build freebsd 386
|
||||
build freebsd amd64
|
||||
build freebsd arm
|
||||
build linux 386
|
||||
build linux amd64
|
||||
build linux arm
|
||||
build linux arm64
|
||||
build linux mips64
|
||||
build linux mips64le
|
||||
build linux ppc64
|
||||
build linux ppc64le
|
||||
build netbsd 386
|
||||
build netbsd amd64
|
||||
build netbsd arm
|
||||
build openbsd 386
|
||||
build openbsd amd64
|
||||
build openbsd arm
|
||||
build plan9 386
|
||||
build plan9 amd64
|
||||
build solaris amd64
|
||||
build windows 386 zip
|
||||
build windows amd64 zip
|
||||
480
vendor/github.com/hjson/hjson-go/decode.go
generated
vendored
Normal file
480
vendor/github.com/hjson/hjson-go/decode.go
generated
vendored
Normal file
@@ -0,0 +1,480 @@
|
||||
package hjson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type hjsonParser struct {
|
||||
data []byte
|
||||
at int // The index of the current character
|
||||
ch byte // The current character
|
||||
}
|
||||
|
||||
func (p *hjsonParser) resetAt() {
|
||||
p.at = 0
|
||||
p.ch = ' '
|
||||
}
|
||||
|
||||
func isPunctuatorChar(c byte) bool {
|
||||
return c == '{' || c == '}' || c == '[' || c == ']' || c == ',' || c == ':'
|
||||
}
|
||||
|
||||
func (p *hjsonParser) errAt(message string) error {
|
||||
var i int
|
||||
col := 0
|
||||
line := 1
|
||||
for i = p.at - 1; i > 0 && p.data[i] != '\n'; i-- {
|
||||
col++
|
||||
}
|
||||
for ; i > 0; i-- {
|
||||
if p.data[i] == '\n' {
|
||||
line++
|
||||
}
|
||||
}
|
||||
samEnd := p.at - col + 20
|
||||
if samEnd > len(p.data) {
|
||||
samEnd = len(p.data)
|
||||
}
|
||||
return fmt.Errorf("%s at line %d,%d >>> %s", message, line, col, string(p.data[p.at-col:samEnd]))
|
||||
}
|
||||
|
||||
func (p *hjsonParser) next() bool {
|
||||
// get the next character.
|
||||
if p.at < len(p.data) {
|
||||
p.ch = p.data[p.at]
|
||||
p.at++
|
||||
return true
|
||||
}
|
||||
p.ch = 0
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *hjsonParser) peek(offs int) byte {
|
||||
pos := p.at + offs
|
||||
if pos >= 0 && pos < len(p.data) {
|
||||
return p.data[p.at+offs]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
var escapee = map[byte]byte{
|
||||
'"': '"',
|
||||
'\'': '\'',
|
||||
'\\': '\\',
|
||||
'/': '/',
|
||||
'b': '\b',
|
||||
'f': '\f',
|
||||
'n': '\n',
|
||||
'r': '\r',
|
||||
't': '\t',
|
||||
}
|
||||
|
||||
func (p *hjsonParser) readString(allowML bool) (string, error) {
|
||||
|
||||
// Parse a string value.
|
||||
res := new(bytes.Buffer)
|
||||
|
||||
// callers make sure that (ch === '"' || ch === "'")
|
||||
// When parsing for string values, we must look for " and \ characters.
|
||||
exitCh := p.ch
|
||||
for p.next() {
|
||||
if p.ch == exitCh {
|
||||
p.next()
|
||||
if allowML && exitCh == '\'' && p.ch == '\'' && res.Len() == 0 {
|
||||
// ''' indicates a multiline string
|
||||
p.next()
|
||||
return p.readMLString()
|
||||
} else {
|
||||
return res.String(), nil
|
||||
}
|
||||
}
|
||||
if p.ch == '\\' {
|
||||
p.next()
|
||||
if p.ch == 'u' {
|
||||
uffff := 0
|
||||
for i := 0; i < 4; i++ {
|
||||
p.next()
|
||||
var hex int
|
||||
if p.ch >= '0' && p.ch <= '9' {
|
||||
hex = int(p.ch - '0')
|
||||
} else if p.ch >= 'a' && p.ch <= 'f' {
|
||||
hex = int(p.ch - 'a' + 0xa)
|
||||
} else if p.ch >= 'A' && p.ch <= 'F' {
|
||||
hex = int(p.ch - 'A' + 0xa)
|
||||
} else {
|
||||
return "", p.errAt("Bad \\u char " + string(p.ch))
|
||||
}
|
||||
uffff = uffff*16 + hex
|
||||
}
|
||||
res.WriteRune(rune(uffff))
|
||||
} else if ech, ok := escapee[p.ch]; ok {
|
||||
res.WriteByte(ech)
|
||||
} else {
|
||||
return "", p.errAt("Bad escape \\" + string(p.ch))
|
||||
}
|
||||
} else if p.ch == '\n' || p.ch == '\r' {
|
||||
return "", p.errAt("Bad string containing newline")
|
||||
} else {
|
||||
res.WriteByte(p.ch)
|
||||
}
|
||||
}
|
||||
return "", p.errAt("Bad string")
|
||||
}
|
||||
|
||||
func (p *hjsonParser) readMLString() (value string, err error) {
|
||||
|
||||
// Parse a multiline string value.
|
||||
res := new(bytes.Buffer)
|
||||
triple := 0
|
||||
|
||||
// we are at ''' +1 - get indent
|
||||
indent := 0
|
||||
for {
|
||||
c := p.peek(-indent - 5)
|
||||
if c == 0 || c == '\n' {
|
||||
break
|
||||
}
|
||||
indent++
|
||||
}
|
||||
|
||||
skipIndent := func() {
|
||||
skip := indent
|
||||
for p.ch > 0 && p.ch <= ' ' && p.ch != '\n' && skip > 0 {
|
||||
skip--
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
|
||||
// skip white/to (newline)
|
||||
for p.ch > 0 && p.ch <= ' ' && p.ch != '\n' {
|
||||
p.next()
|
||||
}
|
||||
if p.ch == '\n' {
|
||||
p.next()
|
||||
skipIndent()
|
||||
}
|
||||
|
||||
// When parsing multiline string values, we must look for ' characters.
|
||||
lastLf := false
|
||||
for {
|
||||
if p.ch == 0 {
|
||||
return "", p.errAt("Bad multiline string")
|
||||
} else if p.ch == '\'' {
|
||||
triple++
|
||||
p.next()
|
||||
if triple == 3 {
|
||||
sres := res.Bytes()
|
||||
if lastLf {
|
||||
return string(sres[0 : len(sres)-1]), nil // remove last EOL
|
||||
}
|
||||
return string(sres), nil
|
||||
}
|
||||
continue
|
||||
} else {
|
||||
for triple > 0 {
|
||||
res.WriteByte('\'')
|
||||
triple--
|
||||
lastLf = false
|
||||
}
|
||||
}
|
||||
if p.ch == '\n' {
|
||||
res.WriteByte('\n')
|
||||
lastLf = true
|
||||
p.next()
|
||||
skipIndent()
|
||||
} else {
|
||||
if p.ch != '\r' {
|
||||
res.WriteByte(p.ch)
|
||||
lastLf = false
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *hjsonParser) readKeyname() (string, error) {
|
||||
|
||||
// quotes for keys are optional in Hjson
|
||||
// unless they include {}[],: or whitespace.
|
||||
|
||||
if p.ch == '"' || p.ch == '\'' {
|
||||
return p.readString(false)
|
||||
}
|
||||
|
||||
name := new(bytes.Buffer)
|
||||
start := p.at
|
||||
space := -1
|
||||
for {
|
||||
if p.ch == ':' {
|
||||
if name.Len() == 0 {
|
||||
return "", p.errAt("Found ':' but no key name (for an empty key name use quotes)")
|
||||
} else if space >= 0 && space != name.Len() {
|
||||
p.at = start + space
|
||||
return "", p.errAt("Found whitespace in your key name (use quotes to include)")
|
||||
}
|
||||
return name.String(), nil
|
||||
} else if p.ch <= ' ' {
|
||||
if p.ch == 0 {
|
||||
return "", p.errAt("Found EOF while looking for a key name (check your syntax)")
|
||||
}
|
||||
if space < 0 {
|
||||
space = name.Len()
|
||||
}
|
||||
} else {
|
||||
if isPunctuatorChar(p.ch) {
|
||||
return "", p.errAt("Found '" + string(p.ch) + "' where a key name was expected (check your syntax or use quotes if the key name includes {}[],: or whitespace)")
|
||||
}
|
||||
name.WriteByte(p.ch)
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *hjsonParser) white() {
|
||||
for p.ch > 0 {
|
||||
// Skip whitespace.
|
||||
for p.ch > 0 && p.ch <= ' ' {
|
||||
p.next()
|
||||
}
|
||||
// Hjson allows comments
|
||||
if p.ch == '#' || p.ch == '/' && p.peek(0) == '/' {
|
||||
for p.ch > 0 && p.ch != '\n' {
|
||||
p.next()
|
||||
}
|
||||
} else if p.ch == '/' && p.peek(0) == '*' {
|
||||
p.next()
|
||||
p.next()
|
||||
for p.ch > 0 && !(p.ch == '*' && p.peek(0) == '/') {
|
||||
p.next()
|
||||
}
|
||||
if p.ch > 0 {
|
||||
p.next()
|
||||
p.next()
|
||||
}
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (p *hjsonParser) readTfnns() (interface{}, error) {
|
||||
|
||||
// Hjson strings can be quoteless
|
||||
// returns string, true, false, or null.
|
||||
|
||||
if isPunctuatorChar(p.ch) {
|
||||
return nil, p.errAt("Found a punctuator character '" + string(p.ch) + "' when expecting a quoteless string (check your syntax)")
|
||||
}
|
||||
chf := p.ch
|
||||
value := new(bytes.Buffer)
|
||||
value.WriteByte(p.ch)
|
||||
|
||||
for {
|
||||
p.next()
|
||||
isEol := p.ch == '\r' || p.ch == '\n' || p.ch == 0
|
||||
if isEol ||
|
||||
p.ch == ',' || p.ch == '}' || p.ch == ']' ||
|
||||
p.ch == '#' ||
|
||||
p.ch == '/' && (p.peek(0) == '/' || p.peek(0) == '*') {
|
||||
switch chf {
|
||||
case 'f':
|
||||
if strings.TrimSpace(value.String()) == "false" {
|
||||
return false, nil
|
||||
}
|
||||
case 'n':
|
||||
if strings.TrimSpace(value.String()) == "null" {
|
||||
return nil, nil
|
||||
}
|
||||
case 't':
|
||||
if strings.TrimSpace(value.String()) == "true" {
|
||||
return true, nil
|
||||
}
|
||||
default:
|
||||
if chf == '-' || chf >= '0' && chf <= '9' {
|
||||
if n, err := tryParseNumber(value.Bytes(), false); err == nil {
|
||||
return n, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
if isEol {
|
||||
// remove any whitespace at the end (ignored in quoteless strings)
|
||||
return strings.TrimSpace(value.String()), nil
|
||||
}
|
||||
}
|
||||
value.WriteByte(p.ch)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *hjsonParser) readArray() (value interface{}, err error) {
|
||||
|
||||
// Parse an array value.
|
||||
// assuming ch == '['
|
||||
|
||||
array := make([]interface{}, 0, 1)
|
||||
|
||||
p.next()
|
||||
p.white()
|
||||
|
||||
if p.ch == ']' {
|
||||
p.next()
|
||||
return array, nil // empty array
|
||||
}
|
||||
|
||||
for p.ch > 0 {
|
||||
var val interface{}
|
||||
if val, err = p.readValue(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
array = append(array, val)
|
||||
p.white()
|
||||
// in Hjson the comma is optional and trailing commas are allowed
|
||||
if p.ch == ',' {
|
||||
p.next()
|
||||
p.white()
|
||||
}
|
||||
if p.ch == ']' {
|
||||
p.next()
|
||||
return array, nil
|
||||
}
|
||||
p.white()
|
||||
}
|
||||
|
||||
return nil, p.errAt("End of input while parsing an array (did you forget a closing ']'?)")
|
||||
}
|
||||
|
||||
func (p *hjsonParser) readObject(withoutBraces bool) (value interface{}, err error) {
|
||||
// Parse an object value.
|
||||
|
||||
object := make(map[string]interface{})
|
||||
|
||||
if !withoutBraces {
|
||||
// assuming ch == '{'
|
||||
p.next()
|
||||
}
|
||||
|
||||
p.white()
|
||||
if p.ch == '}' && !withoutBraces {
|
||||
p.next()
|
||||
return object, nil // empty object
|
||||
}
|
||||
for p.ch > 0 {
|
||||
var key string
|
||||
if key, err = p.readKeyname(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.white()
|
||||
if p.ch != ':' {
|
||||
return nil, p.errAt("Expected ':' instead of '" + string(p.ch) + "'")
|
||||
}
|
||||
p.next()
|
||||
// duplicate keys overwrite the previous value
|
||||
var val interface{}
|
||||
if val, err = p.readValue(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
object[key] = val
|
||||
p.white()
|
||||
// in Hjson the comma is optional and trailing commas are allowed
|
||||
if p.ch == ',' {
|
||||
p.next()
|
||||
p.white()
|
||||
}
|
||||
if p.ch == '}' && !withoutBraces {
|
||||
p.next()
|
||||
return object, nil
|
||||
}
|
||||
p.white()
|
||||
}
|
||||
|
||||
if withoutBraces {
|
||||
return object, nil
|
||||
}
|
||||
return nil, p.errAt("End of input while parsing an object (did you forget a closing '}'?)")
|
||||
}
|
||||
|
||||
func (p *hjsonParser) readValue() (interface{}, error) {
|
||||
|
||||
// Parse a Hjson value. It could be an object, an array, a string, a number or a word.
|
||||
|
||||
p.white()
|
||||
switch p.ch {
|
||||
case '{':
|
||||
return p.readObject(false)
|
||||
case '[':
|
||||
return p.readArray()
|
||||
case '"', '\'':
|
||||
return p.readString(true)
|
||||
default:
|
||||
return p.readTfnns()
|
||||
}
|
||||
}
|
||||
|
||||
func (p *hjsonParser) rootValue() (interface{}, error) {
|
||||
// Braces for the root object are optional
|
||||
|
||||
p.white()
|
||||
switch p.ch {
|
||||
case '{':
|
||||
return p.checkTrailing(p.readObject(false))
|
||||
case '[':
|
||||
return p.checkTrailing(p.readArray())
|
||||
}
|
||||
|
||||
// assume we have a root object without braces
|
||||
res, err := p.checkTrailing(p.readObject(true))
|
||||
if err == nil {
|
||||
return res, nil
|
||||
}
|
||||
|
||||
// test if we are dealing with a single JSON value instead (true/false/null/num/"")
|
||||
p.resetAt()
|
||||
if res2, err2 := p.checkTrailing(p.readValue()); err2 == nil {
|
||||
return res2, nil
|
||||
}
|
||||
return res, err
|
||||
}
|
||||
|
||||
func (p *hjsonParser) checkTrailing(v interface{}, err error) (interface{}, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
p.white()
|
||||
if p.ch > 0 {
|
||||
return nil, p.errAt("Syntax error, found trailing characters")
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// Unmarshal parses the Hjson-encoded data and stores the result
|
||||
// in the value pointed to by v.
|
||||
//
|
||||
// Unmarshal uses the inverse of the encodings that
|
||||
// Marshal uses, allocating maps, slices, and pointers as necessary.
|
||||
//
|
||||
func Unmarshal(data []byte, v interface{}) (err error) {
|
||||
var value interface{}
|
||||
parser := &hjsonParser{data, 0, ' '}
|
||||
parser.resetAt()
|
||||
value, err = parser.rootValue()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rv := reflect.ValueOf(v)
|
||||
if rv.Kind() != reflect.Ptr || rv.IsNil() {
|
||||
return fmt.Errorf("non-pointer %v", reflect.TypeOf(v))
|
||||
}
|
||||
for rv.Kind() == reflect.Ptr {
|
||||
rv = rv.Elem()
|
||||
}
|
||||
defer func() {
|
||||
if e := recover(); e != nil {
|
||||
err = fmt.Errorf("%v", e)
|
||||
}
|
||||
}()
|
||||
rv.Set(reflect.ValueOf(value))
|
||||
return err
|
||||
}
|
||||
492
vendor/github.com/hjson/hjson-go/encode.go
generated
vendored
Normal file
492
vendor/github.com/hjson/hjson-go/encode.go
generated
vendored
Normal file
@@ -0,0 +1,492 @@
|
||||
package hjson
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"unicode/utf8"
|
||||
)
|
||||
|
||||
// EncoderOptions defines options for encoding to Hjson.
|
||||
type EncoderOptions struct {
|
||||
// End of line, should be either \n or \r\n
|
||||
Eol string
|
||||
// Place braces on the same line
|
||||
BracesSameLine bool
|
||||
// Emit braces for the root object
|
||||
EmitRootBraces bool
|
||||
// Always place string in quotes
|
||||
QuoteAlways bool
|
||||
// Place string in quotes if it could otherwise be a number, boolean or null
|
||||
QuoteAmbiguousStrings bool
|
||||
// Indent string
|
||||
IndentBy string
|
||||
// Base indentation string
|
||||
BaseIndentation string
|
||||
// Allow the -0 value (unlike ES6)
|
||||
AllowMinusZero bool
|
||||
// Encode unknown values as 'null'
|
||||
UnknownAsNull bool
|
||||
}
|
||||
|
||||
// DefaultOptions returns the default encoding options.
|
||||
func DefaultOptions() EncoderOptions {
|
||||
opt := EncoderOptions{}
|
||||
opt.Eol = "\n"
|
||||
opt.BracesSameLine = false
|
||||
opt.EmitRootBraces = true
|
||||
opt.QuoteAlways = false
|
||||
opt.QuoteAmbiguousStrings = true
|
||||
opt.IndentBy = " "
|
||||
opt.BaseIndentation = ""
|
||||
opt.AllowMinusZero = false
|
||||
opt.UnknownAsNull = false
|
||||
return opt
|
||||
}
|
||||
|
||||
type hjsonEncoder struct {
|
||||
bytes.Buffer // output
|
||||
EncoderOptions
|
||||
indent int
|
||||
}
|
||||
|
||||
var needsEscape, needsQuotes, needsEscapeML, startsWithKeyword, needsEscapeName *regexp.Regexp
|
||||
|
||||
func init() {
|
||||
var commonRange = `\x7f-\x9f\x{00ad}\x{0600}-\x{0604}\x{070f}\x{17b4}\x{17b5}\x{200c}-\x{200f}\x{2028}-\x{202f}\x{2060}-\x{206f}\x{feff}\x{fff0}-\x{ffff}`
|
||||
// needsEscape tests if the string can be written without escapes
|
||||
needsEscape = regexp.MustCompile(`[\\\"\x00-\x1f` + commonRange + `]`)
|
||||
// needsQuotes tests if the string can be written as a quoteless string (includes needsEscape but without \\ and \")
|
||||
needsQuotes = regexp.MustCompile(`^\s|^"|^'|^#|^/\*|^//|^\{|^\}|^\[|^\]|^:|^,|\s$|[\x00-\x1f\x7f-\x9f\x{00ad}\x{0600}-\x{0604}\x{070f}\x{17b4}\x{17b5}\x{200c}-\x{200f}\x{2028}-\x{202f}\x{2060}-\x{206f}\x{feff}\x{fff0}-\x{ffff}]`)
|
||||
// needsEscapeML tests if the string can be written as a multiline string (like needsEscape but without \n, \r, \\, \", \t)
|
||||
var x08Or9 = `\x08` // `\x09` for the old behavior
|
||||
needsEscapeML = regexp.MustCompile(`'''|^[\s]+$|[\x00-` + x08Or9 + `\x0b\x0c\x0e-\x1f` + commonRange + `]`)
|
||||
// starts with a keyword and optionally is followed by a comment
|
||||
startsWithKeyword = regexp.MustCompile(`^(true|false|null)\s*((,|\]|\}|#|//|/\*).*)?$`)
|
||||
needsEscapeName = regexp.MustCompile(`[,\{\[\}\]\s:#"']|//|/\*`)
|
||||
}
|
||||
|
||||
var meta = map[byte][]byte{
|
||||
// table of character substitutions
|
||||
'\b': []byte("\\b"),
|
||||
'\t': []byte("\\t"),
|
||||
'\n': []byte("\\n"),
|
||||
'\f': []byte("\\f"),
|
||||
'\r': []byte("\\r"),
|
||||
'"': []byte("\\\""),
|
||||
'\\': []byte("\\\\"),
|
||||
}
|
||||
|
||||
func (e *hjsonEncoder) quoteReplace(text string) string {
|
||||
return string(needsEscape.ReplaceAllFunc([]byte(text), func(a []byte) []byte {
|
||||
c := meta[a[0]]
|
||||
if c != nil {
|
||||
return c
|
||||
}
|
||||
r, _ := utf8.DecodeRune(a)
|
||||
return []byte(fmt.Sprintf("\\u%04x", r))
|
||||
}))
|
||||
}
|
||||
|
||||
func (e *hjsonEncoder) quote(value string, separator string, isRootObject bool) {
|
||||
|
||||
// Check if we can insert this string without quotes
|
||||
// see hjson syntax (must not parse as true, false, null or number)
|
||||
|
||||
if len(value) == 0 {
|
||||
e.WriteString(separator + `""`)
|
||||
} else if e.QuoteAlways ||
|
||||
needsQuotes.MatchString(value) || (e.QuoteAmbiguousStrings && (startsWithNumber([]byte(value)) ||
|
||||
startsWithKeyword.MatchString(value))) {
|
||||
|
||||
// If the string contains no control characters, no quote characters, and no
|
||||
// backslash characters, then we can safely slap some quotes around it.
|
||||
// Otherwise we first check if the string can be expressed in multiline
|
||||
// format or we must replace the offending characters with safe escape
|
||||
// sequences.
|
||||
|
||||
if !needsEscape.MatchString(value) {
|
||||
e.WriteString(separator + `"` + value + `"`)
|
||||
} else if !needsEscapeML.MatchString(value) && !isRootObject {
|
||||
e.mlString(value, separator)
|
||||
} else {
|
||||
e.WriteString(separator + `"` + e.quoteReplace(value) + `"`)
|
||||
}
|
||||
} else {
|
||||
// return without quotes
|
||||
e.WriteString(separator + value)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *hjsonEncoder) mlString(value string, separator string) {
|
||||
// wrap the string into the ''' (multiline) format
|
||||
|
||||
a := strings.Split(strings.Replace(value, "\r", "", -1), "\n")
|
||||
|
||||
if len(a) == 1 {
|
||||
// The string contains only a single line. We still use the multiline
|
||||
// format as it avoids escaping the \ character (e.g. when used in a
|
||||
// regex).
|
||||
e.WriteString(separator + "'''")
|
||||
e.WriteString(a[0])
|
||||
} else {
|
||||
e.writeIndent(e.indent + 1)
|
||||
e.WriteString("'''")
|
||||
for _, v := range a {
|
||||
indent := e.indent + 1
|
||||
if len(v) == 0 {
|
||||
indent = 0
|
||||
}
|
||||
e.writeIndent(indent)
|
||||
e.WriteString(v)
|
||||
}
|
||||
e.writeIndent(e.indent + 1)
|
||||
}
|
||||
e.WriteString("'''")
|
||||
}
|
||||
|
||||
func (e *hjsonEncoder) quoteName(name string) string {
|
||||
if len(name) == 0 {
|
||||
return `""`
|
||||
}
|
||||
|
||||
// Check if we can insert this name without quotes
|
||||
|
||||
if needsEscapeName.MatchString(name) {
|
||||
if needsEscape.MatchString(name) {
|
||||
name = e.quoteReplace(name)
|
||||
}
|
||||
return `"` + name + `"`
|
||||
}
|
||||
// without quotes
|
||||
return name
|
||||
}
|
||||
|
||||
type sortAlpha []reflect.Value
|
||||
|
||||
func (s sortAlpha) Len() int {
|
||||
return len(s)
|
||||
}
|
||||
func (s sortAlpha) Swap(i, j int) {
|
||||
s[i], s[j] = s[j], s[i]
|
||||
}
|
||||
func (s sortAlpha) Less(i, j int) bool {
|
||||
return s[i].String() < s[j].String()
|
||||
}
|
||||
|
||||
func (e *hjsonEncoder) writeIndent(indent int) {
|
||||
e.WriteString(e.Eol)
|
||||
e.WriteString(e.BaseIndentation)
|
||||
for i := 0; i < indent; i++ {
|
||||
e.WriteString(e.IndentBy)
|
||||
}
|
||||
}
|
||||
|
||||
func (e *hjsonEncoder) useMarshaler(value reflect.Value, separator string) error {
|
||||
b, err := value.Interface().(json.Marshaler).MarshalJSON()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
e.WriteString(separator)
|
||||
e.WriteString(string(b))
|
||||
return nil
|
||||
}
|
||||
|
||||
var marshaler = reflect.TypeOf((*json.Marshaler)(nil)).Elem()
|
||||
|
||||
func (e *hjsonEncoder) str(value reflect.Value, noIndent bool, separator string, isRootObject bool) error {
|
||||
|
||||
// Produce a string from value.
|
||||
|
||||
kind := value.Kind()
|
||||
|
||||
if kind == reflect.Interface || kind == reflect.Ptr {
|
||||
if value.IsNil() {
|
||||
e.WriteString(separator)
|
||||
e.WriteString("null")
|
||||
return nil
|
||||
}
|
||||
return e.str(value.Elem(),noIndent,separator,isRootObject)
|
||||
}
|
||||
|
||||
if value.Type().Implements(marshaler) {
|
||||
return e.useMarshaler(value, separator)
|
||||
}
|
||||
|
||||
switch kind {
|
||||
case reflect.String:
|
||||
e.quote(value.String(), separator, isRootObject)
|
||||
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
e.WriteString(separator)
|
||||
e.WriteString(strconv.FormatInt(value.Int(), 10))
|
||||
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64,
|
||||
reflect.Uintptr:
|
||||
e.WriteString(separator)
|
||||
e.WriteString(strconv.FormatUint(value.Uint(), 10))
|
||||
|
||||
case reflect.Float32, reflect.Float64:
|
||||
// JSON numbers must be finite. Encode non-finite numbers as null.
|
||||
e.WriteString(separator)
|
||||
number := value.Float()
|
||||
if math.IsInf(number, 0) || math.IsNaN(number) {
|
||||
e.WriteString("null")
|
||||
} else if !e.AllowMinusZero && number == -0 {
|
||||
e.WriteString("0")
|
||||
} else {
|
||||
// find shortest representation ('G' does not work)
|
||||
val := strconv.FormatFloat(number, 'f', -1, 64)
|
||||
exp := strconv.FormatFloat(number, 'E', -1, 64)
|
||||
if len(exp) < len(val) {
|
||||
val = strings.ToLower(exp)
|
||||
}
|
||||
e.WriteString(val)
|
||||
}
|
||||
|
||||
case reflect.Bool:
|
||||
e.WriteString(separator)
|
||||
if value.Bool() {
|
||||
e.WriteString("true")
|
||||
} else {
|
||||
e.WriteString("false")
|
||||
}
|
||||
|
||||
case reflect.Slice, reflect.Array:
|
||||
|
||||
len := value.Len()
|
||||
if len == 0 {
|
||||
e.WriteString(separator)
|
||||
e.WriteString("[]")
|
||||
break
|
||||
}
|
||||
|
||||
indent1 := e.indent
|
||||
e.indent++
|
||||
|
||||
if !noIndent && !e.BracesSameLine {
|
||||
e.writeIndent(indent1)
|
||||
} else {
|
||||
e.WriteString(separator)
|
||||
}
|
||||
e.WriteString("[")
|
||||
|
||||
// Join all of the element texts together, separated with newlines
|
||||
for i := 0; i < len; i++ {
|
||||
e.writeIndent(e.indent)
|
||||
if err := e.str(value.Index(i), true, "", false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
e.writeIndent(indent1)
|
||||
e.WriteString("]")
|
||||
|
||||
e.indent = indent1
|
||||
|
||||
case reflect.Map:
|
||||
|
||||
len := value.Len()
|
||||
if len == 0 {
|
||||
e.WriteString(separator)
|
||||
e.WriteString("{}")
|
||||
break
|
||||
}
|
||||
|
||||
indent1 := e.indent
|
||||
if !isRootObject || e.EmitRootBraces {
|
||||
if !noIndent && !e.BracesSameLine {
|
||||
e.writeIndent(e.indent)
|
||||
} else {
|
||||
e.WriteString(separator)
|
||||
}
|
||||
|
||||
e.indent++
|
||||
e.WriteString("{")
|
||||
}
|
||||
|
||||
keys := value.MapKeys()
|
||||
sort.Sort(sortAlpha(keys))
|
||||
|
||||
// Join all of the member texts together, separated with newlines
|
||||
for i := 0; i < len; i++ {
|
||||
if i > 0 || !isRootObject || e.EmitRootBraces {
|
||||
e.writeIndent(e.indent)
|
||||
}
|
||||
e.WriteString(e.quoteName(keys[i].String()))
|
||||
e.WriteString(":")
|
||||
if err := e.str(value.MapIndex(keys[i]), false, " ", false); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if !isRootObject || e.EmitRootBraces {
|
||||
e.writeIndent(indent1)
|
||||
e.WriteString("}")
|
||||
}
|
||||
e.indent = indent1
|
||||
|
||||
case reflect.Struct:
|
||||
|
||||
l := value.NumField()
|
||||
if l == 0 {
|
||||
e.WriteString(separator)
|
||||
e.WriteString("{}")
|
||||
break
|
||||
}
|
||||
|
||||
indent1 := e.indent
|
||||
if !isRootObject || e.EmitRootBraces {
|
||||
if !noIndent && !e.BracesSameLine {
|
||||
e.writeIndent(e.indent)
|
||||
} else {
|
||||
e.WriteString(separator)
|
||||
}
|
||||
|
||||
e.indent++
|
||||
e.WriteString("{")
|
||||
}
|
||||
|
||||
// Join all of the member texts together, separated with newlines
|
||||
for i := 0; i < l; i++ {
|
||||
curStructField := value.Type().Field(i)
|
||||
curField := value.Field(i)
|
||||
|
||||
name := curStructField.Name
|
||||
jsonTag := curStructField.Tag.Get("json")
|
||||
jsonComment := curStructField.Tag.Get("comment")
|
||||
omitEmpty := false
|
||||
if jsonTag == "-" {
|
||||
continue
|
||||
}
|
||||
splits := strings.Split(jsonTag, ",")
|
||||
if splits[0] != "" {
|
||||
name = splits[0]
|
||||
}
|
||||
if len(splits) > 1 {
|
||||
for _, opt := range splits[1:] {
|
||||
if opt == "omitempty" {
|
||||
omitEmpty = true
|
||||
}
|
||||
}
|
||||
}
|
||||
if omitEmpty && isEmptyValue(curField) {
|
||||
continue
|
||||
}
|
||||
if len(jsonComment) > 0 {
|
||||
for _, line := range strings.Split(jsonComment, e.Eol) {
|
||||
if i > 0 || !isRootObject || e.EmitRootBraces {
|
||||
e.writeIndent(e.indent)
|
||||
}
|
||||
e.WriteString(fmt.Sprintf("# %s", line))
|
||||
}
|
||||
}
|
||||
if i > 0 || !isRootObject || e.EmitRootBraces {
|
||||
e.writeIndent(e.indent)
|
||||
}
|
||||
e.WriteString(e.quoteName(name))
|
||||
e.WriteString(":")
|
||||
if err := e.str(curField, false, " ", false); err != nil {
|
||||
return err
|
||||
}
|
||||
if len(jsonComment) > 0 && i < l-1 {
|
||||
e.WriteString(e.Eol)
|
||||
}
|
||||
}
|
||||
|
||||
if !isRootObject || e.EmitRootBraces {
|
||||
e.writeIndent(indent1)
|
||||
e.WriteString("}")
|
||||
}
|
||||
|
||||
e.indent = indent1
|
||||
|
||||
default:
|
||||
if e.UnknownAsNull {
|
||||
// Use null as a placeholder for non-JSON values.
|
||||
e.WriteString("null")
|
||||
} else {
|
||||
return errors.New("Unsupported type " + value.Type().String())
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func isEmptyValue(v reflect.Value) bool {
|
||||
switch v.Kind() {
|
||||
case reflect.Array, reflect.Map, reflect.Slice, reflect.String:
|
||||
return v.Len() == 0
|
||||
case reflect.Bool:
|
||||
return !v.Bool()
|
||||
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
|
||||
return v.Int() == 0
|
||||
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
|
||||
return v.Uint() == 0
|
||||
case reflect.Float32, reflect.Float64:
|
||||
return v.Float() == 0
|
||||
case reflect.Interface, reflect.Ptr:
|
||||
return v.IsNil()
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Marshal returns the Hjson encoding of v using
|
||||
// default options.
|
||||
//
|
||||
// See MarshalWithOptions.
|
||||
//
|
||||
func Marshal(v interface{}) ([]byte, error) {
|
||||
return MarshalWithOptions(v, DefaultOptions())
|
||||
}
|
||||
|
||||
// MarshalWithOptions returns the Hjson encoding of v.
|
||||
//
|
||||
// Marshal traverses the value v recursively.
|
||||
//
|
||||
// Boolean values encode as JSON booleans.
|
||||
//
|
||||
// Floating point, integer, and Number values encode as JSON numbers.
|
||||
//
|
||||
// String values encode as Hjson strings (quoteless, multiline or
|
||||
// JSON).
|
||||
//
|
||||
// Array and slice values encode as JSON arrays.
|
||||
//
|
||||
// Map values encode as JSON objects. The map's key type must be a
|
||||
// string. The map keys are sorted and used as JSON object keys.
|
||||
//
|
||||
// Pointer values encode as the value pointed to.
|
||||
// A nil pointer encodes as the null JSON value.
|
||||
//
|
||||
// Interface values encode as the value contained in the interface.
|
||||
// A nil interface value encodes as the null JSON value.
|
||||
//
|
||||
// JSON cannot represent cyclic data structures and Marshal does not
|
||||
// handle them. Passing cyclic structures to Marshal will result in
|
||||
// an infinite recursion.
|
||||
//
|
||||
func MarshalWithOptions(v interface{}, options EncoderOptions) ([]byte, error) {
|
||||
e := &hjsonEncoder{}
|
||||
e.indent = 0
|
||||
e.Eol = options.Eol
|
||||
e.BracesSameLine = options.BracesSameLine
|
||||
e.EmitRootBraces = options.EmitRootBraces
|
||||
e.QuoteAlways = options.QuoteAlways
|
||||
e.QuoteAmbiguousStrings = options.QuoteAmbiguousStrings
|
||||
e.IndentBy = options.IndentBy
|
||||
e.BaseIndentation = options.BaseIndentation
|
||||
|
||||
err := e.str(reflect.ValueOf(v), true, e.BaseIndentation, true)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return e.Bytes(), nil
|
||||
}
|
||||
108
vendor/github.com/hjson/hjson-go/parseNumber.go
generated
vendored
Normal file
108
vendor/github.com/hjson/hjson-go/parseNumber.go
generated
vendored
Normal file
@@ -0,0 +1,108 @@
|
||||
package hjson
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type parseNumber struct {
|
||||
data []byte
|
||||
at int // The index of the current character
|
||||
ch byte // The current character
|
||||
}
|
||||
|
||||
func (p *parseNumber) next() bool {
|
||||
// get the next character.
|
||||
len := len(p.data)
|
||||
if p.at < len {
|
||||
p.ch = p.data[p.at]
|
||||
p.at++
|
||||
return true
|
||||
}
|
||||
if p.at == len {
|
||||
p.at++
|
||||
p.ch = 0
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *parseNumber) peek(offs int) byte {
|
||||
pos := p.at + offs
|
||||
if pos >= 0 && pos < len(p.data) {
|
||||
return p.data[pos]
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func startsWithNumber(text []byte) bool {
|
||||
if _, err := tryParseNumber(text, true); err == nil {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func tryParseNumber(text []byte, stopAtNext bool) (float64, error) {
|
||||
// Parse a number value.
|
||||
|
||||
p := parseNumber{text, 0, ' '}
|
||||
leadingZeros := 0
|
||||
testLeading := true
|
||||
p.next()
|
||||
if p.ch == '-' {
|
||||
p.next()
|
||||
}
|
||||
for p.ch >= '0' && p.ch <= '9' {
|
||||
if testLeading {
|
||||
if p.ch == '0' {
|
||||
leadingZeros++
|
||||
} else {
|
||||
testLeading = false
|
||||
}
|
||||
}
|
||||
p.next()
|
||||
}
|
||||
if testLeading {
|
||||
leadingZeros--
|
||||
} // single 0 is allowed
|
||||
if p.ch == '.' {
|
||||
for p.next() && p.ch >= '0' && p.ch <= '9' {
|
||||
}
|
||||
}
|
||||
if p.ch == 'e' || p.ch == 'E' {
|
||||
p.next()
|
||||
if p.ch == '-' || p.ch == '+' {
|
||||
p.next()
|
||||
}
|
||||
for p.ch >= '0' && p.ch <= '9' {
|
||||
p.next()
|
||||
}
|
||||
}
|
||||
|
||||
end := p.at
|
||||
|
||||
// skip white/to (newline)
|
||||
for p.ch > 0 && p.ch <= ' ' {
|
||||
p.next()
|
||||
}
|
||||
|
||||
if stopAtNext {
|
||||
// end scan if we find a punctuator character like ,}] or a comment
|
||||
if p.ch == ',' || p.ch == '}' || p.ch == ']' ||
|
||||
p.ch == '#' || p.ch == '/' && (p.peek(0) == '/' || p.peek(0) == '*') {
|
||||
p.ch = 0
|
||||
}
|
||||
}
|
||||
|
||||
if p.ch > 0 || leadingZeros != 0 {
|
||||
return 0, errors.New("Invalid number")
|
||||
}
|
||||
number, err := strconv.ParseFloat(string(p.data[0:end-1]), 64)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
if math.IsInf(number, 0) || math.IsNaN(number) {
|
||||
return 0, errors.New("Invalid number")
|
||||
}
|
||||
return number, nil
|
||||
}
|
||||
Reference in New Issue
Block a user