vendor/github.com/pelletier/go-toml/keysparsing.go
author Mikael Berthe <mikael@lilotux.net>
Sun, 16 Feb 2020 18:54:01 +0100
changeset 251 1c52a0eeb952
parent 242 2a9ec03fe5a1
child 256 6d9efbef00a9
permissions -rw-r--r--
Update dependencies This should fix #22.

// Parsing keys handling both bare and quoted keys.

package toml

import (
	"errors"
	"fmt"
	"unicode"
)

// Convert the bare key group string to an array.
// The input supports double quotation and single quotation,
// but escape sequences are not supported. Lexers must unescape them beforehand.
func parseKey(key string) ([]string, error) {
	runes := []rune(key)
	var groups []string

	if len(key) == 0 {
		return nil, errors.New("empty key")
	}

	idx := 0
	for idx < len(runes) {
		for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
			// skip leading whitespace
		}
		if idx >= len(runes) {
			break
		}
		r := runes[idx]
		if isValidBareChar(r) {
			// parse bare key
			startIdx := idx
			endIdx := -1
			idx++
			for idx < len(runes) {
				r = runes[idx]
				if isValidBareChar(r) {
					idx++
				} else if r == '.' {
					endIdx = idx
					break
				} else if isSpace(r) {
					endIdx = idx
					for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
						// skip trailing whitespace
					}
					if idx < len(runes) && runes[idx] != '.' {
						return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
					}
					break
				} else {
					return nil, fmt.Errorf("invalid bare key character: %c", r)
				}
			}
			if endIdx == -1 {
				endIdx = idx
			}
			groups = append(groups, string(runes[startIdx:endIdx]))
		} else if r == '\'' {
			// parse single quoted key
			idx++
			startIdx := idx
			for {
				if idx >= len(runes) {
					return nil, fmt.Errorf("unclosed single-quoted key")
				}
				r = runes[idx]
				if r == '\'' {
					groups = append(groups, string(runes[startIdx:idx]))
					idx++
					break
				}
				idx++
			}
		} else if r == '"' {
			// parse double quoted key
			idx++
			startIdx := idx
			for {
				if idx >= len(runes) {
					return nil, fmt.Errorf("unclosed double-quoted key")
				}
				r = runes[idx]
				if r == '"' {
					groups = append(groups, string(runes[startIdx:idx]))
					idx++
					break
				}
				idx++
			}
		} else if r == '.' {
			idx++
			if idx >= len(runes) {
				return nil, fmt.Errorf("unexpected end of key")
			}
			r = runes[idx]
			if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
				return nil, fmt.Errorf("expecting key part after dot")
			}
		} else {
			return nil, fmt.Errorf("invalid key character: %c", r)
		}
	}
	if len(groups) == 0 {
		return nil, fmt.Errorf("empty key")
	}
	return groups, nil
}

func isValidBareChar(r rune) bool {
	return isAlphanumeric(r) || r == '-' || unicode.IsNumber(r)
}