diff options
Diffstat (limited to 'src/cmd/compile/internal/syntax/positions.go')
-rw-r--r-- | src/cmd/compile/internal/syntax/positions.go | 364 |
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 +} |