| OLD | NEW |
| 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "tools/gn/file_template.h" | 5 #include "tools/gn/file_template.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <iostream> | 8 #include <iostream> |
| 9 | 9 |
| 10 #include "tools/gn/escape.h" | 10 #include "tools/gn/escape.h" |
| 11 #include "tools/gn/filesystem_utils.h" | 11 #include "tools/gn/filesystem_utils.h" |
| 12 #include "tools/gn/string_utils.h" | 12 #include "tools/gn/string_utils.h" |
| 13 #include "tools/gn/target.h" | 13 #include "tools/gn/target.h" |
| 14 | 14 |
| 15 const char FileTemplate::kSource[] = "{{source}}"; | 15 const char FileTemplate::kSource[] = "{{source}}"; |
| 16 const char FileTemplate::kSourceNamePart[] = "{{source_name_part}}"; | 16 const char FileTemplate::kSourceNamePart[] = "{{source_name_part}}"; |
| 17 const char FileTemplate::kSourceFilePart[] = "{{source_file_part}}"; | 17 const char FileTemplate::kSourceFilePart[] = "{{source_file_part}}"; |
| 18 const char FileTemplate::kSourceDir[] = "{{source_dir}}"; |
| 19 const char FileTemplate::kRootRelDir[] = "{{source_root_relative_dir}}"; |
| 20 const char FileTemplate::kSourceGenDir[] = "{{source_gen_dir}}"; |
| 21 const char FileTemplate::kSourceOutDir[] = "{{source_out_dir}}"; |
| 18 | 22 |
| 19 const char kSourceExpansion_Help[] = | 23 const char kSourceExpansion_Help[] = |
| 20 "How Source Expansion Works\n" | 24 "How Source Expansion Works\n" |
| 21 "\n" | 25 "\n" |
| 22 " Source expansion is used for the action_foreach and copy target types\n" | 26 " Source expansion is used for the action_foreach and copy target types\n" |
| 23 " to map source file names to output file names or arguments.\n" | 27 " to map source file names to output file names or arguments.\n" |
| 24 "\n" | 28 "\n" |
| 25 " To perform source expansion in the outputs, GN maps every entry in the\n" | 29 " To perform source expansion in the outputs, GN maps every entry in the\n" |
| 26 " sources to every entry in the outputs list, producing the cross\n" | 30 " sources to every entry in the outputs list, producing the cross\n" |
| 27 " product of all combinations, expanding placeholders (see below).\n" | 31 " product of all combinations, expanding placeholders (see below).\n" |
| 28 "\n" | 32 "\n" |
| 29 " Source expansion in the args works similarly, but performing the\n" | 33 " Source expansion in the args works similarly, but performing the\n" |
| 30 " placeholder substitution produces a different set of arguments for\n" | 34 " placeholder substitution produces a different set of arguments for\n" |
| 31 " each invocation of the script.\n" | 35 " each invocation of the script.\n" |
| 32 "\n" | 36 "\n" |
| 33 " If no placeholders are found, the outputs or args list will be treated\n" | 37 " If no placeholders are found, the outputs or args list will be treated\n" |
| 34 " as a static list of literal file names that do not depend on the\n" | 38 " as a static list of literal file names that do not depend on the\n" |
| 35 " sources.\n" | 39 " sources.\n" |
| 36 "\n" | 40 "\n" |
| 37 " See \"gn help copy\" and \"gn help action_foreach\" for more on how\n" | 41 " See \"gn help copy\" and \"gn help action_foreach\" for more on how\n" |
| 38 " this is applied.\n" | 42 " this is applied.\n" |
| 39 "\n" | 43 "\n" |
| 40 "Placeholders\n" | 44 "Placeholders\n" |
| 41 "\n" | 45 "\n" |
| 42 " {{source}}\n" | 46 " {{source}}\n" |
| 43 " The name of the source file relative to the root build output\n" | 47 " The name of the source file relative to the root build output\n" |
| 44 " directory (which is the current directory when running compilers\n" | 48 " directory (which is the current directory when running compilers\n" |
| 45 " and scripts). This will generally be used for specifying inputs\n" | 49 " and scripts). This will generally be used for specifying inputs\n" |
| 46 " to a script in the \"args\" variable.\n" | 50 " to a script in the \"args\" variable.\n" |
| 51 " \"//foo/bar/baz.txt\" => \"../../foo/bar/baz.txt\"\n" |
| 47 "\n" | 52 "\n" |
| 48 " {{source_file_part}}\n" | 53 " {{source_file_part}}\n" |
| 49 " The file part of the source including the extension. For the\n" | 54 " The file part of the source including the extension.\n" |
| 50 " source \"foo/bar.txt\" the source file part will be \"bar.txt\".\n" | 55 " \"//foo/bar/baz.txt\" => \"baz.txt\"\n" |
| 51 "\n" | 56 "\n" |
| 52 " {{source_name_part}}\n" | 57 " {{source_name_part}}\n" |
| 53 " The filename part of the source file with no directory or\n" | 58 " The filename part of the source file with no directory or\n" |
| 54 " extension. This will generally be used for specifying a\n" | 59 " extension. This will generally be used for specifying a\n" |
| 55 " transformation from a soruce file to a destination file with the\n" | 60 " transformation from a soruce file to a destination file with the\n" |
| 56 " same name but different extension. For the source \"foo/bar.txt\"\n" | 61 " same name but different extension.\n" |
| 57 " the source name part will be \"bar\".\n" | 62 " \"//foo/bar/baz.txt\" => \"baz\"\n" |
| 63 "\n" |
| 64 " {{source_dir}}\n" |
| 65 " The directory containing the source file, relative to the build\n" |
| 66 " directory, with no trailing slash.\n" |
| 67 " \"//foo/bar/baz.txt\" => \"../../foo/bar\"\n" |
| 68 "\n" |
| 69 " {{source_root_relative_dir}}\n" |
| 70 " The path to the source file's directory relative to the source\n" |
| 71 " root, with no leading \"//\" or trailing slashes. If the path is\n" |
| 72 " system-absolute, (beginning in a single slash) this will just\n" |
| 73 " return the path with no trailing slash.\n" |
| 74 " \"//foo/bar/baz.txt\" => \"foo/bar\"\n" |
| 75 "\n" |
| 76 " {{source_gen_dir}}\n" |
| 77 " The generated file directory corresponding to the source file's\n" |
| 78 " path, relative to the build directory. This will be different than\n" |
| 79 " the target's generated file directory if the source file is in a\n" |
| 80 " different directory than the build.gn file. If the input path is\n" |
| 81 " system absolute, this will return the root generated file\n" |
| 82 " directory." |
| 83 " \"//foo/bar/baz.txt\" => \"gen/foo/bar\"\n" |
| 84 "\n" |
| 85 " {{source_out_dir}}\n" |
| 86 " The object file directory corresponding to the source file's\n" |
| 87 " path, relative to the build directory. this us be different than\n" |
| 88 " the target's out directory if the source file is in a different\n" |
| 89 " directory than the build.gn file. if the input path is system\n" |
| 90 " absolute, this will return the root generated file directory.\n" |
| 91 " \"//foo/bar/baz.txt\" => \"obj/foo/bar\"\n" |
| 58 "\n" | 92 "\n" |
| 59 "Examples\n" | 93 "Examples\n" |
| 60 "\n" | 94 "\n" |
| 61 " Non-varying outputs:\n" | 95 " Non-varying outputs:\n" |
| 62 " action(\"hardcoded_outputs\") {\n" | 96 " action(\"hardcoded_outputs\") {\n" |
| 63 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" | 97 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" |
| 64 " outputs = [ \"$target_out_dir/output1.dat\",\n" | 98 " outputs = [ \"$target_out_dir/output1.dat\",\n" |
| 65 " \"$target_out_dir/output2.dat\" ]\n" | 99 " \"$target_out_dir/output2.dat\" ]\n" |
| 66 " }\n" | 100 " }\n" |
| 67 " The outputs in this case will be the two literal files given.\n" | 101 " The outputs in this case will be the two literal files given.\n" |
| 68 "\n" | 102 "\n" |
| 69 " Varying outputs:\n" | 103 " Varying outputs:\n" |
| 70 " action_foreach(\"varying_outputs\") {\n" | 104 " action_foreach(\"varying_outputs\") {\n" |
| 71 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" | 105 " sources = [ \"input1.idl\", \"input2.idl\" ]\n" |
| 72 " outputs = [ \"$target_out_dir/{{source_name_part}}.h\",\n" | 106 " outputs = [ \"$target_out_dir/{{source_name_part}}.h\",\n" |
| 73 " \"$target_out_dir/{{source_name_part}}.cc\" ]\n" | 107 " \"$target_out_dir/{{source_name_part}}.cc\" ]\n" |
| 74 " }\n" | 108 " }\n" |
| 75 " Performing source expansion will result in the following output names:\n" | 109 " Performing source expansion will result in the following output names:\n" |
| 76 " //out/Debug/obj/mydirectory/input1.h\n" | 110 " //out/Debug/obj/mydirectory/input1.h\n" |
| 77 " //out/Debug/obj/mydirectory/input1.cc\n" | 111 " //out/Debug/obj/mydirectory/input1.cc\n" |
| 78 " //out/Debug/obj/mydirectory/input2.h\n" | 112 " //out/Debug/obj/mydirectory/input2.h\n" |
| 79 " //out/Debug/obj/mydirectory/input2.cc\n"; | 113 " //out/Debug/obj/mydirectory/input2.cc\n"; |
| 80 | 114 |
| 81 FileTemplate::FileTemplate(const Value& t, Err* err) | 115 FileTemplate::FileTemplate(const Settings* settings, const Value& t, Err* err) |
| 82 : has_substitutions_(false) { | 116 : settings_(settings), |
| 117 has_substitutions_(false) { |
| 83 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); | 118 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); |
| 84 ParseInput(t, err); | 119 ParseInput(t, err); |
| 85 } | 120 } |
| 86 | 121 |
| 87 FileTemplate::FileTemplate(const std::vector<std::string>& t) | 122 FileTemplate::FileTemplate(const Settings* settings, |
| 88 : has_substitutions_(false) { | 123 const std::vector<std::string>& t) |
| 124 : settings_(settings), |
| 125 has_substitutions_(false) { |
| 89 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); | 126 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); |
| 90 for (size_t i = 0; i < t.size(); i++) | 127 for (size_t i = 0; i < t.size(); i++) |
| 91 ParseOneTemplateString(t[i]); | 128 ParseOneTemplateString(t[i]); |
| 92 } | 129 } |
| 93 | 130 |
| 94 FileTemplate::FileTemplate(const std::vector<SourceFile>& t) | 131 FileTemplate::FileTemplate(const Settings* settings, |
| 95 : has_substitutions_(false) { | 132 const std::vector<SourceFile>& t) |
| 133 : settings_(settings), |
| 134 has_substitutions_(false) { |
| 96 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); | 135 std::fill(types_required_, &types_required_[Subrange::NUM_TYPES], false); |
| 97 for (size_t i = 0; i < t.size(); i++) | 136 for (size_t i = 0; i < t.size(); i++) |
| 98 ParseOneTemplateString(t[i].value()); | 137 ParseOneTemplateString(t[i].value()); |
| 99 } | 138 } |
| 100 | 139 |
| 101 FileTemplate::~FileTemplate() { | 140 FileTemplate::~FileTemplate() { |
| 102 } | 141 } |
| 103 | 142 |
| 104 // static | 143 // static |
| 105 FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) { | 144 FileTemplate FileTemplate::GetForTargetOutputs(const Target* target) { |
| 106 const Target::FileList& outputs = target->action_values().outputs(); | 145 const Target::FileList& outputs = target->action_values().outputs(); |
| 107 std::vector<std::string> output_template_args; | 146 std::vector<std::string> output_template_args; |
| 108 for (size_t i = 0; i < outputs.size(); i++) | 147 for (size_t i = 0; i < outputs.size(); i++) |
| 109 output_template_args.push_back(outputs[i].value()); | 148 output_template_args.push_back(outputs[i].value()); |
| 110 return FileTemplate(output_template_args); | 149 return FileTemplate(target->settings(), output_template_args); |
| 111 } | 150 } |
| 112 | 151 |
| 113 bool FileTemplate::IsTypeUsed(Subrange::Type type) const { | 152 bool FileTemplate::IsTypeUsed(Subrange::Type type) const { |
| 114 DCHECK(type > Subrange::LITERAL && type < Subrange::NUM_TYPES); | 153 DCHECK(type > Subrange::LITERAL && type < Subrange::NUM_TYPES); |
| 115 return types_required_[type]; | 154 return types_required_[type]; |
| 116 } | 155 } |
| 117 | 156 |
| 118 void FileTemplate::Apply(const Value& sources, | 157 void FileTemplate::Apply(const SourceFile& source, |
| 119 const ParseNode* origin, | 158 std::vector<std::string>* output) const { |
| 120 std::vector<Value>* dest, | |
| 121 Err* err) const { | |
| 122 if (!sources.VerifyTypeIs(Value::LIST, err)) | |
| 123 return; | |
| 124 dest->reserve(sources.list_value().size() * templates_.container().size()); | |
| 125 | |
| 126 // Temporary holding place, allocate outside to re-use- buffer. | |
| 127 std::vector<std::string> string_output; | |
| 128 | |
| 129 const std::vector<Value>& sources_list = sources.list_value(); | |
| 130 for (size_t i = 0; i < sources_list.size(); i++) { | |
| 131 string_output.clear(); | |
| 132 if (!sources_list[i].VerifyTypeIs(Value::STRING, err)) | |
| 133 return; | |
| 134 | |
| 135 ApplyString(sources_list[i].string_value(), &string_output); | |
| 136 for (size_t out_i = 0; out_i < string_output.size(); out_i++) | |
| 137 dest->push_back(Value(origin, string_output[out_i])); | |
| 138 } | |
| 139 } | |
| 140 | |
| 141 void FileTemplate::ApplyString(const std::string& str, | |
| 142 std::vector<std::string>* output) const { | |
| 143 // Compute all substitutions needed so we can just do substitutions below. | 159 // Compute all substitutions needed so we can just do substitutions below. |
| 144 // We skip the LITERAL one since that varies each time. | 160 // We skip the LITERAL one since that varies each time. |
| 145 std::string subst[Subrange::NUM_TYPES]; | 161 std::string subst[Subrange::NUM_TYPES]; |
| 146 for (int i = 1; i < Subrange::NUM_TYPES; i++) { | 162 for (int i = 1; i < Subrange::NUM_TYPES; i++) { |
| 147 if (types_required_[i]) | 163 if (types_required_[i]) { |
| 148 subst[i] = GetSubstitution(str, static_cast<Subrange::Type>(i)); | 164 subst[i] = |
| 165 GetSubstitution(settings_, source, static_cast<Subrange::Type>(i)); |
| 166 } |
| 149 } | 167 } |
| 150 | 168 |
| 151 size_t first_output_index = output->size(); | 169 size_t first_output_index = output->size(); |
| 152 output->resize(output->size() + templates_.container().size()); | 170 output->resize(output->size() + templates_.container().size()); |
| 153 for (size_t template_i = 0; | 171 for (size_t template_i = 0; |
| 154 template_i < templates_.container().size(); template_i++) { | 172 template_i < templates_.container().size(); template_i++) { |
| 155 const Template& t = templates_[template_i]; | 173 const Template& t = templates_[template_i]; |
| 156 std::string& cur_output = (*output)[first_output_index + template_i]; | 174 std::string& cur_output = (*output)[first_output_index + template_i]; |
| 157 for (size_t subrange_i = 0; subrange_i < t.container().size(); | 175 for (size_t subrange_i = 0; subrange_i < t.container().size(); |
| 158 subrange_i++) { | 176 subrange_i++) { |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 // argument. | 220 // argument. |
| 203 out << '"' << item_str << '"'; | 221 out << '"' << item_str << '"'; |
| 204 } else { | 222 } else { |
| 205 out << item_str; | 223 out << item_str; |
| 206 } | 224 } |
| 207 } | 225 } |
| 208 } | 226 } |
| 209 | 227 |
| 210 void FileTemplate::WriteNinjaVariablesForSubstitution( | 228 void FileTemplate::WriteNinjaVariablesForSubstitution( |
| 211 std::ostream& out, | 229 std::ostream& out, |
| 212 const std::string& source, | 230 const Settings* settings, |
| 231 const SourceFile& source, |
| 213 const EscapeOptions& escape_options) const { | 232 const EscapeOptions& escape_options) const { |
| 214 for (int i = 1; i < Subrange::NUM_TYPES; i++) { | 233 for (int i = 1; i < Subrange::NUM_TYPES; i++) { |
| 215 if (types_required_[i]) { | 234 if (types_required_[i]) { |
| 216 Subrange::Type type = static_cast<Subrange::Type>(i); | 235 Subrange::Type type = static_cast<Subrange::Type>(i); |
| 217 out << " " << GetNinjaVariableNameForType(type) << " = "; | 236 out << " " << GetNinjaVariableNameForType(type) << " = "; |
| 218 EscapeStringToStream(out, GetSubstitution(source, type), escape_options); | 237 EscapeStringToStream(out, GetSubstitution(settings, source, type), |
| 238 escape_options); |
| 219 out << std::endl; | 239 out << std::endl; |
| 220 } | 240 } |
| 221 } | 241 } |
| 222 } | 242 } |
| 223 | 243 |
| 224 // static | 244 // static |
| 225 const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) { | 245 const char* FileTemplate::GetNinjaVariableNameForType(Subrange::Type type) { |
| 226 switch (type) { | 246 switch (type) { |
| 227 case Subrange::SOURCE: | 247 case Subrange::SOURCE: |
| 228 return "source"; | 248 return "source"; |
| 229 case Subrange::NAME_PART: | 249 case Subrange::NAME_PART: |
| 230 return "source_name_part"; | 250 return "source_name_part"; |
| 231 case Subrange::FILE_PART: | 251 case Subrange::FILE_PART: |
| 232 return "source_file_part"; | 252 return "source_file_part"; |
| 253 case Subrange::SOURCE_DIR: |
| 254 return "source_dir"; |
| 255 case Subrange::ROOT_RELATIVE_DIR: |
| 256 return "source_root_rel_dir"; |
| 257 case Subrange::SOURCE_GEN_DIR: |
| 258 return "source_gen_dir"; |
| 259 case Subrange::SOURCE_OUT_DIR: |
| 260 return "source_out_dir"; |
| 261 |
| 233 default: | 262 default: |
| 234 NOTREACHED(); | 263 NOTREACHED(); |
| 235 } | 264 } |
| 236 return ""; | 265 return ""; |
| 237 } | 266 } |
| 238 | 267 |
| 239 // static | 268 // static |
| 240 std::string FileTemplate::GetSubstitution(const std::string& source, | 269 std::string FileTemplate::GetSubstitution(const Settings* settings, |
| 270 const SourceFile& source, |
| 241 Subrange::Type type) { | 271 Subrange::Type type) { |
| 242 switch (type) { | 272 switch (type) { |
| 243 case Subrange::SOURCE: | 273 case Subrange::SOURCE: |
| 244 return source; | 274 if (source.is_system_absolute()) |
| 275 return source.value(); |
| 276 return RebaseSourceAbsolutePath(source.value(), |
| 277 settings->build_settings()->build_dir()); |
| 278 |
| 245 case Subrange::NAME_PART: | 279 case Subrange::NAME_PART: |
| 246 return FindFilenameNoExtension(&source).as_string(); | 280 return FindFilenameNoExtension(&source.value()).as_string(); |
| 281 |
| 247 case Subrange::FILE_PART: | 282 case Subrange::FILE_PART: |
| 248 return FindFilename(&source).as_string(); | 283 return source.GetName(); |
| 284 |
| 285 case Subrange::SOURCE_DIR: |
| 286 if (source.is_system_absolute()) |
| 287 return DirectoryWithNoLastSlash(source.GetDir()); |
| 288 return RebaseSourceAbsolutePath( |
| 289 DirectoryWithNoLastSlash(source.GetDir()), |
| 290 settings->build_settings()->build_dir()); |
| 291 |
| 292 case Subrange::ROOT_RELATIVE_DIR: |
| 293 if (source.is_system_absolute()) |
| 294 return DirectoryWithNoLastSlash(source.GetDir()); |
| 295 return RebaseSourceAbsolutePath( |
| 296 DirectoryWithNoLastSlash(source.GetDir()), SourceDir("//")); |
| 297 |
| 298 case Subrange::SOURCE_GEN_DIR: |
| 299 return RebaseSourceAbsolutePath( |
| 300 DirectoryWithNoLastSlash( |
| 301 GetGenDirForSourceDir(settings, source.GetDir())), |
| 302 settings->build_settings()->build_dir()); |
| 303 |
| 304 case Subrange::SOURCE_OUT_DIR: |
| 305 return RebaseSourceAbsolutePath( |
| 306 DirectoryWithNoLastSlash( |
| 307 GetOutputDirForSourceDir(settings, source.GetDir())), |
| 308 settings->build_settings()->build_dir()); |
| 309 |
| 249 default: | 310 default: |
| 250 NOTREACHED(); | 311 NOTREACHED(); |
| 251 } | 312 } |
| 252 return std::string(); | 313 return std::string(); |
| 253 } | 314 } |
| 254 | 315 |
| 255 void FileTemplate::ParseInput(const Value& value, Err* err) { | 316 void FileTemplate::ParseInput(const Value& value, Err* err) { |
| 256 switch (value.type()) { | 317 switch (value.type()) { |
| 257 case Value::STRING: | 318 case Value::STRING: |
| 258 ParseOneTemplateString(value.string_value()); | 319 ParseOneTemplateString(value.string_value()); |
| (...skipping 22 matching lines...) Expand all Loading... |
| 281 // Pick up everything from the previous spot to here as a literal. | 342 // Pick up everything from the previous spot to here as a literal. |
| 282 if (next == std::string::npos) { | 343 if (next == std::string::npos) { |
| 283 if (cur != str.size()) | 344 if (cur != str.size()) |
| 284 t.container().push_back(Subrange(Subrange::LITERAL, str.substr(cur))); | 345 t.container().push_back(Subrange(Subrange::LITERAL, str.substr(cur))); |
| 285 break; | 346 break; |
| 286 } else if (next > cur) { | 347 } else if (next > cur) { |
| 287 t.container().push_back( | 348 t.container().push_back( |
| 288 Subrange(Subrange::LITERAL, str.substr(cur, next - cur))); | 349 Subrange(Subrange::LITERAL, str.substr(cur, next - cur))); |
| 289 } | 350 } |
| 290 | 351 |
| 352 // Given the name of the string constant and enum for a template parameter, |
| 353 // checks for it and stores it. Writing this as a function requires passing |
| 354 // the entire state of this function as arguments, so this actually ends |
| 355 // up being more clear. |
| 356 #define IF_MATCH_THEN_STORE(const_name, enum_name) \ |
| 357 if (str.compare(next, arraysize(const_name) - 1, const_name) == 0) { \ |
| 358 t.container().push_back(Subrange(Subrange::enum_name)); \ |
| 359 types_required_[Subrange::enum_name] = true; \ |
| 360 has_substitutions_ = true; \ |
| 361 cur = next + arraysize(const_name) - 1; \ |
| 362 } |
| 363 |
| 291 // Decode the template param. | 364 // Decode the template param. |
| 292 if (str.compare(next, arraysize(kSource) - 1, kSource) == 0) { | 365 IF_MATCH_THEN_STORE(kSource, SOURCE) |
| 293 t.container().push_back(Subrange(Subrange::SOURCE)); | 366 else IF_MATCH_THEN_STORE(kSourceNamePart, NAME_PART) |
| 294 types_required_[Subrange::SOURCE] = true; | 367 else IF_MATCH_THEN_STORE(kSourceFilePart, FILE_PART) |
| 295 has_substitutions_ = true; | 368 else IF_MATCH_THEN_STORE(kSourceDir, SOURCE_DIR) |
| 296 cur = next + arraysize(kSource) - 1; | 369 else IF_MATCH_THEN_STORE(kRootRelDir, ROOT_RELATIVE_DIR) |
| 297 } else if (str.compare(next, arraysize(kSourceNamePart) - 1, | 370 else IF_MATCH_THEN_STORE(kSourceGenDir, SOURCE_GEN_DIR) |
| 298 kSourceNamePart) == 0) { | 371 else IF_MATCH_THEN_STORE(kSourceOutDir, SOURCE_OUT_DIR) |
| 299 t.container().push_back(Subrange(Subrange::NAME_PART)); | 372 else { |
| 300 types_required_[Subrange::NAME_PART] = true; | |
| 301 has_substitutions_ = true; | |
| 302 cur = next + arraysize(kSourceNamePart) - 1; | |
| 303 } else if (str.compare(next, arraysize(kSourceFilePart) - 1, | |
| 304 kSourceFilePart) == 0) { | |
| 305 t.container().push_back(Subrange(Subrange::FILE_PART)); | |
| 306 types_required_[Subrange::FILE_PART] = true; | |
| 307 has_substitutions_ = true; | |
| 308 cur = next + arraysize(kSourceFilePart) - 1; | |
| 309 } else { | |
| 310 // If it's not a match, treat it like a one-char literal (this will be | 373 // If it's not a match, treat it like a one-char literal (this will be |
| 311 // rare, so it's not worth the bother to add to the previous literal) so | 374 // rare, so it's not worth the bother to add to the previous literal) so |
| 312 // we can keep going. | 375 // we can keep going. |
| 313 t.container().push_back(Subrange(Subrange::LITERAL, "{")); | 376 t.container().push_back(Subrange(Subrange::LITERAL, "{")); |
| 314 cur = next + 1; | 377 cur = next + 1; |
| 315 } | 378 } |
| 379 |
| 380 #undef IF_MATCH_THEN_STORE |
| 316 } | 381 } |
| 317 } | 382 } |
| OLD | NEW |