gfx/angle/src/compiler/preprocessor/MacroExpander.cpp

Sat, 03 Jan 2015 20:18:00 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Sat, 03 Jan 2015 20:18:00 +0100
branch
TOR_BUG_3246
changeset 7
129ffea94266
permissions
-rw-r--r--

Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.

michael@0 1 //
michael@0 2 // Copyright (c) 2011 The ANGLE Project Authors. All rights reserved.
michael@0 3 // Use of this source code is governed by a BSD-style license that can be
michael@0 4 // found in the LICENSE file.
michael@0 5 //
michael@0 6
michael@0 7 #include "MacroExpander.h"
michael@0 8
michael@0 9 #include <algorithm>
michael@0 10 #include <sstream>
michael@0 11
michael@0 12 #include "DiagnosticsBase.h"
michael@0 13 #include "Token.h"
michael@0 14
michael@0 15 namespace pp
michael@0 16 {
michael@0 17
michael@0 18 class TokenLexer : public Lexer
michael@0 19 {
michael@0 20 public:
michael@0 21 typedef std::vector<Token> TokenVector;
michael@0 22
michael@0 23 TokenLexer(TokenVector* tokens)
michael@0 24 {
michael@0 25 tokens->swap(mTokens);
michael@0 26 mIter = mTokens.begin();
michael@0 27 }
michael@0 28
michael@0 29 virtual void lex(Token* token)
michael@0 30 {
michael@0 31 if (mIter == mTokens.end())
michael@0 32 {
michael@0 33 token->reset();
michael@0 34 token->type = Token::LAST;
michael@0 35 }
michael@0 36 else
michael@0 37 {
michael@0 38 *token = *mIter++;
michael@0 39 }
michael@0 40 }
michael@0 41
michael@0 42 private:
michael@0 43 PP_DISALLOW_COPY_AND_ASSIGN(TokenLexer);
michael@0 44
michael@0 45 TokenVector mTokens;
michael@0 46 TokenVector::const_iterator mIter;
michael@0 47 };
michael@0 48
michael@0 49 MacroExpander::MacroExpander(Lexer* lexer,
michael@0 50 MacroSet* macroSet,
michael@0 51 Diagnostics* diagnostics) :
michael@0 52 mLexer(lexer),
michael@0 53 mMacroSet(macroSet),
michael@0 54 mDiagnostics(diagnostics)
michael@0 55 {
michael@0 56 }
michael@0 57
michael@0 58 MacroExpander::~MacroExpander()
michael@0 59 {
michael@0 60 for (std::size_t i = 0; i < mContextStack.size(); ++i)
michael@0 61 {
michael@0 62 delete mContextStack[i];
michael@0 63 }
michael@0 64 }
michael@0 65
michael@0 66 void MacroExpander::lex(Token* token)
michael@0 67 {
michael@0 68 while (true)
michael@0 69 {
michael@0 70 getToken(token);
michael@0 71
michael@0 72 if (token->type != Token::IDENTIFIER)
michael@0 73 break;
michael@0 74
michael@0 75 if (token->expansionDisabled())
michael@0 76 break;
michael@0 77
michael@0 78 MacroSet::const_iterator iter = mMacroSet->find(token->text);
michael@0 79 if (iter == mMacroSet->end())
michael@0 80 break;
michael@0 81
michael@0 82 const Macro& macro = iter->second;
michael@0 83 if (macro.disabled)
michael@0 84 {
michael@0 85 // If a particular token is not expanded, it is never expanded.
michael@0 86 token->setExpansionDisabled(true);
michael@0 87 break;
michael@0 88 }
michael@0 89 if ((macro.type == Macro::kTypeFunc) && !isNextTokenLeftParen())
michael@0 90 {
michael@0 91 // If the token immediately after the macro name is not a '(',
michael@0 92 // this macro should not be expanded.
michael@0 93 break;
michael@0 94 }
michael@0 95
michael@0 96 pushMacro(macro, *token);
michael@0 97 }
michael@0 98 }
michael@0 99
michael@0 100 void MacroExpander::getToken(Token* token)
michael@0 101 {
michael@0 102 if (mReserveToken.get())
michael@0 103 {
michael@0 104 *token = *mReserveToken;
michael@0 105 mReserveToken.reset();
michael@0 106 return;
michael@0 107 }
michael@0 108
michael@0 109 // First pop all empty macro contexts.
michael@0 110 while (!mContextStack.empty() && mContextStack.back()->empty())
michael@0 111 {
michael@0 112 popMacro();
michael@0 113 }
michael@0 114
michael@0 115 if (!mContextStack.empty())
michael@0 116 {
michael@0 117 *token = mContextStack.back()->get();
michael@0 118 }
michael@0 119 else
michael@0 120 {
michael@0 121 mLexer->lex(token);
michael@0 122 }
michael@0 123 }
michael@0 124
michael@0 125 void MacroExpander::ungetToken(const Token& token)
michael@0 126 {
michael@0 127 if (!mContextStack.empty())
michael@0 128 {
michael@0 129 MacroContext* context = mContextStack.back();
michael@0 130 context->unget();
michael@0 131 assert(context->replacements[context->index] == token);
michael@0 132 }
michael@0 133 else
michael@0 134 {
michael@0 135 assert(!mReserveToken.get());
michael@0 136 mReserveToken.reset(new Token(token));
michael@0 137 }
michael@0 138 }
michael@0 139
michael@0 140 bool MacroExpander::isNextTokenLeftParen()
michael@0 141 {
michael@0 142 Token token;
michael@0 143 getToken(&token);
michael@0 144
michael@0 145 bool lparen = token.type == '(';
michael@0 146 ungetToken(token);
michael@0 147
michael@0 148 return lparen;
michael@0 149 }
michael@0 150
michael@0 151 bool MacroExpander::pushMacro(const Macro& macro, const Token& identifier)
michael@0 152 {
michael@0 153 assert(!macro.disabled);
michael@0 154 assert(!identifier.expansionDisabled());
michael@0 155 assert(identifier.type == Token::IDENTIFIER);
michael@0 156 assert(identifier.text == macro.name);
michael@0 157
michael@0 158 std::vector<Token> replacements;
michael@0 159 if (!expandMacro(macro, identifier, &replacements))
michael@0 160 return false;
michael@0 161
michael@0 162 // Macro is disabled for expansion until it is popped off the stack.
michael@0 163 macro.disabled = true;
michael@0 164
michael@0 165 MacroContext* context = new MacroContext;
michael@0 166 context->macro = &macro;
michael@0 167 context->replacements.swap(replacements);
michael@0 168 mContextStack.push_back(context);
michael@0 169 return true;
michael@0 170 }
michael@0 171
michael@0 172 void MacroExpander::popMacro()
michael@0 173 {
michael@0 174 assert(!mContextStack.empty());
michael@0 175
michael@0 176 MacroContext* context = mContextStack.back();
michael@0 177 mContextStack.pop_back();
michael@0 178
michael@0 179 assert(context->empty());
michael@0 180 assert(context->macro->disabled);
michael@0 181 context->macro->disabled = false;
michael@0 182 delete context;
michael@0 183 }
michael@0 184
michael@0 185 bool MacroExpander::expandMacro(const Macro& macro,
michael@0 186 const Token& identifier,
michael@0 187 std::vector<Token>* replacements)
michael@0 188 {
michael@0 189 replacements->clear();
michael@0 190 if (macro.type == Macro::kTypeObj)
michael@0 191 {
michael@0 192 replacements->assign(macro.replacements.begin(),
michael@0 193 macro.replacements.end());
michael@0 194
michael@0 195 if (macro.predefined)
michael@0 196 {
michael@0 197 static const std::string kLine = "__LINE__";
michael@0 198 static const std::string kFile = "__FILE__";
michael@0 199
michael@0 200 assert(replacements->size() == 1);
michael@0 201 Token& repl = replacements->front();
michael@0 202 if (macro.name == kLine)
michael@0 203 {
michael@0 204 std::ostringstream stream;
michael@0 205 stream << identifier.location.line;
michael@0 206 repl.text = stream.str();
michael@0 207 }
michael@0 208 else if (macro.name == kFile)
michael@0 209 {
michael@0 210 std::ostringstream stream;
michael@0 211 stream << identifier.location.file;
michael@0 212 repl.text = stream.str();
michael@0 213 }
michael@0 214 }
michael@0 215 }
michael@0 216 else
michael@0 217 {
michael@0 218 assert(macro.type == Macro::kTypeFunc);
michael@0 219 std::vector<MacroArg> args;
michael@0 220 args.reserve(macro.parameters.size());
michael@0 221 if (!collectMacroArgs(macro, identifier, &args))
michael@0 222 return false;
michael@0 223
michael@0 224 replaceMacroParams(macro, args, replacements);
michael@0 225 }
michael@0 226
michael@0 227 for (std::size_t i = 0; i < replacements->size(); ++i)
michael@0 228 {
michael@0 229 Token& repl = replacements->at(i);
michael@0 230 if (i == 0)
michael@0 231 {
michael@0 232 // The first token in the replacement list inherits the padding
michael@0 233 // properties of the identifier token.
michael@0 234 repl.setAtStartOfLine(identifier.atStartOfLine());
michael@0 235 repl.setHasLeadingSpace(identifier.hasLeadingSpace());
michael@0 236 }
michael@0 237 repl.location = identifier.location;
michael@0 238 }
michael@0 239 return true;
michael@0 240 }
michael@0 241
michael@0 242 bool MacroExpander::collectMacroArgs(const Macro& macro,
michael@0 243 const Token& identifier,
michael@0 244 std::vector<MacroArg>* args)
michael@0 245 {
michael@0 246 Token token;
michael@0 247 getToken(&token);
michael@0 248 assert(token.type == '(');
michael@0 249
michael@0 250 args->push_back(MacroArg());
michael@0 251 for (int openParens = 1; openParens != 0; )
michael@0 252 {
michael@0 253 getToken(&token);
michael@0 254
michael@0 255 if (token.type == Token::LAST)
michael@0 256 {
michael@0 257 mDiagnostics->report(Diagnostics::MACRO_UNTERMINATED_INVOCATION,
michael@0 258 identifier.location, identifier.text);
michael@0 259 // Do not lose EOF token.
michael@0 260 ungetToken(token);
michael@0 261 return false;
michael@0 262 }
michael@0 263
michael@0 264 bool isArg = false; // True if token is part of the current argument.
michael@0 265 switch (token.type)
michael@0 266 {
michael@0 267 case '(':
michael@0 268 ++openParens;
michael@0 269 isArg = true;
michael@0 270 break;
michael@0 271 case ')':
michael@0 272 --openParens;
michael@0 273 isArg = openParens != 0;
michael@0 274 break;
michael@0 275 case ',':
michael@0 276 // The individual arguments are separated by comma tokens, but
michael@0 277 // the comma tokens between matching inner parentheses do not
michael@0 278 // seperate arguments.
michael@0 279 if (openParens == 1) args->push_back(MacroArg());
michael@0 280 isArg = openParens != 1;
michael@0 281 break;
michael@0 282 default:
michael@0 283 isArg = true;
michael@0 284 break;
michael@0 285 }
michael@0 286 if (isArg)
michael@0 287 {
michael@0 288 MacroArg& arg = args->back();
michael@0 289 // Initial whitespace is not part of the argument.
michael@0 290 if (arg.empty()) token.setHasLeadingSpace(false);
michael@0 291 arg.push_back(token);
michael@0 292 }
michael@0 293 }
michael@0 294
michael@0 295 const Macro::Parameters& params = macro.parameters;
michael@0 296 // If there is only one empty argument, it is equivalent to no argument.
michael@0 297 if (params.empty() && (args->size() == 1) && args->front().empty())
michael@0 298 {
michael@0 299 args->clear();
michael@0 300 }
michael@0 301 // Validate the number of arguments.
michael@0 302 if (args->size() != params.size())
michael@0 303 {
michael@0 304 Diagnostics::ID id = args->size() < macro.parameters.size() ?
michael@0 305 Diagnostics::MACRO_TOO_FEW_ARGS :
michael@0 306 Diagnostics::MACRO_TOO_MANY_ARGS;
michael@0 307 mDiagnostics->report(id, identifier.location, identifier.text);
michael@0 308 return false;
michael@0 309 }
michael@0 310
michael@0 311 // Pre-expand each argument before substitution.
michael@0 312 // This step expands each argument individually before they are
michael@0 313 // inserted into the macro body.
michael@0 314 for (std::size_t i = 0; i < args->size(); ++i)
michael@0 315 {
michael@0 316 MacroArg& arg = args->at(i);
michael@0 317 TokenLexer lexer(&arg);
michael@0 318 MacroExpander expander(&lexer, mMacroSet, mDiagnostics);
michael@0 319
michael@0 320 arg.clear();
michael@0 321 expander.lex(&token);
michael@0 322 while (token.type != Token::LAST)
michael@0 323 {
michael@0 324 arg.push_back(token);
michael@0 325 expander.lex(&token);
michael@0 326 }
michael@0 327 }
michael@0 328 return true;
michael@0 329 }
michael@0 330
michael@0 331 void MacroExpander::replaceMacroParams(const Macro& macro,
michael@0 332 const std::vector<MacroArg>& args,
michael@0 333 std::vector<Token>* replacements)
michael@0 334 {
michael@0 335 for (std::size_t i = 0; i < macro.replacements.size(); ++i)
michael@0 336 {
michael@0 337 const Token& repl = macro.replacements[i];
michael@0 338 if (repl.type != Token::IDENTIFIER)
michael@0 339 {
michael@0 340 replacements->push_back(repl);
michael@0 341 continue;
michael@0 342 }
michael@0 343
michael@0 344 // TODO(alokp): Optimize this.
michael@0 345 // There is no need to search for macro params every time.
michael@0 346 // The param index can be cached with the replacement token.
michael@0 347 Macro::Parameters::const_iterator iter = std::find(
michael@0 348 macro.parameters.begin(), macro.parameters.end(), repl.text);
michael@0 349 if (iter == macro.parameters.end())
michael@0 350 {
michael@0 351 replacements->push_back(repl);
michael@0 352 continue;
michael@0 353 }
michael@0 354
michael@0 355 std::size_t iArg = std::distance(macro.parameters.begin(), iter);
michael@0 356 const MacroArg& arg = args[iArg];
michael@0 357 if (arg.empty())
michael@0 358 {
michael@0 359 continue;
michael@0 360 }
michael@0 361 std::size_t iRepl = replacements->size();
michael@0 362 replacements->insert(replacements->end(), arg.begin(), arg.end());
michael@0 363 // The replacement token inherits padding properties from
michael@0 364 // macro replacement token.
michael@0 365 replacements->at(iRepl).setHasLeadingSpace(repl.hasLeadingSpace());
michael@0 366 }
michael@0 367 }
michael@0 368
michael@0 369 } // namespace pp
michael@0 370

mercurial