initial commits
parent
d60a2755b8
commit
0aa3328241
|
@ -0,0 +1,6 @@
|
|||
package brace
|
||||
|
||||
const (
|
||||
leftbrace rune = '{'
|
||||
rightbrace rune = '}'
|
||||
)
|
|
@ -0,0 +1,31 @@
|
|||
package brace
|
||||
|
||||
import (
|
||||
"sourcecode.social/reiver/go-erorr"
|
||||
)
|
||||
|
||||
const (
|
||||
errEmptyString = erorr.Error("empty string")
|
||||
errNilRuneScanner = erorr.Error("brace: nil rune-scanner")
|
||||
errNilWriter = erorr.Error("brace: nil writer")
|
||||
)
|
||||
|
||||
func errFileEndedBeforeBraceStringLiteralClosed(depth int64) error {
|
||||
return erorr.Errorf("file ended before the brace-string literal was closed — expected %d more %q (%U) character(s)", depth, rightbrace, rightbrace)
|
||||
}
|
||||
|
||||
func errInternalError(err error) error {
|
||||
return erorr.Errorf("brace: internal error: %w", err)
|
||||
}
|
||||
|
||||
func errParserDepthNegative(depth int64) error {
|
||||
return erorr.Errorf("brace: parser depth (%d) is negative", depth)
|
||||
}
|
||||
|
||||
func errProblemReadingCharacterNumber(num uint64, err error) error {
|
||||
return erorr.Errorf("brace: problem reading character №%d of what should have been a brace-string literal: %w", num, err)
|
||||
}
|
||||
|
||||
func errProblemUnreadingCharacterNumber(num uint64, err error, r rune) error {
|
||||
return erorr.Errorf("brace: problem unreading character №%d (which is a %q (%U)) of what should have been a brace-string literal: %w", num, r, r, err)
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package brace
|
||||
|
||||
import (
|
||||
"io"
|
||||
|
||||
"sourcecode.social/reiver/go-erorr"
|
||||
)
|
||||
|
||||
// Parse parses a brace-string literal from a io.RuneScanner.
|
||||
//
|
||||
// Parse will call ‘fn’ for each logical character it receives.
|
||||
// So — if this is the brace-literal it parses:
|
||||
//
|
||||
// `{a b \{ c \} d}`
|
||||
//
|
||||
// Then ‘fn’ would be called 11 times, and given these runes:
|
||||
//
|
||||
// 'a'
|
||||
// ' '
|
||||
// 'b'
|
||||
// ' '
|
||||
// '{'
|
||||
// ' '
|
||||
// 'c'
|
||||
// ' '
|
||||
// '}'
|
||||
// ' '
|
||||
// 'd'
|
||||
//
|
||||
// Note that the beginning '{' and ending '}' of the brace-string literal are not part of this.
|
||||
// Also note that the '\' (black-slash) before the '{' and the '}' was not included either.
|
||||
func Parse(fn func(rune)error, runescanner io.RuneScanner) error {
|
||||
|
||||
if nil == runescanner {
|
||||
return errNilRuneScanner
|
||||
}
|
||||
|
||||
var nextRead uint64 = 1
|
||||
|
||||
{
|
||||
r, _, err := runescanner.ReadRune()
|
||||
if io.EOF == err {
|
||||
return errProblemReadingCharacterNumber(nextRead, errEmptyString)
|
||||
}
|
||||
if nil != err {
|
||||
return errProblemReadingCharacterNumber(nextRead, err)
|
||||
}
|
||||
nextRead++
|
||||
|
||||
{
|
||||
const expected = leftbrace
|
||||
actual := r
|
||||
|
||||
if expected != actual {
|
||||
err := runescanner.UnreadRune()
|
||||
if nil != err {
|
||||
return errProblemUnreadingCharacterNumber(nextRead, errEmptyString, r)
|
||||
}
|
||||
|
||||
return erorr.Errorf("brace: expected first character of brace-string literal to be a %q (%U), but actually was %q (%U)", expected, expected, actual, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var depth int64 = 1
|
||||
loop: for {
|
||||
r, _, err := runescanner.ReadRune()
|
||||
if io.EOF == err {
|
||||
return errProblemReadingCharacterNumber(nextRead, errFileEndedBeforeBraceStringLiteralClosed(depth))
|
||||
}
|
||||
if nil != err {
|
||||
return errProblemReadingCharacterNumber(nextRead, err)
|
||||
}
|
||||
nextRead++
|
||||
|
||||
switch r {
|
||||
case leftbrace:
|
||||
depth++
|
||||
case rightbrace:
|
||||
depth--
|
||||
case '\\':
|
||||
r, _, err = runescanner.ReadRune()
|
||||
if io.EOF == err {
|
||||
return errProblemReadingCharacterNumber(nextRead, errFileEndedBeforeBraceStringLiteralClosed(depth))
|
||||
}
|
||||
if nil != err {
|
||||
return erorr.Errorf("brace: problem reading character №%d (which would have followed a black-slash %q (%U) that was just read) of what should have been a brace-string literal: %w", nextRead, r, r, err)
|
||||
}
|
||||
nextRead++
|
||||
}
|
||||
|
||||
switch {
|
||||
case 0 == depth:
|
||||
////////////// BREAK
|
||||
break loop
|
||||
case depth < 0:
|
||||
return errInternalError(errParserDepthNegative(depth))
|
||||
}
|
||||
|
||||
{
|
||||
err := fn(r)
|
||||
if nil != err {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue