package lexer import "fmt" // Position indicates a line and column pair on a file. // Counting starts at 1. type Position struct { Line int Column int } // String generates a pretty "(Line, Column)"" representation of the Position func (p Position) String() string { if p.Line == 0 { p.Reset() } return fmt.Sprintf("(%v, %v)", p.Line, p.Column) } // GoString generates a string representation of the Position for %#v usage func (p Position) GoString() string { if p.Line == 0 { p.Reset() } return fmt.Sprintf("lexer.Position{%v, %v}", p.Line, p.Column) } // Reset places a position at (1,1) func (p *Position) Reset() { p.Line, p.Column = 1, 1 } // Step moves the column one place func (p *Position) Step() { if p.Line == 0 { p.Reset() } p.Column++ } // StepN moves the column N places forward func (p *Position) StepN(n int) { if p.Line == 0 { p.Reset() } switch { case n > 0: p.Column += n default: panic(fmt.Errorf("invalid %v increment", n)) } } // StepLine moves position to the start of the next line func (p *Position) StepLine() { if p.Line == 0 { p.Reset() } p.Line++ p.Column = 1 } // Add adds a relative position considering // potential new lines func (p *Position) Add(rel Position) { if p.Line == 0 { p.Reset() } switch { case rel.Line == 0: // nothing case rel.Line > 1: // includes new lines p.Line += rel.Line - 1 p.Column = rel.Column default: // same line p.Column += rel.Column - 1 } }