From d4dbc28aeed684d3a6c15030ca9051fdb5747fad Mon Sep 17 00:00:00 2001 From: Alejandro Mery Date: Fri, 24 Oct 2014 06:35:16 +0200 Subject: [PATCH] scanner.Scanner: initial struct and methods for the low level text scanner Signed-off-by: Alejandro Mery --- scanner/scanner.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/scanner/scanner.go b/scanner/scanner.go index 95a12d4..2a2676b 100644 --- a/scanner/scanner.go +++ b/scanner/scanner.go @@ -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 +}