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

package expressions

type T struct {
	x, y, z int
}

var (
	a, b, c, d, e int
	under_bar int
	longIdentifier1, longIdentifier2, longIdentifier3 int
	t0, t1, t2 T
	s string
	p *int
)


func _() {
	// no spaces around simple or parenthesized expressions
	_ = (a+0)
	_ = a+b
	_ = a+b+c
	_ = a+b-c
	_ = a-b-c
	_ = a+(b*c)
	_ = a+(b/c)
	_ = a-(b%c)
	_ = 1+a
	_ = a+1
	_ = a+b+1
	_ = s[a]
	_ = s[a:]
	_ = s[:b]
	_ = s[1:2]
	_ = s[a:b]
	_ = s[0:len(s)]
	_ = s[0]<<1
	_ = (s[0]<<1)&0xf
	_ = s[0] << 2 | s[1] >> 4
	_ = "foo"+s
	_ = s+"foo"
	_ = 'a'+'b'
	_ = len(s)/2
	_ = len(t0.x)/a

	// spaces around expressions of different precedence or expressions containing spaces
	_ = a + -b
	_ = a - ^b
	_ = a / *p
	_ = a + b*c
	_ = 1 + b*c
	_ = a + 2*c
	_ = a + c*2
	_ = 1 + 2*3
	_ = s[1 : 2*3]
	_ = s[a : b-c]
	_ = s[0:]
	_ = s[a+b]
	_ = s[: b-c]
	_ = s[a+b :]
	_ = a[a<<b+1]
	_ = a[a<<b+1 :]
	_ = s[a+b : len(s)]
	_ = s[len(s) : -a]
	_ = s[a : len(s)+1]
	_ = s[a : len(s)+1]+s

	// spaces around operators with equal or lower precedence than comparisons
	_ = a == b
	_ = a != b
	_ = a > b
	_ = a >= b
	_ = a < b
	_ = a <= b
	_ = a < b && c > d
	_ = a < b || c > d

	// spaces around "long" operands
	_ = a + longIdentifier1
	_ = longIdentifier1 + a
	_ = longIdentifier1 + longIdentifier2 * longIdentifier3
	_ = s + "a longer string"

	// some selected cases
	_ = a + t0.x
	_ = a + t0.x + t1.x * t2.x
	_ = a + b + c + d + e + 2*3
	_ = a + b + c + 2*3 + d + e
	_ = (a+b+c)*2
	_ = a - b + c - d + (a+b+c) + d&e
	_ = under_bar-1
	_ = Open(dpath + "/file", O_WRONLY | O_CREAT, 0666)
	_ = int(c0&_Mask4)<<18 | int(c1&_Maskx)<<12 | int(c2&_Maskx)<<6 | int(c3&_Maskx)

	// the parser does not restrict expressions that may appear as statements
	true
	42
	"foo"
	x
	(x)
	a+b
	a+b+c
	a+(b*c)
	a+(b/c)
	1+a
	a+1
	s[a]
	x<<1
	(s[0]<<1)&0xf
	"foo"+s
	x == y
	x < y || z > 42
}


func _() {
	_ = a+b
	_ = a+b+c
	_ = a+b*c
	_ = a+(b*c)
	_ = (a+b)*c
	_ = a+(b*c*d)
	_ = a+(b*c+d)

	_ = 1<<x
	_ = -1<<x
	_ = 1<<x-1
	_ = -1<<x-1

	_ = f(a+b)
	_ = f(a+b+c)
	_ = f(a+b*c)
	_ = f(a+(b*c))
	_ = f(1<<x-1, 1<<x-2)

	_ = 1<<d.logWindowSize-1

	buf = make(x, 2*cap(b.buf) + n)

	dst[i*3+2] = dbuf[0]<<2
	dst[i*3+2] = dbuf[0]<<2 | dbuf[1]>>4

	b.buf = b.buf[0:b.off+m+n]
	b.buf = b.buf[0:b.off+m*n]
	f(b.buf[0:b.off+m+n])

	signed += ' '*8
	tw.octal(header[148:155], chksum)

	_ = x > 0 && i >= 0

	x1, x0 := x>>w2, x&m2
	z0 = t1<<w2+t0
	z1 = (t1+t0>>w2)>>w2
	q1, r1 := x1/d1, x1%d1
	r1 = r1*b2 | x0>>w2
	x1 = (x1<<z)|(x0>>(uint(w)-z))
	x1 = x1<<z | x0>>(uint(w)-z)

	_ = buf[0:len(buf)+1]
	_ = buf[0:n+1]

	a,b = b,a
	a = b+c
	a = b*c+d
	_ = a*b+c
	_ = a-b-c
	_ = a-(b-c)
	_ = a-b*c
	_ = a-(b*c)
	_ = a*b/c
	_ = a/ *b
	_ = x[a|^b]
	_ = x[a/ *b]
	_ = a& ^b
	_ = a+ +b
	_ = a- -b
	_ = x[a*-b]
	_ = x[a+ +b]
	_ = x^y^z
	_ = b[a>>24] ^ b[(a>>16)&0xFF] ^ b[(a>>8)&0xFF] ^ b[a&0xFF]
	_ = len(longVariableName)*2

	_ = token(matchType + xlength<<lengthShift + xoffset)
}


func f(x int, args ...int) {
	f(0, args...)
	f(1, args)
	f(2, args[0])

	// make sure syntactically legal code remains syntactically legal
	f(3, 42 ...) // a blank must remain between 42 and ...
	f(4, 42. ...)
	f(5, 42....)
	f(6, 42.0 ...)
	f(7, 42.0...)
	f(8, .42 ...)
	f(9, .42...)
	f(10, 42e0 ...)
	f(11, 42e0...)

	_ = 42 .x // a blank must remain between 42 and .x
	_ = 42. .x
	_ = 42..x
	_ = 42.0 .x
	_ = 42.0.x
	_ = .42 .x
	_ = .42.x
	_ = 42e0 .x
	_ = 42e0.x

	// a blank must remain between the binary operator and the 2nd operand
	_ = x/ *y
	_ = x< -1
	_ = x< <-1
	_ = x+ +1
	_ = x- -1
	_ = x& &x
	_ = x& ^x

	_ = f(x/ *y, x< -1, x< <-1, x+ +1, x- -1, x& &x, x& ^x)
}


func _() {
	_ = T{}
	_ = struct{}{}
	_ = [10]T{}
	_ = [...]T{}
	_ = []T{}
	_ = map[int]T{}
}


// one-line structs/interfaces in composite literals (up to a threshold)
func _() {
	_ = struct{}{}
	_ = struct{ x int }{0}
	_ = struct{ x, y, z int }{0, 1, 2}
	_ = struct{ int }{0}
	_ = struct{ s struct { int } }{struct{ int}{0} }
}


func _() {
	// do not modify literals
	_ = "tab1	tab2	tab3	end"  // string contains 3 tabs
	_ = "tab1 tab2 tab3 end"  // same string with 3 blanks - may be unaligned because editors see tabs in strings
	_ = ""  // this comment should be aligned with the one on the previous line
	_ = ``
	_ = `
`
_ = `foo
		bar`
	_ = `three spaces before the end of the line starting here:   
they must not be removed`
}


func _() {
	// smart handling of indentation for multi-line raw strings
	var _ = ``
	var _ = `foo`
	var _ = `foo
bar`


var _ =
	``
var _ =
	`foo`
var _ =
	// the next line should remain indented
	`foo
bar`


	var _ = // comment
		``
	var _ = // comment
		`foo`
	var _ = // comment
		// the next line should remain indented
		`foo
bar`


var _ = /* comment */ ``
var _ = /* comment */ `foo`
var _ = /* comment */ `foo
bar`


	var _ = /* comment */
		``
	var _ = /* comment */
		`foo`
	var _ = /* comment */
		// the next line should remain indented
		`foo
bar`


var board = []int(
	`...........
...........
....●●●....
....●●●....
..●●●●●●●..
..●●●○●●●..
..●●●●●●●..
....●●●....
....●●●....
...........
...........
`)


	var state = S{
		"foo",
		// the next line should remain indented
		`...........
...........
....●●●....
....●●●....
..●●●●●●●..
..●●●○●●●..
..●●●●●●●..
....●●●....
....●●●....
...........
...........
`,
		"bar",
	}
}


func _() {
	// one-line function literals (body is on a single line)
	_ = func() {}
	_ = func() int { return 0 }
	_ = func(x, y int) bool { m := (x+y)/2; return m < 0 }

	// multi-line function literals (body is not on one line)
	_ = func() {
	}
	_ = func() int {
		return 0
	}
	_ = func(x, y int) bool {
		m := (x+y)/2; return x < y }

	f(func() {
	})
	f(func() int {
		return 0
	})
	f(func(x, y int) bool {
		m := (x+y)/2; return x < y })
}


func _() {
	_ = [][]int {
		[]int{1},
		[]int{1, 2},
		[]int{1, 2, 3},
	}
	_ = [][]int {
		{1},
		[]int{1, 2},
		[]int{1, 2, 3},
	}
	_ = [][]int {
		{1},
		{1, 2},
		{1, 2, 3},
	}
	_ = [][]int {{1}, {1, 2}, {1, 2, 3}}
}


// various multi-line expressions
func _() {
	// do not add extra indentation to multi-line string lists
	_ = "foo" + "bar"
	_ = "foo" +
	"bar" +
	"bah"
	_ = []string {
		"abc" +
		"def",
		"foo" +
		"bar",
	}
}


const _ = F1 +
	`string = "%s";` +
	`ptr = *;` +
	`datafmt.T2 = s ["-" p "-"];`


const _ =
	`datafmt "datafmt";` +
	`default = "%v";` +
	`array = *;` +
	`datafmt.T3 = s  {" " a a / ","};`


const _ = `datafmt "datafmt";` +
`default = "%v";` +
`array = *;` +
`datafmt.T3 = s  {" " a a / ","};`


func _() {
	_ = F1 +
		`string = "%s";` +
		`ptr = *;` +
		`datafmt.T2 = s ["-" p "-"];`

	_ =
		`datafmt "datafmt";` +
		`default = "%v";` +
		`array = *;` +
		`datafmt.T3 = s  {" " a a / ","};`

	_ = `datafmt "datafmt";` +
	`default = "%v";` +
	`array = *;` +
	`datafmt.T3 = s  {" " a a / ","};`
}


func _() {
	// respect source lines in multi-line expressions
	_ = a+
	b+
	c
	_ = a < b ||
		b < a
	_ = "933262154439441526816992388562667004907159682643816214685929" +
	"638952175999932299156089414639761565182862536979208272237582" +
	"51185210916864000000000000000000000000"  // 100!
	_ = "170141183460469231731687303715884105727"  // prime
}


// Alignment after overlong lines
const (
	_ = "991"
	_ = "2432902008176640000"  // 20!
	_ = "933262154439441526816992388562667004907159682643816214685929" +
	"638952175999932299156089414639761565182862536979208272237582" +
	"51185210916864000000000000000000000000"  // 100!
	_ = "170141183460469231731687303715884105727"  // prime
)


// Correct placement of operators and comments in multi-line expressions
func _() {
	_ = a +  // comment
		b +  // comment
		c
	_ = "a"	+
		"b" +	// comment
		"c"
	_ = "ba0408" + "7265717569726564"     // field 71, encoding 2, string "required"
}


// Correct placement of terminating comma/closing parentheses in multi-line calls.
func _() {
	f(1,
		2,
		3)
	f(1,
		2,
		3,
	)
	f(1,
		2,
		3)  // comment
	f(1,
		2,
		3,  // comment
	)
	f(1,
		2,
		3)// comment
	f(1,
		2,
		3,// comment
	)
}


// Align comments in multi-line lists of single-line expressions.
var txpix = [NCOL]draw.Color{
	draw.Yellow, // yellow
	draw.Cyan, // cyan
	draw.Green, // lime green
	draw.GreyBlue, // slate
	draw.Red, /* red */
	draw.GreyGreen, /* olive green */
	draw.Blue, /* blue */
	draw.Color(0xFF55AAFF), /* pink */
	draw.Color(0xFFAAFFFF), /* lavender */
	draw.Color(0xBB005DFF), /* maroon */
}


func same(t, u *Time) bool {
	// respect source lines in multi-line expressions
	return t.Year == u.Year &&
		t.Month == u.Month &&
		t.Day == u.Day &&
		t.Hour == u.Hour &&
		t.Minute == u.Minute &&
		t.Second == u.Second &&
		t.Weekday == u.Weekday &&
		t.ZoneOffset == u.ZoneOffset &&
		t.Zone == u.Zone
}


func (p *parser) charClass() {
	// respect source lines in multi-line expressions
	if cc.negate && len(cc.ranges) == 2 &&
		cc.ranges[0] == '\n' && cc.ranges[1] == '\n' {
		nl := new(_NotNl)
		p.re.add(nl)
	}
}


func addState(s []state, inst instr, match []int) {
	// handle comments correctly in multi-line expressions
	for i := 0; i < l; i++ {
		if s[i].inst.index() == index && // same instruction
		   s[i].match[0] < pos {	// earlier match already going; leftmost wins
		   	return s
		 }
	}
}

func (self *T) foo(x int) *T { return self }

func _() { module.Func1().Func2() }

func _() {
	_ = new(T).
		foo(1).
			foo(2).
		foo(3)

	_ = new(T).
	foo(1).
	foo(2). // inline comments
	foo(3)

	_ = new(T).foo(1).foo(2).foo(3)

	// handle multiline argument list correctly
	_ = new(T).
	foo(
		1).
		foo(2)

	_ = new(T).foo(
		1).foo(2)

	_ = Array[3 +
4]

	_ = Method(1, 2,
		3)

	_ = new(T).
   foo().
   bar() . (*Type)

	_ = new(T).
foo().
bar().(*Type).
baz()

	_ = new(T).
	foo().
	bar()["idx"]

	_ = new(T).
	foo().
	bar()["idx"]	.
	baz()

	_ = new(T).
	foo().
	bar()[1:2]

	_ = new(T).
	foo().
	bar()[1:2].
	baz()

	_ = new(T).
		Field.
		Array[3+
       		4].
		Table ["foo"].
		Blob. (*Type).
	Slices[1:4].
	Method(1, 2,
	3).
		Thingy

	_ = a.b.c
	_ = a.
	b.
	c
	_ = a.b().c
	_ = a.
	b().
	c
	_ = a.b[0].c
	_ = a.
	b[0].
	c
	_ = a.b[0:].c
	_ = a.
	b[0:].
	c
	_ = a.b.(T).c
	_ = a.
	b.
	(T).
	c
}


// Don't introduce extra newlines in strangely formatted expression lists.
func f() {
	// os.Open parameters should remain on two lines
	if writer, err = os.Open(outfile, s.O_WRONLY|os.O_CREATE|
		os.O_TRUNC, 0666); err != nil {
	    log.Fatal(err)
	}
}

// Handle multi-line argument lists ending in ... correctly.
// Was issue 3130.
func _() {
	_ = append(s, a...)
	_ = append(
		s, a...)
	_ = append(s,
		a...)
	_ = append(
		s,
		a...)
	_ = append(s, a...,
	)
	_ = append(s,
		a...,
	)
	_ = append(
		s,
		a...,
	)
}
