// Copyright 2017 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package format

import (
	
	
)

// A Parser parses a format string. The result from the parse are set in the
// struct fields.
type Parser struct {
	Verb rune

	WidthPresent bool
	PrecPresent  bool
	Minus        bool
	Plus         bool
	Sharp        bool
	Space        bool
	Zero         bool

	// For the formats %+v %#v, we set the plusV/sharpV flags
	// and clear the plus/sharp flags since %+v and %#v are in effect
	// different, flagless formats set at the top level.
	PlusV  bool
	SharpV bool

	HasIndex bool

	Width int
	Prec  int // precision

	// retain arguments across calls.
	Args []interface{}
	// retain current argument number across calls
	ArgNum int

	// reordered records whether the format string used argument reordering.
	Reordered bool
	// goodArgNum records whether the most recent reordering directive was valid.
	goodArgNum bool

	// position info
	format   string
	startPos int
	endPos   int
	Status   Status
}

// Reset initializes a parser to scan format strings for the given args.
func ( *Parser) ( []interface{}) {
	.Args = 
	.ArgNum = 0
	.startPos = 0
	.Reordered = false
}

// Text returns the part of the format string that was parsed by the last call
// to Scan. It returns the original substitution clause if the current scan
// parsed a substitution.
func ( *Parser) () string { return .format[.startPos:.endPos] }

// SetFormat sets a new format string to parse. It does not reset the argument
// count.
func ( *Parser) ( string) {
	.format = 
	.startPos = 0
	.endPos = 0
}

// Status indicates the result type of a call to Scan.
type Status int

const (
	StatusText Status = iota
	StatusSubstitution
	StatusBadWidthSubstitution
	StatusBadPrecSubstitution
	StatusNoVerb
	StatusBadArgNum
	StatusMissingArg
)

// ClearFlags reset the parser to default behavior.
func ( *Parser) () {
	.WidthPresent = false
	.PrecPresent = false
	.Minus = false
	.Plus = false
	.Sharp = false
	.Space = false
	.Zero = false

	.PlusV = false
	.SharpV = false

	.HasIndex = false
}

// Scan scans the next part of the format string and sets the status to
// indicate whether it scanned a string literal, substitution or error.
func ( *Parser) () bool {
	.Status = StatusText
	 := .format
	 := len()
	if .endPos >=  {
		return false
	}
	 := false // previous item in format was an index like [3].

	.startPos = .endPos
	.goodArgNum = true
	 := .startPos
	for  <  && [] != '%' {
		++
	}
	if  > .startPos {
		.endPos = 
		return true
	}
	// Process one verb
	++

	.Status = StatusSubstitution

	// Do we have flags?
	.ClearFlags()

:
	for ;  < ; ++ {
		 := .format[]
		switch  {
		case '#':
			.Sharp = true
		case '0':
			.Zero = !.Minus // Only allow zero padding to the left.
		case '+':
			.Plus = true
		case '-':
			.Minus = true
			.Zero = false // Do not pad with zeros to the right.
		case ' ':
			.Space = true
		default:
			// Fast path for common case of ascii lower case simple verbs
			// without precision or width or argument indices.
			if 'a' <=  &&  <= 'z' && .ArgNum < len(.Args) {
				if  == 'v' {
					// Go syntax
					.SharpV = .Sharp
					.Sharp = false
					// Struct-field syntax
					.PlusV = .Plus
					.Plus = false
				}
				.Verb = rune()
				.ArgNum++
				.endPos =  + 1
				return true
			}
			// Format is more complex than simple flags and a verb or is malformed.
			break 
		}
	}

	// Do we have an explicit argument index?
	,  = .updateArgNumber(, )

	// Do we have width?
	if  <  && [] == '*' {
		++
		.Width, .WidthPresent = .intFromArg()

		if !.WidthPresent {
			.Status = StatusBadWidthSubstitution
		}

		// We have a negative width, so take its value and ensure
		// that the minus flag is set
		if .Width < 0 {
			.Width = -.Width
			.Minus = true
			.Zero = false // Do not pad with zeros to the right.
		}
		 = false
	} else {
		.Width, .WidthPresent,  = parsenum(, , )
		if  && .WidthPresent { // "%[3]2d"
			.goodArgNum = false
		}
	}

	// Do we have precision?
	if +1 <  && [] == '.' {
		++
		if  { // "%[3].2d"
			.goodArgNum = false
		}
		,  = .updateArgNumber(, )
		if  <  && [] == '*' {
			++
			.Prec, .PrecPresent = .intFromArg()
			// Negative precision arguments don't make sense
			if .Prec < 0 {
				.Prec = 0
				.PrecPresent = false
			}
			if !.PrecPresent {
				.Status = StatusBadPrecSubstitution
			}
			 = false
		} else {
			.Prec, .PrecPresent,  = parsenum(, , )
			if !.PrecPresent {
				.Prec = 0
				.PrecPresent = true
			}
		}
	}

	if ! {
		,  = .updateArgNumber(, )
	}
	.HasIndex = 

	if  >=  {
		.endPos = 
		.Status = StatusNoVerb
		return true
	}

	,  := utf8.DecodeRuneInString([:])
	.endPos =  + 
	.Verb = 

	switch {
	case  == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
		.startPos = .endPos - 1
		.Status = StatusText
	case !.goodArgNum:
		.Status = StatusBadArgNum
	case .ArgNum >= len(.Args): // No argument left over to print for the current verb.
		.Status = StatusMissingArg
		.ArgNum++
	case  == 'v':
		// Go syntax
		.SharpV = .Sharp
		.Sharp = false
		// Struct-field syntax
		.PlusV = .Plus
		.Plus = false
		fallthrough
	default:
		.ArgNum++
	}
	return true
}

// intFromArg gets the ArgNumth element of Args. On return, isInt reports
// whether the argument has integer type.
func ( *Parser) () ( int,  bool) {
	if .ArgNum < len(.Args) {
		 := .Args[.ArgNum]
		,  = .(int) // Almost always OK.
		if ! {
			// Work harder.
			switch  := reflect.ValueOf(); .Kind() {
			case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
				 := .Int()
				if int64(int()) ==  {
					 = int()
					 = true
				}
			case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
				 := .Uint()
				if int64() >= 0 && uint64(int()) ==  {
					 = int()
					 = true
				}
			default:
				// Already 0, false.
			}
		}
		.ArgNum++
		if tooLarge() {
			 = 0
			 = false
		}
	}
	return
}

// parseArgNumber returns the value of the bracketed number, minus 1
// (explicit argument numbers are one-indexed but we want zero-indexed).
// The opening bracket is known to be present at format[0].
// The returned values are the index, the number of bytes to consume
// up to the closing paren, if present, and whether the number parsed
// ok. The bytes to consume will be 1 if no closing paren is present.
func parseArgNumber( string) ( int,  int,  bool) {
	// There must be at least 3 bytes: [n].
	if len() < 3 {
		return 0, 1, false
	}

	// Find closing bracket.
	for  := 1;  < len(); ++ {
		if [] == ']' {
			, ,  := parsenum(, 1, )
			if ! ||  !=  {
				return 0,  + 1, false
			}
			return  - 1,  + 1, true // arg numbers are one-indexed and skip paren.
		}
	}
	return 0, 1, false
}

// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in
// argNum or the value of the bracketed integer that begins format[i:]. It also returns
// the new value of i, that is, the index of the next byte of the format to process.
func ( *Parser) ( string,  int) ( int,  bool) {
	if len() <=  || [] != '[' {
		return , false
	}
	.Reordered = true
	, ,  := parseArgNumber([:])
	if  && 0 <=  &&  < len(.Args) {
		.ArgNum = 
		return  + , true
	}
	.goodArgNum = false
	return  + , 
}

// tooLarge reports whether the magnitude of the integer is
// too large to be used as a formatting width or precision.
func tooLarge( int) bool {
	const  int = 1e6
	return  >  ||  < -
}

// parsenum converts ASCII to integer.  num is 0 (and isnum is false) if no number present.
func parsenum( string, ,  int) ( int,  bool,  int) {
	if  >=  {
		return 0, false, 
	}
	for  = ;  <  && '0' <= [] && [] <= '9'; ++ {
		if tooLarge() {
			return 0, false,  // Overflow; crazy long number most likely.
		}
		 = *10 + int([]-'0')
		 = true
	}
	return
}