cmd/geth: add --config file flag (#13875)

* p2p/discover, p2p/discv5: add marshaling methods to Node

* p2p/netutil: make Netlist decodable from TOML

* common/math: encode nil HexOrDecimal256 as 0x0

* cmd/geth: add --config file flag

* cmd/geth: add missing license header

* eth: prettify Config again, fix tests

* eth: use gasprice.Config instead of duplicating its fields

* eth/gasprice: hide nil default from dumpconfig output

* cmd/geth: hide genesis block in dumpconfig output

* node: make tests compile

* console: fix tests

* cmd/geth: make TOML keys look exactly like Go struct fields

* p2p: use discovery by default

This makes the zero Config slightly more useful. It also fixes package
node tests because Node detects reuse of the datadir through the
NodeDatabase.

* cmd/geth: make ethstats URL settable through config file

* cmd/faucet: fix configuration

* cmd/geth: dedup attach tests

* eth: add comment for DefaultConfig

* eth: pass downloader.SyncMode in Config

This removes the FastSync, LightSync flags in favour of a more
general SyncMode flag.

* cmd/utils: remove jitvm flags

* cmd/utils: make mutually exclusive flag error prettier

It now reads:

   Fatal: flags --dev, --testnet can't be used at the same time

* p2p: fix typo

* node: add DefaultConfig, use it for geth

* mobile: add missing NoDiscovery option

* cmd/utils: drop MakeNode

This exposed a couple of places that needed to be updated to use
node.DefaultConfig.

* node: fix typo

* eth: make fast sync the default mode

* cmd/utils: remove IPCApiFlag (unused)

* node: remove default IPC path

Set it in the frontends instead.

* cmd/geth: add --syncmode

* cmd/utils: make --ipcdisable and --ipcpath mutually exclusive

* cmd/utils: don't enable WS, HTTP when setting addr

* cmd/utils: fix --identity
This commit is contained in:
Felix Lange
2017-04-12 16:27:23 +02:00
committed by Péter Szilágyi
parent b57680b0b2
commit 30d706c35e
55 changed files with 6620 additions and 653 deletions

19
vendor/github.com/naoina/go-stringutil/LICENSE generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2015 Naoya Inada <naoina@kuune.org>
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.

13
vendor/github.com/naoina/go-stringutil/README.md generated vendored Normal file
View File

@ -0,0 +1,13 @@
# stringutil [![Build Status](https://travis-ci.org/naoina/go-stringutil.svg?branch=master)](https://travis-ci.org/naoina/go-stringutil)
## Installation
go get -u github.com/naoina/go-stringutil
## Documentation
See https://godoc.org/github.com/naoina/go-stringutil
## License
MIT

253
vendor/github.com/naoina/go-stringutil/da.go generated vendored Normal file
View File

@ -0,0 +1,253 @@
package stringutil
import (
"fmt"
"sort"
"unicode/utf8"
)
const (
terminationCharacter = '#'
)
func mustDoubleArray(da *doubleArray, err error) *doubleArray {
if err != nil {
panic(err)
}
return da
}
func (da *doubleArray) Build(keys []string) error {
records := makeRecords(keys)
if err := da.build(records, 1, 0, make(map[int]struct{})); err != nil {
return err
}
return nil
}
type doubleArray struct {
bc []baseCheck
node []int
}
func newDoubleArray(keys []string) (*doubleArray, error) {
da := &doubleArray{
bc: []baseCheck{0},
node: []int{-1}, // A start index is adjusting to 1 because 0 will be used as a mark of non-existent node.
}
if err := da.Build(keys); err != nil {
return nil, err
}
return da, nil
}
// baseCheck contains BASE, CHECK and Extra flags.
// From the top, 22bits of BASE, 2bits of Extra flags and 8bits of CHECK.
//
// BASE (22bit) | Extra flags (2bit) | CHECK (8bit)
// |----------------------|--|--------|
// 32 10 8 0
type baseCheck uint32
func (bc baseCheck) Base() int {
return int(bc >> 10)
}
func (bc *baseCheck) SetBase(base int) {
*bc |= baseCheck(base) << 10
}
func (bc baseCheck) Check() byte {
return byte(bc)
}
func (bc *baseCheck) SetCheck(check byte) {
*bc |= baseCheck(check)
}
func (bc baseCheck) IsEmpty() bool {
return bc&0xfffffcff == 0
}
func (da *doubleArray) Lookup(path string) (length int) {
idx := 1
tmpIdx := idx
for i := 0; i < len(path); i++ {
c := path[i]
tmpIdx = da.nextIndex(da.bc[tmpIdx].Base(), c)
if tmpIdx >= len(da.bc) || da.bc[tmpIdx].Check() != c {
break
}
idx = tmpIdx
}
if next := da.nextIndex(da.bc[idx].Base(), terminationCharacter); next < len(da.bc) && da.bc[next].Check() == terminationCharacter {
return da.node[da.bc[next].Base()]
}
return -1
}
func (da *doubleArray) LookupByBytes(path []byte) (length int) {
idx := 1
tmpIdx := idx
for i := 0; i < len(path); i++ {
c := path[i]
tmpIdx = da.nextIndex(da.bc[tmpIdx].Base(), c)
if tmpIdx >= len(da.bc) || da.bc[tmpIdx].Check() != c {
break
}
idx = tmpIdx
}
if next := da.nextIndex(da.bc[idx].Base(), terminationCharacter); next < len(da.bc) && da.bc[next].Check() == terminationCharacter {
return da.node[da.bc[next].Base()]
}
return -1
}
func (da *doubleArray) build(srcs []record, idx, depth int, usedBase map[int]struct{}) error {
sort.Stable(recordSlice(srcs))
base, siblings, leaf, err := da.arrange(srcs, idx, depth, usedBase)
if err != nil {
return err
}
if leaf != nil {
da.bc[idx].SetBase(len(da.node))
da.node = append(da.node, leaf.value)
}
for _, sib := range siblings {
da.setCheck(da.nextIndex(base, sib.c), sib.c)
}
for _, sib := range siblings {
if err := da.build(srcs[sib.start:sib.end], da.nextIndex(base, sib.c), depth+1, usedBase); err != nil {
return err
}
}
return nil
}
func (da *doubleArray) setBase(i, base int) {
da.bc[i].SetBase(base)
}
func (da *doubleArray) setCheck(i int, check byte) {
da.bc[i].SetCheck(check)
}
func (da *doubleArray) findEmptyIndex(start int) int {
i := start
for ; i < len(da.bc); i++ {
if da.bc[i].IsEmpty() {
break
}
}
return i
}
// findBase returns good BASE.
func (da *doubleArray) findBase(siblings []sibling, start int, usedBase map[int]struct{}) (base int) {
for idx, firstChar := start+1, siblings[0].c; ; idx = da.findEmptyIndex(idx + 1) {
base = da.nextIndex(idx, firstChar)
if _, used := usedBase[base]; used {
continue
}
i := 0
for ; i < len(siblings); i++ {
next := da.nextIndex(base, siblings[i].c)
if len(da.bc) <= next {
da.bc = append(da.bc, make([]baseCheck, next-len(da.bc)+1)...)
}
if !da.bc[next].IsEmpty() {
break
}
}
if i == len(siblings) {
break
}
}
usedBase[base] = struct{}{}
return base
}
func (da *doubleArray) arrange(records []record, idx, depth int, usedBase map[int]struct{}) (base int, siblings []sibling, leaf *record, err error) {
siblings, leaf, err = makeSiblings(records, depth)
if err != nil {
return -1, nil, nil, err
}
if len(siblings) < 1 {
return -1, nil, leaf, nil
}
base = da.findBase(siblings, idx, usedBase)
da.setBase(idx, base)
return base, siblings, leaf, err
}
type sibling struct {
start int
end int
c byte
}
func (da *doubleArray) nextIndex(base int, c byte) int {
return base ^ int(c)
}
func makeSiblings(records []record, depth int) (sib []sibling, leaf *record, err error) {
var (
pc byte
n int
)
for i, r := range records {
if len(r.key) <= depth {
leaf = &r
continue
}
c := r.key[depth]
switch {
case pc < c:
sib = append(sib, sibling{start: i, c: c})
case pc == c:
continue
default:
return nil, nil, fmt.Errorf("stringutil: BUG: records hasn't been sorted")
}
if n > 0 {
sib[n-1].end = i
}
pc = c
n++
}
if n == 0 {
return nil, leaf, nil
}
sib[n-1].end = len(records)
return sib, leaf, nil
}
type record struct {
key string
value int
}
func makeRecords(srcs []string) (records []record) {
termChar := string(terminationCharacter)
for _, s := range srcs {
records = append(records, record{
key: string(s + termChar),
value: utf8.RuneCountInString(s),
})
}
return records
}
type recordSlice []record
func (rs recordSlice) Len() int {
return len(rs)
}
func (rs recordSlice) Less(i, j int) bool {
return rs[i].key < rs[j].key
}
func (rs recordSlice) Swap(i, j int) {
rs[i], rs[j] = rs[j], rs[i]
}

320
vendor/github.com/naoina/go-stringutil/strings.go generated vendored Normal file
View File

@ -0,0 +1,320 @@
package stringutil
import (
"sync"
"unicode"
"unicode/utf8"
)
var (
mu sync.Mutex
// Based on https://github.com/golang/lint/blob/32a87160691b3c96046c0c678fe57c5bef761456/lint.go#L702
commonInitialismMap = map[string]struct{}{
"API": struct{}{},
"ASCII": struct{}{},
"CPU": struct{}{},
"CSRF": struct{}{},
"CSS": struct{}{},
"DNS": struct{}{},
"EOF": struct{}{},
"GUID": struct{}{},
"HTML": struct{}{},
"HTTP": struct{}{},
"HTTPS": struct{}{},
"ID": struct{}{},
"IP": struct{}{},
"JSON": struct{}{},
"LHS": struct{}{},
"QPS": struct{}{},
"RAM": struct{}{},
"RHS": struct{}{},
"RPC": struct{}{},
"SLA": struct{}{},
"SMTP": struct{}{},
"SQL": struct{}{},
"SSH": struct{}{},
"TCP": struct{}{},
"TLS": struct{}{},
"TTL": struct{}{},
"UDP": struct{}{},
"UI": struct{}{},
"UID": struct{}{},
"UUID": struct{}{},
"URI": struct{}{},
"URL": struct{}{},
"UTF8": struct{}{},
"VM": struct{}{},
"XML": struct{}{},
"XSRF": struct{}{},
"XSS": struct{}{},
}
commonInitialisms = keys(commonInitialismMap)
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
longestLen = longestLength(commonInitialisms)
shortestLen = shortestLength(commonInitialisms, longestLen)
)
// ToUpperCamelCase returns a copy of the string s with all Unicode letters mapped to their camel case.
// It will convert to upper case previous letter of '_' and first letter, and remove letter of '_'.
func ToUpperCamelCase(s string) string {
if s == "" {
return ""
}
upper := true
start := 0
result := make([]byte, 0, len(s))
var runeBuf [utf8.UTFMax]byte
var initialism []byte
for _, c := range s {
if c == '_' {
upper = true
candidate := string(result[start:])
initialism = initialism[:0]
for _, r := range candidate {
if r < utf8.RuneSelf {
initialism = append(initialism, toUpperASCII(byte(r)))
} else {
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(r))
initialism = append(initialism, runeBuf[:n]...)
}
}
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
result = append(result[:start], initialism...)
}
start = len(result)
continue
}
if upper {
if c < utf8.RuneSelf {
result = append(result, toUpperASCII(byte(c)))
} else {
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(c))
result = append(result, runeBuf[:n]...)
}
upper = false
continue
}
if c < utf8.RuneSelf {
result = append(result, byte(c))
} else {
n := utf8.EncodeRune(runeBuf[:], c)
result = append(result, runeBuf[:n]...)
}
}
candidate := string(result[start:])
initialism = initialism[:0]
for _, r := range candidate {
if r < utf8.RuneSelf {
initialism = append(initialism, toUpperASCII(byte(r)))
} else {
n := utf8.EncodeRune(runeBuf[:], unicode.ToUpper(r))
initialism = append(initialism, runeBuf[:n]...)
}
}
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
result = append(result[:start], initialism...)
}
return string(result)
}
// ToUpperCamelCaseASCII is similar to ToUpperCamelCase, but optimized for
// only the ASCII characters.
// ToUpperCamelCaseASCII is faster than ToUpperCamelCase, but doesn't work if
// contains non-ASCII characters.
func ToUpperCamelCaseASCII(s string) string {
if s == "" {
return ""
}
upper := true
start := 0
result := make([]byte, 0, len(s))
var initialism []byte
for i := 0; i < len(s); i++ {
c := s[i]
if c == '_' {
upper = true
candidate := result[start:]
initialism = initialism[:0]
for _, b := range candidate {
initialism = append(initialism, toUpperASCII(b))
}
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
result = append(result[:start], initialism...)
}
start = len(result)
continue
}
if upper {
result = append(result, toUpperASCII(c))
upper = false
continue
}
result = append(result, c)
}
candidate := result[start:]
initialism = initialism[:0]
for _, b := range candidate {
initialism = append(initialism, toUpperASCII(b))
}
if length := commonInitialism.LookupByBytes(initialism); length > 0 {
result = append(result[:start], initialism...)
}
return string(result)
}
// ToSnakeCase returns a copy of the string s with all Unicode letters mapped to their snake case.
// It will insert letter of '_' at position of previous letter of uppercase and all
// letters convert to lower case.
// ToSnakeCase does not insert '_' letter into a common initialism word like ID, URL and so on.
func ToSnakeCase(s string) string {
if s == "" {
return ""
}
result := make([]byte, 0, len(s))
var runeBuf [utf8.UTFMax]byte
var j, skipCount int
for i, c := range s {
if i < skipCount {
continue
}
if unicode.IsUpper(c) {
if i != 0 {
result = append(result, '_')
}
next := nextIndex(j, len(s))
if length := commonInitialism.Lookup(s[j:next]); length > 0 {
for _, r := range s[j : j+length] {
if r < utf8.RuneSelf {
result = append(result, toLowerASCII(byte(r)))
} else {
n := utf8.EncodeRune(runeBuf[:], unicode.ToLower(r))
result = append(result, runeBuf[:n]...)
}
}
j += length - 1
skipCount = i + length
continue
}
}
if c < utf8.RuneSelf {
result = append(result, toLowerASCII(byte(c)))
} else {
n := utf8.EncodeRune(runeBuf[:], unicode.ToLower(c))
result = append(result, runeBuf[:n]...)
}
j++
}
return string(result)
}
// ToSnakeCaseASCII is similar to ToSnakeCase, but optimized for only the ASCII
// characters.
// ToSnakeCaseASCII is faster than ToSnakeCase, but doesn't work correctly if
// contains non-ASCII characters.
func ToSnakeCaseASCII(s string) string {
if s == "" {
return ""
}
result := make([]byte, 0, len(s))
for i := 0; i < len(s); i++ {
c := s[i]
if isUpperASCII(c) {
if i != 0 {
result = append(result, '_')
}
if k := i + shortestLen - 1; k < len(s) && isUpperASCII(s[k]) {
if length := commonInitialism.Lookup(s[i:nextIndex(i, len(s))]); length > 0 {
for j, buf := 0, s[i:i+length]; j < len(buf); j++ {
result = append(result, toLowerASCII(buf[j]))
}
i += length - 1
continue
}
}
}
result = append(result, toLowerASCII(c))
}
return string(result)
}
// AddCommonInitialism adds ss to list of common initialisms.
func AddCommonInitialism(ss ...string) {
mu.Lock()
defer mu.Unlock()
for _, s := range ss {
commonInitialismMap[s] = struct{}{}
}
commonInitialisms = keys(commonInitialismMap)
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
longestLen = longestLength(commonInitialisms)
shortestLen = shortestLength(commonInitialisms, longestLen)
}
// DelCommonInitialism deletes ss from list of common initialisms.
func DelCommonInitialism(ss ...string) {
mu.Lock()
defer mu.Unlock()
for _, s := range ss {
delete(commonInitialismMap, s)
}
commonInitialisms = keys(commonInitialismMap)
commonInitialism = mustDoubleArray(newDoubleArray(commonInitialisms))
longestLen = longestLength(commonInitialisms)
shortestLen = shortestLength(commonInitialisms, longestLen)
}
func isUpperASCII(c byte) bool {
return 'A' <= c && c <= 'Z'
}
func isLowerASCII(c byte) bool {
return 'a' <= c && c <= 'z'
}
func toUpperASCII(c byte) byte {
if isLowerASCII(c) {
return c - ('a' - 'A')
}
return c
}
func toLowerASCII(c byte) byte {
if isUpperASCII(c) {
return c + 'a' - 'A'
}
return c
}
func nextIndex(i, maxlen int) int {
if n := i + longestLen; n < maxlen {
return n
}
return maxlen
}
func keys(m map[string]struct{}) []string {
result := make([]string, 0, len(m))
for k := range m {
result = append(result, k)
}
return result
}
func shortestLength(strs []string, shortest int) int {
for _, s := range strs {
if candidate := utf8.RuneCountInString(s); candidate < shortest {
shortest = candidate
}
}
return shortest
}
func longestLength(strs []string) (longest int) {
for _, s := range strs {
if candidate := utf8.RuneCountInString(s); candidate > longest {
longest = candidate
}
}
return longest
}

19
vendor/github.com/naoina/toml/LICENSE generated vendored Normal file
View File

@ -0,0 +1,19 @@
Copyright (c) 2014 Naoya Inada <naoina@kuune.org>
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.

392
vendor/github.com/naoina/toml/README.md generated vendored Normal file
View File

@ -0,0 +1,392 @@
# TOML parser and encoder library for Golang [![Build Status](https://travis-ci.org/naoina/toml.png?branch=master)](https://travis-ci.org/naoina/toml)
[TOML](https://github.com/toml-lang/toml) parser and encoder library for [Golang](http://golang.org/).
This library is compatible with TOML version [v0.4.0](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md).
## Installation
go get -u github.com/naoina/toml
## Usage
The following TOML save as `example.toml`.
```toml
# This is a TOML document. Boom.
title = "TOML Example"
[owner]
name = "Lance Uppercut"
dob = 1979-05-27T07:32:00-08:00 # First class dates? Why not?
[database]
server = "192.168.1.1"
ports = [ 8001, 8001, 8002 ]
connection_max = 5000
enabled = true
[servers]
# You can indent as you please. Tabs or spaces. TOML don't care.
[servers.alpha]
ip = "10.0.0.1"
dc = "eqdc10"
[servers.beta]
ip = "10.0.0.2"
dc = "eqdc10"
[clients]
data = [ ["gamma", "delta"], [1, 2] ]
# Line breaks are OK when inside arrays
hosts = [
"alpha",
"omega"
]
```
Then above TOML will mapping to `tomlConfig` struct using `toml.Unmarshal`.
```go
package main
import (
"io/ioutil"
"os"
"time"
"github.com/naoina/toml"
)
type tomlConfig struct {
Title string
Owner struct {
Name string
Dob time.Time
}
Database struct {
Server string
Ports []int
ConnectionMax uint
Enabled bool
}
Servers map[string]ServerInfo
Clients struct {
Data [][]interface{}
Hosts []string
}
}
type ServerInfo struct {
IP net.IP
DC string
}
func main() {
f, err := os.Open("example.toml")
if err != nil {
panic(err)
}
defer f.Close()
var config Config
if err := toml.NewDecoder(f).Decode(&config); err != nil {
panic(err)
}
// then to use the unmarshaled config...
fmt.Println("IP of server 'alpha':", config.Servers["alpha"].IP)
}
```
## Mappings
A key and value of TOML will map to the corresponding field.
The fields of struct for mapping must be exported.
The rules of the mapping of key are following:
#### Exact matching
```toml
timeout_seconds = 256
```
```go
type Config struct {
Timeout_seconds int
}
```
#### Camelcase matching
```toml
server_name = "srv1"
```
```go
type Config struct {
ServerName string
}
```
#### Uppercase matching
```toml
ip = "10.0.0.1"
```
```go
type Config struct {
IP string
}
```
See the following examples for the value mappings.
### String
```toml
val = "string"
```
```go
type Config struct {
Val string
}
```
### Integer
```toml
val = 100
```
```go
type Config struct {
Val int
}
```
All types that can be used are following:
* int8 (from `-128` to `127`)
* int16 (from `-32768` to `32767`)
* int32 (from `-2147483648` to `2147483647`)
* int64 (from `-9223372036854775808` to `9223372036854775807`)
* int (same as `int32` on 32bit environment, or `int64` on 64bit environment)
* uint8 (from `0` to `255`)
* uint16 (from `0` to `65535`)
* uint32 (from `0` to `4294967295`)
* uint64 (from `0` to `18446744073709551615`)
* uint (same as `uint` on 32bit environment, or `uint64` on 64bit environment)
### Float
```toml
val = 3.1415
```
```go
type Config struct {
Val float32
}
```
All types that can be used are following:
* float32
* float64
### Boolean
```toml
val = true
```
```go
type Config struct {
Val bool
}
```
### Datetime
```toml
val = 2014-09-28T21:27:39Z
```
```go
type Config struct {
Val time.Time
}
```
### Array
```toml
val = ["a", "b", "c"]
```
```go
type Config struct {
Val []string
}
```
Also following examples all can be mapped:
```toml
val1 = [1, 2, 3]
val2 = [["a", "b"], ["c", "d"]]
val3 = [[1, 2, 3], ["a", "b", "c"]]
val4 = [[1, 2, 3], [["a", "b"], [true, false]]]
```
```go
type Config struct {
Val1 []int
Val2 [][]string
Val3 [][]interface{}
Val4 [][]interface{}
}
```
### Table
```toml
[server]
type = "app"
[server.development]
ip = "10.0.0.1"
[server.production]
ip = "10.0.0.2"
```
```go
type Config struct {
Server map[string]Server
}
type Server struct {
IP string
}
```
You can also use the following struct instead of map of struct.
```go
type Config struct {
Server struct {
Development Server
Production Server
}
}
type Server struct {
IP string
}
```
### Array of Tables
```toml
[[fruit]]
name = "apple"
[fruit.physical]
color = "red"
shape = "round"
[[fruit.variety]]
name = "red delicious"
[[fruit.variety]]
name = "granny smith"
[[fruit]]
name = "banana"
[[fruit.variety]]
name = "plantain"
```
```go
type Config struct {
Fruit []struct {
Name string
Physical struct {
Color string
Shape string
}
Variety []struct {
Name string
}
}
}
```
### Using the `encoding.TextUnmarshaler` interface
Package toml supports `encoding.TextUnmarshaler` (and `encoding.TextMarshaler`). You can
use it to apply custom marshaling rules for certain types. The `UnmarshalText` method is
called with the value text found in the TOML input. TOML strings are passed unquoted.
```toml
duration = "10s"
```
```go
import time
type Duration time.Duration
// UnmarshalText implements encoding.TextUnmarshaler
func (d *Duration) UnmarshalText(data []byte) error {
duration, err := time.ParseDuration(string(data))
if err == nil {
*d = Duration(duration)
}
return err
}
// MarshalText implements encoding.TextMarshaler
func (d Duration) MarshalText() ([]byte, error) {
return []byte(time.Duration(d).String()), nil
}
type ConfigWithDuration struct {
Duration Duration
}
```
### Using the `toml.UnmarshalerRec` interface
You can also override marshaling rules specifically for TOML using the `UnmarshalerRec`
and `MarshalerRec` interfaces. These are useful if you want to control how structs or
arrays are handled. You can apply additional validation or set unexported struct fields.
Note: `encoding.TextUnmarshaler` and `encoding.TextMarshaler` should be preferred for
simple (scalar) values because they're also compatible with other formats like JSON or
YAML.
[See the UnmarshalerRec example](https://godoc.org/github.com/naoina/toml/#example_UnmarshalerRec).
### Using the `toml.Unmarshaler` interface
If you want to deal with raw TOML syntax, use the `Unmarshaler` and `Marshaler`
interfaces. Their input and output is raw TOML syntax. As such, these interfaces are
useful if you want to handle TOML at the syntax level.
[See the Unmarshaler example](https://godoc.org/github.com/naoina/toml/#example_Unmarshaler).
## API documentation
See [Godoc](http://godoc.org/github.com/naoina/toml).
## License
MIT

192
vendor/github.com/naoina/toml/ast/ast.go generated vendored Normal file
View File

@ -0,0 +1,192 @@
package ast
import (
"strconv"
"strings"
"time"
)
type Position struct {
Begin int
End int
}
type Value interface {
Pos() int
End() int
Source() string
}
type String struct {
Position Position
Value string
Data []rune
}
func (s *String) Pos() int {
return s.Position.Begin
}
func (s *String) End() int {
return s.Position.End
}
func (s *String) Source() string {
return string(s.Data)
}
type Integer struct {
Position Position
Value string
Data []rune
}
func (i *Integer) Pos() int {
return i.Position.Begin
}
func (i *Integer) End() int {
return i.Position.End
}
func (i *Integer) Source() string {
return string(i.Data)
}
func (i *Integer) Int() (int64, error) {
return strconv.ParseInt(i.Value, 10, 64)
}
type Float struct {
Position Position
Value string
Data []rune
}
func (f *Float) Pos() int {
return f.Position.Begin
}
func (f *Float) End() int {
return f.Position.End
}
func (f *Float) Source() string {
return string(f.Data)
}
func (f *Float) Float() (float64, error) {
return strconv.ParseFloat(f.Value, 64)
}
type Boolean struct {
Position Position
Value string
Data []rune
}
func (b *Boolean) Pos() int {
return b.Position.Begin
}
func (b *Boolean) End() int {
return b.Position.End
}
func (b *Boolean) Source() string {
return string(b.Data)
}
func (b *Boolean) Boolean() (bool, error) {
return strconv.ParseBool(b.Value)
}
type Datetime struct {
Position Position
Value string
Data []rune
}
func (d *Datetime) Pos() int {
return d.Position.Begin
}
func (d *Datetime) End() int {
return d.Position.End
}
func (d *Datetime) Source() string {
return string(d.Data)
}
func (d *Datetime) Time() (time.Time, error) {
switch {
case !strings.Contains(d.Value, ":"):
return time.Parse("2006-01-02", d.Value)
case !strings.Contains(d.Value, "-"):
return time.Parse("15:04:05.999999999", d.Value)
default:
return time.Parse(time.RFC3339Nano, d.Value)
}
}
type Array struct {
Position Position
Value []Value
Data []rune
}
func (a *Array) Pos() int {
return a.Position.Begin
}
func (a *Array) End() int {
return a.Position.End
}
func (a *Array) Source() string {
return string(a.Data)
}
type TableType uint8
const (
TableTypeNormal TableType = iota
TableTypeArray
)
var tableTypes = [...]string{
"normal",
"array",
}
func (t TableType) String() string {
return tableTypes[t]
}
type Table struct {
Position Position
Line int
Name string
Fields map[string]interface{}
Type TableType
Data []rune
}
func (t *Table) Pos() int {
return t.Position.Begin
}
func (t *Table) End() int {
return t.Position.End
}
func (t *Table) Source() string {
return string(t.Data)
}
type KeyValue struct {
Key string
Value Value
Line int
}

86
vendor/github.com/naoina/toml/config.go generated vendored Normal file
View File

@ -0,0 +1,86 @@
package toml
import (
"fmt"
"io"
"reflect"
"strings"
stringutil "github.com/naoina/go-stringutil"
"github.com/naoina/toml/ast"
)
// Config contains options for encoding and decoding.
type Config struct {
// NormFieldName is used to match TOML keys to struct fields. The function runs for
// both input keys and struct field names and should return a string that makes the
// two match. You must set this field to use the decoder.
//
// Example: The function in the default config removes _ and lowercases all keys. This
// allows a key called 'api_key' to match the struct field 'APIKey' because both are
// normalized to 'apikey'.
//
// Note that NormFieldName is not used for fields which define a TOML
// key through the struct tag.
NormFieldName func(typ reflect.Type, keyOrField string) string
// FieldToKey determines the TOML key of a struct field when encoding.
// You must set this field to use the encoder.
//
// Note that FieldToKey is not used for fields which define a TOML
// key through the struct tag.
FieldToKey func(typ reflect.Type, field string) string
// MissingField, if non-nil, is called when the decoder encounters a key for which no
// matching struct field exists. The default behavior is to return an error.
MissingField func(typ reflect.Type, key string) error
}
// DefaultConfig contains the default options for encoding and decoding.
// Snake case (i.e. 'foo_bar') is used for key names.
var DefaultConfig = Config{
NormFieldName: defaultNormFieldName,
FieldToKey: snakeCase,
}
func defaultNormFieldName(typ reflect.Type, s string) string {
return strings.Replace(strings.ToLower(s), "_", "", -1)
}
func snakeCase(typ reflect.Type, s string) string {
return stringutil.ToSnakeCase(s)
}
func defaultMissingField(typ reflect.Type, key string) error {
return fmt.Errorf("field corresponding to `%s' is not defined in %v", key, typ)
}
// NewEncoder returns a new Encoder that writes to w.
// It is shorthand for DefaultConfig.NewEncoder(w).
func NewEncoder(w io.Writer) *Encoder {
return DefaultConfig.NewEncoder(w)
}
// Marshal returns the TOML encoding of v.
// It is shorthand for DefaultConfig.Marshal(v).
func Marshal(v interface{}) ([]byte, error) {
return DefaultConfig.Marshal(v)
}
// Unmarshal parses the TOML data and stores the result in the value pointed to by v.
// It is shorthand for DefaultConfig.Unmarshal(data, v).
func Unmarshal(data []byte, v interface{}) error {
return DefaultConfig.Unmarshal(data, v)
}
// UnmarshalTable applies the contents of an ast.Table to the value pointed at by v.
// It is shorthand for DefaultConfig.UnmarshalTable(t, v).
func UnmarshalTable(t *ast.Table, v interface{}) error {
return DefaultConfig.UnmarshalTable(t, v)
}
// NewDecoder returns a new Decoder that reads from r.
// It is shorthand for DefaultConfig.NewDecoder(r).
func NewDecoder(r io.Reader) *Decoder {
return DefaultConfig.NewDecoder(r)
}

478
vendor/github.com/naoina/toml/decode.go generated vendored Normal file
View File

@ -0,0 +1,478 @@
// Package toml encodes and decodes the TOML configuration format using reflection.
//
// This library is compatible with TOML version v0.4.0.
package toml
import (
"encoding"
"fmt"
"io"
"io/ioutil"
"reflect"
"strconv"
"strings"
"time"
"github.com/naoina/toml/ast"
)
const (
tableSeparator = '.'
)
var (
escapeReplacer = strings.NewReplacer(
"\b", "\\n",
"\f", "\\f",
"\n", "\\n",
"\r", "\\r",
"\t", "\\t",
)
underscoreReplacer = strings.NewReplacer(
"_", "",
)
)
var timeType = reflect.TypeOf(time.Time{})
// Unmarshal parses the TOML data and stores the result in the value pointed to by v.
//
// Unmarshal will mapped to v that according to following rules:
//
// TOML strings to string
// TOML integers to any int type
// TOML floats to float32 or float64
// TOML booleans to bool
// TOML datetimes to time.Time
// TOML arrays to any type of slice
// TOML tables to struct or map
// TOML array tables to slice of struct or map
func (cfg *Config) Unmarshal(data []byte, v interface{}) error {
table, err := Parse(data)
if err != nil {
return err
}
if err := cfg.UnmarshalTable(table, v); err != nil {
return err
}
return nil
}
// A Decoder reads and decodes TOML from an input stream.
type Decoder struct {
r io.Reader
cfg *Config
}
// NewDecoder returns a new Decoder that reads from r.
// Note that it reads all from r before parsing it.
func (cfg *Config) NewDecoder(r io.Reader) *Decoder {
return &Decoder{r, cfg}
}
// Decode parses the TOML data from its input and stores it in the value pointed to by v.
// See the documentation for Unmarshal for details about the conversion of TOML into a Go value.
func (d *Decoder) Decode(v interface{}) error {
b, err := ioutil.ReadAll(d.r)
if err != nil {
return err
}
return d.cfg.Unmarshal(b, v)
}
// UnmarshalerRec may be implemented by types to customize their behavior when being
// unmarshaled from TOML. You can use it to implement custom validation or to set
// unexported fields.
//
// UnmarshalTOML receives a function that can be called to unmarshal the original TOML
// value into a field or variable. It is safe to call the function more than once if
// necessary.
type UnmarshalerRec interface {
UnmarshalTOML(fn func(interface{}) error) error
}
// Unmarshaler can be used to capture and process raw TOML source of a table or value.
// UnmarshalTOML must copy the input if it wishes to retain it after returning.
//
// Note: this interface is retained for backwards compatibility. You probably want
// to implement encoding.TextUnmarshaler or UnmarshalerRec instead.
type Unmarshaler interface {
UnmarshalTOML(input []byte) error
}
// UnmarshalTable applies the contents of an ast.Table to the value pointed at by v.
//
// UnmarshalTable will mapped to v that according to following rules:
//
// TOML strings to string
// TOML integers to any int type
// TOML floats to float32 or float64
// TOML booleans to bool
// TOML datetimes to time.Time
// TOML arrays to any type of slice
// TOML tables to struct or map
// TOML array tables to slice of struct or map
func (cfg *Config) UnmarshalTable(t *ast.Table, v interface{}) error {
rv := reflect.ValueOf(v)
toplevelMap := rv.Kind() == reflect.Map
if (!toplevelMap && rv.Kind() != reflect.Ptr) || rv.IsNil() {
return &invalidUnmarshalError{reflect.TypeOf(v)}
}
return unmarshalTable(cfg, rv, t, toplevelMap)
}
// used for UnmarshalerRec.
func unmarshalTableOrValue(cfg *Config, rv reflect.Value, av interface{}) error {
if (rv.Kind() != reflect.Ptr && rv.Kind() != reflect.Map) || rv.IsNil() {
return &invalidUnmarshalError{rv.Type()}
}
rv = indirect(rv)
switch av.(type) {
case *ast.KeyValue, *ast.Table, []*ast.Table:
if err := unmarshalField(cfg, rv, av); err != nil {
return lineError(fieldLineNumber(av), err)
}
return nil
case ast.Value:
return setValue(cfg, rv, av.(ast.Value))
default:
panic(fmt.Sprintf("BUG: unhandled AST node type %T", av))
}
}
// unmarshalTable unmarshals the fields of a table into a struct or map.
//
// toplevelMap is true when rv is an (unadressable) map given to UnmarshalTable. In this
// (special) case, the map is used as-is instead of creating a new map.
func unmarshalTable(cfg *Config, rv reflect.Value, t *ast.Table, toplevelMap bool) error {
rv = indirect(rv)
if err, ok := setUnmarshaler(cfg, rv, t); ok {
return lineError(t.Line, err)
}
switch {
case rv.Kind() == reflect.Struct:
fc := makeFieldCache(cfg, rv.Type())
for key, fieldAst := range t.Fields {
fv, fieldName, err := fc.findField(cfg, rv, key)
if err != nil {
return lineError(fieldLineNumber(fieldAst), err)
}
if fv.IsValid() {
if err := unmarshalField(cfg, fv, fieldAst); err != nil {
return lineErrorField(fieldLineNumber(fieldAst), rv.Type().String()+"."+fieldName, err)
}
}
}
case rv.Kind() == reflect.Map || isEface(rv):
m := rv
if !toplevelMap {
if rv.Kind() == reflect.Interface {
m = reflect.ValueOf(make(map[string]interface{}))
} else {
m = reflect.MakeMap(rv.Type())
}
}
elemtyp := m.Type().Elem()
for key, fieldAst := range t.Fields {
kv, err := unmarshalMapKey(m.Type().Key(), key)
if err != nil {
return lineError(fieldLineNumber(fieldAst), err)
}
fv := reflect.New(elemtyp).Elem()
if err := unmarshalField(cfg, fv, fieldAst); err != nil {
return lineError(fieldLineNumber(fieldAst), err)
}
m.SetMapIndex(kv, fv)
}
if !toplevelMap {
rv.Set(m)
}
default:
return lineError(t.Line, &unmarshalTypeError{"table", "struct or map", rv.Type()})
}
return nil
}
func fieldLineNumber(fieldAst interface{}) int {
switch av := fieldAst.(type) {
case *ast.KeyValue:
return av.Line
case *ast.Table:
return av.Line
case []*ast.Table:
return av[0].Line
default:
panic(fmt.Sprintf("BUG: unhandled node type %T", fieldAst))
}
}
func unmarshalField(cfg *Config, rv reflect.Value, fieldAst interface{}) error {
switch av := fieldAst.(type) {
case *ast.KeyValue:
return setValue(cfg, rv, av.Value)
case *ast.Table:
return unmarshalTable(cfg, rv, av, false)
case []*ast.Table:
rv = indirect(rv)
if err, ok := setUnmarshaler(cfg, rv, fieldAst); ok {
return err
}
var slice reflect.Value
switch {
case rv.Kind() == reflect.Slice:
slice = reflect.MakeSlice(rv.Type(), len(av), len(av))
case isEface(rv):
slice = reflect.ValueOf(make([]interface{}, len(av)))
default:
return &unmarshalTypeError{"array table", "slice", rv.Type()}
}
for i, tbl := range av {
vv := reflect.New(slice.Type().Elem()).Elem()
if err := unmarshalTable(cfg, vv, tbl, false); err != nil {
return err
}
slice.Index(i).Set(vv)
}
rv.Set(slice)
default:
panic(fmt.Sprintf("BUG: unhandled AST node type %T", av))
}
return nil
}
func unmarshalMapKey(typ reflect.Type, key string) (reflect.Value, error) {
rv := reflect.New(typ).Elem()
if u, ok := rv.Addr().Interface().(encoding.TextUnmarshaler); ok {
return rv, u.UnmarshalText([]byte(key))
}
switch typ.Kind() {
case reflect.String:
rv.SetString(key)
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
i, err := strconv.ParseInt(key, 10, int(typ.Size()*8))
if err != nil {
return rv, convertNumError(typ.Kind(), err)
}
rv.SetInt(i)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
i, err := strconv.ParseUint(key, 10, int(typ.Size()*8))
if err != nil {
return rv, convertNumError(typ.Kind(), err)
}
rv.SetUint(i)
default:
return rv, fmt.Errorf("invalid map key type %s", typ)
}
return rv, nil
}
func setValue(cfg *Config, lhs reflect.Value, val ast.Value) error {
lhs = indirect(lhs)
if err, ok := setUnmarshaler(cfg, lhs, val); ok {
return err
}
if err, ok := setTextUnmarshaler(lhs, val); ok {
return err
}
switch v := val.(type) {
case *ast.Integer:
return setInt(lhs, v)
case *ast.Float:
return setFloat(lhs, v)
case *ast.String:
return setString(lhs, v)
case *ast.Boolean:
return setBoolean(lhs, v)
case *ast.Datetime:
return setDatetime(lhs, v)
case *ast.Array:
return setArray(cfg, lhs, v)
default:
panic(fmt.Sprintf("BUG: unhandled node type %T", v))
}
}
func indirect(rv reflect.Value) reflect.Value {
for rv.Kind() == reflect.Ptr {
if rv.IsNil() {
rv.Set(reflect.New(rv.Type().Elem()))
}
rv = rv.Elem()
}
return rv
}
func setUnmarshaler(cfg *Config, lhs reflect.Value, av interface{}) (error, bool) {
if lhs.CanAddr() {
if u, ok := lhs.Addr().Interface().(UnmarshalerRec); ok {
err := u.UnmarshalTOML(func(v interface{}) error {
return unmarshalTableOrValue(cfg, reflect.ValueOf(v), av)
})
return err, true
}
if u, ok := lhs.Addr().Interface().(Unmarshaler); ok {
return u.UnmarshalTOML(unmarshalerSource(av)), true
}
}
return nil, false
}
func unmarshalerSource(av interface{}) []byte {
var source []byte
switch av := av.(type) {
case []*ast.Table:
for i, tab := range av {
source = append(source, tab.Source()...)
if i != len(av)-1 {
source = append(source, '\n')
}
}
case ast.Value:
source = []byte(av.Source())
default:
panic(fmt.Sprintf("BUG: unhandled node type %T", av))
}
return source
}
func setTextUnmarshaler(lhs reflect.Value, val ast.Value) (error, bool) {
if !lhs.CanAddr() {
return nil, false
}
u, ok := lhs.Addr().Interface().(encoding.TextUnmarshaler)
if !ok || lhs.Type() == timeType {
return nil, false
}
var data string
switch val := val.(type) {
case *ast.Array:
return &unmarshalTypeError{"array", "", lhs.Type()}, true
case *ast.String:
data = val.Value
default:
data = val.Source()
}
return u.UnmarshalText([]byte(data)), true
}
func setInt(fv reflect.Value, v *ast.Integer) error {
k := fv.Kind()
switch {
case k >= reflect.Int && k <= reflect.Int64:
i, err := strconv.ParseInt(v.Value, 10, int(fv.Type().Size()*8))
if err != nil {
return convertNumError(fv.Kind(), err)
}
fv.SetInt(i)
case k >= reflect.Uint && k <= reflect.Uintptr:
i, err := strconv.ParseUint(v.Value, 10, int(fv.Type().Size()*8))
if err != nil {
return convertNumError(fv.Kind(), err)
}
fv.SetUint(i)
case isEface(fv):
i, err := strconv.ParseInt(v.Value, 10, 64)
if err != nil {
return convertNumError(reflect.Int64, err)
}
fv.Set(reflect.ValueOf(i))
default:
return &unmarshalTypeError{"integer", "", fv.Type()}
}
return nil
}
func setFloat(fv reflect.Value, v *ast.Float) error {
f, err := v.Float()
if err != nil {
return err
}
switch {
case fv.Kind() == reflect.Float32 || fv.Kind() == reflect.Float64:
if fv.OverflowFloat(f) {
return &overflowError{fv.Kind(), v.Value}
}
fv.SetFloat(f)
case isEface(fv):
fv.Set(reflect.ValueOf(f))
default:
return &unmarshalTypeError{"float", "", fv.Type()}
}
return nil
}
func setString(fv reflect.Value, v *ast.String) error {
switch {
case fv.Kind() == reflect.String:
fv.SetString(v.Value)
case isEface(fv):
fv.Set(reflect.ValueOf(v.Value))
default:
return &unmarshalTypeError{"string", "", fv.Type()}
}
return nil
}
func setBoolean(fv reflect.Value, v *ast.Boolean) error {
b, _ := v.Boolean()
switch {
case fv.Kind() == reflect.Bool:
fv.SetBool(b)
case isEface(fv):
fv.Set(reflect.ValueOf(b))
default:
return &unmarshalTypeError{"boolean", "", fv.Type()}
}
return nil
}
func setDatetime(rv reflect.Value, v *ast.Datetime) error {
t, err := v.Time()
if err != nil {
return err
}
if !timeType.AssignableTo(rv.Type()) {
return &unmarshalTypeError{"datetime", "", rv.Type()}
}
rv.Set(reflect.ValueOf(t))
return nil
}
func setArray(cfg *Config, rv reflect.Value, v *ast.Array) error {
var slicetyp reflect.Type
switch {
case rv.Kind() == reflect.Slice:
slicetyp = rv.Type()
case isEface(rv):
slicetyp = reflect.SliceOf(rv.Type())
default:
return &unmarshalTypeError{"array", "slice", rv.Type()}
}
if len(v.Value) == 0 {
// Ensure defined slices are always set to a non-nil value.
rv.Set(reflect.MakeSlice(slicetyp, 0, 0))
return nil
}
tomltyp := reflect.TypeOf(v.Value[0])
slice := reflect.MakeSlice(slicetyp, len(v.Value), len(v.Value))
typ := slicetyp.Elem()
for i, vv := range v.Value {
if i > 0 && tomltyp != reflect.TypeOf(vv) {
return errArrayMultiType
}
tmp := reflect.New(typ).Elem()
if err := setValue(cfg, tmp, vv); err != nil {
return err
}
slice.Index(i).Set(tmp)
}
rv.Set(slice)
return nil
}
func isEface(rv reflect.Value) bool {
return rv.Kind() == reflect.Interface && rv.Type().NumMethod() == 0
}

398
vendor/github.com/naoina/toml/encode.go generated vendored Normal file
View File

@ -0,0 +1,398 @@
package toml
import (
"bytes"
"encoding"
"fmt"
"io"
"reflect"
"sort"
"strconv"
"time"
"github.com/naoina/toml/ast"
)
const (
tagOmitempty = "omitempty"
tagSkip = "-"
)
// Marshal returns the TOML encoding of v.
//
// Struct values encode as TOML. Each exported struct field becomes a field of
// the TOML structure unless
// - the field's tag is "-", or
// - the field is empty and its tag specifies the "omitempty" option.
//
// The "toml" key in the struct field's tag value is the key name, followed by
// an optional comma and options. Examples:
//
// // Field is ignored by this package.
// Field int `toml:"-"`
//
// // Field appears in TOML as key "myName".
// Field int `toml:"myName"`
//
// // Field appears in TOML as key "myName" and the field is omitted from the
// // result of encoding if its value is empty.
// Field int `toml:"myName,omitempty"`
//
// // Field appears in TOML as key "field", but the field is skipped if
// // empty. Note the leading comma.
// Field int `toml:",omitempty"`
func (cfg *Config) Marshal(v interface{}) ([]byte, error) {
buf := new(bytes.Buffer)
err := cfg.NewEncoder(buf).Encode(v)
return buf.Bytes(), err
}
// A Encoder writes TOML to an output stream.
type Encoder struct {
w io.Writer
cfg *Config
}
// NewEncoder returns a new Encoder that writes to w.
func (cfg *Config) NewEncoder(w io.Writer) *Encoder {
return &Encoder{w, cfg}
}
// Encode writes the TOML of v to the stream.
// See the documentation for Marshal for details about the conversion of Go values to TOML.
func (e *Encoder) Encode(v interface{}) error {
rv := reflect.ValueOf(v)
for rv.Kind() == reflect.Ptr {
if rv.IsNil() {
return &marshalNilError{rv.Type()}
}
rv = rv.Elem()
}
buf := &tableBuf{typ: ast.TableTypeNormal}
var err error
switch rv.Kind() {
case reflect.Struct:
err = buf.structFields(e.cfg, rv)
case reflect.Map:
err = buf.mapFields(e.cfg, rv)
default:
err = &marshalTableError{rv.Type()}
}
if err != nil {
return err
}
return buf.writeTo(e.w, "")
}
// Marshaler can be implemented to override the encoding of TOML values. The returned text
// must be a simple TOML value (i.e. not a table) and is inserted into marshaler output.
//
// This interface exists for backwards-compatibility reasons. You probably want to
// implement encoding.TextMarshaler or MarshalerRec instead.
type Marshaler interface {
MarshalTOML() ([]byte, error)
}
// MarshalerRec can be implemented to override the TOML encoding of a type.
// The returned value is marshaled in place of the receiver.
type MarshalerRec interface {
MarshalTOML() (interface{}, error)
}
type tableBuf struct {
name string // already escaped / quoted
body []byte
children []*tableBuf
typ ast.TableType
arrayDepth int
}
func (b *tableBuf) writeTo(w io.Writer, prefix string) error {
key := b.name // TODO: escape dots
if prefix != "" {
key = prefix + "." + key
}
if b.name != "" {
head := "[" + key + "]"
if b.typ == ast.TableTypeArray {
head = "[" + head + "]"
}
head += "\n"
if _, err := io.WriteString(w, head); err != nil {
return err
}
}
if _, err := w.Write(b.body); err != nil {
return err
}
for i, child := range b.children {
if len(b.body) > 0 || i > 0 {
if _, err := w.Write([]byte("\n")); err != nil {
return err
}
}
if err := child.writeTo(w, key); err != nil {
return err
}
}
return nil
}
func (b *tableBuf) newChild(name string) *tableBuf {
child := &tableBuf{name: quoteName(name), typ: ast.TableTypeNormal}
if b.arrayDepth > 0 {
child.typ = ast.TableTypeArray
}
return child
}
func (b *tableBuf) addChild(child *tableBuf) {
// Empty table elision: we can avoid writing a table that doesn't have any keys on its
// own. Array tables can't be elided because they define array elements (which would
// be missing if elided).
if len(child.body) == 0 && child.typ == ast.TableTypeNormal {
for _, gchild := range child.children {
gchild.name = child.name + "." + gchild.name
b.addChild(gchild)
}
return
}
b.children = append(b.children, child)
}
func (b *tableBuf) structFields(cfg *Config, rv reflect.Value) error {
rt := rv.Type()
for i := 0; i < rv.NumField(); i++ {
ft := rt.Field(i)
if ft.PkgPath != "" && !ft.Anonymous { // not exported
continue
}
name, rest := extractTag(ft.Tag.Get(fieldTagName))
if name == tagSkip {
continue
}
fv := rv.Field(i)
if rest == tagOmitempty && isEmptyValue(fv) {
continue
}
if name == "" {
name = cfg.FieldToKey(rt, ft.Name)
}
if err := b.field(cfg, name, fv); err != nil {
return err
}
}
return nil
}
type mapKeyList []struct {
key string
value reflect.Value
}
func (l mapKeyList) Len() int { return len(l) }
func (l mapKeyList) Swap(i, j int) { l[i], l[j] = l[j], l[i] }
func (l mapKeyList) Less(i, j int) bool { return l[i].key < l[j].key }
func (b *tableBuf) mapFields(cfg *Config, rv reflect.Value) error {
keys := rv.MapKeys()
keylist := make(mapKeyList, len(keys))
for i, key := range keys {
var err error
keylist[i].key, err = encodeMapKey(key)
if err != nil {
return err
}
keylist[i].value = rv.MapIndex(key)
}
sort.Sort(keylist)
for _, kv := range keylist {
if err := b.field(cfg, kv.key, kv.value); err != nil {
return err
}
}
return nil
}
func (b *tableBuf) field(cfg *Config, name string, rv reflect.Value) error {
off := len(b.body)
b.body = append(b.body, quoteName(name)...)
b.body = append(b.body, " = "...)
isTable, err := b.value(cfg, rv, name)
if isTable {
b.body = b.body[:off] // rub out "key ="
} else {
b.body = append(b.body, '\n')
}
return err
}
func (b *tableBuf) value(cfg *Config, rv reflect.Value, name string) (bool, error) {
isMarshaler, isTable, err := b.marshaler(cfg, rv, name)
if isMarshaler {
return isTable, err
}
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
b.body = strconv.AppendInt(b.body, rv.Int(), 10)
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
b.body = strconv.AppendUint(b.body, rv.Uint(), 10)
case reflect.Float32, reflect.Float64:
b.body = strconv.AppendFloat(b.body, rv.Float(), 'e', -1, 64)
case reflect.Bool:
b.body = strconv.AppendBool(b.body, rv.Bool())
case reflect.String:
b.body = strconv.AppendQuote(b.body, rv.String())
case reflect.Ptr, reflect.Interface:
if rv.IsNil() {
return false, &marshalNilError{rv.Type()}
}
return b.value(cfg, rv.Elem(), name)
case reflect.Slice, reflect.Array:
rvlen := rv.Len()
if rvlen == 0 {
b.body = append(b.body, '[', ']')
return false, nil
}
b.arrayDepth++
wroteElem := false
b.body = append(b.body, '[')
for i := 0; i < rvlen; i++ {
isTable, err := b.value(cfg, rv.Index(i), name)
if err != nil {
return isTable, err
}
wroteElem = wroteElem || !isTable
if wroteElem {
if i < rvlen-1 {
b.body = append(b.body, ',', ' ')
} else {
b.body = append(b.body, ']')
}
}
}
if !wroteElem {
b.body = b.body[:len(b.body)-1] // rub out '['
}
b.arrayDepth--
return !wroteElem, nil
case reflect.Struct:
child := b.newChild(name)
err := child.structFields(cfg, rv)
b.addChild(child)
return true, err
case reflect.Map:
child := b.newChild(name)
err := child.mapFields(cfg, rv)
b.addChild(child)
return true, err
default:
return false, fmt.Errorf("toml: marshal: unsupported type %v", rv.Kind())
}
return false, nil
}
func (b *tableBuf) marshaler(cfg *Config, rv reflect.Value, name string) (handled, isTable bool, err error) {
switch t := rv.Interface().(type) {
case encoding.TextMarshaler:
enc, err := t.MarshalText()
if err != nil {
return true, false, err
}
b.body = encodeTextMarshaler(b.body, string(enc))
return true, false, nil
case MarshalerRec:
newval, err := t.MarshalTOML()
if err != nil {
return true, false, err
}
isTable, err = b.value(cfg, reflect.ValueOf(newval), name)
return true, isTable, err
case Marshaler:
enc, err := t.MarshalTOML()
if err != nil {
return true, false, err
}
b.body = append(b.body, enc...)
return true, false, nil
}
return false, false, nil
}
func encodeTextMarshaler(buf []byte, v string) []byte {
// Emit the value without quotes if possible.
if v == "true" || v == "false" {
return append(buf, v...)
} else if _, err := time.Parse(time.RFC3339Nano, v); err == nil {
return append(buf, v...)
} else if _, err := strconv.ParseInt(v, 10, 64); err == nil {
return append(buf, v...)
} else if _, err := strconv.ParseUint(v, 10, 64); err == nil {
return append(buf, v...)
} else if _, err := strconv.ParseFloat(v, 64); err == nil {
return append(buf, v...)
}
return strconv.AppendQuote(buf, v)
}
func encodeMapKey(rv reflect.Value) (string, error) {
if rv.Kind() == reflect.String {
return rv.String(), nil
}
if tm, ok := rv.Interface().(encoding.TextMarshaler); ok {
b, err := tm.MarshalText()
return string(b), err
}
switch rv.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
return strconv.FormatInt(rv.Int(), 10), nil
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
return strconv.FormatUint(rv.Uint(), 10), nil
}
return "", fmt.Errorf("toml: invalid map key type %v", rv.Type())
}
func isEmptyValue(v reflect.Value) bool {
switch v.Kind() {
case reflect.Array:
// encoding/json treats all arrays with non-zero length as non-empty. We check the
// array content here because zero-length arrays are almost never used.
len := v.Len()
for i := 0; i < len; i++ {
if !isEmptyValue(v.Index(i)) {
return false
}
}
return true
case 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()
}
return false
}
func quoteName(s string) string {
if len(s) == 0 {
return strconv.Quote(s)
}
for _, r := range s {
if r >= '0' && r <= '9' || r >= 'A' && r <= 'Z' || r >= 'a' && r <= 'z' || r == '-' || r == '_' {
continue
}
return strconv.Quote(s)
}
return s
}

107
vendor/github.com/naoina/toml/error.go generated vendored Normal file
View File

@ -0,0 +1,107 @@
package toml
import (
"errors"
"fmt"
"reflect"
"strconv"
)
var (
errArrayMultiType = errors.New("array can't contain multiple types")
)
// LineError is returned by Unmarshal, UnmarshalTable and Parse
// if the error is local to a line.
type LineError struct {
Line int
StructField string
Err error
}
func (err *LineError) Error() string {
field := ""
if err.StructField != "" {
field = "(" + err.StructField + ") "
}
return fmt.Sprintf("line %d: %s%v", err.Line, field, err.Err)
}
func lineError(line int, err error) error {
if err == nil {
return nil
}
if _, ok := err.(*LineError); ok {
return err
}
return &LineError{Line: line, Err: err}
}
func lineErrorField(line int, field string, err error) error {
if lerr, ok := err.(*LineError); ok {
return lerr
} else if err != nil {
err = &LineError{Line: line, StructField: field, Err: err}
}
return err
}
type overflowError struct {
kind reflect.Kind
v string
}
func (err *overflowError) Error() string {
return fmt.Sprintf("value %s is out of range for %v", err.v, err.kind)
}
func convertNumError(kind reflect.Kind, err error) error {
if numerr, ok := err.(*strconv.NumError); ok && numerr.Err == strconv.ErrRange {
return &overflowError{kind, numerr.Num}
}
return err
}
type invalidUnmarshalError struct {
typ reflect.Type
}
func (err *invalidUnmarshalError) Error() string {
if err.typ == nil {
return "toml: Unmarshal(nil)"
}
if err.typ.Kind() != reflect.Ptr {
return "toml: Unmarshal(non-pointer " + err.typ.String() + ")"
}
return "toml: Unmarshal(nil " + err.typ.String() + ")"
}
type unmarshalTypeError struct {
what string
want string
typ reflect.Type
}
func (err *unmarshalTypeError) Error() string {
msg := fmt.Sprintf("cannot unmarshal TOML %s into %s", err.what, err.typ)
if err.want != "" {
msg += " (need " + err.want + ")"
}
return msg
}
type marshalNilError struct {
typ reflect.Type
}
func (err *marshalNilError) Error() string {
return fmt.Sprintf("toml: cannot marshal nil %s", err.typ)
}
type marshalTableError struct {
typ reflect.Type
}
func (err *marshalTableError) Error() string {
return fmt.Sprintf("toml: cannot marshal %s as table, want struct or map type", err.typ)
}

376
vendor/github.com/naoina/toml/parse.go generated vendored Normal file
View File

@ -0,0 +1,376 @@
package toml
import (
"errors"
"fmt"
"strconv"
"strings"
"github.com/naoina/toml/ast"
)
// The parser is generated by github.com/pointlander/peg. To regenerate it, do:
//
// go get -u github.com/pointlander/peg
// go generate .
//go:generate peg -switch -inline parse.peg
var errParse = errors.New("invalid TOML syntax")
// Parse returns an AST representation of TOML.
// The toplevel is represented by a table.
func Parse(data []byte) (*ast.Table, error) {
d := &parseState{p: &tomlParser{Buffer: string(data)}}
d.init()
if err := d.parse(); err != nil {
return nil, err
}
return d.p.toml.table, nil
}
type parseState struct {
p *tomlParser
}
func (d *parseState) init() {
d.p.Init()
d.p.toml.init(d.p.buffer)
}
func (d *parseState) parse() error {
if err := d.p.Parse(); err != nil {
if err, ok := err.(*parseError); ok {
return lineError(err.Line(), errParse)
}
return err
}
return d.execute()
}
func (d *parseState) execute() (err error) {
defer func() {
if e := recover(); e != nil {
lerr, ok := e.(*LineError)
if !ok {
panic(e)
}
err = lerr
}
}()
d.p.Execute()
return nil
}
func (e *parseError) Line() int {
tokens := []token32{e.max}
positions, p := make([]int, 2*len(tokens)), 0
for _, token := range tokens {
positions[p], p = int(token.begin), p+1
positions[p], p = int(token.end), p+1
}
for _, t := range translatePositions(e.p.buffer, positions) {
if e.p.line < t.line {
e.p.line = t.line
}
}
return e.p.line
}
type stack struct {
key string
table *ast.Table
}
type array struct {
parent *array
child *array
current *ast.Array
line int
}
type toml struct {
table *ast.Table
line int
currentTable *ast.Table
s string
key string
val ast.Value
arr *array
stack []*stack
skip bool
}
func (p *toml) init(data []rune) {
p.line = 1
p.table = p.newTable(ast.TableTypeNormal, "")
p.table.Position.End = len(data) - 1
p.table.Data = data[:len(data)-1] // truncate the end_symbol added by PEG parse generator.
p.currentTable = p.table
}
func (p *toml) Error(err error) {
panic(lineError(p.line, err))
}
func (p *tomlParser) SetTime(begin, end int) {
p.val = &ast.Datetime{
Position: ast.Position{Begin: begin, End: end},
Data: p.buffer[begin:end],
Value: string(p.buffer[begin:end]),
}
}
func (p *tomlParser) SetFloat64(begin, end int) {
p.val = &ast.Float{
Position: ast.Position{Begin: begin, End: end},
Data: p.buffer[begin:end],
Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
}
}
func (p *tomlParser) SetInt64(begin, end int) {
p.val = &ast.Integer{
Position: ast.Position{Begin: begin, End: end},
Data: p.buffer[begin:end],
Value: underscoreReplacer.Replace(string(p.buffer[begin:end])),
}
}
func (p *tomlParser) SetString(begin, end int) {
p.val = &ast.String{
Position: ast.Position{Begin: begin, End: end},
Data: p.buffer[begin:end],
Value: p.s,
}
p.s = ""
}
func (p *tomlParser) SetBool(begin, end int) {
p.val = &ast.Boolean{
Position: ast.Position{Begin: begin, End: end},
Data: p.buffer[begin:end],
Value: string(p.buffer[begin:end]),
}
}
func (p *tomlParser) StartArray() {
if p.arr == nil {
p.arr = &array{line: p.line, current: &ast.Array{}}
return
}
p.arr.child = &array{parent: p.arr, line: p.line, current: &ast.Array{}}
p.arr = p.arr.child
}
func (p *tomlParser) AddArrayVal() {
if p.arr.current == nil {
p.arr.current = &ast.Array{}
}
p.arr.current.Value = append(p.arr.current.Value, p.val)
}
func (p *tomlParser) SetArray(begin, end int) {
p.arr.current.Position = ast.Position{Begin: begin, End: end}
p.arr.current.Data = p.buffer[begin:end]
p.val = p.arr.current
p.arr = p.arr.parent
}
func (p *toml) SetTable(buf []rune, begin, end int) {
p.setTable(p.table, buf, begin, end)
}
func (p *toml) setTable(parent *ast.Table, buf []rune, begin, end int) {
name := string(buf[begin:end])
names := splitTableKey(name)
parent, err := p.lookupTable(parent, names[:len(names)-1])
if err != nil {
p.Error(err)
}
last := names[len(names)-1]
tbl := p.newTable(ast.TableTypeNormal, last)
switch v := parent.Fields[last].(type) {
case nil:
parent.Fields[last] = tbl
case []*ast.Table:
p.Error(fmt.Errorf("table `%s' is in conflict with array table in line %d", name, v[0].Line))
case *ast.Table:
if (v.Position == ast.Position{}) {
// This table was created as an implicit parent.
// Replace it with the real defined table.
tbl.Fields = v.Fields
parent.Fields[last] = tbl
} else {
p.Error(fmt.Errorf("table `%s' is in conflict with table in line %d", name, v.Line))
}
case *ast.KeyValue:
p.Error(fmt.Errorf("table `%s' is in conflict with line %d", name, v.Line))
default:
p.Error(fmt.Errorf("BUG: table `%s' is in conflict but it's unknown type `%T'", last, v))
}
p.currentTable = tbl
}
func (p *toml) newTable(typ ast.TableType, name string) *ast.Table {
return &ast.Table{
Line: p.line,
Name: name,
Type: typ,
Fields: make(map[string]interface{}),
}
}
func (p *tomlParser) SetTableString(begin, end int) {
p.currentTable.Data = p.buffer[begin:end]
p.currentTable.Position.Begin = begin
p.currentTable.Position.End = end
}
func (p *toml) SetArrayTable(buf []rune, begin, end int) {
p.setArrayTable(p.table, buf, begin, end)
}
func (p *toml) setArrayTable(parent *ast.Table, buf []rune, begin, end int) {
name := string(buf[begin:end])
names := splitTableKey(name)
parent, err := p.lookupTable(parent, names[:len(names)-1])
if err != nil {
p.Error(err)
}
last := names[len(names)-1]
tbl := p.newTable(ast.TableTypeArray, last)
switch v := parent.Fields[last].(type) {
case nil:
parent.Fields[last] = []*ast.Table{tbl}
case []*ast.Table:
parent.Fields[last] = append(v, tbl)
case *ast.Table:
p.Error(fmt.Errorf("array table `%s' is in conflict with table in line %d", name, v.Line))
case *ast.KeyValue:
p.Error(fmt.Errorf("array table `%s' is in conflict with line %d", name, v.Line))
default:
p.Error(fmt.Errorf("BUG: array table `%s' is in conflict but it's unknown type `%T'", name, v))
}
p.currentTable = tbl
}
func (p *toml) StartInlineTable() {
p.skip = false
p.stack = append(p.stack, &stack{p.key, p.currentTable})
buf := []rune(p.key)
if p.arr == nil {
p.setTable(p.currentTable, buf, 0, len(buf))
} else {
p.setArrayTable(p.currentTable, buf, 0, len(buf))
}
}
func (p *toml) EndInlineTable() {
st := p.stack[len(p.stack)-1]
p.key, p.currentTable = st.key, st.table
p.stack[len(p.stack)-1] = nil
p.stack = p.stack[:len(p.stack)-1]
p.skip = true
}
func (p *toml) AddLineCount(i int) {
p.line += i
}
func (p *toml) SetKey(buf []rune, begin, end int) {
p.key = string(buf[begin:end])
}
func (p *toml) AddKeyValue() {
if p.skip {
p.skip = false
return
}
if val, exists := p.currentTable.Fields[p.key]; exists {
switch v := val.(type) {
case *ast.Table:
p.Error(fmt.Errorf("key `%s' is in conflict with table in line %d", p.key, v.Line))
case *ast.KeyValue:
p.Error(fmt.Errorf("key `%s' is in conflict with line %xd", p.key, v.Line))
default:
p.Error(fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", p.key, v))
}
}
p.currentTable.Fields[p.key] = &ast.KeyValue{Key: p.key, Value: p.val, Line: p.line}
}
func (p *toml) SetBasicString(buf []rune, begin, end int) {
p.s = p.unquote(string(buf[begin:end]))
}
func (p *toml) SetMultilineString() {
p.s = p.unquote(`"` + escapeReplacer.Replace(strings.TrimLeft(p.s, "\r\n")) + `"`)
}
func (p *toml) AddMultilineBasicBody(buf []rune, begin, end int) {
p.s += string(buf[begin:end])
}
func (p *toml) SetLiteralString(buf []rune, begin, end int) {
p.s = string(buf[begin:end])
}
func (p *toml) SetMultilineLiteralString(buf []rune, begin, end int) {
p.s = strings.TrimLeft(string(buf[begin:end]), "\r\n")
}
func (p *toml) unquote(s string) string {
s, err := strconv.Unquote(s)
if err != nil {
p.Error(err)
}
return s
}
func (p *toml) lookupTable(t *ast.Table, keys []string) (*ast.Table, error) {
for _, s := range keys {
val, exists := t.Fields[s]
if !exists {
tbl := p.newTable(ast.TableTypeNormal, s)
t.Fields[s] = tbl
t = tbl
continue
}
switch v := val.(type) {
case *ast.Table:
t = v
case []*ast.Table:
t = v[len(v)-1]
case *ast.KeyValue:
return nil, fmt.Errorf("key `%s' is in conflict with line %d", s, v.Line)
default:
return nil, fmt.Errorf("BUG: key `%s' is in conflict but it's unknown type `%T'", s, v)
}
}
return t, nil
}
func splitTableKey(tk string) []string {
key := make([]byte, 0, 1)
keys := make([]string, 0, 1)
inQuote := false
for i := 0; i < len(tk); i++ {
k := tk[i]
switch {
case k == tableSeparator && !inQuote:
keys = append(keys, string(key))
key = key[:0] // reuse buffer.
case k == '"':
inQuote = !inQuote
case (k == ' ' || k == '\t') && !inQuote:
// skip.
default:
key = append(key, k)
}
}
keys = append(keys, string(key))
return keys
}

145
vendor/github.com/naoina/toml/parse.peg generated vendored Normal file
View File

@ -0,0 +1,145 @@
package toml
type tomlParser Peg {
toml
}
TOML <- Expression (newline Expression)* newline? !. { _ = buffer }
Expression <- (
<ws table ws comment? (wsnl keyval ws comment?)*> { p.SetTableString(begin, end) }
/ ws keyval ws comment?
/ ws comment?
/ ws
)
newline <- <[\r\n]+> { p.AddLineCount(end - begin) }
ws <- [ \t]*
wsnl <- (
[ \t]
/ <[\r\n]> { p.AddLineCount(end - begin) }
)*
comment <- '#' <[\t -\0x10FFFF]*>
keyval <- key ws '=' ws val { p.AddKeyValue() }
key <- bareKey / quotedKey
bareKey <- <[0-9A-Za-z\-_]+> { p.SetKey(p.buffer, begin, end) }
quotedKey <- '"' <basicChar+> '"' { p.SetKey(p.buffer, begin-1, end+1) }
val <- (
<datetime> { p.SetTime(begin, end) }
/ <float> { p.SetFloat64(begin, end) }
/ <integer> { p.SetInt64(begin, end) }
/ <string> { p.SetString(begin, end) }
/ <boolean> { p.SetBool(begin, end) }
/ <array> { p.SetArray(begin, end) }
/ inlineTable
)
table <- stdTable / arrayTable
stdTable <- '[' ws <tableKey> ws ']' { p.SetTable(p.buffer, begin, end) }
arrayTable <- '[[' ws <tableKey> ws ']]' { p.SetArrayTable(p.buffer, begin, end) }
inlineTable <- (
'{' { p.StartInlineTable() }
ws inlineTableKeyValues ws
'}' { p.EndInlineTable() }
)
inlineTableKeyValues <- (keyval inlineTableValSep?)*
tableKey <- key (tableKeySep key)*
tableKeySep <- ws '.' ws
inlineTableValSep <- ws ',' ws
integer <- [\-+]? int
int <- [1-9] (digit / '_' digit)+ / digit
float <- integer (frac exp? / frac? exp)
frac <- '.' digit (digit / '_' digit)*
exp <- [eE] [\-+]? digit (digit / '_' digit)*
string <- (
mlLiteralString
/ literalString
/ mlBasicString
/ basicString
)
basicString <- <'"' basicChar* '"'> { p.SetBasicString(p.buffer, begin, end) }
basicChar <- basicUnescaped / escaped
escaped <- escape ([btnfr"/\\] / 'u' hexQuad / 'U' hexQuad hexQuad)
basicUnescaped <- [ -!#-\[\]-\0x10FFFF]
escape <- '\\'
mlBasicString <- '"""' mlBasicBody '"""' { p.SetMultilineString() }
mlBasicBody <- (
<basicChar / newline> { p.AddMultilineBasicBody(p.buffer, begin, end) }
/ escape newline wsnl
)*
literalString <- "'" <literalChar*> "'" { p.SetLiteralString(p.buffer, begin, end) }
literalChar <- [\t -&(-\0x10FFFF]
mlLiteralString <- "'''" <mlLiteralBody> "'''" { p.SetMultilineLiteralString(p.buffer, begin, end) }
mlLiteralBody <- (!"'''" (mlLiteralChar / newline))*
mlLiteralChar <- [\t -\0x10FFFF]
hexdigit <- [0-9A-Fa-f]
hexQuad <- hexdigit hexdigit hexdigit hexdigit
boolean <- 'true' / 'false'
dateFullYear <- digitQuad
dateMonth <- digitDual
dateMDay <- digitDual
timeHour <- digitDual
timeMinute <- digitDual
timeSecond <- digitDual
timeSecfrac <- '.' digit+
timeNumoffset <- [\-+] timeHour ':' timeMinute
timeOffset <- 'Z' / timeNumoffset
partialTime <- timeHour ':' timeMinute ':' timeSecond timeSecfrac?
fullDate <- dateFullYear '-' dateMonth '-' dateMDay
fullTime <- partialTime timeOffset
datetime <- (fullDate ('T' fullTime)?) / partialTime
digit <- [0-9]
digitDual <- digit digit
digitQuad <- digitDual digitDual
array <- (
'[' { p.StartArray() }
wsnl arrayValues? wsnl
']'
)
arrayValues <- (
val { p.AddArrayVal() }
(
wsnl comment?
wsnl arraySep
wsnl comment?
wsnl val { p.AddArrayVal() }
)*
wsnl arraySep?
wsnl comment?
)
arraySep <- ','

2556
vendor/github.com/naoina/toml/parse.peg.go generated vendored Normal file

File diff suppressed because it is too large Load Diff

65
vendor/github.com/naoina/toml/util.go generated vendored Normal file
View File

@ -0,0 +1,65 @@
package toml
import (
"fmt"
"reflect"
"strings"
)
const fieldTagName = "toml"
// fieldCache maps normalized field names to their position in a struct.
type fieldCache struct {
named map[string]fieldInfo // fields with an explicit name in tag
auto map[string]fieldInfo // fields with auto-assigned normalized names
}
type fieldInfo struct {
index []int
name string
ignored bool
}
func makeFieldCache(cfg *Config, rt reflect.Type) fieldCache {
named, auto := make(map[string]fieldInfo), make(map[string]fieldInfo)
for i := 0; i < rt.NumField(); i++ {
ft := rt.Field(i)
// skip unexported fields
if ft.PkgPath != "" && !ft.Anonymous {
continue
}
col, _ := extractTag(ft.Tag.Get(fieldTagName))
info := fieldInfo{index: ft.Index, name: ft.Name, ignored: col == "-"}
if col == "" || col == "-" {
auto[cfg.NormFieldName(rt, ft.Name)] = info
} else {
named[col] = info
}
}
return fieldCache{named, auto}
}
func (fc fieldCache) findField(cfg *Config, rv reflect.Value, name string) (reflect.Value, string, error) {
info, found := fc.named[name]
if !found {
info, found = fc.auto[cfg.NormFieldName(rv.Type(), name)]
}
if !found {
if cfg.MissingField == nil {
return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' is not defined in %v", name, rv.Type())
} else {
return reflect.Value{}, "", cfg.MissingField(rv.Type(), name)
}
} else if info.ignored {
return reflect.Value{}, "", fmt.Errorf("field corresponding to `%s' in %v cannot be set through TOML", name, rv.Type())
}
return rv.FieldByIndex(info.index), info.name, nil
}
func extractTag(tag string) (col, rest string) {
tags := strings.SplitN(tag, ",", 2)
if len(tags) == 2 {
return strings.TrimSpace(tags[0]), strings.TrimSpace(tags[1])
}
return strings.TrimSpace(tags[0]), ""
}