bzick / tokenizer

Tokenizer (lexer) for golang
MIT License
92 stars 6 forks source link

stream.IsNextSequence is infinitely running, if `keys` is longer, than the stream sequence itself #13

Closed DanikNik closed 5 months ago

DanikNik commented 6 months ago

Using github.com/bzick/tokenizer v1.4.0

Way to meet the issue:

const TOK_CMD = 100
var parser = tokenizer.New()
parser.DefineTokens(TOK_CMD, []string{"CMD"})

stream := parser.ParseSting("CMD CMD")

ok := stream.IsNextSequence(TOK_CMD, TOK_CMD, TOK_CMD, TOK_CMD)
// here it is stuck forever

Where the problem lies is the code of func (s *Stream) IsNextSequence(keys ...TokenKey) bool and func (s *Stream) GoTo(id int) *Stream

// IsNextSequence checks if these are next tokens in exactly the same sequence as specified.
func (s *Stream) IsNextSequence(keys ...TokenKey) bool {
    var (
        result = true
        hSize  = 0
        id     = s.CurrentToken().ID()
    )
    if s.historySize > 0 && s.historySize < len(keys) {
        hSize = s.historySize
        s.historySize = len(keys)
    }

    for _, key := range keys {
                // at the moment of parsing the second "CMD" s.GoNext().CurrentToken() is going to be undefToken
        if !s.GoNext().CurrentToken().Is(key) {
            result = false
            break
        }
    }
    s.GoTo(id)

    if hSize != 0 {
        s.SetHistorySize(hSize)
    }
    return result
}

func (s *Stream) GoTo(id int) *Stream {
        // s.current is undefToken, thus s.current.id is -1
        // but the id of the token, which was pointed by s.current at the moment s.IsNextSequence(...) was called is 0
        // this leads to condition `id > s.current.id` to be always true in infinite cycle
    if id > s.current.id {
        for s.current != nil && id != s.current.id {
            s.GoNext()
        }
    } else if id < s.current.id {
        for s.current != nil && id != s.current.id {
            s.GoPrev()
        }
    }
    return s
}
bzick commented 5 months ago

You are right. GoTo should checks undefToken before

bzick commented 5 months ago

fixed in 1.4.1