// Copyright 2009 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.

// This is a package for testing comment placement by go/printer.
//
package main

import "fmt"	// fmt

const c0 = 0	// zero
const (
	c1	= iota	// c1
	c2		// c2
)

// Alignment of comments in declarations>
const (
	_	T	= iota	// comment
	_			// comment
	_			// comment
	_	= iota + 10
	_	// comments

	_		= 10	// comment
	_	T	= 20	// comment
)

const (
	_____	= iota	// foo
	_		// bar
	_	= 0	// bal
	_		// bat
)

const (
	_	T	= iota	// comment
	_			// comment
	_			// comment
	_	= iota + 10
	_		// comment
	_		= 10
	_		= 20	// comment
	_	T	= 0	// comment
)

// The SZ struct; it is empty.
type SZ struct{}

// The S0 struct; no field is exported.
type S0 struct {
	int
	x, y, z	int	// 3 unexported fields
}

// The S1 struct; some fields are not exported.
type S1 struct {
	S0
	A, B, C	float	// 3 exported fields
	D, b, c	int	// 2 unexported fields
}

// The S2 struct; all fields are exported.
type S2 struct {
	S1
	A, B, C	float	// 3 exported fields
}

// The IZ interface; it is empty.
type SZ interface{}

// The I0 interface; no method is exported.
type I0 interface {
	f(x int) int	// unexported method
}

// The I1 interface; some methods are not exported.
type I1 interface {
	I0
	F(x float) float	// exported methods
	g(x int) int		// unexported method
}

// The I2 interface; all methods are exported.
type I2 interface {
	I0
	F(x float) float	// exported method
	G(x float) float	// exported method
}

// The S3 struct; all comments except for the last one must appear in the export.
type S3 struct {
	// lead comment for F1
	F1	int	// line comment for F1
	// lead comment for F2
	F2	int	// line comment for F2
	f3	int	// f3 is not exported
}

// This comment group should be separated
// with a newline from the next comment
// group.

// This comment should NOT be associated with the next declaration.

var x int	// x
var ()

// This comment SHOULD be associated with f0.
func f0() {
	const pi = 3.14	// pi
	var s1 struct{}	/* an empty struct */	/* foo */
	// a struct constructor
	// --------------------
	var s2 struct{} = struct{}{}
	x := pi
}

//
// This comment should be associated with f1, with one blank line before the comment.
//
func f1() {
	f0()
	/* 1 */
	// 2
	/* 3 */
	/* 4 */
	f0()
}

func _() {
	// this comment should be properly indented
}

func _(x int) int {
	if x < 0 {	// the tab printed before this comment's // must not affect the remaining lines
		return -x	// this statement should be properly indented
	}
	if x < 0 {	/* the tab printed before this comment's /* must not affect the remaining lines */
		return -x	// this statement should be properly indented
	}
	return x
}

func typeswitch(x interface{}) {
	switch v := x.(type) {
	case bool, int, float:
	case string:
	default:
	}

	switch x.(type) {
	}

	switch v0, ok := x.(int); v := x.(type) {
	}

	switch v0, ok := x.(int); x.(type) {
	case byte:	// this comment should be on the same line as the keyword
		// this comment should be normally indented
		_ = 0
	case bool, int, float:
		// this comment should be indented
	case string:
	default:
		// this comment should be indented
	}
	// this comment should not be indented
}

//
// Indentation of comments after possibly indented multi-line constructs
// (test cases for issue 3147).
//

func _() {
	s := 1 +
		2
	// should be indented like s
}

func _() {
	s := 1 +
		2	// comment
	// should be indented like s
}

func _() {
	s := 1 +
		2	// comment
	// should be indented like s
	_ = 0
}

func _() {
	s := 1 +
		2
	// should be indented like s
	_ = 0
}

func _() {
	s := 1 +
		2

	// should be indented like s
}

func _() {
	s := 1 +
		2	// comment

	// should be indented like s
}

func _() {
	s := 1 +
		2	// comment

	// should be indented like s
	_ = 0
}

func _() {
	s := 1 +
		2

	// should be indented like s
	_ = 0
}

// Test case from issue 3147.
func f() {
	templateText := "a" +	// A
		"b" +	// B
		"c"	// C

	// should be aligned with f()
	f()
}

// Modified test case from issue 3147.
func f() {
	templateText := "a" +	// A
		"b" +	// B
		"c"	// C

		// may not be aligned with f() (source is not aligned)
	f()
}

//
// Test cases for alignment of lines in general comments.
//

func _() {
	/* freestanding comment
	   aligned		line
	   aligned line
	*/
}

func _() {
	/* freestanding comment
	   aligned		line
	   aligned line
	*/
}

func _() {
	/* freestanding comment
	   aligned		line
	   aligned line */
}

func _() {
	/*	freestanding comment
		aligned		line
		aligned line
	*/
}

func _() {
	/*	freestanding comment
		aligned		line
		aligned line
	*/
}

func _() {
	/*	freestanding comment
		aligned		line
		aligned line */
}

func _() {
	/*
	   freestanding comment
	   aligned		line
	   aligned line
	*/
}

func _() {
	/*
	   freestanding comment
	   aligned		line
	   aligned line
	*/
}

func _() {
	/*
	   freestanding comment
	   aligned		line
	   aligned line */
}

func _() {
	/*
		freestanding comment
		aligned		line
		aligned line
	*/
}

func _() {
	/*
		freestanding comment
		aligned		line
		aligned line
	*/
}

func _() {
	/*
		freestanding comment
		aligned		line
		aligned line */
}

func _() {
	/* freestanding comment
	   aligned line
	*/
}

func _() {
	/* freestanding comment
	   aligned line
	*/
}

func _() {
	/* freestanding comment
	   aligned line */
}

func _() {
	/*	freestanding comment
		aligned line
	*/
}

func _() {
	/*	freestanding comment
		aligned line
	*/
}

func _() {
	/*	freestanding comment
		aligned line */
}

func _() {
	/*
	   freestanding comment
	   aligned line
	*/
}

func _() {
	/*
	   freestanding comment
	   aligned line
	*/
}

func _() {
	/*
	   freestanding comment
	   aligned line */
}

func _() {
	/*
		freestanding comment
		aligned line
	*/
}

func _() {
	/*
		freestanding comment
		aligned line
	*/
}

func _() {
	/*
		freestanding comment
		aligned line */
}

/*
 * line
 * of
 * stars
 */

/* another line
 * of
 * stars */

/*	and another line
 *	of
 *	stars */

/* a line of
 * stars */

/*	and another line of
 *	stars */

/* a line of stars
 */

/*	and another line of
 */

/* a line of stars
 */

/*	and another line of
 */

/*
aligned in middle
here
        not here
*/

/*
blank line in middle:

with no leading spaces on blank line.
*/

/*
   aligned in middle
   here
           not here
*/

/*
	blank line in middle:

	with no leading spaces on blank line.
*/

func _() {
	/*
	 * line
	 * of
	 * stars
	 */

	/*
		aligned in middle
		here
			not here
	*/

	/*
		blank line in middle:

		with no leading spaces on blank line.
	*/
}

// Some interesting interspersed comments.
// See below for more common cases.
func _( /* this */ x /* is */ /* an */ int) {
}

func _( /* no params - extra blank before and after comment */ )	{}
func _(a, b int /* params - no extra blank after comment */)		{}

func _()	{ f( /* no args - extra blank before and after comment */ ) }
func _()	{ f(a, b /* args - no extra blank after comment */) }

func _() {
	f( /* no args - extra blank before and after comment */ )
	f(a, b /* args - no extra blank after comment */)
}

func ( /* comment1 */ T /* comment2 */) _()	{}

func _()	{ /* "short-ish one-line functions with comments are formatted as multi-line functions */ }
func _()	{ x := 0; /* comment */ y = x /* comment */ }

func _() {
	_ = 0
	/* closing curly brace should be on new line */
}

func _() {
	_ = []int{0, 1 /* don't introduce a newline after this comment - was issue 1365 */}
}

// Test cases from issue 1542:
// Comments must not be placed before commas and cause invalid programs.
func _() {
	var a = []int{1, 2	/*jasldf*/}
	_ = a
}

func _() {
	var a = []int{1, 2}/*jasldf
	 */

	_ = a
}

func _() {
	var a = []int{1, 2}// jasldf

	_ = a
}

// Comments immediately adjacent to punctuation followed by a newline
// remain after the punctuation (looks better and permits alignment of
// comments).
func _() {
	_ = T{
		1,	// comment after comma
		2,	/* comment after comma */
		3,	// comment after comma
	}
	_ = T{
		1,	// comment after comma
		2,	/* comment after comma */
		3,	// comment after comma
	}
	_ = T{
		/* comment before literal */ 1,
		2,	/* comment before comma - ok to move after comma */
		3,	/* comment before comma - ok to move after comma */
	}

	for i = 0;	// comment after semicolon
	i < 9;		/* comment after semicolon */
	i++ {		// comment after opening curly brace
	}

	// TODO(gri) the last comment in this example should be aligned */
	for i = 0;	// comment after semicolon
	i < 9;		/* comment before semicolon - ok to move after semicolon */
	i++ /* comment before opening curly brace */ {
	}
}

// If there is no newline following punctuation, commas move before the punctuation.
// This way, commas interspersed in lists stay with the respective expression.
func f(x /* comment */, y int, z int /* comment */, u, v, w int /* comment */) {
	f(x /* comment */, y)
	f(x,	/* comment */
		y)
	f(
		x,	/* comment */
	)
}

func g(
	x int,	/* comment */
) {
}

type _ struct {
	a, b /* comment */, c int
}

type _ struct {
	a, b /* comment */, c int
}

func _() {
	for a /* comment */, b := range x {
	}
}

// Print line directives correctly.

// The following is a legal line directive.
//line foo:1
func _() {
	_ = 0
	// The following is a legal line directive. It must not be indented:
//line foo:2
	_ = 1

	// The following is not a legal line directive (it doesn't start in column 1):
	//line foo:2
	_ = 2

	// The following is not a legal line directive (negative line number):
	//line foo:-3
	_ = 3
}

// Line comments with tabs
func _() {
	var finput *bufio.Reader	// input file
	var stderr *bufio.Writer
	var ftable *bufio.Writer	// y.go file
	var foutput *bufio.Writer	// y.output file

	var oflag string	// -o [y.go]		- y.go file
	var vflag string	// -v [y.output]	- y.output file
	var lflag bool		// -l			- disable line directives
}

// Trailing white space in comments should be trimmed
func _() {
	// This comment has 4 blanks following that should be trimmed:
	/* Each line of this comment has blanks or tabs following that should be trimmed:
	   line 2:
	   line 3:
	*/
}

/* This comment is the last entry in this file. It must be printed and should be followed by a newline */
