Alejandro Mery
10 years ago
1 changed files with 72 additions and 0 deletions
@ -1 +1,73 @@
|
||||
package scanner |
||||
|
||||
import ( |
||||
"unicode/utf8" |
||||
) |
||||
|
||||
const ( |
||||
EOF = -1 |
||||
) |
||||
|
||||
type Position struct { |
||||
Offset uint |
||||
Line, Column uint |
||||
} |
||||
|
||||
type Scanner struct { |
||||
name string |
||||
input string |
||||
|
||||
base Position |
||||
cursor Position |
||||
runes uint |
||||
} |
||||
|
||||
// Creates new Scanner to parse a given string, or nil if empty
|
||||
func NewScannerFromString(name, input string) *Scanner { |
||||
if len(input) == 0 { |
||||
return nil |
||||
} |
||||
|
||||
return &Scanner{ |
||||
name: name, |
||||
input: input, |
||||
base: Position{0, 1, 1}, |
||||
cursor: Position{0, 1, 1}, |
||||
runes: 0, |
||||
} |
||||
} |
||||
|
||||
// Current length of the upcomming Terminal
|
||||
func (l *Scanner) Length() (uint, uint) { |
||||
return l.cursor.Offset - l.base.Offset, l.runes |
||||
} |
||||
|
||||
// Is the upcoming Terminal stil empty?
|
||||
func (l *Scanner) Empty() bool { |
||||
return l.runes == 0 |
||||
} |
||||
|
||||
// Move cursor forward
|
||||
func (l *Scanner) StepForth(runes, bytes uint) { |
||||
l.cursor.Offset += bytes |
||||
l.cursor.Column += runes |
||||
l.runes += runes |
||||
} |
||||
|
||||
// Return the next rune but not moving the cursor
|
||||
func (l *Scanner) Peek() (rune, uint) { |
||||
if l.cursor.Offset == uint(len(l.input)) { |
||||
return EOF, 0 |
||||
} |
||||
r, bytes := utf8.DecodeRuneInString(l.input[l.cursor.Offset:]) |
||||
return r, uint(bytes) |
||||
} |
||||
|
||||
// Return the next rune but moving the cursor
|
||||
func (l *Scanner) Next() (rune, uint) { |
||||
r, bytes := l.Peek() |
||||
if bytes > 0 { |
||||
l.StepForth(1, bytes) |
||||
} |
||||
return r, bytes |
||||
} |
||||
|
Loading…
Reference in new issue