/******************************************************************************* * Copyright (c) 2008 Borland Software Corporation and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Borland Software Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.m2m.internal.qvt.oml.editor.ui.completion.collectors; import java.util.Collection; import lpg.runtime.IPrsStream; import lpg.runtime.IToken; import org.eclipse.emf.ecore.EClassifier; import org.eclipse.emf.ecore.EParameter; import org.eclipse.jface.text.contentassist.ICompletionProposal; import org.eclipse.m2m.internal.qvt.oml.cst.parser.QVTOParsersym; import org.eclipse.m2m.internal.qvt.oml.editor.ui.completion.CompletionProposalUtil; import org.eclipse.m2m.internal.qvt.oml.editor.ui.completion.LightweightParserUtil; import org.eclipse.m2m.internal.qvt.oml.editor.ui.completion.QvtCompletionData; import org.eclipse.ocl.ecore.TypeExp; import org.eclipse.ocl.expressions.OCLExpression; import org.eclipse.ocl.expressions.Variable; /** * @author aigdalov */ public class StructuralFeatureCollector extends AbstractCollector { private static final String SCTRUCTURALFEATURE_CONTAINER_FLAG = StructuralFeatureCollector.class + "SCTRUCTURALFEATURE_CONTAINER_FLAG"; //$NON-NLS-1$ private static final int[] SCTRUCTURALFEATURE_CONTAINER_TERMINALS = { QVTOParsersym.TK_object, QVTOParsersym.TK_mapping }; private static final int[] SCTRUCTURALFEATURE_CONTAINER_TERMINALS_WITH_MAPPING_CLAUSES = LightweightParserUtil.uniteIntArrays(SCTRUCTURALFEATURE_CONTAINER_TERMINALS, LightweightParserUtil.MAPPING_CLAUSE_TOKENS); @Override protected boolean isApplicableInternal(QvtCompletionData data) { IToken leftToken = data.getLeftToken(); if ((leftToken.getKind() == QVTOParsersym.TK_SEMICOLON) || (leftToken.getKind() == QVTOParsersym.TK_LBRACE) || (leftToken.getKind() == QVTOParsersym.TK_RBRACE) ) { IToken structuralFeatureContainerToken = data.getParentBracingExpression(new QvtCompletionData.ITokenQualificator() { public boolean isSuited(IToken token) { return QvtCompletionData.isKindOf(token, SCTRUCTURALFEATURE_CONTAINER_TERMINALS_WITH_MAPPING_CLAUSES); } }, QVTOParsersym.TK_LBRACE, QVTOParsersym.TK_RBRACE, 1, null, null, LightweightParserUtil.MAPPING_CLAUSE_TOKENS); if ((structuralFeatureContainerToken != null) && QvtCompletionData.isKindOf(structuralFeatureContainerToken, SCTRUCTURALFEATURE_CONTAINER_TERMINALS)) { data.getUserData().put(SCTRUCTURALFEATURE_CONTAINER_FLAG, structuralFeatureContainerToken); return true; } } return false; } public void addPropoposals(Collection<ICompletionProposal> proposals, QvtCompletionData data) { IToken structuralFeatureContainerToken = (IToken) data.getUserData().get(SCTRUCTURALFEATURE_CONTAINER_FLAG); IToken[] typeTokens = null; EClassifier objectExpType = null; if (structuralFeatureContainerToken.getKind() == QVTOParsersym.TK_mapping) { typeTokens = extractMappingType(structuralFeatureContainerToken); } else { IToken firstTypeToken = LightweightParserUtil.getNextToken(structuralFeatureContainerToken); if (firstTypeToken != null) { if (QvtCompletionData.isKindOf(firstTypeToken, QVTOParsersym.TK_LBRACE)) { // type not specified // use type in mapping declaration IToken mappingToken = data.getParentBracingExpression(new QvtCompletionData.ITokenQualificator() { public boolean isSuited(IToken token) { return QvtCompletionData.isKindOf(token, new int[] {QVTOParsersym.TK_mapping}); } }, QVTOParsersym.TK_LBRACE, QVTOParsersym.TK_RBRACE, 2, null, null, LightweightParserUtil.MAPPING_CLAUSE_TOKENS); if (mappingToken != null) { typeTokens = extractMappingType(mappingToken); } } else { IToken[] tokens = QvtCompletionData.extractTokens(firstTypeToken, QVTOParsersym.TK_LBRACE); if ((tokens != null) && (tokens.length >= 2) && QvtCompletionData.isKindOf(tokens[1], QVTOParsersym.TK_COLON)) { if (tokens.length == 2) { // varName ':' Variable<EClassifier, EParameter> variable = data.getEnvironment().lookup(tokens[0].toString()); objectExpType = variable.getType(); } else { // varName ':' TypeCS typeTokens = new IToken[tokens.length - 2]; System.arraycopy(tokens, 2, typeTokens, 0, typeTokens.length); } } else { typeTokens = tokens; } } } } if (typeTokens != null) { OCLExpression<EClassifier> oclExpression = LightweightParserUtil.getOclExpression(typeTokens, data, LightweightParserUtil.ParserTypeEnum.LIGHTWEIGHT_TYPE_PARSER); if (oclExpression instanceof TypeExp) { TypeExp typeExp = (TypeExp) oclExpression; objectExpType = typeExp.getReferredType(); } } if (objectExpType != null) { CompletionProposalUtil.addStructuralFeatures(proposals, objectExpType, data); } if (QvtCompletionData.isKindOf(structuralFeatureContainerToken,QVTOParsersym.TK_mapping)) { CompletionProposalUtil.addKeywords(proposals, new int[] { QVTOParsersym.TK_init, QVTOParsersym.TK_object, QVTOParsersym.TK_end }, data); } } private static IToken[] extractMappingType(IToken mappingToken) { IToken lParen = LightweightParserUtil.getNextTokenByKind(mappingToken, QVTOParsersym.TK_LPAREN); if (lParen != null) { IToken rParen = LightweightParserUtil.getPairingBrace(lParen, true); if (rParen != null) { IToken colon = LightweightParserUtil.getNextToken(rParen); if ((colon != null) && (colon.getKind() == QVTOParsersym.TK_COLON)) { IToken firstTypeToken = LightweightParserUtil.getNextToken(colon); if (firstTypeToken != null) { return QvtCompletionData.extractTokens(firstTypeToken, QvtCompletionData.MAPPING_DECLARATION_TRAILING_TOKEN_KINDS); } } else { IToken token = lParen; IToken lastColoncolon = null; for (;;) { IToken prevToken = LightweightParserUtil.getPreviousToken(token); if ((prevToken == null) || QvtCompletionData.isKindOf(prevToken, QVTOParsersym.TK_mapping)) { break; } if (QvtCompletionData.isKindOf(prevToken, QVTOParsersym.TK_COLONCOLON)) { lastColoncolon = prevToken; } if ((QvtCompletionData.isKindOf(prevToken, QVTOParsersym.TK_inout)) && (lastColoncolon != null)) { IPrsStream prsStream = token.getIPrsStream(); IToken[] tokenArray = new IToken[lastColoncolon.getTokenIndex() - token.getTokenIndex()]; for (int i = token.getTokenIndex(); i < lastColoncolon.getTokenIndex(); i++) { tokenArray[i - token.getTokenIndex()] = prsStream.getTokenAt(i); } return tokenArray; } token = prevToken; } } } } return null; } }