Skip to content

Commit

Permalink
Fixes couchbaselabs#20: N1QL-like parser using participle
Browse files Browse the repository at this point in the history
This commit uses participle to build a parser that will be used for XDCR's advanced filtering feature.
It is similar to N1QL with a few differences
  • Loading branch information
nelio2k committed Feb 1, 2019
1 parent 9c708ec commit 6f37ea2
Show file tree
Hide file tree
Showing 10 changed files with 1,957 additions and 44 deletions.
73 changes: 72 additions & 1 deletion constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ package gojsonsm

import (
"fmt"
"regexp"
)

// Function related constants
const (
DateFunc string = "date"
DateFuncParser string = "DATE"
MathFuncAbs string = "mathAbs"
MathFuncAcos string = "mathAcos"
MathFuncAsin string = "mathAsin"
Expand All @@ -30,11 +30,61 @@ const (
MathFuncSin string = "mathSin"
MathFuncSqrt string = "mathSqrt"
MathFuncTan string = "mathTan"

FuncAbs string = "ABS"
FuncAcos string = "ACOS"
FuncAsin string = "ASIN"
FuncAtan string = "ATAN"
FuncAtan2 string = "ATAN2"
FuncCeil string = "CEIL"
FuncCos string = "COS"
FuncDate string = "DATE"
FuncDeg string = "DEGREES"
FuncExp string = "EXP"
FuncFloor string = "FLOOR"
FuncLog string = "LOG"
FuncLn string = "LN"
FuncPower string = "POW"
FuncRad string = "RADIANS"
FuncRegexp string = "REGEXP_CONTAINS"
FuncSin string = "SIN"
FuncTan string = "TAN"
FuncRound string = "ROUND"
FuncSqrt string = "SQRT"
)

// Parser related constants
const (
OperatorOr string = "OR"
OperatorAnd string = "AND"
OperatorNot string = "NOT"
OperatorTrue string = "TRUE"
OperatorFalse string = "FALSE"
OperatorMeta string = "META"
OperatorEquals string = "="
OperatorNotEquals string = "<>"
OperatorGreaterThan string = ">"
OperatorGreaterThanEq string = ">="
OperatorLessThan string = "<"
OperatorLessThanEq string = "<="
OperatorExists string = "EXISTS"
OperatorMissing string = "IS MISSING"
OperatorNotMissing string = "IS NOT MISSING"
OperatorNull string = "IS NULL"
OperatorNotNull string = "IS NOT NULL"
)

// Participle parser can cause stack overflow if certain inputs (i.e. a single word regex) is passed in
// This slice allows callers to get a list of valid operators that are used, so they can check whether
// or not a valid expression is valid prior to passing into the FilterExpression Parser
var GojsonsmOperators []string = []string{OperatorOr, OperatorAnd, OperatorNot, OperatorTrue,
OperatorFalse, OperatorMeta, OperatorEquals, OperatorNotEquals, OperatorGreaterThan, OperatorGreaterThanEq,
OperatorExists, OperatorMissing, OperatorNotMissing, OperatorNull, OperatorNotNull,
/* BooleanFuncs*/ FuncRegexp}

// Error constants
var emptyExpression Expression
var ErrorEmptyInput error = fmt.Errorf("Error: Input is empty")
var ErrorNotFound error = fmt.Errorf("Error: Specified resource was not found")
var ErrorNoMoreTokens error = fmt.Errorf("Error: No more token found")
var ErrorNeedToStartOneNewCtx error = fmt.Errorf("Error: Need to spawn one subcontext")
Expand Down Expand Up @@ -104,3 +154,24 @@ const (
type checkAndGetKeyFunc func(string) (bool, string)
type funcNameType string
type funcRecursiveIdx int

// Support for pcre's lookahead class of regex
const lookAheadPattern = "\\(\\?\\=.+\\)"
const lookBehindPattern = "\\(\\?\\<.+\\)"
const negLookAheadPattern = "\\(\\?\\!.+\\)"
const negLookBehindPattern = "\\(\\?\\<\\!.+\\)"

var pcreCheckers [4]*regexp.Regexp = [...]*regexp.Regexp{regexp.MustCompile(lookAheadPattern),
regexp.MustCompile(lookBehindPattern),
regexp.MustCompile(negLookAheadPattern),
regexp.MustCompile(negLookBehindPattern)}

// Returns true if the value is to be used for pcre types
func tokenIsPcreValueType(token string) bool {
for _, pcreChecker := range pcreCheckers {
if pcreChecker.MatchString(token) {
return true
}
}
return false
}
2 changes: 2 additions & 0 deletions fastMatcherDef.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ func (value OpType) String() string {
return "in"
case OpTypeExists:
return "exists"
case OpTypeMatches:
return "matches"
}

return "??unknown??"
Expand Down
8 changes: 7 additions & 1 deletion fastval.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ func (val FastVal) String() string {
return "??OBJECT??"
case TimeValue:
return val.GetTime().String()
case RegexValue:
return "(regexp)" + val.data.(*regexp.Regexp).String()
}

panic("unexpected data type")
panic(fmt.Sprintf("unexpected data type: %v", val.dataType))
}

func (val FastVal) Type() ValueType {
Expand Down Expand Up @@ -435,6 +437,8 @@ func (val FastVal) Matches(other FastVal) bool {

func NewFastVal(val interface{}) FastVal {
switch val := val.(type) {
case int:
return NewIntFastVal(int64(val))
case int8:
return NewIntFastVal(int64(val))
case int16:
Expand All @@ -443,6 +447,8 @@ func NewFastVal(val interface{}) FastVal {
return NewIntFastVal(int64(val))
case int64:
return NewIntFastVal(int64(val))
case uint:
return NewUintFastVal(uint64(val))
case uint8:
return NewUintFastVal(uint64(val))
case uint16:
Expand Down
Loading

0 comments on commit 6f37ea2

Please sign in to comment.