vendor/github.com/pelletier/go-toml/parser.go
changeset 256 6d9efbef00a9
parent 251 1c52a0eeb952
child 260 445e01aede7e
equal deleted inserted replaced
255:4f153a23adab 256:6d9efbef00a9
     5 import (
     5 import (
     6 	"errors"
     6 	"errors"
     7 	"fmt"
     7 	"fmt"
     8 	"math"
     8 	"math"
     9 	"reflect"
     9 	"reflect"
    10 	"regexp"
       
    11 	"strconv"
    10 	"strconv"
    12 	"strings"
    11 	"strings"
    13 	"time"
    12 	"time"
    14 )
    13 )
    15 
    14 
   156 		p.raiseError(key, "invalid table array key: %s", err)
   155 		p.raiseError(key, "invalid table array key: %s", err)
   157 	}
   156 	}
   158 	if err := p.tree.createSubTree(keys, startToken.Position); err != nil {
   157 	if err := p.tree.createSubTree(keys, startToken.Position); err != nil {
   159 		p.raiseError(key, "%s", err)
   158 		p.raiseError(key, "%s", err)
   160 	}
   159 	}
       
   160 	destTree := p.tree.GetPath(keys)
       
   161 	if target, ok := destTree.(*Tree); ok && target != nil && target.inline {
       
   162 		p.raiseError(key, "could not re-define exist inline table or its sub-table : %s",
       
   163 			strings.Join(keys, "."))
       
   164 	}
   161 	p.assume(tokenRightBracket)
   165 	p.assume(tokenRightBracket)
   162 	p.currentTable = keys
   166 	p.currentTable = keys
   163 	return p.parseStart
   167 	return p.parseStart
   164 }
   168 }
   165 
   169 
   199 	default:
   203 	default:
   200 		p.raiseError(key, "Unknown table type for path: %s",
   204 		p.raiseError(key, "Unknown table type for path: %s",
   201 			strings.Join(tableKey, "."))
   205 			strings.Join(tableKey, "."))
   202 	}
   206 	}
   203 
   207 
       
   208 	if targetNode.inline {
       
   209 		p.raiseError(key, "could not add key or sub-table to exist inline table or its sub-table : %s",
       
   210 			strings.Join(tableKey, "."))
       
   211 	}
       
   212 
   204 	// assign value to the found table
   213 	// assign value to the found table
   205 	keyVal := parsedKey[len(parsedKey)-1]
   214 	keyVal := parsedKey[len(parsedKey)-1]
   206 	localKey := []string{keyVal}
   215 	localKey := []string{keyVal}
   207 	finalKey := append(tableKey, keyVal)
   216 	finalKey := append(tableKey, keyVal)
   208 	if targetNode.GetPath(localKey) != nil {
   217 	if targetNode.GetPath(localKey) != nil {
   219 	}
   228 	}
   220 	targetNode.values[keyVal] = toInsert
   229 	targetNode.values[keyVal] = toInsert
   221 	return p.parseStart
   230 	return p.parseStart
   222 }
   231 }
   223 
   232 
   224 var numberUnderscoreInvalidRegexp *regexp.Regexp
   233 var errInvalidUnderscore = errors.New("invalid use of _ in number")
   225 var hexNumberUnderscoreInvalidRegexp *regexp.Regexp
       
   226 
   234 
   227 func numberContainsInvalidUnderscore(value string) error {
   235 func numberContainsInvalidUnderscore(value string) error {
   228 	if numberUnderscoreInvalidRegexp.MatchString(value) {
   236 	// For large numbers, you may use underscores between digits to enhance
   229 		return errors.New("invalid use of _ in number")
   237 	// readability. Each underscore must be surrounded by at least one digit on
       
   238 	// each side.
       
   239 
       
   240 	hasBefore := false
       
   241 	for idx, r := range value {
       
   242 		if r == '_' {
       
   243 			if !hasBefore || idx+1 >= len(value) {
       
   244 				// can't end with an underscore
       
   245 				return errInvalidUnderscore
       
   246 			}
       
   247 		}
       
   248 		hasBefore = isDigit(r)
   230 	}
   249 	}
   231 	return nil
   250 	return nil
   232 }
   251 }
   233 
   252 
       
   253 var errInvalidUnderscoreHex = errors.New("invalid use of _ in hex number")
       
   254 
   234 func hexNumberContainsInvalidUnderscore(value string) error {
   255 func hexNumberContainsInvalidUnderscore(value string) error {
   235 	if hexNumberUnderscoreInvalidRegexp.MatchString(value) {
   256 	hasBefore := false
   236 		return errors.New("invalid use of _ in hex number")
   257 	for idx, r := range value {
       
   258 		if r == '_' {
       
   259 			if !hasBefore || idx+1 >= len(value) {
       
   260 				// can't end with an underscore
       
   261 				return errInvalidUnderscoreHex
       
   262 			}
       
   263 		}
       
   264 		hasBefore = isHexDigit(r)
   237 	}
   265 	}
   238 	return nil
   266 	return nil
   239 }
   267 }
   240 
   268 
   241 func cleanupNumberToken(value string) string {
   269 func cleanupNumberToken(value string) string {
   310 		val, err := strconv.ParseFloat(cleanedVal, 64)
   338 		val, err := strconv.ParseFloat(cleanedVal, 64)
   311 		if err != nil {
   339 		if err != nil {
   312 			p.raiseError(tok, "%s", err)
   340 			p.raiseError(tok, "%s", err)
   313 		}
   341 		}
   314 		return val
   342 		return val
   315 	case tokenDate:
   343 	case tokenLocalTime:
   316 		layout := time.RFC3339Nano
   344 		val, err := ParseLocalTime(tok.val)
   317 		if !strings.Contains(tok.val, "T") {
       
   318 			layout = strings.Replace(layout, "T", " ", 1)
       
   319 		}
       
   320 		val, err := time.ParseInLocation(layout, tok.val, time.UTC)
       
   321 		if err != nil {
   345 		if err != nil {
   322 			p.raiseError(tok, "%s", err)
   346 			p.raiseError(tok, "%s", err)
   323 		}
   347 		}
   324 		return val
   348 		return val
   325 	case tokenLocalDate:
   349 	case tokenLocalDate:
   326 		v := strings.Replace(tok.val, " ", "T", -1)
   350 		// a local date may be followed by:
   327 		isDateTime := false
   351 		// * nothing: this is a local date
   328 		isTime := false
   352 		// * a local time: this is a local date-time
   329 		for _, c := range v {
   353 
   330 			if c == 'T' || c == 't' {
   354 		next := p.peek()
   331 				isDateTime = true
   355 		if next == nil || next.typ != tokenLocalTime {
   332 				break
   356 			val, err := ParseLocalDate(tok.val)
   333 			}
   357 			if err != nil {
   334 			if c == ':' {
   358 				p.raiseError(tok, "%s", err)
   335 				isTime = true
   359 			}
   336 				break
   360 			return val
   337 			}
   361 		}
   338 		}
   362 
   339 
   363 		localDate := tok
   340 		var val interface{}
   364 		localTime := p.getToken()
   341 		var err error
   365 
   342 
   366 		next = p.peek()
   343 		if isDateTime {
   367 		if next == nil || next.typ != tokenTimeOffset {
   344 			val, err = ParseLocalDateTime(v)
   368 			v := localDate.val + "T" + localTime.val
   345 		} else if isTime {
   369 			val, err := ParseLocalDateTime(v)
   346 			val, err = ParseLocalTime(v)
   370 			if err != nil {
   347 		} else {
   371 				p.raiseError(tok, "%s", err)
   348 			val, err = ParseLocalDate(v)
   372 			}
   349 		}
   373 			return val
   350 
   374 		}
       
   375 
       
   376 		offset := p.getToken()
       
   377 
       
   378 		layout := time.RFC3339Nano
       
   379 		v := localDate.val + "T" + localTime.val + offset.val
       
   380 		val, err := time.ParseInLocation(layout, v, time.UTC)
   351 		if err != nil {
   381 		if err != nil {
   352 			p.raiseError(tok, "%s", err)
   382 			p.raiseError(tok, "%s", err)
   353 		}
   383 		}
   354 		return val
   384 		return val
   355 	case tokenLeftBracket:
   385 	case tokenLeftBracket:
   358 		return p.parseInlineTable()
   388 		return p.parseInlineTable()
   359 	case tokenEqual:
   389 	case tokenEqual:
   360 		p.raiseError(tok, "cannot have multiple equals for the same key")
   390 		p.raiseError(tok, "cannot have multiple equals for the same key")
   361 	case tokenError:
   391 	case tokenError:
   362 		p.raiseError(tok, "%s", tok)
   392 		p.raiseError(tok, "%s", tok)
   363 	}
   393 	default:
   364 
   394 		panic(fmt.Errorf("unhandled token: %v", tok))
   365 	p.raiseError(tok, "never reached")
   395 	}
   366 
   396 
   367 	return nil
   397 	return nil
   368 }
   398 }
   369 
   399 
   370 func tokenIsComma(t *token) bool {
   400 func tokenIsComma(t *token) bool {
   409 		previous = follow
   439 		previous = follow
   410 	}
   440 	}
   411 	if tokenIsComma(previous) {
   441 	if tokenIsComma(previous) {
   412 		p.raiseError(previous, "trailing comma at the end of inline table")
   442 		p.raiseError(previous, "trailing comma at the end of inline table")
   413 	}
   443 	}
       
   444 	tree.inline = true
   414 	return tree
   445 	return tree
   415 }
   446 }
   416 
   447 
   417 func (p *tomlParser) parseArray() interface{} {
   448 func (p *tomlParser) parseArray() interface{} {
   418 	var array []interface{}
   449 	var array []interface{}
   419 	arrayType := reflect.TypeOf(nil)
   450 	arrayType := reflect.TypeOf(newTree())
   420 	for {
   451 	for {
   421 		follow := p.peek()
   452 		follow := p.peek()
   422 		if follow == nil || follow.typ == tokenEOF {
   453 		if follow == nil || follow.typ == tokenEOF {
   423 			p.raiseError(follow, "unterminated array")
   454 			p.raiseError(follow, "unterminated array")
   424 		}
   455 		}
   425 		if follow.typ == tokenRightBracket {
   456 		if follow.typ == tokenRightBracket {
   426 			p.getToken()
   457 			p.getToken()
   427 			break
   458 			break
   428 		}
   459 		}
   429 		val := p.parseRvalue()
   460 		val := p.parseRvalue()
   430 		if arrayType == nil {
       
   431 			arrayType = reflect.TypeOf(val)
       
   432 		}
       
   433 		if reflect.TypeOf(val) != arrayType {
   461 		if reflect.TypeOf(val) != arrayType {
   434 			p.raiseError(follow, "mixed types in array")
   462 			arrayType = nil
   435 		}
   463 		}
   436 		array = append(array, val)
   464 		array = append(array, val)
   437 		follow = p.peek()
   465 		follow = p.peek()
   438 		if follow == nil || follow.typ == tokenEOF {
   466 		if follow == nil || follow.typ == tokenEOF {
   439 			p.raiseError(follow, "unterminated array")
   467 			p.raiseError(follow, "unterminated array")
   442 			p.raiseError(follow, "missing comma")
   470 			p.raiseError(follow, "missing comma")
   443 		}
   471 		}
   444 		if follow.typ == tokenComma {
   472 		if follow.typ == tokenComma {
   445 			p.getToken()
   473 			p.getToken()
   446 		}
   474 		}
       
   475 	}
       
   476 
       
   477 	// if the array is a mixed-type array or its length is 0,
       
   478 	// don't convert it to a table array
       
   479 	if len(array) <= 0 {
       
   480 		arrayType = nil
   447 	}
   481 	}
   448 	// An array of Trees is actually an array of inline
   482 	// An array of Trees is actually an array of inline
   449 	// tables, which is a shorthand for a table array. If the
   483 	// tables, which is a shorthand for a table array. If the
   450 	// array was not converted from []interface{} to []*Tree,
   484 	// array was not converted from []interface{} to []*Tree,
   451 	// the two notations would not be equivalent.
   485 	// the two notations would not be equivalent.
   470 		seenTableKeys: make([]string, 0),
   504 		seenTableKeys: make([]string, 0),
   471 	}
   505 	}
   472 	parser.run()
   506 	parser.run()
   473 	return result
   507 	return result
   474 }
   508 }
   475 
       
   476 func init() {
       
   477 	numberUnderscoreInvalidRegexp = regexp.MustCompile(`([^\d]_|_[^\d])|_$|^_`)
       
   478 	hexNumberUnderscoreInvalidRegexp = regexp.MustCompile(`(^0x_)|([^\da-f]_|_[^\da-f])|_$|^_`)
       
   479 }