package jen

import (
	
	
	
	
)

type tokenType string

const (
	packageToken     tokenType = "package"
	identifierToken  tokenType = "identifier"
	qualifiedToken   tokenType = "qualified"
	keywordToken     tokenType = "keyword"
	operatorToken    tokenType = "operator"
	delimiterToken   tokenType = "delimiter"
	literalToken     tokenType = "literal"
	literalRuneToken tokenType = "literal_rune"
	literalByteToken tokenType = "literal_byte"
	nullToken        tokenType = "null"
	layoutToken      tokenType = "layout"
)

type token struct {
	typ     tokenType
	content interface{}
}

func ( token) ( *File) bool {
	if .typ == packageToken {
		// package token is null if the path is a dot-import or the local package path
		return .isDotImport(.content.(string)) || .isLocal(.content.(string))
	}
	return .typ == nullToken
}

func ( token) ( *File,  io.Writer,  *Statement) error {
	switch .typ {
	case literalToken:
		var  string
		switch .content.(type) {
		case bool, string, int, complex128:
			// default constant types can be left bare
			 = fmt.Sprintf("%#v", .content)
		case float64:
			 = fmt.Sprintf("%#v", .content)
			if !strings.Contains(, ".") && !strings.Contains(, "e") {
				// If the formatted value is not in scientific notation, and does not have a dot, then
				// we add ".0". Otherwise it will be interpreted as an int.
				// See:
				// https://github.com/dave/jennifer/issues/39
				// https://github.com/golang/go/issues/26363
				 += ".0"
			}
		case float32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
			// other built-in types need specific type info
			 = fmt.Sprintf("%T(%#v)", .content, .content)
		case complex64:
			// fmt package already renders parenthesis for complex64
			 = fmt.Sprintf("%T%#v", .content, .content)
		default:
			panic(fmt.Sprintf("unsupported type for literal: %T", .content))
		}
		if ,  := .Write([]byte());  != nil {
			return 
		}
	case literalRuneToken:
		if ,  := .Write([]byte(strconv.QuoteRune(.content.(rune))));  != nil {
			return 
		}
	case literalByteToken:
		if ,  := .Write([]byte(fmt.Sprintf("byte(%#v)", .content)));  != nil {
			return 
		}
	case keywordToken, operatorToken, layoutToken, delimiterToken:
		if ,  := .Write([]byte(fmt.Sprintf("%s", .content)));  != nil {
			return 
		}
		if .content.(string) == "default" {
			// Special case for Default, which must always be followed by a colon
			if ,  := .Write([]byte(":"));  != nil {
				return 
			}
		}
	case packageToken:
		 := .content.(string)
		 := .register()
		if ,  := .Write([]byte());  != nil {
			return 
		}
	case identifierToken:
		if ,  := .Write([]byte(.content.(string)));  != nil {
			return 
		}
	case nullToken: // notest
		// do nothing (should never render a null token)
	}
	return nil
}

// Null adds a null item. Null items render nothing and are not followed by a
// separator in lists.
func () *Statement {
	return newStatement().Null()
}

// Null adds a null item. Null items render nothing and are not followed by a
// separator in lists.
func ( *Group) () *Statement {
	 := Null()
	.items = append(.items, )
	return 
}

// Null adds a null item. Null items render nothing and are not followed by a
// separator in lists.
func ( *Statement) () *Statement {
	 := token{
		typ: nullToken,
	}
	* = append(*, )
	return 
}

// Empty adds an empty item. Empty items render nothing but are followed by a
// separator in lists.
func () *Statement {
	return newStatement().Empty()
}

// Empty adds an empty item. Empty items render nothing but are followed by a
// separator in lists.
func ( *Group) () *Statement {
	 := Empty()
	.items = append(.items, )
	return 
}

// Empty adds an empty item. Empty items render nothing but are followed by a
// separator in lists.
func ( *Statement) () *Statement {
	 := token{
		typ:     operatorToken,
		content: "",
	}
	* = append(*, )
	return 
}

// Op renders the provided operator / token.
func ( string) *Statement {
	return newStatement().Op()
}

// Op renders the provided operator / token.
func ( *Group) ( string) *Statement {
	 := Op()
	.items = append(.items, )
	return 
}

// Op renders the provided operator / token.
func ( *Statement) ( string) *Statement {
	 := token{
		typ:     operatorToken,
		content: ,
	}
	* = append(*, )
	return 
}

// Dot renders a period followed by an identifier. Use for fields and selectors.
func ( string) *Statement {
	// notest
	// don't think this can be used in valid code?
	return newStatement().Dot()
}

// Dot renders a period followed by an identifier. Use for fields and selectors.
func ( *Group) ( string) *Statement {
	// notest
	// don't think this can be used in valid code?
	 := Dot()
	.items = append(.items, )
	return 
}

// Dot renders a period followed by an identifier. Use for fields and selectors.
func ( *Statement) ( string) *Statement {
	 := token{
		typ:     delimiterToken,
		content: ".",
	}
	 := token{
		typ:     identifierToken,
		content: ,
	}
	* = append(*, , )
	return 
}

// Id renders an identifier.
func ( string) *Statement {
	return newStatement().Id()
}

// Id renders an identifier.
func ( *Group) ( string) *Statement {
	 := Id()
	.items = append(.items, )
	return 
}

// Id renders an identifier.
func ( *Statement) ( string) *Statement {
	 := token{
		typ:     identifierToken,
		content: ,
	}
	* = append(*, )
	return 
}

// Qual renders a qualified identifier. Imports are automatically added when
// used with a File. If the path matches the local path, the package name is
// omitted. If package names conflict they are automatically renamed. Note that
// it is not possible to reliably determine the package name given an arbitrary
// package path, so a sensible name is guessed from the path and added as an
// alias. The names of all standard library packages are known so these do not
// need to be aliased. If more control is needed of the aliases, see
// [File.ImportName](#importname) or [File.ImportAlias](#importalias).
func (,  string) *Statement {
	return newStatement().Qual(, )
}

// Qual renders a qualified identifier. Imports are automatically added when
// used with a File. If the path matches the local path, the package name is
// omitted. If package names conflict they are automatically renamed. Note that
// it is not possible to reliably determine the package name given an arbitrary
// package path, so a sensible name is guessed from the path and added as an
// alias. The names of all standard library packages are known so these do not
// need to be aliased. If more control is needed of the aliases, see
// [File.ImportName](#importname) or [File.ImportAlias](#importalias).
func ( *Group) (,  string) *Statement {
	 := Qual(, )
	.items = append(.items, )
	return 
}

// Qual renders a qualified identifier. Imports are automatically added when
// used with a File. If the path matches the local path, the package name is
// omitted. If package names conflict they are automatically renamed. Note that
// it is not possible to reliably determine the package name given an arbitrary
// package path, so a sensible name is guessed from the path and added as an
// alias. The names of all standard library packages are known so these do not
// need to be aliased. If more control is needed of the aliases, see
// [File.ImportName](#importname) or [File.ImportAlias](#importalias).
func ( *Statement) (,  string) *Statement {
	 := &Group{
		close: "",
		items: []Code{
			token{
				typ:     packageToken,
				content: ,
			},
			token{
				typ:     identifierToken,
				content: ,
			},
		},
		name:      "qual",
		open:      "",
		separator: ".",
	}
	* = append(*, )
	return 
}

// Line inserts a blank line.
func () *Statement {
	return newStatement().Line()
}

// Line inserts a blank line.
func ( *Group) () *Statement {
	 := Line()
	.items = append(.items, )
	return 
}

// Line inserts a blank line.
func ( *Statement) () *Statement {
	 := token{
		typ:     layoutToken,
		content: "\n",
	}
	* = append(*, )
	return 
}