| 231 | } |
| 232 | |
| 233 | Value MacroProcessor::InternalResolveMacros(const String& str, const ResolverList& resolvers, |
| 234 | const CheckResult::Ptr& cr, String *missingMacro, |
| 235 | const MacroProcessor::EscapeCallback& escapeFn, const Dictionary::Ptr& resolvedMacros, |
| 236 | bool useResolvedMacros, int recursionLevel) |
| 237 | { |
| 238 | CONTEXT("Resolving macros for string '" << str << "'"); |
| 239 | |
| 240 | if (recursionLevel > 15) |
| 241 | BOOST_THROW_EXCEPTION(std::runtime_error("Infinite recursion detected while resolving macros")); |
| 242 | |
| 243 | size_t offset, pos_first, pos_second; |
| 244 | offset = 0; |
| 245 | |
| 246 | Dictionary::Ptr resolvers_this; |
| 247 | |
| 248 | String result = str; |
| 249 | while ((pos_first = result.FindFirstOf("$", offset)) != String::NPos) { |
| 250 | pos_second = result.FindFirstOf("$", pos_first + 1); |
| 251 | |
| 252 | if (pos_second == String::NPos) |
| 253 | BOOST_THROW_EXCEPTION(std::runtime_error("Closing $ not found in macro format string.")); |
| 254 | |
| 255 | String name = result.SubStr(pos_first + 1, pos_second - pos_first - 1); |
| 256 | |
| 257 | Value resolved_macro; |
| 258 | bool recursive_macro; |
| 259 | bool found; |
| 260 | |
| 261 | if (useResolvedMacros) { |
| 262 | recursive_macro = false; |
| 263 | found = resolvedMacros->Contains(name); |
| 264 | |
| 265 | if (found) |
| 266 | resolved_macro = resolvedMacros->Get(name); |
| 267 | } else |
| 268 | found = ResolveMacro(name, resolvers, cr, &resolved_macro, &recursive_macro); |
| 269 | |
| 270 | /* $$ is an escape sequence for $. */ |
| 271 | if (name.IsEmpty()) { |
| 272 | resolved_macro = "$"; |
| 273 | found = true; |
| 274 | } |
| 275 | |
| 276 | if (resolved_macro.IsObjectType<Function>()) { |
| 277 | resolved_macro = EvaluateFunction(resolved_macro, resolvers, cr, |
| 278 | resolvedMacros, useResolvedMacros, recursionLevel + 1); |
| 279 | } |
| 280 | |
| 281 | if (!found) { |
| 282 | if (!missingMacro) |
| 283 | Log(LogWarning, "MacroProcessor") |
| 284 | << "Macro '" << name << "' is not defined."; |
| 285 | else |
| 286 | *missingMacro = name; |
| 287 | } |
| 288 | |
| 289 | /* recursively resolve macros in the macro if it was a user macro */ |
| 290 | if (recursive_macro) { |
nothing calls this directly
no test coverage detected