// Copyright 2018 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 xerrors

import (
	
	
	
	

	
)

const percentBangString = "%!"

// Errorf formats according to a format specifier and returns the string as a
// value that satisfies error.
//
// The returned error includes the file and line number of the caller when
// formatted with additional detail enabled. If the last argument is an error
// the returned error's Format method will return it if the format string ends
// with ": %s", ": %v", or ": %w". If the last argument is an error and the
// format string ends with ": %w", the returned error implements an Unwrap
// method returning it.
//
// If the format specifier includes a %w verb with an error operand in a
// position other than at the end, the returned error will still implement an
// Unwrap method returning the operand, but the error's Format method will not
// return the wrapped error.
//
// It is invalid to include more than one %w verb or to supply it with an
// operand that does not implement the error interface. The %w verb is otherwise
// a synonym for %v.
//
// Note that as of Go 1.13, the fmt.Errorf function will do error formatting,
// but it will not capture a stack backtrace.
func ( string,  ...any) error {
	 = formatPlusW()
	// Support a ": %[wsv]" suffix, which works well with xerrors.Formatter.
	 := strings.HasSuffix(, ": %w")
	, ,  := parsePercentW()
	 := ! &&  >= 0
	if ! && ( || strings.HasSuffix(, ": %s") || strings.HasSuffix(, ": %v")) {
		 := errorAt(, len()-1)
		if  == nil {
			return &noWrapError{fmt.Sprintf(, ...), nil, Caller(1)}
		}
		// TODO: this is not entirely correct. The error value could be
		// printed elsewhere in format if it mixes numbered with unnumbered
		// substitutions. With relatively small changes to doPrintf we can
		// have it optionally ignore extra arguments and pass the argument
		// list in its entirety.
		 := fmt.Sprintf([:len()-len(": %s")], [:len()-1]...)
		 := Frame{}
		if internal.EnableTrace {
			 = Caller(1)
		}
		if  {
			return &wrapError{, , }
		}
		return &noWrapError{, , }
	}
	// Support %w anywhere.
	// TODO: don't repeat the wrapped error's message when %w occurs in the middle.
	 := fmt.Sprintf(, ...)
	if  < 0 {
		return &noWrapError{, nil, Caller(1)}
	}
	 := errorAt(, )
	if ! ||  == nil {
		// Too many %ws or argument of %w is not an error. Approximate the Go
		// 1.13 fmt.Errorf message.
		return &noWrapError{fmt.Sprintf("%sw(%s)", percentBangString, ), nil, Caller(1)}
	}
	 := Frame{}
	if internal.EnableTrace {
		 = Caller(1)
	}
	return &wrapError{, , }
}

func errorAt( []any,  int) error {
	if  < 0 ||  >= len() {
		return nil
	}
	,  := [].(error)
	if ! {
		return nil
	}
	return 
}

// formatPlusW is used to avoid the vet check that will barf at %w.
func formatPlusW( string) string {
	return 
}

// Return the index of the only %w in format, or -1 if none.
// Also return a rewritten format string with %w replaced by %v, and
// false if there is more than one %w.
// TODO: handle "%[N]w".
func parsePercentW( string) ( int,  string,  bool) {
	// Loosely copied from golang.org/x/tools/go/analysis/passes/printf/printf.go.
	 = -1
	 = true
	 := 0
	 := 0
	var  bool
	for  := 0;  < len();  +=  {
		if [] != '%' {
			 = 1
			continue
		}
		// "%%" is not a format directive.
		if +1 < len() && [+1] == '%' {
			 = 2
			continue
		}
		,  = parsePrintfVerb([:])
		if  {
			if  >= 0 {
				 = false
			} else {
				 = 
			}
			// "Replace" the last character, the 'w', with a 'v'.
			 :=  +  - 1
			 = [:] + "v" + [+1:]
		}
		++
	}
	return , , 
}

// Parse the printf verb starting with a % at s[0].
// Return how many bytes it occupies and whether the verb is 'w'.
func parsePrintfVerb( string) (int, bool) {
	// Assume only that the directive is a sequence of non-letters followed by a single letter.
	 := 0
	var  rune
	for  := 1;  < len();  +=  {
		,  = utf8.DecodeRuneInString([:])
		if unicode.IsLetter() {
			return  + ,  == 'w'
		}
	}
	return len(), false
}

type noWrapError struct {
	msg   string
	err   error
	frame Frame
}

func ( *noWrapError) () string {
	return fmt.Sprint()
}

func ( *noWrapError) ( fmt.State,  rune) { FormatError(, , ) }

func ( *noWrapError) ( Printer) ( error) {
	.Print(.msg)
	.frame.Format()
	return .err
}

type wrapError struct {
	msg   string
	err   error
	frame Frame
}

func ( *wrapError) () string {
	return fmt.Sprint()
}

func ( *wrapError) ( fmt.State,  rune) { FormatError(, , ) }

func ( *wrapError) ( Printer) ( error) {
	.Print(.msg)
	.frame.Format()
	return .err
}

func ( *wrapError) () error {
	return .err
}