flabk/pkg/asld/walker.go

162 lines
3.1 KiB
Go
Raw Normal View History

package asld
import "fmt"
// Walker.... texas ranger.
// Except he's a cringe conservative.
//
// This is also cringe but not for cringe reasons.
func (w walker) Debug_PRINT() {
for index, b := range w.content {
out := string(b)
if w.position == index {
out = "<[>" + out + "<]>"
}
print(out)
}
print("\n")
}
func (w walker) SliceInner() (walker, bool) {
// the !ok scenario here is only if the code is bad
s, ok := byByte[w.Current()]
// Debug
if !ok {
panic(w)
}
var height uint
for pos := w.position + 1; pos < w.len; pos++ {
curr := w.content[pos]
if curr == s.self && s.self != s.closer {
height++
continue
}
if curr == s.closer {
if height == 0 {
return newWalker(w.content[w.position+1 : pos]), ok
}
height--
}
}
return w, false
}
// Sub returns a subwalker from the current position
func (w walker) Sub() walker {
w.content = w.content[w.position:]
w.len = len(w.content)
w.position = 0
return w
}
type walker struct {
content []byte
len int
position int
}
func newWalker(data []byte) walker {
return walker{
content: data,
len: len(data),
}
}
// Until returns a subwalker from position 0 to the current position
func (w walker) Until() walker {
w.content = w.content[:w.position]
w.len = len(w.content)
return w
}
// ToOrStay will stay at where the walker is if b is the
// same as the current walker position.
//
// Otherwise, calls To
func (w walker) ToOrStay(b byte) (walker, bool) {
if w.Current() == b {
return w, true
}
return w.To(b)
}
func (w walker) To(b byte) (walker, bool) {
for pos := w.position + 1; pos < w.len; pos++ {
if w.content[pos] == b {
w.position = pos
return w, true
}
}
return w, false
}
func (w walker) Next() (walker, bool) {
w, ok := w.ToNext()
return w.Sub(), ok
}
func (w walker) ToNext() (walker, bool) {
for pos := w.position + 1; pos < w.len; pos++ {
if in(symbolsRaw, w.content[pos]) {
w.position = pos
return w, true
}
}
return w, false
}
// CommaOrEnd walks to the next comma, or, if none
// is present in the current walker scope, returns
// itself with status statusWalkerNotAffected.
func (w walker) CommaOrEnd() (walkerStatus, error) {
if w.Current() == ',' {
w.position++
}
for pos := w.position; pos < w.len; pos++ {
if in(openRaw, w.content[pos]) {
sb, ok := byByte[w.content[pos]]
if !ok {
panic("ok someone fucked up somewhere")
}
w, ok = w.To(sb.closer)
if !ok {
return walkerStatus{
status: statusError,
walker: w,
}, fmt.Errorf("%w %s", ErrNoMatching, string(sb.closer))
}
pos = w.position
continue
}
if w.content[pos] == ',' {
w.position = pos
return walkerStatus{
status: statusOK,
walker: w,
}, nil
}
}
return walkerStatus{
status: statusWalkerNotAffected,
walker: w,
}, nil
}
func (w walker) Current() byte {
return w.content[w.position]
}
func (w walker) CurrentSymbol() (Symbol, bool) {
b, ok := byByte[w.Current()]
return b, ok
}
func (w walker) String() string {
if w.Current() == '"' {
w, _ = w.SliceInner()
}
return string(w.content)
}