...

Source file src/cuelang.org/go/cue/format/node.go

Documentation: cuelang.org/go/cue/format

     1  // Copyright 2018 The CUE Authors
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package format
    16  
    17  import (
    18  	"fmt"
    19  	"strings"
    20  
    21  	"cuelang.org/go/cue/ast"
    22  	"cuelang.org/go/cue/literal"
    23  	"cuelang.org/go/cue/token"
    24  	"cuelang.org/go/internal"
    25  )
    26  
    27  func printNode(node interface{}, f *printer) error {
    28  	s := newFormatter(f)
    29  
    30  	ls := labelSimplifier{scope: map[string]bool{}}
    31  
    32  	// format node
    33  	f.allowed = nooverride // gobble initial whitespace.
    34  	switch x := node.(type) {
    35  	case *ast.File:
    36  		if f.cfg.simplify {
    37  			ls.markReferences(x)
    38  		}
    39  		s.file(x)
    40  	case ast.Expr:
    41  		if f.cfg.simplify {
    42  			ls.markReferences(x)
    43  		}
    44  		s.expr(x)
    45  	case ast.Decl:
    46  		if f.cfg.simplify {
    47  			ls.markReferences(x)
    48  		}
    49  		s.decl(x)
    50  	// case ast.Node: // TODO: do we need this?
    51  	// 	s.walk(x)
    52  	case []ast.Decl:
    53  		if f.cfg.simplify {
    54  			ls.processDecls(x)
    55  		}
    56  		s.walkDeclList(x)
    57  	default:
    58  		goto unsupported
    59  	}
    60  
    61  	return s.errs
    62  
    63  unsupported:
    64  	return fmt.Errorf("cue/format: unsupported node type %T", node)
    65  }
    66  
    67  func isRegularField(tok token.Token) bool {
    68  	return tok == token.ILLEGAL || tok == token.COLON
    69  }
    70  
    71  // Helper functions for common node lists. They may be empty.
    72  
    73  func nestDepth(f *ast.Field) int {
    74  	d := 1
    75  	if s, ok := f.Value.(*ast.StructLit); ok {
    76  		switch {
    77  		case len(s.Elts) != 1:
    78  			d = 0
    79  		default:
    80  			if f, ok := s.Elts[0].(*ast.Field); ok {
    81  				d += nestDepth(f)
    82  			}
    83  		}
    84  	}
    85  	return d
    86  }
    87  
    88  // TODO: be more accurate and move to astutil
    89  func hasDocComments(d ast.Decl) bool {
    90  	if len(d.Comments()) > 0 {
    91  		return true
    92  	}
    93  	switch x := d.(type) {
    94  	case *ast.Field:
    95  		return len(x.Label.Comments()) > 0
    96  	case *ast.Alias:
    97  		return len(x.Ident.Comments()) > 0
    98  	case *ast.LetClause:
    99  		return len(x.Ident.Comments()) > 0
   100  	}
   101  	return false
   102  }
   103  
   104  func (f *formatter) walkDeclList(list []ast.Decl) {
   105  	f.before(nil)
   106  	d := 0
   107  	hasEllipsis := false
   108  	for i, x := range list {
   109  		if i > 0 {
   110  			f.print(declcomma)
   111  			nd := 0
   112  			if f, ok := x.(*ast.Field); ok {
   113  				nd = nestDepth(f)
   114  			}
   115  			if f.current.parentSep == newline && (d == 0 || nd != d) {
   116  				f.print(f.formfeed())
   117  			}
   118  			if hasDocComments(x) {
   119  				switch x := list[i-1].(type) {
   120  				case *ast.Field:
   121  					if internal.IsDefinition(x.Label) {
   122  						f.print(newsection)
   123  					}
   124  
   125  				default:
   126  					f.print(newsection)
   127  				}
   128  			}
   129  		}
   130  		if f.printer.cfg.simplify && internal.IsEllipsis(x) {
   131  			hasEllipsis = true
   132  			continue
   133  		}
   134  		f.decl(x)
   135  		d = 0
   136  		if f, ok := x.(*ast.Field); ok {
   137  			d = nestDepth(f)
   138  		}
   139  		if j := i + 1; j < len(list) {
   140  			switch x := list[j].(type) {
   141  			case *ast.Field:
   142  				switch x := x.Value.(type) {
   143  				case *ast.StructLit:
   144  					// TODO: not entirely correct: could have multiple elements,
   145  					// not have a valid Lbrace, and be marked multiline. This
   146  					// cannot occur for ASTs resulting from a parse, though.
   147  					if x.Lbrace.IsValid() || len(x.Elts) != 1 {
   148  						f.print(f.formfeed())
   149  						continue
   150  					}
   151  				case *ast.ListLit:
   152  					f.print(f.formfeed())
   153  					continue
   154  				}
   155  			}
   156  		}
   157  		f.print(f.current.parentSep)
   158  	}
   159  	if hasEllipsis {
   160  		f.decl(&ast.Ellipsis{})
   161  		f.print(f.current.parentSep)
   162  	}
   163  	f.after(nil)
   164  }
   165  
   166  func (f *formatter) walkSpecList(list []*ast.ImportSpec) {
   167  	f.before(nil)
   168  	for _, x := range list {
   169  		f.before(x)
   170  		f.importSpec(x)
   171  		f.after(x)
   172  	}
   173  	f.after(nil)
   174  }
   175  
   176  func (f *formatter) walkClauseList(list []ast.Clause, ws whiteSpace) {
   177  	f.before(nil)
   178  	for _, x := range list {
   179  		f.before(x)
   180  		f.print(ws)
   181  		f.clause(x)
   182  		f.after(x)
   183  	}
   184  	f.after(nil)
   185  }
   186  
   187  func (f *formatter) walkListElems(list []ast.Expr) {
   188  	f.before(nil)
   189  	for _, x := range list {
   190  		f.before(x)
   191  		switch n := x.(type) {
   192  		case *ast.Comprehension:
   193  			f.walkClauseList(n.Clauses, blank)
   194  			f.print(blank, nooverride)
   195  			f.expr(n.Value)
   196  
   197  		case *ast.Ellipsis:
   198  			f.ellipsis(n)
   199  
   200  		case *ast.Alias:
   201  			f.expr(n.Ident)
   202  			f.print(n.Equal, token.BIND)
   203  			f.expr(n.Expr)
   204  
   205  			// TODO: ast.CommentGroup: allows comment groups in ListLits.
   206  
   207  		case ast.Expr:
   208  			f.exprRaw(n, token.LowestPrec, 1)
   209  		}
   210  		f.print(comma, blank)
   211  		f.after(x)
   212  	}
   213  	f.after(nil)
   214  }
   215  
   216  func (f *formatter) walkArgsList(list []ast.Expr, depth int) {
   217  	f.before(nil)
   218  	for _, x := range list {
   219  		f.before(x)
   220  		f.exprRaw(x, token.LowestPrec, depth)
   221  		f.print(comma, blank)
   222  		f.after(x)
   223  	}
   224  	f.after(nil)
   225  }
   226  
   227  func (f *formatter) file(file *ast.File) {
   228  	f.before(file)
   229  	f.walkDeclList(file.Decls)
   230  	f.after(file)
   231  	f.print(token.EOF)
   232  }
   233  
   234  func (f *formatter) inlineField(n *ast.Field) *ast.Field {
   235  	regular := internal.IsRegularField(n)
   236  	// shortcut single-element structs.
   237  	// If the label has a valid position, we assume that an unspecified
   238  	// Lbrace signals the intend to collapse fields.
   239  	if !n.Label.Pos().IsValid() && !(f.printer.cfg.simplify && regular) {
   240  		return nil
   241  	}
   242  
   243  	obj, ok := n.Value.(*ast.StructLit)
   244  	if !ok || len(obj.Elts) != 1 ||
   245  		(obj.Lbrace.IsValid() && !f.printer.cfg.simplify) ||
   246  		(obj.Lbrace.IsValid() && hasDocComments(n)) ||
   247  		len(n.Attrs) > 0 {
   248  		return nil
   249  	}
   250  
   251  	mem, ok := obj.Elts[0].(*ast.Field)
   252  	if !ok || len(mem.Attrs) > 0 {
   253  		return nil
   254  	}
   255  
   256  	if hasDocComments(mem) {
   257  		// TODO: this inserts curly braces even in spaces where this
   258  		// may not be desirable, such as:
   259  		// a:
   260  		//   // foo
   261  		//   b: 3
   262  		return nil
   263  	}
   264  	return mem
   265  }
   266  
   267  func (f *formatter) decl(decl ast.Decl) {
   268  	if decl == nil {
   269  		return
   270  	}
   271  	defer f.after(decl)
   272  	if !f.before(decl) {
   273  		return
   274  	}
   275  
   276  	switch n := decl.(type) {
   277  	case *ast.Field:
   278  		constraint, _ := internal.ConstraintToken(n)
   279  		f.label(n.Label, constraint)
   280  
   281  		regular := isRegularField(n.Token)
   282  		if regular {
   283  			f.print(noblank, nooverride, n.TokenPos, token.COLON)
   284  		} else {
   285  			f.print(blank, nooverride, n.Token)
   286  		}
   287  
   288  		if mem := f.inlineField(n); mem != nil {
   289  			switch {
   290  			default:
   291  				fallthrough
   292  
   293  			case regular && f.cfg.simplify:
   294  				f.print(blank, nooverride)
   295  				f.decl(mem)
   296  
   297  			case mem.Label.Pos().IsNewline():
   298  				f.print(indent, formfeed)
   299  				f.decl(mem)
   300  				f.indent--
   301  			}
   302  			return
   303  		}
   304  
   305  		nextFF := f.nextNeedsFormfeed(n.Value)
   306  		tab := vtab
   307  		if nextFF {
   308  			tab = blank
   309  		}
   310  
   311  		f.print(tab)
   312  
   313  		if n.Value != nil {
   314  			switch n.Value.(type) {
   315  			case *ast.ListLit, *ast.StructLit:
   316  				f.expr(n.Value)
   317  			default:
   318  				f.print(indent)
   319  				f.expr(n.Value)
   320  				f.markUnindentLine()
   321  			}
   322  		} else {
   323  			f.current.pos++
   324  			f.visitComments(f.current.pos)
   325  		}
   326  
   327  		space := tab
   328  		for _, a := range n.Attrs {
   329  			if f.before(a) {
   330  				f.print(space, a.At, a)
   331  			}
   332  			f.after(a)
   333  			space = blank
   334  		}
   335  
   336  		if nextFF {
   337  			f.print(formfeed)
   338  		}
   339  
   340  	case *ast.BadDecl:
   341  		f.print(n.From, "*bad decl*", declcomma)
   342  
   343  	case *ast.Package:
   344  		f.print(n.PackagePos, "package")
   345  		f.print(blank, n.Name, newsection, nooverride)
   346  
   347  	case *ast.ImportDecl:
   348  		f.print(n.Import, "import")
   349  		if len(n.Specs) == 0 {
   350  			f.print(blank, n.Lparen, token.LPAREN, n.Rparen, token.RPAREN, newline)
   351  			break
   352  		}
   353  		switch {
   354  		case len(n.Specs) == 1 && len(n.Specs[0].Comments()) == 0:
   355  			if !n.Lparen.IsValid() {
   356  				f.print(blank)
   357  				f.walkSpecList(n.Specs)
   358  				break
   359  			}
   360  			fallthrough
   361  		default:
   362  			f.print(blank, n.Lparen, token.LPAREN, newline, indent)
   363  			f.walkSpecList(n.Specs)
   364  			f.print(unindent, newline, n.Rparen, token.RPAREN, newline)
   365  		}
   366  		f.print(newsection, nooverride)
   367  
   368  	case *ast.LetClause:
   369  		if !decl.Pos().HasRelPos() || decl.Pos().RelPos() >= token.Newline {
   370  			f.print(formfeed)
   371  		}
   372  		f.print(n.Let, token.LET, blank, nooverride)
   373  		f.expr(n.Ident)
   374  		f.print(blank, nooverride, n.Equal, token.BIND, blank)
   375  		f.expr(n.Expr)
   376  		f.print(declcomma) // implied
   377  
   378  	case *ast.EmbedDecl:
   379  		if !n.Pos().HasRelPos() || n.Pos().RelPos() >= token.Newline {
   380  			f.print(formfeed)
   381  		}
   382  		f.expr(n.Expr)
   383  		f.print(newline, noblank)
   384  
   385  	case *ast.Attribute:
   386  		f.print(n.At, n)
   387  
   388  	case *ast.CommentGroup:
   389  		f.printComment(n)
   390  		f.print(newsection)
   391  
   392  	case ast.Expr:
   393  		f.embedding(n)
   394  	}
   395  }
   396  
   397  func (f *formatter) embedding(decl ast.Expr) {
   398  	switch n := decl.(type) {
   399  	case *ast.Comprehension:
   400  		if !n.Pos().HasRelPos() || n.Pos().RelPos() >= token.Newline {
   401  			f.print(formfeed)
   402  		}
   403  		f.walkClauseList(n.Clauses, blank)
   404  		f.print(blank, nooverride)
   405  		f.expr(n.Value)
   406  
   407  	case *ast.Ellipsis:
   408  		f.ellipsis(n)
   409  
   410  	case *ast.Alias:
   411  		if !decl.Pos().HasRelPos() || decl.Pos().RelPos() >= token.Newline {
   412  			f.print(formfeed)
   413  		}
   414  		f.expr(n.Ident)
   415  		f.print(blank, n.Equal, token.BIND, blank)
   416  		f.expr(n.Expr)
   417  		f.print(declcomma) // implied
   418  
   419  		// TODO: ast.CommentGroup: allows comment groups in ListLits.
   420  
   421  	case ast.Expr:
   422  		f.exprRaw(n, token.LowestPrec, 1)
   423  	}
   424  }
   425  
   426  func (f *formatter) nextNeedsFormfeed(n ast.Expr) bool {
   427  	switch x := n.(type) {
   428  	case *ast.StructLit:
   429  		return true
   430  	case *ast.BasicLit:
   431  		return strings.IndexByte(x.Value, '\n') >= 0
   432  	case *ast.ListLit:
   433  		return true
   434  	case *ast.UnaryExpr:
   435  		return f.nextNeedsFormfeed(x.X)
   436  	case *ast.BinaryExpr:
   437  		return f.nextNeedsFormfeed(x.X) || f.nextNeedsFormfeed(x.Y)
   438  	case *ast.CallExpr:
   439  		for _, arg := range x.Args {
   440  			if f.nextNeedsFormfeed(arg) {
   441  				return true
   442  			}
   443  		}
   444  	}
   445  	return false
   446  }
   447  
   448  func (f *formatter) importSpec(x *ast.ImportSpec) {
   449  	if x.Name != nil {
   450  		f.label(x.Name, token.ILLEGAL)
   451  		f.print(blank)
   452  	} else {
   453  		f.current.pos++
   454  		f.visitComments(f.current.pos)
   455  	}
   456  	f.expr(x.Path)
   457  	f.print(newline)
   458  }
   459  
   460  func (f *formatter) label(l ast.Label, constraint token.Token) {
   461  	f.before(l)
   462  	defer f.after(l)
   463  	switch n := l.(type) {
   464  	case *ast.Alias:
   465  		f.expr(n)
   466  
   467  	case *ast.Ident:
   468  		// Escape an identifier that has invalid characters. This may happen,
   469  		// if the AST is not generated by the parser.
   470  		name := n.Name
   471  		if !ast.IsValidIdent(name) {
   472  			name = literal.String.Quote(n.Name)
   473  		}
   474  		f.print(n.NamePos, name)
   475  
   476  	case *ast.BasicLit:
   477  		str := n.Value
   478  		// Allow any CUE string in the AST, but ensure it is formatted
   479  		// according to spec.
   480  		if strings.HasPrefix(str, `"""`) || strings.HasPrefix(str, "#") {
   481  			if u, err := literal.Unquote(str); err == nil {
   482  				str = literal.String.Quote(u)
   483  			}
   484  		}
   485  		f.print(n.ValuePos, str)
   486  
   487  	case *ast.ListLit:
   488  		f.expr(n)
   489  
   490  	case *ast.ParenExpr:
   491  		f.expr(n)
   492  
   493  	case *ast.Interpolation:
   494  		f.expr(n)
   495  
   496  	default:
   497  		panic(fmt.Sprintf("unknown label type %T", n))
   498  	}
   499  	if constraint != token.ILLEGAL {
   500  		f.print(constraint)
   501  	}
   502  }
   503  
   504  func (f *formatter) ellipsis(x *ast.Ellipsis) {
   505  	f.print(x.Ellipsis, token.ELLIPSIS)
   506  	if x.Type != nil && !isTop(x.Type) {
   507  		f.expr(x.Type)
   508  	}
   509  }
   510  
   511  func (f *formatter) expr(x ast.Expr) {
   512  	const depth = 1
   513  	f.expr1(x, token.LowestPrec, depth)
   514  }
   515  
   516  func (f *formatter) expr0(x ast.Expr, depth int) {
   517  	f.expr1(x, token.LowestPrec, depth)
   518  }
   519  
   520  func (f *formatter) expr1(expr ast.Expr, prec1, depth int) {
   521  	if f.before(expr) {
   522  		f.exprRaw(expr, prec1, depth)
   523  	}
   524  	f.after(expr)
   525  }
   526  
   527  func (f *formatter) exprRaw(expr ast.Expr, prec1, depth int) {
   528  
   529  	switch x := expr.(type) {
   530  	case *ast.BadExpr:
   531  		f.print(x.From, "_|_")
   532  
   533  	case *ast.BottomLit:
   534  		f.print(x.Bottom, token.BOTTOM)
   535  
   536  	case *ast.Alias:
   537  		// Aliases in expression positions are printed in short form.
   538  		f.label(x.Ident, token.ILLEGAL)
   539  		f.print(x.Equal, token.BIND)
   540  		f.expr(x.Expr)
   541  
   542  	case *ast.Ident:
   543  		f.print(x.NamePos, x)
   544  
   545  	case *ast.BinaryExpr:
   546  		if depth < 1 {
   547  			f.internalError("depth < 1:", depth)
   548  			depth = 1
   549  		}
   550  		f.binaryExpr(x, prec1, cutoff(x, depth), depth)
   551  
   552  	case *ast.UnaryExpr:
   553  		const prec = token.UnaryPrec
   554  		if prec < prec1 {
   555  			// parenthesis needed
   556  			f.print(token.LPAREN, nooverride)
   557  			f.expr(x)
   558  			f.print(token.RPAREN)
   559  		} else {
   560  			// no parenthesis needed
   561  			f.print(x.OpPos, x.Op, nooverride)
   562  			f.expr1(x.X, prec, depth)
   563  		}
   564  
   565  	case *ast.BasicLit:
   566  		f.print(x.ValuePos, x)
   567  
   568  	case *ast.Interpolation:
   569  		f.before(nil)
   570  		for _, x := range x.Elts {
   571  			f.expr0(x, depth+1)
   572  		}
   573  		f.after(nil)
   574  
   575  	case *ast.ParenExpr:
   576  		if _, hasParens := x.X.(*ast.ParenExpr); hasParens {
   577  			// don't print parentheses around an already parenthesized expression
   578  			// TODO: consider making this more general and incorporate precedence levels
   579  			f.expr0(x.X, depth)
   580  		} else {
   581  			f.print(x.Lparen, token.LPAREN)
   582  			f.expr0(x.X, reduceDepth(depth)) // parentheses undo one level of depth
   583  			f.print(x.Rparen, token.RPAREN)
   584  		}
   585  
   586  	case *ast.SelectorExpr:
   587  		f.selectorExpr(x, depth)
   588  
   589  	case *ast.IndexExpr:
   590  		f.expr1(x.X, token.HighestPrec, 1)
   591  		f.print(x.Lbrack, token.LBRACK)
   592  		f.expr0(x.Index, depth+1)
   593  		f.print(x.Rbrack, token.RBRACK)
   594  
   595  	case *ast.SliceExpr:
   596  		f.expr1(x.X, token.HighestPrec, 1)
   597  		f.print(x.Lbrack, token.LBRACK)
   598  		indices := []ast.Expr{x.Low, x.High}
   599  		for i, y := range indices {
   600  			if i > 0 {
   601  				// blanks around ":" if both sides exist and either side is a binary expression
   602  				x := indices[i-1]
   603  				if depth <= 1 && x != nil && y != nil && (isBinary(x) || isBinary(y)) {
   604  					f.print(blank, token.COLON, blank)
   605  				} else {
   606  					f.print(token.COLON)
   607  				}
   608  			}
   609  			if y != nil {
   610  				f.expr0(y, depth+1)
   611  			}
   612  		}
   613  		f.print(x.Rbrack, token.RBRACK)
   614  
   615  	case *ast.CallExpr:
   616  		if len(x.Args) > 1 {
   617  			depth++
   618  		}
   619  		wasIndented := f.possibleSelectorExpr(x.Fun, token.HighestPrec, depth)
   620  		f.print(x.Lparen, token.LPAREN)
   621  		f.walkArgsList(x.Args, depth)
   622  		f.print(trailcomma, noblank, x.Rparen, token.RPAREN)
   623  		if wasIndented {
   624  			f.print(unindent)
   625  		}
   626  
   627  	case *ast.StructLit:
   628  		var l line
   629  		ws := noblank
   630  		ff := f.formfeed()
   631  
   632  		switch {
   633  		case len(x.Elts) == 0:
   634  			if !x.Rbrace.HasRelPos() {
   635  				// collapse curly braces if the body is empty.
   636  				ffAlt := blank | nooverride
   637  				for _, c := range x.Comments() {
   638  					if c.Position == 1 {
   639  						ffAlt = ff
   640  					}
   641  				}
   642  				ff = ffAlt
   643  			}
   644  		case !x.Rbrace.HasRelPos() || !x.Elts[0].Pos().HasRelPos():
   645  			ws |= newline | nooverride
   646  		}
   647  		f.print(x.Lbrace, token.LBRACE, &l, ws, ff, indent)
   648  
   649  		f.walkDeclList(x.Elts)
   650  		f.matchUnindent()
   651  
   652  		ws = noblank
   653  		if f.lineout != l {
   654  			ws |= newline
   655  			if f.lastTok != token.RBRACE && f.lastTok != token.RBRACK {
   656  				ws |= nooverride
   657  			}
   658  		}
   659  		f.print(ws, x.Rbrace, token.RBRACE)
   660  
   661  	case *ast.ListLit:
   662  		f.print(x.Lbrack, token.LBRACK, noblank, indent)
   663  		f.walkListElems(x.Elts)
   664  		f.print(trailcomma, noblank)
   665  		f.visitComments(f.current.pos)
   666  		f.matchUnindent()
   667  		f.print(noblank, x.Rbrack, token.RBRACK)
   668  
   669  	case *ast.Ellipsis:
   670  		f.ellipsis(x)
   671  
   672  	default:
   673  		panic(fmt.Sprintf("unimplemented type %T", x))
   674  	}
   675  }
   676  
   677  func (f *formatter) clause(clause ast.Clause) {
   678  	switch n := clause.(type) {
   679  	case *ast.ForClause:
   680  		f.print(n.For, "for", blank)
   681  		f.print(indent)
   682  		if n.Key != nil {
   683  			f.label(n.Key, token.ILLEGAL)
   684  			f.print(n.Colon, token.COMMA, blank)
   685  		} else {
   686  			f.current.pos++
   687  			f.visitComments(f.current.pos)
   688  		}
   689  		f.label(n.Value, token.ILLEGAL)
   690  		f.print(blank, n.In, "in", blank)
   691  		f.expr(n.Source)
   692  		f.markUnindentLine()
   693  
   694  	case *ast.IfClause:
   695  		f.print(n.If, "if", blank)
   696  		f.print(indent)
   697  		f.expr(n.Condition)
   698  		f.markUnindentLine()
   699  
   700  	case *ast.LetClause:
   701  		f.print(n.Let, token.LET, blank, nooverride)
   702  		f.print(indent)
   703  		f.expr(n.Ident)
   704  		f.print(blank, nooverride, n.Equal, token.BIND, blank)
   705  		f.expr(n.Expr)
   706  		f.markUnindentLine()
   707  
   708  	default:
   709  		panic("unknown clause type")
   710  	}
   711  }
   712  
   713  func walkBinary(e *ast.BinaryExpr) (has6, has7, has8 bool, maxProblem int) {
   714  	switch e.Op.Precedence() {
   715  	case 6:
   716  		has6 = true
   717  	case 7:
   718  		has7 = true
   719  	case 8:
   720  		has8 = true
   721  	}
   722  
   723  	switch l := e.X.(type) {
   724  	case *ast.BinaryExpr:
   725  		if l.Op.Precedence() < e.Op.Precedence() {
   726  			// parens will be inserted.
   727  			// pretend this is an *syntax.ParenExpr and do nothing.
   728  			break
   729  		}
   730  		h6, h7, h8, mp := walkBinary(l)
   731  		has6 = has6 || h6
   732  		has7 = has7 || h7
   733  		has8 = has8 || h8
   734  		if maxProblem < mp {
   735  			maxProblem = mp
   736  		}
   737  	}
   738  
   739  	switch r := e.Y.(type) {
   740  	case *ast.BinaryExpr:
   741  		if r.Op.Precedence() <= e.Op.Precedence() {
   742  			// parens will be inserted.
   743  			// pretend this is an *syntax.ParenExpr and do nothing.
   744  			break
   745  		}
   746  		h6, h7, h8, mp := walkBinary(r)
   747  		has6 = has6 || h6
   748  		has7 = has7 || h7
   749  		has8 = has8 || h8
   750  		if maxProblem < mp {
   751  			maxProblem = mp
   752  		}
   753  
   754  	case *ast.UnaryExpr:
   755  		switch e.Op.String() + r.Op.String() {
   756  		case "/*":
   757  			maxProblem = 8
   758  		case "++", "--":
   759  			if maxProblem < 6 {
   760  				maxProblem = 6
   761  			}
   762  		}
   763  	}
   764  	return
   765  }
   766  
   767  func cutoff(e *ast.BinaryExpr, depth int) int {
   768  	has6, has7, has8, maxProblem := walkBinary(e)
   769  	if maxProblem > 0 {
   770  		return maxProblem + 1
   771  	}
   772  	if (has6 || has7) && has8 {
   773  		if depth == 1 {
   774  			return 8
   775  		}
   776  		if has7 {
   777  			return 7
   778  		}
   779  		return 6
   780  	}
   781  	if has6 && has7 {
   782  		if depth == 1 {
   783  			return 7
   784  		}
   785  		return 6
   786  	}
   787  	if depth == 1 {
   788  		return 8
   789  	}
   790  	return 6
   791  }
   792  
   793  func diffPrec(expr ast.Expr, prec int) int {
   794  	x, ok := expr.(*ast.BinaryExpr)
   795  	if !ok || prec != x.Op.Precedence() {
   796  		return 1
   797  	}
   798  	return 0
   799  }
   800  
   801  func reduceDepth(depth int) int {
   802  	depth--
   803  	if depth < 1 {
   804  		depth = 1
   805  	}
   806  	return depth
   807  }
   808  
   809  // Format the binary expression: decide the cutoff and then format.
   810  // Let's call depth == 1 Normal mode, and depth > 1 Compact mode.
   811  // (Algorithm suggestion by Russ Cox.)
   812  //
   813  // The precedences are:
   814  //
   815  //	7             *  /  % quo rem div mod
   816  //	6             +  -
   817  //	5             ==  !=  <  <=  >  >=
   818  //	4             &&
   819  //	3             ||
   820  //	2             &
   821  //	1             |
   822  //
   823  // The only decision is whether there will be spaces around levels 6 and 7.
   824  // There are never spaces at level 8 (unary), and always spaces at levels 5 and below.
   825  //
   826  // To choose the cutoff, look at the whole expression but excluding primary
   827  // expressions (function calls, parenthesized exprs), and apply these rules:
   828  //
   829  //  1. If there is a binary operator with a right side unary operand
   830  //     that would clash without a space, the cutoff must be (in order):
   831  //
   832  //     /*	8
   833  //     ++	7 // not necessary, but to avoid confusion
   834  //     --	7
   835  //
   836  //     (Comparison operators always have spaces around them.)
   837  //
   838  //  2. If there is a mix of level 7 and level 6 operators, then the cutoff
   839  //     is 7 (use spaces to distinguish precedence) in Normal mode
   840  //     and 6 (never use spaces) in Compact mode.
   841  //
   842  //  3. If there are no level 6 operators or no level 7 operators, then the
   843  //     cutoff is 8 (always use spaces) in Normal mode
   844  //     and 6 (never use spaces) in Compact mode.
   845  func (f *formatter) binaryExpr(x *ast.BinaryExpr, prec1, cutoff, depth int) {
   846  	f.nestExpr++
   847  	defer func() { f.nestExpr-- }()
   848  
   849  	prec := x.Op.Precedence()
   850  	if prec < prec1 {
   851  		// parenthesis needed
   852  		// Note: The parser inserts an syntax.ParenExpr node; thus this case
   853  		//       can only occur if the AST is created in a different way.
   854  		// defer p.pushComment(nil).pop()
   855  		f.print(token.LPAREN, nooverride)
   856  		f.expr0(x, reduceDepth(depth)) // parentheses undo one level of depth
   857  		f.print(token.RPAREN)
   858  		return
   859  	}
   860  
   861  	printBlank := prec < cutoff
   862  
   863  	f.expr1(x.X, prec, depth+diffPrec(x.X, prec))
   864  	f.print(nooverride)
   865  	if printBlank {
   866  		f.print(blank)
   867  	}
   868  	f.print(x.OpPos, x.Op)
   869  	if x.Y.Pos().IsNewline() {
   870  		// at least one line break, but respect an extra empty line
   871  		// in the source
   872  		f.print(formfeed)
   873  		printBlank = false // no blank after line break
   874  	} else {
   875  		f.print(nooverride)
   876  	}
   877  	if printBlank {
   878  		f.print(blank)
   879  	}
   880  	f.expr1(x.Y, prec+1, depth+1)
   881  }
   882  
   883  func isBinary(expr ast.Expr) bool {
   884  	_, ok := expr.(*ast.BinaryExpr)
   885  	return ok
   886  }
   887  
   888  func (f *formatter) possibleSelectorExpr(expr ast.Expr, prec1, depth int) bool {
   889  	if x, ok := expr.(*ast.SelectorExpr); ok {
   890  		return f.selectorExpr(x, depth)
   891  	}
   892  	f.expr1(expr, prec1, depth)
   893  	return false
   894  }
   895  
   896  // selectorExpr handles an *syntax.SelectorExpr node and returns whether x spans
   897  // multiple lines.
   898  func (f *formatter) selectorExpr(x *ast.SelectorExpr, depth int) bool {
   899  	f.expr1(x.X, token.HighestPrec, depth)
   900  	f.print(token.PERIOD)
   901  	if x.Sel.Pos().IsNewline() {
   902  		f.print(indent, formfeed)
   903  		f.expr(x.Sel.(ast.Expr))
   904  		f.print(unindent)
   905  		return true
   906  	}
   907  	f.print(noblank)
   908  	f.expr(x.Sel.(ast.Expr))
   909  	return false
   910  }
   911  
   912  func isTop(e ast.Expr) bool {
   913  	ident, ok := e.(*ast.Ident)
   914  	return ok && ident.Name == "_"
   915  }
   916  

View as plain text