Source file src/cmd/compile/internal/syntax/positions.go

     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  
     7  package syntax
     8  
     9  // StartPos returns the start position of n.
    10  func 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.
   124  func 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  
   339  func lastDecl(list []Decl) Decl {
   340  	if l := len(list); l > 0 {
   341  		return list[l-1]
   342  	}
   343  	return nil
   344  }
   345  
   346  func lastExpr(list []Expr) Expr {
   347  	if l := len(list); l > 0 {
   348  		return list[l-1]
   349  	}
   350  	return nil
   351  }
   352  
   353  func lastStmt(list []Stmt) Stmt {
   354  	if l := len(list); l > 0 {
   355  		return list[l-1]
   356  	}
   357  	return nil
   358  }
   359  
   360  func lastField(list []*Field) *Field {
   361  	if l := len(list); l > 0 {
   362  		return list[l-1]
   363  	}
   364  	return nil
   365  }
   366  

View as plain text