mirror of https://github.com/minio/minio.git
124 lines
2.7 KiB
Go
124 lines
2.7 KiB
Go
|
package participle
|
||
|
|
||
|
import (
|
||
|
"reflect"
|
||
|
|
||
|
"github.com/alecthomas/participle/lexer"
|
||
|
)
|
||
|
|
||
|
type contextFieldSet struct {
|
||
|
pos lexer.Position
|
||
|
strct reflect.Value
|
||
|
field structLexerField
|
||
|
fieldValue []reflect.Value
|
||
|
}
|
||
|
|
||
|
// Context for a single parse.
|
||
|
type parseContext struct {
|
||
|
*rewinder
|
||
|
lookahead int
|
||
|
caseInsensitive map[rune]bool
|
||
|
apply []*contextFieldSet
|
||
|
}
|
||
|
|
||
|
func newParseContext(lex lexer.Lexer, lookahead int, caseInsensitive map[rune]bool) (*parseContext, error) {
|
||
|
rew, err := newRewinder(lex)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
return &parseContext{
|
||
|
rewinder: rew,
|
||
|
caseInsensitive: caseInsensitive,
|
||
|
lookahead: lookahead,
|
||
|
}, nil
|
||
|
}
|
||
|
|
||
|
// Defer adds a function to be applied once a branch has been picked.
|
||
|
func (p *parseContext) Defer(pos lexer.Position, strct reflect.Value, field structLexerField, fieldValue []reflect.Value) {
|
||
|
p.apply = append(p.apply, &contextFieldSet{pos, strct, field, fieldValue})
|
||
|
}
|
||
|
|
||
|
// Apply deferred functions.
|
||
|
func (p *parseContext) Apply() error {
|
||
|
for _, apply := range p.apply {
|
||
|
if err := setField(apply.pos, apply.strct, apply.field, apply.fieldValue); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
p.apply = nil
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
// Branch accepts the branch as the correct branch.
|
||
|
func (p *parseContext) Accept(branch *parseContext) {
|
||
|
p.apply = append(p.apply, branch.apply...)
|
||
|
p.rewinder = branch.rewinder
|
||
|
}
|
||
|
|
||
|
// Branch starts a new lookahead branch.
|
||
|
func (p *parseContext) Branch() *parseContext {
|
||
|
branch := &parseContext{}
|
||
|
*branch = *p
|
||
|
branch.apply = nil
|
||
|
branch.rewinder = p.rewinder.Lookahead()
|
||
|
return branch
|
||
|
}
|
||
|
|
||
|
// Stop returns true if parsing should terminate after the given "branch" failed to match.
|
||
|
func (p *parseContext) Stop(branch *parseContext) bool {
|
||
|
if branch.cursor > p.cursor+p.lookahead {
|
||
|
p.Accept(branch)
|
||
|
return true
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
type rewinder struct {
|
||
|
cursor, limit int
|
||
|
tokens []lexer.Token
|
||
|
}
|
||
|
|
||
|
func newRewinder(lex lexer.Lexer) (*rewinder, error) {
|
||
|
r := &rewinder{}
|
||
|
for {
|
||
|
t, err := lex.Next()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
if t.EOF() {
|
||
|
break
|
||
|
}
|
||
|
r.tokens = append(r.tokens, t)
|
||
|
}
|
||
|
return r, nil
|
||
|
}
|
||
|
|
||
|
func (r *rewinder) Next() (lexer.Token, error) {
|
||
|
if r.cursor >= len(r.tokens) {
|
||
|
return lexer.EOFToken(lexer.Position{}), nil
|
||
|
}
|
||
|
r.cursor++
|
||
|
return r.tokens[r.cursor-1], nil
|
||
|
}
|
||
|
|
||
|
func (r *rewinder) Peek(n int) (lexer.Token, error) {
|
||
|
i := r.cursor + n
|
||
|
if i >= len(r.tokens) {
|
||
|
return lexer.EOFToken(lexer.Position{}), nil
|
||
|
}
|
||
|
return r.tokens[i], nil
|
||
|
}
|
||
|
|
||
|
// Lookahead returns a new rewinder usable for lookahead.
|
||
|
func (r *rewinder) Lookahead() *rewinder {
|
||
|
clone := &rewinder{}
|
||
|
*clone = *r
|
||
|
clone.limit = clone.cursor
|
||
|
return clone
|
||
|
}
|
||
|
|
||
|
// Keep this lookahead rewinder.
|
||
|
func (r *rewinder) Keep() {
|
||
|
r.limit = 0
|
||
|
}
|