001/*-------------------------------------------------------------------------+ 002| | 003| Copyright 2005-2011 the ConQAT Project | 004| | 005| Licensed under the Apache License, Version 2.0 (the "License"); | 006| you may not use this file except in compliance with the License. | 007| You may obtain a copy of the License at | 008| | 009| http://www.apache.org/licenses/LICENSE-2.0 | 010| | 011| Unless required by applicable law or agreed to in writing, software | 012| distributed under the License is distributed on an "AS IS" BASIS, | 013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 014| See the License for the specific language governing permissions and | 015| limitations under the License. | 016+-------------------------------------------------------------------------*/ 017package eu.cqse.check.framework.shallowparser.languages.cpp; 018 019import static eu.cqse.check.framework.scanner.ETokenType.LBRACK; 020import static eu.cqse.check.framework.scanner.ETokenType.RBRACK; 021import static eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates.IN_EXPRESSION; 022 023import java.util.EnumSet; 024import java.util.List; 025 026import eu.cqse.check.framework.scanner.ETokenType; 027import eu.cqse.check.framework.scanner.IToken; 028import eu.cqse.check.framework.shallowparser.TokenStreamUtils; 029import eu.cqse.check.framework.shallowparser.framework.ParserState; 030import eu.cqse.check.framework.shallowparser.framework.RecognizerBase; 031import eu.cqse.check.framework.shallowparser.languages.base.CStyleShallowParserBase; 032import eu.cqse.check.framework.shallowparser.languages.base.EGenericParserStates; 033 034/** 035 * Recognizer that finds C++ lambdas and continues parsing within these. 036 */ 037public class CppLambdaRecognizer extends RecognizerBase<EGenericParserStates> { 038 039 private EnumSet<ETokenType> typeOrIdentifier; 040 041 /** 042 * Constructor. Needs to know which token types represent built-in types or 043 * identifiers to avoid treating int[0] {} as a lambda expression. 044 */ 045 public CppLambdaRecognizer(EnumSet<ETokenType> typeOrIdentifier) { 046 this.typeOrIdentifier = typeOrIdentifier; 047 } 048 049 /** {@inheritDoc} */ 050 @Override 051 protected int matchesLocally(ParserState<EGenericParserStates> parserState, List<IToken> tokens, int startOffset) { 052 if (isPrecededByType(tokens, startOffset)) { 053 return NO_MATCH; 054 } 055 int currentOffset = skipCaptureList(tokens, startOffset); 056 if (currentOffset == NO_MATCH) { 057 return NO_MATCH; 058 } 059 060 currentOffset = CStyleShallowParserBase.skipOptionalParameters(tokens, currentOffset); 061 if (currentOffset == NO_MATCH) { 062 return NO_MATCH; 063 } 064 065 // At this point we cannot be sure if this is really a lambda, but the 066 // rule in the parser does the final check whether this is a lambda or 067 // not. 068 return parserState.parse(IN_EXPRESSION, tokens, startOffset); 069 } 070 071 /** 072 * Whether the token at the current offset is preceded by a type (built-in or 073 * user-defined) 074 */ 075 private boolean isPrecededByType(List<IToken> tokens, int currentOffset) { 076 IToken preceedingToken = tokens.get(currentOffset - 1); 077 return typeOrIdentifier.contains(preceedingToken.getType()); 078 } 079 080 /** 081 * Skips over the capture list and returns the new offset or 082 * {@link RecognizerBase#NO_MATCH} if none is found. 083 */ 084 private static int skipCaptureList(List<IToken> tokens, int currentOffset) { 085 if (!TokenStreamUtils.hasTokenTypeSequence(tokens, currentOffset, LBRACK)) { 086 return NO_MATCH; 087 } 088 089 // if a second bracket follows, this is not a lambda but rather an annotation 090 if (currentOffset + 1 >= tokens.size() || tokens.get(currentOffset + 1).getType() == LBRACK) { 091 return NO_MATCH; 092 } 093 094 int closingBracket = TokenStreamUtils.findMatchingClosingToken(tokens, currentOffset + 1, LBRACK, RBRACK); 095 if (closingBracket == TokenStreamUtils.NOT_FOUND) { 096 return NO_MATCH; 097 } 098 return closingBracket + 1; 099 } 100 101}