go-toml/parsekit/matching.go

121 lines
3.6 KiB
Go

package parsekit
import (
"strings"
)
// AtEndOfFile returns true when there is no more data available in the input.
func (p *P) AtEndOfFile() bool {
return p.pos >= p.len
}
// AtEndOfLine returns true when the cursor is either at the end of the line
// or at the end of the file. The cursor is not moved to a new position
// by this method.
func (p *P) AtEndOfLine() bool {
return p.AtEndOfFile() ||
p.Upcoming("\r", "\n") ||
p.Upcoming("\n")
}
// SkipEndOfLine returns true when the cursor is either at the end of the line
// or at the end of the file. Additionally, when not at the end of the file,
// the cursor is moved forward to beyond the newline.
func (p *P) SkipEndOfLine() bool {
return p.AtEndOfFile() ||
p.SkipMatching("\r", "\n") ||
p.SkipMatching("\n")
}
// AcceptEndOfLine returns true when the cursor is either at the end of the line
// or at the end of the file. When not at the end of the file, a normalized
// newline (only a '\n' character, even with '\r\n' on the input)
// is added to the string buffer.
func (p *P) AcceptEndOfLine() bool {
if p.AtEndOfFile() {
return true
}
if p.SkipEndOfLine() {
p.buffer.writeRune('\n')
return true
}
return false
}
// Match checks if the upcoming runes satisfy all provided patterns.
// It returns a slice of runes that were found, a slice containing
// their respective byte widths, and a boolean indicating whether
// or not all provided patterns were satisfied by the input data.
func (p *P) Match(patterns ...string) ([]rune, []int, bool) {
peeked, widths, ok := p.peekMulti(len(patterns))
if ok {
for i, r := range patterns {
if strings.IndexRune(r, peeked[i]) < 0 {
return peeked, widths, false
}
}
return peeked, widths, true
}
return peeked, widths, false
}
// Upcoming checks if the upcoming runes satisfy all provided patterns.
// Returns true if all provided patterns are satisfied.
// This is basically the same as the Match method, but with only
// the boolean return parameter for programmer convenciency.
func (p *P) Upcoming(patterns ...string) bool {
_, _, ok := p.Match(patterns...)
return ok
}
// AcceptAny adds the next rune from the input to the string buffer.
// If no rune could be read (end of file or invalid UTF8 data),
// then false is returned.
func (p *P) AcceptAny() bool {
if r, ok := p.next(); ok {
p.buffer.writeRune(r)
return true
}
return false
}
// AcceptMatching adds the next runes to the string buffer, but only
// if the upcoming runes satisfy the provided patterns.
// When runes were added then true is returned, false otherwise.
func (p *P) AcceptMatching(patterns ...string) bool {
return p.progress(func(r rune) { p.buffer.writeRune(r) }, patterns...)
}
// AcceptConsecutive adds consecutive runes from the input to the string
// buffer, as long as they exist in the pattern.
// If any runes were added then true is returned, false otherwise.
func (p *P) AcceptConsecutive(pattern string) bool {
accepted := false
for p.AcceptMatching(pattern) {
accepted = true
}
return accepted
}
// SkipMatching skips runes, but only when all provided patterns are satisfied.
// Returns true when one or more runes were skipped.
func (p *P) SkipMatching(patterns ...string) bool {
if runes, widths, ok := p.Match(patterns...); ok {
for i, r := range runes {
p.advanceCursor(r, widths[i])
}
return true
}
return false
}
// SkipConsecutive skips consecutive runes from the provided pattern.
// Returns true when one or more runes were skipped.
func (p *P) SkipConsecutive(pattern string) bool {
didSkip := false
for p.SkipMatching(pattern) {
didSkip = true
}
return didSkip
}