pos.mx raw

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