| // Copyright 2008, 2010 The Apache Software Foundation |
| // |
| // 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. |
| |
| lexer grammar PropertyExpressionLexer; |
| |
| |
| options |
| { |
| superClass='org.apache.tapestry5.internal.antlr.BaseLexer'; |
| } |
| |
| @header |
| { |
| package org.apache.tapestry5.internal.antlr; |
| } |
| |
| |
| // Integer constant |
| fragment INTEGER |
| : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */}; |
| |
| // Read a property or invoke a method. |
| fragment DEREF |
| : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */}; |
| |
| // Range operator, ".." between two integers. |
| fragment RANGEOP |
| : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */}; |
| |
| // Decimal number |
| fragment DECIMAL |
| : {this.getClass(); /* Fix java.lang.VerifyError: Stack size too large */}; |
| |
| fragment LETTER |
| : ('a'..'z'|'A'..'Z'); |
| fragment DIGIT |
| : '0'..'9'; |
| fragment SIGN |
| : ('+'|'-'); |
| LPAREN : '('; |
| RPAREN : ')'; |
| LBRACKET: '['; |
| RBRACKET: ']'; |
| COMMA : ','; |
| BANG : '!'; |
| |
| fragment QUOTE |
| : '\''; |
| |
| // Clumsy but effective approach to case-insensitive identifiers. |
| |
| fragment A |
| : ('a' | 'A'); |
| fragment E |
| : ('e' | 'E'); |
| fragment F |
| : ('f' | 'F'); |
| fragment H |
| : ('h' | 'H'); |
| fragment I |
| : ('i' | 'I'); |
| fragment L |
| : ('l' | 'L'); |
| fragment N |
| : ('n'|'N'); |
| fragment R |
| : ('r' | 'R'); |
| fragment S |
| : ('s' | 'S'); |
| fragment T |
| : ('t' | 'T'); |
| fragment U |
| : ('u' | 'U'); |
| |
| // Identifiers are case insensitive |
| |
| NULL : N U L L; |
| TRUE : T R U E; |
| FALSE : F A L S E; |
| THIS : T H I S; |
| |
| IDENTIFIER |
| : JAVA_ID_START (JAVA_ID_PART)* |
| ; |
| |
| fragment |
| JAVA_ID_START |
| : '\u0024' |
| | '\u0041'..'\u005a' |
| | '\u005f' |
| | '\u0061'..'\u007a' |
| | '\u00c0'..'\u00d6' |
| | '\u00d8'..'\u00f6' |
| | '\u00f8'..'\u00ff' |
| | '\u0100'..'\u1fff' |
| | '\u3040'..'\u318f' |
| | '\u3300'..'\u337f' |
| | '\u3400'..'\u3d2d' |
| | '\u4e00'..'\u9fff' |
| | '\uf900'..'\ufaff' |
| ; |
| |
| fragment |
| JAVA_ID_PART |
| : JAVA_ID_START |
| | '\u0030'..'\u0039' |
| ; |
| |
| |
| // The Safe Dereference operator understands not to de-reference through |
| // a null. |
| |
| SAFEDEREF |
| : '?.'; |
| |
| WS : (' '|'\t'|'\n'|'\r')+ { skip(); }; |
| |
| |
| // Literal strings are always inside single quotes. |
| STRING |
| : QUOTE (options {greedy=false;} : .)* QUOTE { setText(getText().substring(1, getText().length()-1)); }; |
| |
| |
| // Special rule that uses parsing tricks to identify numbers and ranges; it's all about |
| // the dot ('.'). |
| // Recognizes: |
| // '.' as DEREF |
| // '..' as RANGEOP |
| // INTEGER (sign? digit+) |
| // DECIMAL (sign? digits* . digits+) |
| // Has to watch out for embedded rangeop (i.e. "1..10" is not "1." and ".10"). |
| |
| NUMBER_OR_RANGEOP |
| : SIGN? DIGIT+ |
| ( |
| { input.LA(2) != '.' }? => '.' DIGIT* { $type = DECIMAL; stripLeadingPlus(); } |
| | { $type = INTEGER; stripLeadingPlus(); } |
| ) |
| |
| | SIGN '.' DIGIT+ { $type = DECIMAL; stripLeadingPlus(); } |
| |
| | '.' |
| ( |
| DIGIT+ { $type = DECIMAL; stripLeadingPlus();} |
| | '.' {$type = RANGEOP; } |
| | {$type = DEREF; } |
| ) |
| ; |
| |