1// Copyright 2020 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// This file implements helper functions for scope position computations.
6
7package syntax
8
9// StartPos returns the start position of n.
10func StartPos(n Node) Pos {
11	// Cases for nodes which don't need a correction are commented out.
12	for m := n; ; {
13		switch n := m.(type) {
14		case nil:
15			panic("nil node")
16
17		// packages
18		case *File:
19			// file block starts at the beginning of the file
20			return MakePos(n.Pos().Base(), 1, 1)
21
22		// declarations
23		// case *ImportDecl:
24		// case *ConstDecl:
25		// case *TypeDecl:
26		// case *VarDecl:
27		// case *FuncDecl:
28
29		// expressions
30		// case *BadExpr:
31		// case *Name:
32		// case *BasicLit:
33		case *CompositeLit:
34			if n.Type != nil {
35				m = n.Type
36				continue
37			}
38			return n.Pos()
39		case *KeyValueExpr:
40			m = n.Key
41		// case *FuncLit:
42		// case *ParenExpr:
43		case *SelectorExpr:
44			m = n.X
45		case *IndexExpr:
46			m = n.X
47		// case *SliceExpr:
48		case *AssertExpr:
49			m = n.X
50		case *TypeSwitchGuard:
51			if n.Lhs != nil {
52				m = n.Lhs
53				continue
54			}
55			m = n.X
56		case *Operation:
57			if n.Y != nil {
58				m = n.X
59				continue
60			}
61			return n.Pos()
62		case *CallExpr:
63			m = n.Fun
64		case *ListExpr:
65			if len(n.ElemList) > 0 {
66				m = n.ElemList[0]
67				continue
68			}
69			return n.Pos()
70		// types
71		// case *ArrayType:
72		// case *SliceType:
73		// case *DotsType:
74		// case *StructType:
75		// case *Field:
76		// case *InterfaceType:
77		// case *FuncType:
78		// case *MapType:
79		// case *ChanType:
80
81		// statements
82		// case *EmptyStmt:
83		// case *LabeledStmt:
84		// case *BlockStmt:
85		// case *ExprStmt:
86		case *SendStmt:
87			m = n.Chan
88		// case *DeclStmt:
89		case *AssignStmt:
90			m = n.Lhs
91		// case *BranchStmt:
92		// case *CallStmt:
93		// case *ReturnStmt:
94		// case *IfStmt:
95		// case *ForStmt:
96		// case *SwitchStmt:
97		// case *SelectStmt:
98
99		// helper nodes
100		case *RangeClause:
101			if n.Lhs != nil {
102				m = n.Lhs
103				continue
104			}
105			m = n.X
106		// case *CaseClause:
107		// case *CommClause:
108
109		default:
110			return n.Pos()
111		}
112	}
113}
114
115// EndPos returns the approximate end position of n in the source.
116// For some nodes (*Name, *BasicLit) it returns the position immediately
117// following the node; for others (*BlockStmt, *SwitchStmt, etc.) it
118// returns the position of the closing '}'; and for some (*ParenExpr)
119// the returned position is the end position of the last enclosed
120// expression.
121// Thus, EndPos should not be used for exact demarcation of the
122// end of a node in the source; it is mostly useful to determine
123// scope ranges where there is some leeway.
124func EndPos(n Node) Pos {
125	for m := n; ; {
126		switch n := m.(type) {
127		case nil:
128			panic("nil node")
129
130		// packages
131		case *File:
132			return n.EOF
133
134		// declarations
135		case *ImportDecl:
136			m = n.Path
137		case *ConstDecl:
138			if n.Values != nil {
139				m = n.Values
140				continue
141			}
142			if n.Type != nil {
143				m = n.Type
144				continue
145			}
146			if l := len(n.NameList); l > 0 {
147				m = n.NameList[l-1]
148				continue
149			}
150			return n.Pos()
151		case *TypeDecl:
152			m = n.Type
153		case *VarDecl:
154			if n.Values != nil {
155				m = n.Values
156				continue
157			}
158			if n.Type != nil {
159				m = n.Type
160				continue
161			}
162			if l := len(n.NameList); l > 0 {
163				m = n.NameList[l-1]
164				continue
165			}
166			return n.Pos()
167		case *FuncDecl:
168			if n.Body != nil {
169				m = n.Body
170				continue
171			}
172			m = n.Type
173
174		// expressions
175		case *BadExpr:
176			return n.Pos()
177		case *Name:
178			p := n.Pos()
179			return MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
180		case *BasicLit:
181			p := n.Pos()
182			return MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
183		case *CompositeLit:
184			return n.Rbrace
185		case *KeyValueExpr:
186			m = n.Value
187		case *FuncLit:
188			m = n.Body
189		case *ParenExpr:
190			m = n.X
191		case *SelectorExpr:
192			m = n.Sel
193		case *IndexExpr:
194			m = n.Index
195		case *SliceExpr:
196			for i := len(n.Index) - 1; i >= 0; i-- {
197				if x := n.Index[i]; x != nil {
198					m = x
199					continue
200				}
201			}
202			m = n.X
203		case *AssertExpr:
204			m = n.Type
205		case *TypeSwitchGuard:
206			m = n.X
207		case *Operation:
208			if n.Y != nil {
209				m = n.Y
210				continue
211			}
212			m = n.X
213		case *CallExpr:
214			if l := lastExpr(n.ArgList); l != nil {
215				m = l
216				continue
217			}
218			m = n.Fun
219		case *ListExpr:
220			if l := lastExpr(n.ElemList); l != nil {
221				m = l
222				continue
223			}
224			return n.Pos()
225
226		// types
227		case *ArrayType:
228			m = n.Elem
229		case *SliceType:
230			m = n.Elem
231		case *DotsType:
232			m = n.Elem
233		case *StructType:
234			if l := lastField(n.FieldList); l != nil {
235				m = l
236				continue
237			}
238			return n.Pos()
239			// TODO(gri) need to take TagList into account
240		case *Field:
241			if n.Type != nil {
242				m = n.Type
243				continue
244			}
245			m = n.Name
246		case *InterfaceType:
247			if l := lastField(n.MethodList); l != nil {
248				m = l
249				continue
250			}
251			return n.Pos()
252		case *FuncType:
253			if l := lastField(n.ResultList); l != nil {
254				m = l
255				continue
256			}
257			if l := lastField(n.ParamList); l != nil {
258				m = l
259				continue
260			}
261			return n.Pos()
262		case *MapType:
263			m = n.Value
264		case *ChanType:
265			m = n.Elem
266
267		// statements
268		case *EmptyStmt:
269			return n.Pos()
270		case *LabeledStmt:
271			m = n.Stmt
272		case *BlockStmt:
273			return n.Rbrace
274		case *ExprStmt:
275			m = n.X
276		case *SendStmt:
277			m = n.Value
278		case *DeclStmt:
279			if l := lastDecl(n.DeclList); l != nil {
280				m = l
281				continue
282			}
283			return n.Pos()
284		case *AssignStmt:
285			m = n.Rhs
286			if m == nil {
287				p := EndPos(n.Lhs)
288				return MakePos(p.Base(), p.Line(), p.Col()+2)
289			}
290		case *BranchStmt:
291			if n.Label != nil {
292				m = n.Label
293				continue
294			}
295			return n.Pos()
296		case *CallStmt:
297			m = n.Call
298		case *ReturnStmt:
299			if n.Results != nil {
300				m = n.Results
301				continue
302			}
303			return n.Pos()
304		case *IfStmt:
305			if n.Else != nil {
306				m = n.Else
307				continue
308			}
309			m = n.Then
310		case *ForStmt:
311			m = n.Body
312		case *SwitchStmt:
313			return n.Rbrace
314		case *SelectStmt:
315			return n.Rbrace
316
317		// helper nodes
318		case *RangeClause:
319			m = n.X
320		case *CaseClause:
321			if l := lastStmt(n.Body); l != nil {
322				m = l
323				continue
324			}
325			return n.Colon
326		case *CommClause:
327			if l := lastStmt(n.Body); l != nil {
328				m = l
329				continue
330			}
331			return n.Colon
332
333		default:
334			return n.Pos()
335		}
336	}
337}
338
339func lastDecl(list []Decl) Decl {
340	if l := len(list); l > 0 {
341		return list[l-1]
342	}
343	return nil
344}
345
346func lastExpr(list []Expr) Expr {
347	if l := len(list); l > 0 {
348		return list[l-1]
349	}
350	return nil
351}
352
353func lastStmt(list []Stmt) Stmt {
354	if l := len(list); l > 0 {
355		return list[l-1]
356	}
357	return nil
358}
359
360func lastField(list []*Field) *Field {
361	if l := len(list); l > 0 {
362		return list[l-1]
363	}
364	return nil
365}
366