Как перемотать в текстовом сканере Go? - PullRequest
0 голосов
/ 13 октября 2019

Я использую пакет text/scanner для разбора произвольных выражений. В настоящее время я пытаюсь реализовать параметр not in, то есть, если текущий идентификатор not, а следующий - in, проанализируйте его с помощью функции notin(left, right), а в противном случае мы проанализируем его как negate(right).

Я, по сути, получил код для управления этими случаями, однако я не могу перемотать сканер, если следующий токен не in. Я попытался записать положение, а затем переназначить его позже, но безрезультатно и не смог найти другое решение.

func readToken(stream *scanner.Scanner) {
    switch stream.Scan() {
    case scanner.Ident:
        switch stream.TokenText() {
        case "in":
            in(left, right)
        case "not":
            oldPosition := stream.Position
            nextToken := stream.Scan()
            if nextToken == scanner.Ident {
                switch stream.TokenText() {
                case "in":
                    fmt.Println("notin")
                default:
                    // how do we rewind the scanner?
                    stream.Position = oldPosition 
                    fmt.Println("negate default")
                }
            } else {
                fmt.Println("negate no-ident")
            }
        }
    }
}

Как можно перемотать сканер, если я ненайти действительный идентификатор?

Редактировать, я также попытался использовать Peek(), как показано ниже, но это все еще меняет состояние до точки, которую мне также нужно перематывать.

// other code
case "not":
    nextIdent, err := getNextIdent(stream)
    if err != nil {
        fmt.Println("negate no-ident")
    } else {
        switch nextIdent {
        case "in":
            fmt.Println("notin")
        default:
            fmt.Println("negate default")
        }
    }
// other code


func getNextIdent(s *scanner.Scanner) (string, error) {
    var nextIdent string

    ch := s.Peek()

    // skip white space
    for s.Whitespace&(1<<uint(ch)) != 0 {
        ch = s.Next()
    }

    if isIdentRune(ch, 0) {
        nextIdent = string(ch)
        ch = s.Next()
        nextIdent += string(ch)
        for i := 1; isIdentRune(ch, i); i++ {
            ch = s.Next()
            if s.Whitespace&(1<<uint(ch)) != 0 {
                break
            }
            nextIdent += string(ch)
        }
        return nextIdent, nil
    }

    return "",errors.New("not a ident")
}

Обратите внимание, код, который я получил, - это вилка из Knetic / govaluate в сочетании с PR от пользователя GH generikvault и некоторыми другими вилками. Полный код можно найти в моем профиле Github

1 Ответ

3 голосов
/ 13 октября 2019

Рассматривая ссылки API на text/scanner, я не могу найти способ перемотать сканер так, как вы хотите.

Однако метод Peek() даст вам следующую руну без продвижения сканера. Внутри «не» дела вы можете использовать его, чтобы заранее посмотреть, соответствует ли он.

...