minio/vendor/github.com/alecthomas/participle/context.go
Aditya Manthramurthy 2786055df4 Add new SQL parser to support S3 Select syntax (#7102)
- New parser written from scratch, allows easier and complete parsing
  of the full S3 Select SQL syntax. Parser definition is directly
  provided by the AST defined for the SQL grammar.

- Bring support to parse and interpret SQL involving JSON path
  expressions; evaluation of JSON path expressions will be
  subsequently added.

- Bring automatic type inference and conversion for untyped
  values (e.g. CSV data).
2019-01-28 17:59:48 -08:00

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
}