about summary refs log tree commit diff
path: root/pkg/libs/source
diff options
context:
space:
mode:
authorMel <einebeere@gmail.com>2022-05-09 00:01:02 +0200
committerMel <einebeere@gmail.com>2022-05-09 00:01:02 +0200
commitb09a14147d397904722ee7c25e4defc56135b96f (patch)
tree694dc725528310f3a65d04785b8eea33908ce69f /pkg/libs/source
parentb5a9660b6ac42bce27c746e76013c3ce5992743a (diff)
downloadjinx-b09a14147d397904722ee7c25e4defc56135b96f.tar.zst
jinx-b09a14147d397904722ee7c25e4defc56135b96f.zip
Extract source walk part of scanner
Diffstat (limited to 'pkg/libs/source')
-rw-r--r--pkg/libs/source/errors.go10
-rw-r--r--pkg/libs/source/loc.go10
-rw-r--r--pkg/libs/source/walker.go80
3 files changed, 100 insertions, 0 deletions
diff --git a/pkg/libs/source/errors.go b/pkg/libs/source/errors.go
new file mode 100644
index 0000000..cfcd9e3
--- /dev/null
+++ b/pkg/libs/source/errors.go
@@ -0,0 +1,10 @@
+package source
+
+type ErrUnexpectedChar struct {
+	Expected rune
+	Actual   rune
+}
+
+func (e ErrUnexpectedChar) Error() string {
+	return "unexpected character: expected " + string(e.Expected) + ", actual " + string(e.Actual)
+}
diff --git a/pkg/libs/source/loc.go b/pkg/libs/source/loc.go
new file mode 100644
index 0000000..3089d3b
--- /dev/null
+++ b/pkg/libs/source/loc.go
@@ -0,0 +1,10 @@
+package source
+
+type Loc struct {
+	Row int
+	Col int
+}
+
+func NewLoc(row, col int) Loc {
+	return Loc{row, col}
+}
diff --git a/pkg/libs/source/walker.go b/pkg/libs/source/walker.go
new file mode 100644
index 0000000..aeac82a
--- /dev/null
+++ b/pkg/libs/source/walker.go
@@ -0,0 +1,80 @@
+package source
+
+import (
+	"bufio"
+	"errors"
+	"io"
+)
+
+type Walker struct {
+	source *bufio.Reader
+
+	row int
+	col int
+}
+
+func NewWalker(source io.Reader) *Walker {
+	return &Walker{
+		source: bufio.NewReader(source),
+		row:    0,
+		col:    0,
+	}
+}
+
+func (w *Walker) Loc() Loc {
+	return Loc{
+		Row: w.row,
+		Col: w.col,
+	}
+}
+
+func (w *Walker) Next() (rune, bool, error) {
+	r, _, err := w.source.ReadRune()
+	if err != nil {
+		if errors.Is(err, io.EOF) {
+			return 0, true, nil
+		}
+
+		return 0, false, err
+	}
+
+	if r == '\n' {
+		w.row++
+		w.col = 0
+	} else {
+		w.col++
+	}
+
+	return r, false, nil
+}
+
+func (w *Walker) Consume(want rune) (bool, error) {
+	c, _, err := w.Next()
+	if err != nil {
+		return false, err
+	}
+
+	if c != want {
+		return true, ErrUnexpectedChar{
+			Expected: want,
+			Actual:   c,
+		}
+	}
+
+	return true, nil
+}
+
+func (w *Walker) Peek() (rune, bool, error) {
+	r, _, err := w.source.ReadRune()
+	defer w.source.UnreadRune()
+
+	if err != nil {
+		if errors.Is(err, io.EOF) {
+			return 0, true, nil
+		}
+
+		return 0, false, err
+	}
+
+	return r, false, nil
+}