github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/syntax/pos.go (about) 1 // Copyright 2018 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 package syntax 6 7 import "fmt" 8 9 // PosMax is the largest line or column value that can be represented without loss. 10 // Incoming values (arguments) larger than PosMax will be set to PosMax. 11 const PosMax = 1 << 30 12 13 // A Pos represents an absolute (line, col) source position 14 // with a reference to position base for computing relative 15 // (to a file, or line directive) position information. 16 // Pos values are intentionally light-weight so that they 17 // can be created without too much concern about space use. 18 type Pos struct { 19 base *PosBase 20 line, col uint32 21 } 22 23 // MakePos returns a new Pos for the given PosBase, line and column. 24 func MakePos(base *PosBase, line, col uint) Pos { return Pos{base, sat32(line), sat32(col)} } 25 26 // TODO(gri) IsKnown makes an assumption about linebase < 1. 27 // Maybe we should check for Base() != nil instead. 28 29 func (pos Pos) IsKnown() bool { return pos.line > 0 } 30 func (pos Pos) Base() *PosBase { return pos.base } 31 func (pos Pos) Line() uint { return uint(pos.line) } 32 func (pos Pos) Col() uint { return uint(pos.col) } 33 34 func (pos Pos) RelFilename() string { return pos.base.Filename() } 35 36 func (pos Pos) RelLine() uint { 37 b := pos.base 38 if b.Line() == 0 { 39 // base line is unknown => relative line is unknown 40 return 0 41 } 42 return b.Line() + (pos.Line() - b.Pos().Line()) 43 } 44 45 func (pos Pos) RelCol() uint { 46 b := pos.base 47 if b.Col() == 0 { 48 // base column is unknown => relative column is unknown 49 // (the current specification for line directives requires 50 // this to apply until the next PosBase/line directive, 51 // not just until the new newline) 52 return 0 53 } 54 if pos.Line() == b.Pos().Line() { 55 // pos on same line as pos base => column is relative to pos base 56 return b.Col() + (pos.Col() - b.Pos().Col()) 57 } 58 return pos.Col() 59 } 60 61 func (pos Pos) String() string { 62 rel := position_{pos.RelFilename(), pos.RelLine(), pos.RelCol()} 63 abs := position_{pos.Base().Pos().RelFilename(), pos.Line(), pos.Col()} 64 s := rel.String() 65 if rel != abs { 66 s += "[" + abs.String() + "]" 67 } 68 return s 69 } 70 71 // TODO(gri) cleanup: find better name, avoid conflict with position in error_test.go 72 type position_ struct { 73 filename string 74 line, col uint 75 } 76 77 func (p position_) String() string { 78 if p.line == 0 { 79 if p.filename == "" { 80 return "<unknown position>" 81 } 82 return p.filename 83 } 84 if p.col == 0 { 85 return fmt.Sprintf("%s:%d", p.filename, p.line) 86 } 87 return fmt.Sprintf("%s:%d:%d", p.filename, p.line, p.col) 88 } 89 90 // A PosBase represents the base for relative position information: 91 // At position pos, the relative position is filename:line:col. 92 type PosBase struct { 93 pos Pos 94 filename string 95 line, col uint32 96 } 97 98 // NewFileBase returns a new PosBase for the given filename. 99 // A file PosBase's position is relative to itself, with the 100 // position being filename:1:1. 101 func NewFileBase(filename string) *PosBase { 102 base := &PosBase{MakePos(nil, linebase, colbase), filename, linebase, colbase} 103 base.pos.base = base 104 return base 105 } 106 107 // NewLineBase returns a new PosBase for a line directive "line filename:line:col" 108 // relative to pos, which is the position of the character immediately following 109 // the comment containing the line directive. For a directive in a line comment, 110 // that position is the beginning of the next line (i.e., the newline character 111 // belongs to the line comment). 112 func NewLineBase(pos Pos, filename string, line, col uint) *PosBase { 113 return &PosBase{pos, filename, sat32(line), sat32(col)} 114 } 115 116 func (base *PosBase) IsFileBase() bool { 117 if base == nil { 118 return false 119 } 120 return base.pos.base == base 121 } 122 123 func (base *PosBase) Pos() (_ Pos) { 124 if base == nil { 125 return 126 } 127 return base.pos 128 } 129 130 func (base *PosBase) Filename() string { 131 if base == nil { 132 return "" 133 } 134 return base.filename 135 } 136 137 func (base *PosBase) Line() uint { 138 if base == nil { 139 return 0 140 } 141 return uint(base.line) 142 } 143 144 func (base *PosBase) Col() uint { 145 if base == nil { 146 return 0 147 } 148 return uint(base.col) 149 } 150 151 func sat32(x uint) uint32 { 152 if x > PosMax { 153 return PosMax 154 } 155 return uint32(x) 156 }