162 lines
3.1 KiB
Go
162 lines
3.1 KiB
Go
|
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)
|
||
|
}
|