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

View as plain text