Repository: cayenne Updated Branches: refs/heads/master a6c5efbcd -> d249aa37d
http://git-wip-us.apache.org/repos/asf/cayenne/blob/55e3c975/cayenne-server/src/main/jjtree/org/apache/cayenne/template/parser/SQLTemplateParser.jjt ---------------------------------------------------------------------- diff --git a/cayenne-server/src/main/jjtree/org/apache/cayenne/template/parser/SQLTemplateParser.jjt b/cayenne-server/src/main/jjtree/org/apache/cayenne/template/parser/SQLTemplateParser.jjt new file mode 100644 index 0000000..8e8cae5 --- /dev/null +++ b/cayenne-server/src/main/jjtree/org/apache/cayenne/template/parser/SQLTemplateParser.jjt @@ -0,0 +1,327 @@ +options { + + MULTI = true; + NODE_DEFAULT_VOID = true; + + STATIC = false; + DEBUG_PARSER = false; + DEBUG_LOOKAHEAD = false; + DEBUG_TOKEN_MANAGER = false; + JAVA_UNICODE_ESCAPE = true; + UNICODE_INPUT = true; +} + +PARSER_BEGIN(SQLTemplateParser) +/***************************************************************** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + ****************************************************************/ + +package org.apache.cayenne.template.parser; + +/** + * Parser of Cayenne Templates. + * + * @since 4.1 + */ +public class SQLTemplateParser { +} + +PARSER_END(SQLTemplateParser) + + +ASTBlock template() : {} +{ + block() <EOF> + { + return (ASTBlock) jjtree.rootNode(); + } +} + +void block() #Block : {} +{ + ( text() + | ifElse() + | directive() + ) * +} + +void text() #Text : { + Token t; +} +{ + t = <TEXT> { + jjtThis.setValue(t.image); + } +} + +void ifElse() #IfElse : {} +{ + <IF> <LBRACKET> expression() <RBRACKET> + block() + ( <ELSE> block() )? + <END> +} + +void directive() #Directive : { + Token t; +} +{ + <SHARP> ( t = <IDENTIFIER> ) { + jjtThis.setIdentifier(t.image); + } + <LBRACKET> (expression() (<COMMA> expression())* )? <RBRACKET> +} + +void expression() #Expression : {} +{ + scalar() + | variable() +} + +void scalar() : {} +{ + <SINGLE_QUOTED_STRING> { jjtThis.setValue((String)token_source.literalValue); } #StringScalar(0) + | <DOUBLE_QUOTED_STRING> { jjtThis.setValue((String)token_source.literalValue); } #StringScalar(0) + | <INT_LITERAL> { jjtThis.setValue((Long)token_source.literalValue); } #IntScalar(0) + | <FLOAT_LITERAL> { jjtThis.setValue((Double)token_source.literalValue); } #FloatScalar(0) + | <TRUE> { jjtThis.setValue(true); } #BoolScalar(0) + | <FALSE> { jjtThis.setValue(false); } #BoolScalar(0) +} + +void variable() #Variable : { + Token t; +} +{ + <DOLLAR> ( t = <IDENTIFIER> ) { + jjtThis.setIdentifier(t.image); + } + ( <DOT> method() )* +} + +void method() #Method : { + Token t; +} +{ + ( t = <IDENTIFIER> ) { + jjtThis.setIdentifier(t.image); + } + <LBRACKET> (expression() (<COMMA> expression())* )? <RBRACKET> +} + +/**************************************** + * Copy of ExpressionParser definitions * + ****************************************/ + +TOKEN_MGR_DECLS: +{ + /** Holds the last value computed by a constant token. */ + Object literalValue; + + /** Holds the last string literal parsed. */ + private StringBuffer stringBuffer; + + /** Converts an escape sequence into a character value. */ + private char escapeChar() { + int ofs = image.length() - 1; + switch ( image.charAt(ofs) ) { + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'b': return '\b'; + case 'f': return '\f'; + case '\\': return '\\'; + case '\'': return '\''; + case '\"': return '\"'; + } + + // Otherwise, it's an octal number. Find the backslash and convert. + while ( image.charAt(--ofs) != '\\' ){ + } + + int value = 0; + while ( ++ofs < image.length() ) { + value = (value << 3) | (image.charAt(ofs) - '0'); + } + return (char) value; + } + + private Object makeInt() { + Object result; + String s = image.toString(); + int base = 10; + + if ( s.charAt(0) == '0' ) { + base = (s.length() > 1 && (s.charAt(1) == 'x' || s.charAt(1) == 'X'))? 16 : 8; + } + if ( base == 16 ) { + s = s.substring(2); // Trim the 0x off the front + } + + switch ( s.charAt(s.length()-1) ) { + case 'l': case 'L': + result = Long.valueOf( s.substring(0,s.length()-1), base ); + break; + + default: + result = Long.valueOf( s, base ); + break; + } + return result; + } + + private Object makeFloat() { + String s = image.toString(); + switch ( s.charAt(s.length()-1) ) { + case 'f': case 'F': + return Double.valueOf( s ); + + case 'd': case 'D': + default: + return Double.valueOf( s ); + } + } +} + +TOKEN: +{ + <IF: "#if"> +| <ELSE: "#else"> +| <END: "#end"> +} + +TOKEN: +{ + <TRUE: "true" | "TRUE"> +| <FALSE: "false" | "FALSE"> +} + +TOKEN: +{ + <WHITESPACE : ([" ","\t"])+ > +| <NEWLINE : ("\n" | "\r" | "\r\n") > +} + +TOKEN : +{ + <SHARP: "#"> +| <DOLLAR: "$"> +| <LBRACKET: "("> +| <RBRACKET: ")"> +| <COMMA: "," | " "> +| <DOT: "."> +} + +TOKEN : +{ + <IDENTIFIER: <LETTER> (<LETTER>|<DIGIT>)* > +| <#LETTER: ["_","a"-"z","A"-"Z"] > +| <#DIGIT: ["0"-"9"] > +} + +TOKEN : +{ + < "##" > : IN_SINGLE_LINE_COMMENT +} + +<IN_SINGLE_LINE_COMMENT> +TOKEN : +{ + <SINGLE_LINE_COMMENT_END: "\n" | "\r" | "\r\n" > : DEFAULT +} + +<IN_SINGLE_LINE_COMMENT> +SKIP : +{ + < ~[] > +} + +/** + * Quoted Strings, whose object value is stored in the token manager's + * "literalValue" field. Both single and double qoutes are allowed + */ +MORE: +{ + "'" { stringBuffer = new StringBuffer(); }: WithinSingleQuoteLiteral + | + "\"" { stringBuffer = new StringBuffer(); }: WithinDoubleQuoteLiteral +} + +<WithinSingleQuoteLiteral> MORE: +{ + < ESC: "\\" ( ["n","r","t","b","f","\\","'","`","\""] + | (["0"-"3"])? ["0"-"7"] (["0"-"7"])? + ) + > + { stringBuffer.append( escapeChar() ); } + | + < (~["'","\\"]) > + { stringBuffer.append( image.charAt(image.length()-1) ); } +} + +<WithinSingleQuoteLiteral> TOKEN : +{ + <SINGLE_QUOTED_STRING: "'"> + { literalValue = stringBuffer.toString(); } + : DEFAULT +} + +<WithinDoubleQuoteLiteral> MORE : +{ + < STRING_ESC: <ESC> > + { stringBuffer.append( escapeChar() ); } + | + < (~["\"","\\"]) > + { stringBuffer.append( image.charAt(image.length()-1) ); } +} + +<WithinDoubleQuoteLiteral> TOKEN: +{ + <DOUBLE_QUOTED_STRING: "\""> + { literalValue = stringBuffer.toString(); } + : DEFAULT +} + +TOKEN: +{ + <INT_LITERAL: + ( "0" (["0"-"7"])* | ["1"-"9"] (["0"-"9"])* | "0" ["x","X"] (["0"-"9","a"-"f","A"-"F"])+ ) + (["l","L","h","H"])? + > + { literalValue = makeInt(); } +| <FLOAT_LITERAL: + ( <DEC_FLT> (<EXPONENT>)? (<FLT_SUFF>)? + | <DEC_DIGITS> <EXPONENT> (<FLT_SUFF>)? + | <DEC_DIGITS> <FLT_SUFF> + ) + > + { literalValue = makeFloat(); } + +| <#DEC_FLT: (["0"-"9"])+ "." (["0"-"9"])* | "." (["0"-"9"])+ > +| <#DEC_DIGITS: (["0"-"9"])+ > +| <#EXPONENT: ["e","E"] (["+","-"])? (["0"-"9"])+ > +| <#FLT_SUFF: ["d","D","f","F","b","B"] > +} + +// This must be last to not interfere with string literals +TOKEN : +{ + <DOUBLE_ESCAPE : "\\\\"> +| <ESCAPE: "\\" > +| <TEXT: (~["$", "#", "\\"])* (~["$", "#", "\\", " ", "\t"])+ (~["$", "#", "\\"])* > +} +