github.com/shogo82148/std@v1.22.1-0.20240327122250-4e474527810c/go/token/position.go (about) 1 // Copyright 2010 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 token 6 7 import ( 8 "github.com/shogo82148/std/sync" 9 "github.com/shogo82148/std/sync/atomic" 10 ) 11 12 // Positionはファイル、行、列の位置を含む任意のソース位置を表します。 13 // Positionは行番号が> 0の場合に有効です。 14 type Position struct { 15 Filename string 16 Offset int 17 Line int 18 Column int 19 } 20 21 // IsValid は位置が有効かどうかを報告します。 22 func (pos *Position) IsValid() bool 23 24 // Stringはいくつかの形式で文字列を返します: 25 // 26 // file:line:column ファイル名を含む有効な位置 27 // file:line ファイル名を含む有効な位置だが列がない(column == 0) 28 // line:column ファイル名を含まない有効な位置 29 // line ファイル名もなく列もない有効な位置(column == 0) 30 // file ファイル名を含む無効な位置 31 // - ファイル名もない無効な位置 32 func (pos Position) String() string 33 34 // Posはファイルセット内のソース位置のコンパクトなエンコーディングです。 35 // より便利ながらもはるかに大きい表現のために、[Position] に変換することができます。 36 // 37 // 与えられたファイルに対するPosの値は、[base、base+size]の範囲内の数値です。 38 // baseとsizeは、ファイルがファイルセットに追加される際に指定されます。 39 // Posの値と対応するファイルベースの差は、その位置(Posの値によって表される)からのバイトオフセットに対応します。 40 // したがって、ファイルベースオフセットは、ファイル内の最初のバイトを表すPosの値です。 41 // 42 // 特定のソースオフセット(バイト単位で測定される)のPos値を作成するには、 43 // まず [FileSet.AddFile] を使用して対応するファイルを現在のファイルセットに追加し、 44 // そのファイルのために[File.Pos](offset)を呼び出します。 45 // 特定のファイルセットfsetに対するPos値pを持つ場合、対応する [Position] 値はfset.Position(p)を呼び出すことで得られます。 46 // 47 // Pos値は通常の比較演算子を使って直接比較することができます: 48 // 2つのPos値pとqが同じファイルにある場合、pとqを比較することは、対応するソースファイルのオフセットを比較することと等価です。 49 // pとqが異なるファイルにある場合、qによって指定されるファイルがpによって指定されるファイルよりも前に対応するファイルセットに追加された場合、p < qはtrueです。 50 type Pos int 51 52 // [Pos] のゼロ値はNoPosであり、ファイルおよび行情報は関連付けられていません。 53 // また、NoPos.IsValid()はfalseです。NoPosは常に他の [Pos] 値よりも小さくなります。 54 // NoPosに対応する [Position] 値は [Position] のゼロ値です。 55 const NoPos Pos = 0 56 57 // IsValid は位置が有効かどうかを報告します。 58 func (p Pos) IsValid() bool 59 60 // Fileは、[FileSet] に属するファイルのハンドルです。 61 // Fileには名前、サイズ、行オフセット表があります。 62 type File struct { 63 name string 64 base int 65 size int 66 67 // lines と infos はミューテックスによって保護されています。 68 mutex sync.Mutex 69 lines []int 70 infos []lineInfo 71 } 72 73 // NameはAddFileで登録されたファイルfのファイル名を返します。 74 func (f *File) Name() string 75 76 // Baseは、AddFileで登録されたファイルfの基本オフセットを返します。 77 func (f *File) Base() int 78 79 // SizeはAddFileで登録されたファイルfのサイズを返します。 80 func (f *File) Size() int 81 82 // LineCount returns the number of lines in file f. 83 func (f *File) LineCount() int 84 85 // AddLineは新しい行の行オフセットを追加します。 86 // 行オフセットは前の行のオフセットよりも大きく、ファイルのサイズよりも小さい必要があります。そうでない場合、行オフセットは無視されます。 87 func (f *File) AddLine(offset int) 88 89 // MergeLineは、次の行と行を結合します。これは、行の末尾の改行文字をスペースで置き換えることに似ています(残りのオフセットは変更されません)。行番号を取得するには、[Position.Line] などを参照してください。無効な行番号が指定された場合、MergeLineはパニックを起こします。 90 func (f *File) MergeLine(line int) 91 92 // Linesは [File.SetLines] で指定された形式の効果的な行オフセットの表を返します。 93 // 呼び出し元は結果を変更してはいけません。 94 func (f *File) Lines() []int 95 96 // SetLinesはファイルの行オフセットを設定し、成功したかどうかを報告します。 97 // 行オフセットとは、各行の最初の文字のオフセットです。 98 // たとえば、"ab\nc\n"という内容の場合、行オフセットは{0、3}です。 99 // 空のファイルは空の行オフセットテーブルを持ちます。 100 // 各行のオフセットは、前の行のオフセットよりも大きく、ファイルサイズよりも小さくなければなりません。 101 // それ以外の場合、SetLinesは失敗し、falseを返します。 102 // SetLinesが返された後は、与えられたスライスを変更しないでください。 103 func (f *File) SetLines(lines []int) bool 104 105 // SetLinesForContentは与えられたファイルの内容に対して行のオフセットを設定します。 106 // 位置を変更する//lineコメントは無視されます。 107 func (f *File) SetLinesForContent(content []byte) 108 109 // LineStartは指定された行の開始位置の [Pos] 値を返します。 110 // [File.AddLineColumnInfo] を使用して設定された代替の位置は無視されます。 111 // LineStartは、1ベースの行番号が無効な場合にパニックを引き起こします。 112 func (f *File) LineStart(line int) Pos 113 114 // AddLineInfoは、Column = 1引数を持つ [File.AddLineColumnInfo] と同様です。 115 // Go 1.11より前のコードの後方互換性のためにここにあります。 116 func (f *File) AddLineInfo(offset int, filename string, line int) 117 118 // AddLineColumnInfoは、与えられたファイルオフセットに対して代替のファイル、行、および列番号の情報を追加します。オフセットは、以前に追加された代替の行情報のオフセットよりも大きく、ファイルサイズよりも小さい必要があります。それ以外の場合、情報は無視されます。 119 // AddLineColumnInfoは通常、//line filename:line:columnなどの行ディレクティブの代替位置情報を登録するために使用されます。 120 func (f *File) AddLineColumnInfo(offset int, filename string, line, column int) 121 122 // Posは、指定されたファイルオフセットのPos値を返します。 123 // 124 // オフセットが負の場合、結果はファイルの開始位置です。 125 // オフセットが大きすぎる場合、結果はファイルの終了位置です(go.dev/issue/57490も参照してください)。 126 // 127 // 一般的なPos値には当てはまらないが、結果pに対しては次の不変性が保持されます: 128 // f.Pos(f.Offset(p)) == p. 129 func (f *File) Pos(offset int) Pos 130 131 // Offsetは、指定されたファイル位置pのオフセットを返します。 132 // 133 // pがファイルの開始位置より前(またはpがNoPos)の場合、結果は0です。 134 // pがファイルの終了位置を過ぎている場合、結果はファイルサイズです(go.dev/issue/57490も参照してください)。 135 // 136 // 一般的なオフセット値には当てはまらないが、結果のオフセットに対しては次の不変性が保持されます: 137 // f.Offset(f.Pos(offset)) == offset 138 func (f *File) Offset(p Pos) int 139 140 // Lineは与えられたファイル位置pの行番号を返します。 141 // pはそのファイル内の [Pos] 値または [NoPos] でなければなりません。 142 func (f *File) Line(p Pos) int 143 144 // PositionForは、指定されたファイル位置pに対するPosition値を返します。 145 // pが範囲外の場合、File.Offsetの動作に合わせて調整されます。 146 // adjustedが設定されている場合、位置は位置を変更する 147 // //lineコメントによって調整される可能性があります。それ以外の場合、それらのコメントは無視されます。 148 // pはf内のPos値、またはNoPosでなければなりません。 149 func (f *File) PositionFor(p Pos, adjusted bool) (pos Position) 150 151 // Positionは、指定されたファイル位置pに対するPosition値を返します。 152 // pが範囲外の場合、それはFile.Offsetの動作に合わせて調整されます。 153 // f.Position(p)を呼び出すことは、f.PositionFor(p, true)を呼び出すことと同等です。 154 func (f *File) Position(p Pos) (pos Position) 155 156 // FileSetはソースファイルの集合を表します。 157 // ファイルセットのメソッドは同期されており、複数のゴルーチンが同時に呼び出すことができます。 158 // 159 // ファイルセット内の各ファイルのバイトオフセットは、異なる(整数)間隔、すなわち間隔[base、base+size]にマッピングされます。 [FileSet.Base] はファイルの最初のバイトを表し、sizeは対応するファイルサイズです。 [Pos] 値はそのような間隔内の値です。 [Pos] 値が属する間隔を決定することで、ファイル、そのファイルのベース、そして [Pos] 値が表しているバイトオフセット(位置)を計算することができます。 160 // 161 // 新しいファイルを追加する際には、ファイルベースが必要です。それはすでにファイルセット内の任意のファイルの間隔の終わりを過ぎた整数値である必要があります。便宜上、 [FileSet.Base] はそのような値を提供します。それは単純に最後に追加されたファイルのPos間隔の終わりの位置に+1した値です。後で間隔を拡張する必要がない場合は、 [FileSet.Base] を [FileSet.AddFile] の引数として使用する必要があります。 162 // 163 // FileSetが不要な場合、 [File] はFileSetから削除することができます。これにより、長時間実行されるアプリケーションでメモリ使用量を削減することができます。 164 type FileSet struct { 165 mutex sync.RWMutex 166 base int 167 files []*File 168 last atomic.Pointer[File] 169 } 170 171 // NewFileSetは新しいファイルセットを作成します。 172 func NewFileSet() *FileSet 173 174 // Baseは、次のファイルを追加する際に [FileSet.AddFile] に提供する必要がある最小のベースオフセットを返します。 175 func (s *FileSet) Base() int 176 177 // AddFileは、指定されたファイル名、ベースオフセット、ファイルサイズを持つ新しいファイルをファイルセットsに追加し、ファイルを返します。複数のファイルは同じ名前を持つことができます。ベースオフセットは、 [FileSet.Base] より小さくはならず、サイズは負であってはいけません。特別なケースとして、負のベースが提供された場合、 [FileSet.Base] の現在の値が代わりに使用されます。 178 // ファイルを追加すると、次のファイルのための最小ベース値として、 [FileSet.Base] の値はbase + size + 1に設定されます。与えられたファイルオフセットoffsに対する [Pos] 値pの関係は次のとおりです: 179 // int(p) = base + offs 180 // ただし、offsは範囲[0、size]にあり、したがってpは範囲[base、base+size]にあります。便宜上、 [File.Pos] はファイル固有の位置値をファイルオフセットから作成するために使用できます。 181 func (s *FileSet) AddFile(filename string, base, size int) *File 182 183 // RemoveFileは、 [FileSet] からファイルを削除し、その後の [Pos] 間隔のクエリが負の結果を返すようにします。 184 // これにより、長寿命の [FileSet] のメモリ使用量が減少し、無制限のファイルストリームに遭遇した場合でも処理が可能になります。 185 // 186 // セットに属さないファイルを削除しても効果はありません。 187 func (s *FileSet) RemoveFile(file *File) 188 189 // ファイルセット内のファイルを追加された順にfに呼び出し、fがfalseを返すまで繰り返します。 190 func (s *FileSet) Iterate(f func(*File) bool) 191 192 // File関数は、位置pを含むファイルを返します。 193 // 該当するファイルが見つからない場合(たとえばp == [NoPos] の場合)、結果はnilです。 194 func (s *FileSet) File(p Pos) (f *File) 195 196 // PositionForは、ファイルセット内の [Pos] pを [Position] 値に変換します。 197 // adjustedが設定されている場合、位置は位置変更を行うコメントによって調整される可能性があります。 198 // そうでなければ、そのコメントは無視されます。 199 // pはsまたは [NoPos] の [Pos] 値でなければなりません。 200 func (s *FileSet) PositionFor(p Pos, adjusted bool) (pos Position) 201 202 // Positionはファイルセット内の [Pos] pをPosition値に変換します。 203 // s.Position(p)を呼び出すことは、s.PositionFor(p, true)を呼び出すことと同じです。 204 func (s *FileSet) Position(p Pos) (pos Position)