forked from itod/parsekit
/
nspredicate.grammar
121 lines (83 loc) · 3.38 KB
/
nspredicate.grammar
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/*
A Grammar for Apple's NSPredicate String Format Syntax
See: http://developer.apple.com/documentation/Cocoa/Conceptual/Predicates/Articles/pSyntax.html
*/
@wordState = '#';
@wordChars = '.' '[' ']';
@symbols = '==' '>=' '=>' '<=' '=<' '!=' '<>' '&&' '||';
@start = expr;
// Expressions
expr = orTerm orOrTerm*;
orOrTerm = or orTerm;
orTerm = andTerm andAndTerm*;
andAndTerm = and andTerm;
andTerm = primaryExpr | compoundExpr;
compoundExpr = '('! expr ')'!;
primaryExpr = predicate | negatedPredicate;
negatedPredicate = not predicate;
predicate = boolPredicate | comparisonPredicate | stringTestPredicate | collectionTestPredicate;
// values
value = keyPath | string | num | bool | array;
string = QuotedString;
num = Number;
bool = true | false;
true = 'true'!;
false = 'false'!;
// arrays
array = '{' arrayContentsOpt '}'!;
arrayContentsOpt = Empty | arrayContents;
arrayContents = value commaValue*;
commaValue = ','! value;
// keyPaths
keyPath = Word;
// keyPath = key dotKey*;
// key = name memberAccess?;
// name = Word;
// dotKey = '.' key;
// memberAccess = '[' (num | 'FIRST' | 'LAST' | 'SIZE') ']';
// Comparison Tests
comparisonPredicate = numComparisonPredicate | collectionComparisonPredicate;
numComparisonPredicate = numComparisonValue comparisonOp numComparisonValue;
numComparisonValue = keyPath | num;
comparisonOp = eq | gt | lt | gtEq | ltEq | notEq | between;
eq = '=' | '==';
gt = '>';
lt = '<';
gtEq = '>=' | '=>';
ltEq = '<=' | '=<';
notEq = '!=' | '<>';
between = 'BETWEEN';
// breaking these out to make the assembler callbacks simpler
collectionComparisonPredicate = collectionLtPredicate | collectionGtPredicate | collectionLtEqPredicate | collectionGtEqPredicate | collectionEqPredicate | collectionNotEqPredicate;
collectionLtPredicate = aggregateOp collection lt value;
collectionGtPredicate = aggregateOp collection gt value;
collectionLtEqPredicate = aggregateOp collection ltEq value;
collectionGtEqPredicate = aggregateOp collection gtEq value;
collectionEqPredicate = aggregateOp collection eq value;
collectionNotEqPredicate = aggregateOp collection notEq value;
// Boolean Value Predicates
boolPredicate = truePredicate | falsePredicate;
truePredicate = 'TRUEPREDICATE'!;
falsePredicate = 'FALSEPREDICATE'!;
// Compound Expressions
and = 'AND'! | '&&'!;
or = 'OR'! | '||'!;
not = 'NOT'! | '!'!;
// String Tests
stringTestPredicate = string stringTestOp value;
stringTestOp = beginswith | contains | endswith | like | matches;
beginswith = 'BEGINSWITH';
contains = 'CONTAINS';
endswith = 'ENDSWITH';
like = 'LIKE';
matches = 'MATCHES';
// Collection Tests
collectionTestPredicate = value in collection;
collection = keyPath | array;
in = 'IN'!;
// Aggregate Operators
aggregateOp = any | some | all | none;
any = 'ANY';
some = 'SOME';
all = 'ALL';
none = 'NONE';