/*******************************************************************************
* Copyright (c) 2008 Wind River Systems, Inc. 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:
* Markus Schorn - initial API and implementation
*******************************************************************************/
package org.eclipse.cdt.internal.core.parser.scanner;
import java.util.Map;
import org.eclipse.cdt.core.dom.ast.IASTFileLocation;
import org.eclipse.cdt.core.dom.ast.IASTName;
import org.eclipse.cdt.core.dom.ast.IBinding;
import org.eclipse.cdt.core.dom.ast.IMacroBinding;
import org.eclipse.cdt.core.dom.rewrite.MacroExpansionExplorer;
import org.eclipse.cdt.core.parser.util.CharArrayMap;
import org.eclipse.cdt.internal.core.parser.scanner.Lexer.LexerOptions;
import org.eclipse.text.edits.ReplaceEdit;
/**
* Performs step by step macro expansion for an exact macro expansion location.
* @since 5.0
*/
public class SingleMacroExpansionExplorer extends MacroExpansionExplorer {
private final String fInput;
private final CharArrayMap<PreprocessorMacro> fDictionary;
private MacroExpansionStep fFullExpansion;
private int fExpansionCount;
private final String fFilePath;
private final int fLineNumber;
private final Map<IMacroBinding, IASTFileLocation> fMacroLocationMap;
private final boolean fIsPPCondition;
private final LexerOptions fLexerOptions;
public SingleMacroExpansionExplorer(String input, IASTName[] refs,
Map<IMacroBinding, IASTFileLocation> macroDefinitionLocationMap,
String filePath, int lineNumber, boolean isPPCondition, LexerOptions options) {
fInput= input;
fDictionary= createDictionary(refs);
fMacroLocationMap= macroDefinitionLocationMap;
fFilePath= filePath;
fLineNumber= lineNumber;
fIsPPCondition= isPPCondition;
fLexerOptions= (LexerOptions) options.clone();
fLexerOptions.fCreateImageLocations= false;
}
private CharArrayMap<PreprocessorMacro> createDictionary(IASTName[] refs) {
CharArrayMap<PreprocessorMacro> map= new CharArrayMap<PreprocessorMacro>(refs.length);
for (IASTName name : refs) {
addMacroDefinition(map, name);
}
return map;
}
private void addMacroDefinition(CharArrayMap<PreprocessorMacro> map, IASTName name) {
IBinding binding= name.getBinding();
if (binding instanceof PreprocessorMacro) {
map.put(name.getSimpleID(), (PreprocessorMacro) binding);
}
}
@Override
public IMacroExpansionStep getFullExpansion() {
computeExpansion();
return fFullExpansion;
}
@Override
public int getExpansionStepCount() {
computeExpansion();
return fExpansionCount;
}
private void computeExpansion() {
MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, fLexerOptions);
MacroExpansionTracker tracker= new MacroExpansionTracker(Integer.MAX_VALUE);
expander.expand(fInput, tracker, fFilePath, fLineNumber, fIsPPCondition);
fExpansionCount= tracker.getStepCount();
ReplaceEdit r= tracker.getReplacement();
ReplaceEdit[] replacements= r==null ? new ReplaceEdit[0] : new ReplaceEdit[]{r};
fFullExpansion= new MacroExpansionStep(fInput, null, null, replacements);
}
@Override
public MacroExpansionStep getExpansionStep(int step) throws IndexOutOfBoundsException {
computeExpansion();
if (step < 0 || step >= fExpansionCount) {
throw new IndexOutOfBoundsException();
}
MacroExpander expander= new MacroExpander(ILexerLog.NULL, fDictionary, null, fLexerOptions);
MacroExpansionTracker tracker= new MacroExpansionTracker(step);
expander.expand(fInput, tracker, fFilePath, fLineNumber, fIsPPCondition);
fExpansionCount= tracker.getStepCount();
ReplaceEdit r= tracker.getReplacement();
ReplaceEdit[] replacements= r==null ? new ReplaceEdit[0] : new ReplaceEdit[]{r};
final IMacroBinding macro = tracker.getExpandedMacro();
return new MacroExpansionStep(tracker.getCodeBeforeStep(), macro, fMacroLocationMap.get(macro), replacements);
}
}