pos.mx raw

   1  package token
   2  
   3  const PosMax = 1 << 30
   4  const Linebase = 1
   5  const Colbase = 1
   6  
   7  type Pos struct {
   8  	base      *PosBase
   9  	line, col uint32
  10  }
  11  
  12  func MakePos(base *PosBase, line, col uint32) (p Pos) { return Pos{base, sat32(line), sat32(col)} }
  13  
  14  func (pos *Pos) Pos() (p Pos) { return *pos }
  15  func (pos *Pos) IsKnown() (ok bool) { return pos.line > 0 }
  16  func (pos *Pos) Base() (p *PosBase) { return pos.base }
  17  func (pos *Pos) Line() (n uint32) { return pos.line }
  18  func (pos *Pos) Col() (n uint32) { return pos.col }
  19  
  20  func (pos *Pos) FileBase() (p *PosBase) {
  21  	b := pos.base
  22  	for b != nil && b != b.pos.base {
  23  		b = b.pos.base
  24  	}
  25  	return b
  26  }
  27  
  28  func (pos *Pos) RelFilename() (s string) { return pos.base.Filename() }
  29  
  30  func (pos *Pos) RelLine() (n uint32) {
  31  	b := pos.base
  32  	if b.Line() == 0 {
  33  		return 0
  34  	}
  35  	bp := b.Pos()
  36  	return b.Line() + (pos.Line() - bp.Line())
  37  }
  38  
  39  func (pos *Pos) RelCol() (n uint32) {
  40  	b := pos.base
  41  	if b.Col() == 0 {
  42  		return 0
  43  	}
  44  	bp := b.Pos()
  45  	if pos.Line() == bp.Line() {
  46  		return b.Col() + (pos.Col() - bp.Col())
  47  	}
  48  	return pos.Col()
  49  }
  50  
  51  func (p *Pos) Cmp(q Pos) (n int32) {
  52  	pname := p.RelFilename()
  53  	qname := q.base.Filename()
  54  	switch {
  55  	case pname < qname:
  56  		return -1
  57  	case pname > qname:
  58  		return +1
  59  	}
  60  
  61  	pline := p.Line()
  62  	qline := q.line
  63  	switch {
  64  	case pline < qline:
  65  		return -1
  66  	case pline > qline:
  67  		return +1
  68  	}
  69  
  70  	pcol := p.Col()
  71  	qcol := q.col
  72  	switch {
  73  	case pcol < qcol:
  74  		return -1
  75  	case pcol > qcol:
  76  		return +1
  77  	}
  78  
  79  	return 0
  80  }
  81  
  82  func (pos *Pos) String() (s string) {
  83  	rel := position_{pos.RelFilename(), pos.RelLine(), pos.RelCol()}
  84  	bp := pos.Base().Pos()
  85  	abs := position_{bp.RelFilename(), pos.Line(), pos.Col()}
  86  	s = rel.String()
  87  	if string(rel.filename) != string(abs.filename) || rel.line != abs.line || rel.col != abs.col {
  88  		s = s | "[" | abs.String() | "]"
  89  	}
  90  	return s
  91  }
  92  
  93  type position_ struct {
  94  	filename  string
  95  	line, col uint32
  96  }
  97  
  98  func (p *position_) String() (s string) {
  99  	if p.line == 0 {
 100  		if p.filename == "" {
 101  			return "<unknown position>"
 102  		}
 103  		return p.filename
 104  	}
 105  	if p.col == 0 {
 106  		return p.filename | ":" | SimpleItoaU32(p.line)
 107  	}
 108  	return p.filename | ":" | SimpleItoaU32(p.line) | ":" | SimpleItoaU32(p.col)
 109  }
 110  
 111  func SimpleItoaU32(n uint32) (s string) {
 112  	if n == 0 {
 113  		return "0"
 114  	}
 115  	buf := []byte{:0:10}
 116  	for n > 0 {
 117  		push(buf, byte('0'+n%10))
 118  		n /= 10
 119  	}
 120  	for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 {
 121  		buf[i], buf[j] = buf[j], buf[i]
 122  	}
 123  	return string(buf)
 124  }
 125  
 126  type PosBase struct {
 127  	pos       Pos
 128  	filename  string
 129  	line, col uint32
 130  	trimmed   bool
 131  }
 132  
 133  func NewFileBase(filename string) (p *PosBase) {
 134  	return NewTrimmedFileBase(filename, false)
 135  }
 136  
 137  func NewTrimmedFileBase(filename string, trimmed bool) (p *PosBase) {
 138  	base := &PosBase{MakePos(nil, Linebase, Colbase), filename, Linebase, Colbase, trimmed}
 139  	base.pos.base = base
 140  	return base
 141  }
 142  
 143  func NewLineBase(pos Pos, filename string, trimmed bool, line, col uint32) (p *PosBase) {
 144  	return &PosBase{pos, filename, sat32(line), sat32(col), trimmed}
 145  }
 146  
 147  func (base *PosBase) IsFileBase() (ok bool) {
 148  	if base == nil {
 149  		return false
 150  	}
 151  	return base.pos.base == base
 152  }
 153  
 154  func (base *PosBase) Pos() (_ Pos) {
 155  	if base == nil {
 156  		return
 157  	}
 158  	return base.pos
 159  }
 160  
 161  func (base *PosBase) Filename() (s string) {
 162  	if base == nil {
 163  		return ""
 164  	}
 165  	return base.filename
 166  }
 167  
 168  func (base *PosBase) Line() (n uint32) {
 169  	if base == nil {
 170  		return 0
 171  	}
 172  	return base.line
 173  }
 174  
 175  func (base *PosBase) Col() (n uint32) {
 176  	if base == nil {
 177  		return 0
 178  	}
 179  	return base.col
 180  }
 181  
 182  func (base *PosBase) Trimmed() (ok bool) {
 183  	if base == nil {
 184  		return false
 185  	}
 186  	return base.trimmed
 187  }
 188  
 189  func sat32(x uint32) (n uint32) {
 190  	if x > PosMax {
 191  		return PosMax
 192  	}
 193  	return uint32(x)
 194  }
 195