/** * Method for tracking macro expansions. * * @since 5.0 */ public void expand( String beforeExpansion, MacroExpansionTracker tracker, String filePath, int lineNumber, boolean protectDefinedConstructs) { fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); fFixedInput = beforeExpansion.toCharArray(); fFixedCurrentFilename = filePath; fFixedLineNumber = lineNumber; Lexer lexer = new Lexer(fFixedInput, fLexOptions, fLog, this); try { tracker.start(lexer); Token identifier = lexer.nextToken(); if (identifier.getType() != IToken.tIDENTIFIER) { tracker.fail(); return; } PreprocessorMacro macro = fDictionary.get(identifier.getCharImage()); if (macro == null) { tracker.fail(); return; } lexer.nextToken(); fStartOffset = identifier.getOffset(); fEndOffset = identifier.getEndOffset(); fCompletionMode = false; IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden = new IdentityHashMap<PreprocessorMacro, PreprocessorMacro>(); // setup input sequence TokenSource input = new TokenSource(lexer); TokenList firstExpansion = new TokenList(); firstExpansion.append(new ExpansionBoundary(macro, true)); expandOne(identifier, macro, forbidden, input, firstExpansion, tracker); firstExpansion.append(new ExpansionBoundary(macro, false)); input.prepend(firstExpansion); TokenList result = expandAll(input, forbidden, protectDefinedConstructs, tracker); tracker.finish(result, fEndOffset); } catch (OffsetLimitReachedException e) { } }
/** Expects that the identifier has been consumed, stores the result in the list provided. */ public TokenList expand( ITokenSequence lexer, final boolean isPPCondition, PreprocessorMacro macro, Token identifier, boolean completionMode) throws OffsetLimitReachedException { fImplicitMacroExpansions.clear(); fImageLocationInfos.clear(); fStartOffset = identifier.getOffset(); fEndOffset = identifier.getEndOffset(); fCompletionMode = completionMode; IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden = new IdentityHashMap<PreprocessorMacro, PreprocessorMacro>(); // setup input sequence TokenSource input = new TokenSource(lexer); TokenList firstExpansion = new TokenList(); TokenList result; try { firstExpansion.append(new ExpansionBoundary(macro, true)); expandOne(identifier, macro, forbidden, input, firstExpansion, null); firstExpansion.append(new ExpansionBoundary(macro, false)); input.prepend(firstExpansion); result = expandAll(input, forbidden, isPPCondition, null); } catch (CompletionInMacroExpansionException e) { // for content assist in macro expansions, we return the list of // tokens of the // parameter at the current cursor position and hope that they make // sense if // they are inserted at the position of the expansion. // For a better solution one would have to perform the expansion // with artificial // parameters and then check where the completion token ends up in // the expansion. result = e.getParameterTokens().cloneTokens(); } postProcessTokens(result); return result; }
private TokenList expandAll( TokenSource input, IdentityHashMap<PreprocessorMacro, PreprocessorMacro> forbidden, boolean protectDefinedConstructs, MacroExpansionTracker tracker) throws OffsetLimitReachedException { final TokenList result = new TokenList(); boolean protect = false; Token l = null; Token t = input.removeFirst(); while (t != null) { switch (t.getType()) { case ObjCPreprocessor.tSCOPE_MARKER: ((ExpansionBoundary) t).execute(forbidden); break; case IToken.tIDENTIFIER: final char[] image = t.getCharImage(); PreprocessorMacro macro = fDictionary.get(image); if (protect || (tracker != null && tracker.isDone())) { result.append(t); } else if (protectDefinedConstructs && Arrays.equals(image, Keywords.cDEFINED)) { t.setType(ObjCPreprocessor.tDEFINED); result.append(t); protect = true; } // tricky: don't mark function-style macros if you don't // find the left parenthesis else if (macro == null || (macro.isFunctionStyle() && !input.findLParenthesis())) { result.append(t); } else if (forbidden.containsKey(macro)) { t.setType(ObjCPreprocessor.tEXPANDED_IDENTIFIER); // prevent // any // further // expansion result.append(t); } else { if (fLocationMap != null) { ImageLocationInfo info = null; if (fLexOptions.fCreateImageLocations) { info = createImageLocationInfo(t); } fImplicitMacroExpansions.add( fLocationMap.encounterImplicitMacroExpansion(macro, info)); } TokenList replacement = new TokenList(); addSpacemarker(l, t, replacement); // start expansion replacement.append(new ExpansionBoundary(macro, true)); Token last = expandOne(t, macro, forbidden, input, replacement, tracker); replacement.append(new ExpansionBoundary(macro, false)); addSpacemarker(last, input.first(), replacement); // end // expansion input.prepend(replacement); } break; case IToken.tLPAREN: case ObjCPreprocessor.tNOSPACE: case ObjCPreprocessor.tSPACE: result.append(t); break; default: protect = false; result.append(t); break; } l = t; t = input.removeFirst(); } return result; }