go-ethereum/vendor/github.com/naoina/toml/parse.go
Felix Lange 30d706c35e 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
2017-04-12 17:27:23 +03:00

377 lines
8.9 KiB
Go

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
}