blob: 105d3515303d5c08811975fb3922b1a13b270461 [file] [log] [blame]
// Copyright 2008 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
grammar Query;
options {
language = Java;
output = AST;
}
tokens {
WHERE;
ORDER;
BY;
AND;
LT;
LE;
GT;
GE;
EQ;
ID;
PLACEHOLDER;
COMMA;
ASC;
DESC;
LIMIT;
CONSTANT_INTEGER;
CONSTANT_STRING;
TRUE;
FALSE;
}
@header {
package com.google.gwtorm.schema;
}
@members {
public static Tree parse(final RelationModel m, final String str)
throws QueryParseException {
try {
final QueryParser p = new QueryParser(
new TokenRewriteStream(
new QueryLexer(
new ANTLRStringStream(str)
)
)
);
p.relationModel = m;
return (Tree)p.query().getTree();
} catch (QueryParseInternalException e) {
throw new QueryParseException(e.getMessage());
} catch (RecognitionException e) {
throw new QueryParseException(e.getMessage());
}
}
public static class Column extends CommonTree {
private static ColumnModel resolve(Tree node, RelationModel model) {
ColumnModel c;
if (node.getType() == ID) {
c = model.getField(node.getText());
} else {
c = resolve(node.getChild(0), model);
}
if (c == null) {
throw new QueryParseInternalException("No field " + node.getText());
}
if (node.getType() == DOT) {
c = resolve(node.getChild(1), c);
}
return c;
}
private static ColumnModel resolve(Tree node, ColumnModel model) {
ColumnModel c;
if (node.getType() == ID) {
c = model.getField(node.getText());
} else {
c = resolve(node.getChild(0), model);
}
if (c == null) {
throw new QueryParseInternalException("No field " + node.getText());
}
if (node.getType() == DOT) {
c = resolve(node.getChild(1), c);
}
return c;
}
private final ColumnModel field;
public Column(int ttype, Tree tree, final RelationModel relationModel) {
field = resolve(tree, relationModel);
token = new CommonToken(ID, field.getPathToFieldName());
}
public Column(final Column o, final ColumnModel f) {
token = o.token;
field = f;
}
public ColumnModel getField() {
return field;
}
public Tree dupNode() {
return new Column(this, field);
}
}
private RelationModel relationModel;
public void displayRecognitionError(String[] tokenNames,
RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
throw new QueryParseInternalException(hdr + " " + msg);
}
}
@lexer::header {
package com.google.gwtorm.schema;
}
@lexer::members {
public void displayRecognitionError(String[] tokenNames,
RecognitionException e) {
String hdr = getErrorHeader(e);
String msg = getErrorMessage(e, tokenNames);
throw new QueryParseInternalException(hdr + " " + msg);
}
}
query
: where? orderBy? limit?
;
where
: WHERE^ conditions
;
orderBy
: ORDER^ BY! fieldSort (COMMA! fieldSort)*
;
fieldSort
: field sortDirection^
| field -> ^(ASC field)
;
sortDirection
: ASC
| DESC
;
limit
: LIMIT^ limitArg
;
limitArg
: PLACEHOLDER
| CONSTANT_INTEGER
;
conditions
: condition AND^ condition (AND! condition)*
| condition
;
condition
: field compare_op^ conditionValue
;
compare_op
: LT
| LE
| GT
| GE
| EQ
;
field
: n=qualifiedFieldName -> ID<Column>[(Tree)n.tree, relationModel]
;
qualifiedFieldName
: ID (DOT^ ID)*
;
conditionValue
: PLACEHOLDER
| CONSTANT_INTEGER
| constantBoolean
| CONSTANT_STRING
;
constantBoolean
: TRUE
| FALSE
;
WHERE: 'WHERE' ;
ORDER: 'ORDER' ;
BY: 'BY' ;
AND: 'AND' ;
ASC: 'ASC' ;
DESC: 'DESC' ;
LIMIT: 'LIMIT' ;
TRUE: 'true' ;
FALSE: 'false' ;
LT : '<' ;
LE : '<=' ;
GT : '>' ;
GE : '>=' ;
EQ : '=' ;
PLACEHOLDER: '?' ;
COMMA: ',' ;
DOT: '.' ;
CONSTANT_INTEGER
: '0'
| '1'..'9' ('0'..'9')*
;
CONSTANT_STRING
: '\'' ( ~('\'') )* '\''
;
ID
: ('a'..'z'|'A'..'Z'|'_') ('a'..'z'|'A'..'Z'|'_'|'0'..'9')*
;
WS
: ( ' ' | '\r' | '\t' | '\n' ) { $channel=HIDDEN; }
;