1// Copyright (c) 2014 Couchbase, Inc. 2// 3// Licensed under the Apache License, Version 2.0 (the "License"); 4// you may not use this file except in compliance with the License. 5// You may obtain a copy of the License at 6// 7// http://www.apache.org/licenses/LICENSE-2.0 8// 9// Unless required by applicable law or agreed to in writing, software 10// distributed under the License is distributed on an "AS IS" BASIS, 11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12// See the License for the specific language governing permissions and 13// limitations under the License. 14 15// as of Go 1.8 this requires the goyacc external tool 16// available from golang.org/x/tools/cmd/goyacc 17 18//go:generate goyacc -o query_string.y.go query_string.y 19//go:generate sed -i.tmp -e 1d query_string.y.go 20//go:generate rm query_string.y.go.tmp 21 22// note: OSX sed and gnu sed handle the -i (in-place) option differently. 23// using -i.tmp works on both, at the expense of having to remove 24// the unsightly .tmp files 25 26package query 27 28import ( 29 "fmt" 30 "strings" 31) 32 33var debugParser bool 34var debugLexer bool 35 36func parseQuerySyntax(query string) (rq Query, err error) { 37 if query == "" { 38 return NewMatchNoneQuery(), nil 39 } 40 lex := newLexerWrapper(newQueryStringLex(strings.NewReader(query))) 41 doParse(lex) 42 43 if len(lex.errs) > 0 { 44 return nil, fmt.Errorf(strings.Join(lex.errs, "\n")) 45 } 46 return lex.query, nil 47} 48 49func doParse(lex *lexerWrapper) { 50 defer func() { 51 r := recover() 52 if r != nil { 53 lex.errs = append(lex.errs, fmt.Sprintf("parse error: %v", r)) 54 } 55 }() 56 57 yyParse(lex) 58} 59 60const ( 61 queryShould = iota 62 queryMust 63 queryMustNot 64) 65 66type lexerWrapper struct { 67 lex yyLexer 68 errs []string 69 query *BooleanQuery 70} 71 72func newLexerWrapper(lex yyLexer) *lexerWrapper { 73 return &lexerWrapper{ 74 lex: lex, 75 query: NewBooleanQueryForQueryString(nil, nil, nil), 76 } 77} 78 79func (l *lexerWrapper) Lex(lval *yySymType) int { 80 return l.lex.Lex(lval) 81} 82 83func (l *lexerWrapper) Error(s string) { 84 l.errs = append(l.errs, s) 85} 86