ipld-eth-server/vendor/github.com/dave/jennifer/jen/tokens.go

302 lines
8.2 KiB
Go

package jen
import (
"fmt"
"io"
"strconv"
"strings"
)
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 (t token) isNull(f *File) bool {
if t.typ == packageToken {
// package token is null if the path is a dot-import or the local package path
return f.isDotImport(t.content.(string)) || f.isLocal(t.content.(string))
}
return t.typ == nullToken
}
func (t token) render(f *File, w io.Writer, s *Statement) error {
switch t.typ {
case literalToken:
var out string
switch t.content.(type) {
case bool, string, int, complex128:
// default constant types can be left bare
out = fmt.Sprintf("%#v", t.content)
case float64:
out = fmt.Sprintf("%#v", t.content)
if !strings.Contains(out, ".") && !strings.Contains(out, "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
out += ".0"
}
case float32, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64, uintptr:
// other built-in types need specific type info
out = fmt.Sprintf("%T(%#v)", t.content, t.content)
case complex64:
// fmt package already renders parenthesis for complex64
out = fmt.Sprintf("%T%#v", t.content, t.content)
default:
panic(fmt.Sprintf("unsupported type for literal: %T", t.content))
}
if _, err := w.Write([]byte(out)); err != nil {
return err
}
case literalRuneToken:
if _, err := w.Write([]byte(strconv.QuoteRune(t.content.(rune)))); err != nil {
return err
}
case literalByteToken:
if _, err := w.Write([]byte(fmt.Sprintf("byte(%#v)", t.content))); err != nil {
return err
}
case keywordToken, operatorToken, layoutToken, delimiterToken:
if _, err := w.Write([]byte(fmt.Sprintf("%s", t.content))); err != nil {
return err
}
if t.content.(string) == "default" {
// Special case for Default, which must always be followed by a colon
if _, err := w.Write([]byte(":")); err != nil {
return err
}
}
case packageToken:
path := t.content.(string)
alias := f.register(path)
if _, err := w.Write([]byte(alias)); err != nil {
return err
}
case identifierToken:
if _, err := w.Write([]byte(t.content.(string))); err != nil {
return err
}
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 Null() *Statement {
return newStatement().Null()
}
// Null adds a null item. Null items render nothing and are not followed by a
// separator in lists.
func (g *Group) Null() *Statement {
s := Null()
g.items = append(g.items, s)
return s
}
// Null adds a null item. Null items render nothing and are not followed by a
// separator in lists.
func (s *Statement) Null() *Statement {
t := token{
typ: nullToken,
}
*s = append(*s, t)
return s
}
// Empty adds an empty item. Empty items render nothing but are followed by a
// separator in lists.
func Empty() *Statement {
return newStatement().Empty()
}
// Empty adds an empty item. Empty items render nothing but are followed by a
// separator in lists.
func (g *Group) Empty() *Statement {
s := Empty()
g.items = append(g.items, s)
return s
}
// Empty adds an empty item. Empty items render nothing but are followed by a
// separator in lists.
func (s *Statement) Empty() *Statement {
t := token{
typ: operatorToken,
content: "",
}
*s = append(*s, t)
return s
}
// Op renders the provided operator / token.
func Op(op string) *Statement {
return newStatement().Op(op)
}
// Op renders the provided operator / token.
func (g *Group) Op(op string) *Statement {
s := Op(op)
g.items = append(g.items, s)
return s
}
// Op renders the provided operator / token.
func (s *Statement) Op(op string) *Statement {
t := token{
typ: operatorToken,
content: op,
}
*s = append(*s, t)
return s
}
// Dot renders a period followed by an identifier. Use for fields and selectors.
func Dot(name string) *Statement {
// notest
// don't think this can be used in valid code?
return newStatement().Dot(name)
}
// Dot renders a period followed by an identifier. Use for fields and selectors.
func (g *Group) Dot(name string) *Statement {
// notest
// don't think this can be used in valid code?
s := Dot(name)
g.items = append(g.items, s)
return s
}
// Dot renders a period followed by an identifier. Use for fields and selectors.
func (s *Statement) Dot(name string) *Statement {
d := token{
typ: delimiterToken,
content: ".",
}
t := token{
typ: identifierToken,
content: name,
}
*s = append(*s, d, t)
return s
}
// Id renders an identifier.
func Id(name string) *Statement {
return newStatement().Id(name)
}
// Id renders an identifier.
func (g *Group) Id(name string) *Statement {
s := Id(name)
g.items = append(g.items, s)
return s
}
// Id renders an identifier.
func (s *Statement) Id(name string) *Statement {
t := token{
typ: identifierToken,
content: name,
}
*s = append(*s, t)
return s
}
// 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 Qual(path, name string) *Statement {
return newStatement().Qual(path, name)
}
// 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 (g *Group) Qual(path, name string) *Statement {
s := Qual(path, name)
g.items = append(g.items, s)
return s
}
// 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 (s *Statement) Qual(path, name string) *Statement {
g := &Group{
close: "",
items: []Code{
token{
typ: packageToken,
content: path,
},
token{
typ: identifierToken,
content: name,
},
},
name: "qual",
open: "",
separator: ".",
}
*s = append(*s, g)
return s
}
// Line inserts a blank line.
func Line() *Statement {
return newStatement().Line()
}
// Line inserts a blank line.
func (g *Group) Line() *Statement {
s := Line()
g.items = append(g.items, s)
return s
}
// Line inserts a blank line.
func (s *Statement) Line() *Statement {
t := token{
typ: layoutToken,
content: "\n",
}
*s = append(*s, t)
return s
}