initial commits

master
Charles Iliya Krempeaux 2023-11-22 06:49:43 -08:00
parent d60a2755b8
commit 0aa3328241
3 changed files with 146 additions and 0 deletions

6
braces.go 100644
View File

@ -0,0 +1,6 @@
package brace
const (
leftbrace rune = '{'
rightbrace rune = '}'
)

31
errors.go 100644
View File

@ -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)
}

109
parse.go 100644
View File

@ -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
}