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  	return b.Line() + (pos.Line() - b.Pos().Line())
  36  }
  37  
  38  func (pos Pos) RelCol() (n 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) (n int32) {
  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() (s 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 string(rel.filename) != string(abs.filename) || rel.line != abs.line || rel.col != abs.col {
  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() (s 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 p.filename | ":" | ItoaU32(p.line)
 104  	}
 105  	return p.filename | ":" | ItoaU32(p.line) | ":" | ItoaU32(p.col)
 106  }
 107  
 108  func ItoaU32(n uint32) (s string) {
 109  	if n == 0 {
 110  		return "0"
 111  	}
 112  	buf := []byte{:0:10}
 113  	for n > 0 {
 114  		buf = append(buf, byte('0'+n%10))
 115  		n /= 10
 116  	}
 117  	for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 {
 118  		buf[i], buf[j] = buf[j], buf[i]
 119  	}
 120  	return string(buf)
 121  }
 122  
 123  type PosBase struct {
 124  	pos       Pos
 125  	filename  string
 126  	line, col uint32
 127  	trimmed   bool
 128  }
 129  
 130  func NewFileBase(filename string) (p *PosBase) {
 131  	return NewTrimmedFileBase(filename, false)
 132  }
 133  
 134  func NewTrimmedFileBase(filename string, trimmed bool) (p *PosBase) {
 135  	base := &PosBase{MakePos(nil, Linebase, Colbase), filename, Linebase, Colbase, trimmed}
 136  	base.pos.base = base
 137  	return base
 138  }
 139  
 140  func NewLineBase(pos Pos, filename string, trimmed bool, line, col uint32) (p *PosBase) {
 141  	return &PosBase{pos, filename, sat32(line), sat32(col), trimmed}
 142  }
 143  
 144  func (base *PosBase) IsFileBase() (ok bool) {
 145  	if base == nil {
 146  		return false
 147  	}
 148  	return base.pos.base == base
 149  }
 150  
 151  func (base *PosBase) Pos() (_ Pos) {
 152  	if base == nil {
 153  		return
 154  	}
 155  	return base.pos
 156  }
 157  
 158  func (base *PosBase) Filename() (s string) {
 159  	if base == nil {
 160  		return ""
 161  	}
 162  	return base.filename
 163  }
 164  
 165  func (base *PosBase) Line() (n uint32) {
 166  	if base == nil {
 167  		return 0
 168  	}
 169  	return base.line
 170  }
 171  
 172  func (base *PosBase) Col() (n uint32) {
 173  	if base == nil {
 174  		return 0
 175  	}
 176  	return base.col
 177  }
 178  
 179  func (base *PosBase) Trimmed() (ok bool) {
 180  	if base == nil {
 181  		return false
 182  	}
 183  	return base.trimmed
 184  }
 185  
 186  func sat32(x uint32) (n uint32) {
 187  	if x > PosMax {
 188  		return PosMax
 189  	}
 190  	return uint32(x)
 191  }
 192  
 193  func Itoa(n int32) (s string) {
 194  	if n == 0 {
 195  		return "0"
 196  	}
 197  	neg := false
 198  	if n < 0 {
 199  		neg = true
 200  		n = -n
 201  	}
 202  	buf := []byte{:0:12}
 203  	for n > 0 {
 204  		buf = append(buf, byte('0'+n%10))
 205  		n /= 10
 206  	}
 207  	if neg {
 208  		buf = append(buf, '-')
 209  	}
 210  	for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 {
 211  		buf[i], buf[j] = buf[j], buf[i]
 212  	}
 213  	return string(buf)
 214  }
 215  
 216  func Itoa64(n int64) (s string) {
 217  	if n == 0 {
 218  		return "0"
 219  	}
 220  	neg := false
 221  	if n < 0 {
 222  		neg = true
 223  		n = -n
 224  	}
 225  	buf := []byte{:0:20}
 226  	for n > 0 {
 227  		buf = append(buf, byte('0'+n%10))
 228  		n /= 10
 229  	}
 230  	if neg {
 231  		buf = append(buf, '-')
 232  	}
 233  	for i, j := int32(0), len(buf)-1; i < j; i, j = i+1, j-1 {
 234  		buf[i], buf[j] = buf[j], buf[i]
 235  	}
 236  	return string(buf)
 237  }
 238  
 239  func Contains(tokset uint64, tok Token) (ok bool) {
 240  	var bit uint64 = 1
 241  	bit = bit << tok
 242  	return tokset&bit != 0
 243  }
 244