aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/syntax/positions.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2021-03-29 15:15:56 -0700
committerRobert Griesemer <gri@golang.org>2021-04-06 18:57:04 +0000
commit93466cc1b697836200e73bb103522324d38e894f (patch)
treeec8e32fa317b4bdf994d192c79b61798e055aa21 /src/cmd/compile/internal/syntax/positions.go
parentd57189e92b9b4cd6909aefbcee02e9cb6fc05cff (diff)
downloadgo-93466cc1b697836200e73bb103522324d38e894f.tar.gz
go-93466cc1b697836200e73bb103522324d38e894f.zip
cmd/compile/internal/types2: review of pos.go and move into syntax package
This moves the two helper functions startPos and endPos into the syntax package where they belong. Export the functions and adjust dependent code. Change-Id: I8170faeadd7cfa8f53009f81fcffd50ec0fc6a98 Reviewed-on: https://go-review.googlesource.com/c/go/+/305578 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
Diffstat (limited to 'src/cmd/compile/internal/syntax/positions.go')
-rw-r--r--src/cmd/compile/internal/syntax/positions.go364
1 files changed, 364 insertions, 0 deletions
diff --git a/src/cmd/compile/internal/syntax/positions.go b/src/cmd/compile/internal/syntax/positions.go
new file mode 100644
index 0000000000..b00f86c67c
--- /dev/null
+++ b/src/cmd/compile/internal/syntax/positions.go
@@ -0,0 +1,364 @@
+// Copyright 2020 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 file implements helper functions for scope position computations.
+
+package syntax
+
+// StartPos returns the start position of n.
+func StartPos(n Node) Pos {
+ // Cases for nodes which don't need a correction are commented out.
+ for m := n; ; {
+ switch n := m.(type) {
+ case nil:
+ panic("internal error: nil")
+
+ // packages
+ case *File:
+ // file block starts at the beginning of the file
+ return MakePos(n.Pos().Base(), 1, 1)
+
+ // declarations
+ // case *ImportDecl:
+ // case *ConstDecl:
+ // case *TypeDecl:
+ // case *VarDecl:
+ // case *FuncDecl:
+
+ // expressions
+ // case *BadExpr:
+ // case *Name:
+ // case *BasicLit:
+ case *CompositeLit:
+ if n.Type != nil {
+ m = n.Type
+ continue
+ }
+ return n.Pos()
+ // case *KeyValueExpr:
+ // case *FuncLit:
+ // case *ParenExpr:
+ case *SelectorExpr:
+ m = n.X
+ case *IndexExpr:
+ m = n.X
+ // case *SliceExpr:
+ case *AssertExpr:
+ m = n.X
+ case *TypeSwitchGuard:
+ if n.Lhs != nil {
+ m = n.Lhs
+ continue
+ }
+ m = n.X
+ case *Operation:
+ if n.Y != nil {
+ m = n.X
+ continue
+ }
+ return n.Pos()
+ case *CallExpr:
+ m = n.Fun
+ case *ListExpr:
+ if len(n.ElemList) > 0 {
+ m = n.ElemList[0]
+ continue
+ }
+ return n.Pos()
+ // types
+ // case *ArrayType:
+ // case *SliceType:
+ // case *DotsType:
+ // case *StructType:
+ // case *Field:
+ // case *InterfaceType:
+ // case *FuncType:
+ // case *MapType:
+ // case *ChanType:
+
+ // statements
+ // case *EmptyStmt:
+ // case *LabeledStmt:
+ // case *BlockStmt:
+ // case *ExprStmt:
+ case *SendStmt:
+ m = n.Chan
+ // case *DeclStmt:
+ case *AssignStmt:
+ m = n.Lhs
+ // case *BranchStmt:
+ // case *CallStmt:
+ // case *ReturnStmt:
+ // case *IfStmt:
+ // case *ForStmt:
+ // case *SwitchStmt:
+ // case *SelectStmt:
+
+ // helper nodes
+ case *RangeClause:
+ if n.Lhs != nil {
+ m = n.Lhs
+ continue
+ }
+ m = n.X
+ // case *CaseClause:
+ // case *CommClause:
+
+ default:
+ return n.Pos()
+ }
+ }
+}
+
+// EndPos returns the approximate end position of n in the source.
+// For some nodes (*Name, *BasicLit) it returns the position immediately
+// following the node; for others (*BlockStmt, *SwitchStmt, etc.) it
+// returns the position of the closing '}'; and for some (*ParenExpr)
+// the returned position is the end position of the last enclosed
+// expression.
+// Thus, EndPos should not be used for exact demarcation of the
+// end of a node in the source; it is mostly useful to determine
+// scope ranges where there is some leeway.
+func EndPos(n Node) Pos {
+ for m := n; ; {
+ switch n := m.(type) {
+ case nil:
+ panic("internal error: nil")
+
+ // packages
+ case *File:
+ return n.EOF
+
+ // declarations
+ case *ImportDecl:
+ m = n.Path
+ case *ConstDecl:
+ if n.Values != nil {
+ m = n.Values
+ continue
+ }
+ if n.Type != nil {
+ m = n.Type
+ continue
+ }
+ if l := len(n.NameList); l > 0 {
+ m = n.NameList[l-1]
+ continue
+ }
+ return n.Pos()
+ case *TypeDecl:
+ m = n.Type
+ case *VarDecl:
+ if n.Values != nil {
+ m = n.Values
+ continue
+ }
+ if n.Type != nil {
+ m = n.Type
+ continue
+ }
+ if l := len(n.NameList); l > 0 {
+ m = n.NameList[l-1]
+ continue
+ }
+ return n.Pos()
+ case *FuncDecl:
+ if n.Body != nil {
+ m = n.Body
+ continue
+ }
+ m = n.Type
+
+ // expressions
+ case *BadExpr:
+ return n.Pos()
+ case *Name:
+ p := n.Pos()
+ return MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
+ case *BasicLit:
+ p := n.Pos()
+ return MakePos(p.Base(), p.Line(), p.Col()+uint(len(n.Value)))
+ case *CompositeLit:
+ return n.Rbrace
+ case *KeyValueExpr:
+ m = n.Value
+ case *FuncLit:
+ m = n.Body
+ case *ParenExpr:
+ m = n.X
+ case *SelectorExpr:
+ m = n.Sel
+ case *IndexExpr:
+ m = n.Index
+ case *SliceExpr:
+ for i := len(n.Index) - 1; i >= 0; i-- {
+ if x := n.Index[i]; x != nil {
+ m = x
+ continue
+ }
+ }
+ m = n.X
+ case *AssertExpr:
+ m = n.Type
+ case *TypeSwitchGuard:
+ m = n.X
+ case *Operation:
+ if n.Y != nil {
+ m = n.Y
+ continue
+ }
+ m = n.X
+ case *CallExpr:
+ if l := lastExpr(n.ArgList); l != nil {
+ m = l
+ continue
+ }
+ m = n.Fun
+ case *ListExpr:
+ if l := lastExpr(n.ElemList); l != nil {
+ m = l
+ continue
+ }
+ return n.Pos()
+
+ // types
+ case *ArrayType:
+ m = n.Elem
+ case *SliceType:
+ m = n.Elem
+ case *DotsType:
+ m = n.Elem
+ case *StructType:
+ if l := lastField(n.FieldList); l != nil {
+ m = l
+ continue
+ }
+ return n.Pos()
+ // TODO(gri) need to take TagList into account
+ case *Field:
+ if n.Type != nil {
+ m = n.Type
+ continue
+ }
+ m = n.Name
+ case *InterfaceType:
+ if l := lastField(n.MethodList); l != nil {
+ m = l
+ continue
+ }
+ return n.Pos()
+ case *FuncType:
+ if l := lastField(n.ResultList); l != nil {
+ m = l
+ continue
+ }
+ if l := lastField(n.ParamList); l != nil {
+ m = l
+ continue
+ }
+ return n.Pos()
+ case *MapType:
+ m = n.Value
+ case *ChanType:
+ m = n.Elem
+
+ // statements
+ case *EmptyStmt:
+ return n.Pos()
+ case *LabeledStmt:
+ m = n.Stmt
+ case *BlockStmt:
+ return n.Rbrace
+ case *ExprStmt:
+ m = n.X
+ case *SendStmt:
+ m = n.Value
+ case *DeclStmt:
+ if l := lastDecl(n.DeclList); l != nil {
+ m = l
+ continue
+ }
+ return n.Pos()
+ case *AssignStmt:
+ m = n.Rhs
+ if m == nil {
+ p := EndPos(n.Lhs)
+ return MakePos(p.Base(), p.Line(), p.Col()+2)
+ }
+ case *BranchStmt:
+ if n.Label != nil {
+ m = n.Label
+ continue
+ }
+ return n.Pos()
+ case *CallStmt:
+ m = n.Call
+ case *ReturnStmt:
+ if n.Results != nil {
+ m = n.Results
+ continue
+ }
+ return n.Pos()
+ case *IfStmt:
+ if n.Else != nil {
+ m = n.Else
+ continue
+ }
+ m = n.Then
+ case *ForStmt:
+ m = n.Body
+ case *SwitchStmt:
+ return n.Rbrace
+ case *SelectStmt:
+ return n.Rbrace
+
+ // helper nodes
+ case *RangeClause:
+ m = n.X
+ case *CaseClause:
+ if l := lastStmt(n.Body); l != nil {
+ m = l
+ continue
+ }
+ return n.Colon
+ case *CommClause:
+ if l := lastStmt(n.Body); l != nil {
+ m = l
+ continue
+ }
+ return n.Colon
+
+ default:
+ return n.Pos()
+ }
+ }
+}
+
+func lastDecl(list []Decl) Decl {
+ if l := len(list); l > 0 {
+ return list[l-1]
+ }
+ return nil
+}
+
+func lastExpr(list []Expr) Expr {
+ if l := len(list); l > 0 {
+ return list[l-1]
+ }
+ return nil
+}
+
+func lastStmt(list []Stmt) Stmt {
+ if l := len(list); l > 0 {
+ return list[l-1]
+ }
+ return nil
+}
+
+func lastField(list []*Field) *Field {
+ if l := len(list); l > 0 {
+ return list[l-1]
+ }
+ return nil
+}