vendor/github.com/pelletier/go-toml/keysparsing.go
changeset 251 1c52a0eeb952
parent 242 2a9ec03fe5a1
child 256 6d9efbef00a9
equal deleted inserted replaced
250:c040f992052f 251:1c52a0eeb952
     1 // Parsing keys handling both bare and quoted keys.
     1 // Parsing keys handling both bare and quoted keys.
     2 
     2 
     3 package toml
     3 package toml
     4 
     4 
     5 import (
     5 import (
     6 	"bytes"
       
     7 	"errors"
     6 	"errors"
     8 	"fmt"
     7 	"fmt"
     9 	"unicode"
     8 	"unicode"
    10 )
     9 )
    11 
    10 
    12 // Convert the bare key group string to an array.
    11 // Convert the bare key group string to an array.
    13 // The input supports double quotation to allow "." inside the key name,
    12 // The input supports double quotation and single quotation,
    14 // but escape sequences are not supported. Lexers must unescape them beforehand.
    13 // but escape sequences are not supported. Lexers must unescape them beforehand.
    15 func parseKey(key string) ([]string, error) {
    14 func parseKey(key string) ([]string, error) {
    16 	groups := []string{}
    15 	runes := []rune(key)
    17 	var buffer bytes.Buffer
    16 	var groups []string
    18 	inQuotes := false
       
    19 	wasInQuotes := false
       
    20 	ignoreSpace := true
       
    21 	expectDot := false
       
    22 
    17 
    23 	for _, char := range key {
    18 	if len(key) == 0 {
    24 		if ignoreSpace {
    19 		return nil, errors.New("empty key")
    25 			if char == ' ' {
    20 	}
    26 				continue
    21 
       
    22 	idx := 0
       
    23 	for idx < len(runes) {
       
    24 		for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
       
    25 			// skip leading whitespace
       
    26 		}
       
    27 		if idx >= len(runes) {
       
    28 			break
       
    29 		}
       
    30 		r := runes[idx]
       
    31 		if isValidBareChar(r) {
       
    32 			// parse bare key
       
    33 			startIdx := idx
       
    34 			endIdx := -1
       
    35 			idx++
       
    36 			for idx < len(runes) {
       
    37 				r = runes[idx]
       
    38 				if isValidBareChar(r) {
       
    39 					idx++
       
    40 				} else if r == '.' {
       
    41 					endIdx = idx
       
    42 					break
       
    43 				} else if isSpace(r) {
       
    44 					endIdx = idx
       
    45 					for ; idx < len(runes) && isSpace(runes[idx]); idx++ {
       
    46 						// skip trailing whitespace
       
    47 					}
       
    48 					if idx < len(runes) && runes[idx] != '.' {
       
    49 						return nil, fmt.Errorf("invalid key character after whitespace: %c", runes[idx])
       
    50 					}
       
    51 					break
       
    52 				} else {
       
    53 					return nil, fmt.Errorf("invalid bare key character: %c", r)
       
    54 				}
    27 			}
    55 			}
    28 			ignoreSpace = false
    56 			if endIdx == -1 {
    29 		}
    57 				endIdx = idx
    30 		switch char {
       
    31 		case '"':
       
    32 			if inQuotes {
       
    33 				groups = append(groups, buffer.String())
       
    34 				buffer.Reset()
       
    35 				wasInQuotes = true
       
    36 			}
    58 			}
    37 			inQuotes = !inQuotes
    59 			groups = append(groups, string(runes[startIdx:endIdx]))
    38 			expectDot = false
    60 		} else if r == '\'' {
    39 		case '.':
    61 			// parse single quoted key
    40 			if inQuotes {
    62 			idx++
    41 				buffer.WriteRune(char)
    63 			startIdx := idx
    42 			} else {
    64 			for {
    43 				if !wasInQuotes {
    65 				if idx >= len(runes) {
    44 					if buffer.Len() == 0 {
    66 					return nil, fmt.Errorf("unclosed single-quoted key")
    45 						return nil, errors.New("empty table key")
       
    46 					}
       
    47 					groups = append(groups, buffer.String())
       
    48 					buffer.Reset()
       
    49 				}
    67 				}
    50 				ignoreSpace = true
    68 				r = runes[idx]
    51 				expectDot = false
    69 				if r == '\'' {
    52 				wasInQuotes = false
    70 					groups = append(groups, string(runes[startIdx:idx]))
       
    71 					idx++
       
    72 					break
       
    73 				}
       
    74 				idx++
    53 			}
    75 			}
    54 		case ' ':
    76 		} else if r == '"' {
    55 			if inQuotes {
    77 			// parse double quoted key
    56 				buffer.WriteRune(char)
    78 			idx++
    57 			} else {
    79 			startIdx := idx
    58 				expectDot = true
    80 			for {
       
    81 				if idx >= len(runes) {
       
    82 					return nil, fmt.Errorf("unclosed double-quoted key")
       
    83 				}
       
    84 				r = runes[idx]
       
    85 				if r == '"' {
       
    86 					groups = append(groups, string(runes[startIdx:idx]))
       
    87 					idx++
       
    88 					break
       
    89 				}
       
    90 				idx++
    59 			}
    91 			}
    60 		default:
    92 		} else if r == '.' {
    61 			if !inQuotes && !isValidBareChar(char) {
    93 			idx++
    62 				return nil, fmt.Errorf("invalid bare character: %c", char)
    94 			if idx >= len(runes) {
       
    95 				return nil, fmt.Errorf("unexpected end of key")
    63 			}
    96 			}
    64 			if !inQuotes && expectDot {
    97 			r = runes[idx]
    65 				return nil, errors.New("what?")
    98 			if !isValidBareChar(r) && r != '\'' && r != '"' && r != ' ' {
       
    99 				return nil, fmt.Errorf("expecting key part after dot")
    66 			}
   100 			}
    67 			buffer.WriteRune(char)
   101 		} else {
    68 			expectDot = false
   102 			return nil, fmt.Errorf("invalid key character: %c", r)
    69 		}
   103 		}
    70 	}
   104 	}
    71 	if inQuotes {
       
    72 		return nil, errors.New("mismatched quotes")
       
    73 	}
       
    74 	if buffer.Len() > 0 {
       
    75 		groups = append(groups, buffer.String())
       
    76 	}
       
    77 	if len(groups) == 0 {
   105 	if len(groups) == 0 {
    78 		return nil, errors.New("empty key")
   106 		return nil, fmt.Errorf("empty key")
    79 	}
   107 	}
    80 	return groups, nil
   108 	return groups, nil
    81 }
   109 }
    82 
   110 
    83 func isValidBareChar(r rune) bool {
   111 func isValidBareChar(r rune) bool {