summaryrefslogtreecommitdiffstats
path: root/src/cmd/compile/internal/syntax/positions.go
diff options
context:
space:
mode:
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 0000000..9359655
--- /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("nil node")
+
+ // 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("nil node")
+
+ // 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
+}