blob: f86df28db60f26b9061abc7cf5506e0039e58465 [file] [log] [blame]
Shinichiro Hamaji1d545aa2015-06-23 15:29:13 +09001// Copyright 2015 Google Inc. All rights reserved
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
Fumitoshi Ukai744bb2b2015-06-25 00:10:52 +090015// +build ignore
16
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090017#include "rule.h"
18
Shinichiro Hamaji645cca72015-09-24 17:04:21 +090019#include "expr.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090020#include "log.h"
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090021#include "parser.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090022#include "stringprintf.h"
23#include "strutil.h"
Shinichiro Hamajie7992752015-06-29 18:38:35 +090024#include "symtab.h"
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090025
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090026namespace {
27
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090028static void ParseInputs(Rule* r, StringPiece s) {
29 bool is_order_only = false;
30 for (StringPiece input : WordScanner(s)) {
31 if (input == "|") {
32 is_order_only = true;
33 continue;
34 }
Shinichiro Hamajie7992752015-06-29 18:38:35 +090035 Symbol input_sym = Intern(TrimLeadingCurdir(input));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090036 if (is_order_only) {
Shinichiro Hamajie7992752015-06-29 18:38:35 +090037 r->order_only_inputs.push_back(input_sym);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090038 } else {
Shinichiro Hamajie7992752015-06-29 18:38:35 +090039 r->inputs.push_back(input_sym);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090040 }
41 }
42}
43
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090044bool IsPatternRule(StringPiece s) {
45 return s.find('%') != string::npos;
46}
47
48} // namespace
49
Dan Willemsen3ce083f2017-10-11 22:17:48 -070050Rule::Rule() : is_double_colon(false), is_suffix_rule(false), cmd_lineno(0) {}
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090051
Dan Willemsen3ce083f2017-10-11 22:17:48 -070052void ParseRule(Loc& loc,
53 StringPiece line,
54 char term,
55 const function<string()>& after_term_fn,
56 Rule** out_rule,
57 RuleVarAssignment* rule_var) {
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090058 size_t index = line.find(':');
59 if (index == string::npos) {
Dan Willemsene41c7552017-02-22 14:31:16 -080060 ERROR_LOC(loc, "*** missing separator.");
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090061 }
62
63 StringPiece first = line.substr(0, index);
Shinichiro Hamajie7992752015-06-29 18:38:35 +090064 vector<Symbol> outputs;
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090065 for (StringPiece tok : WordScanner(first)) {
66 outputs.push_back(Intern(TrimLeadingCurdir(tok)));
67 }
68
Dan Willemsen3ce083f2017-10-11 22:17:48 -070069 const bool is_first_pattern =
70 (!outputs.empty() && IsPatternRule(outputs[0].str()));
Shinichiro Hamaji36b65822015-09-11 15:39:29 +090071 for (size_t i = 1; i < outputs.size(); i++) {
72 if (IsPatternRule(outputs[i].str()) != is_first_pattern) {
Dan Willemsene41c7552017-02-22 14:31:16 -080073 ERROR_LOC(loc, "*** mixed implicit and normal rules: deprecated syntax");
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090074 }
75 }
76
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +090077 bool is_double_colon = false;
Shinichiro Hamaji776ca302015-06-06 03:52:48 +090078 index++;
79 if (line.get(index) == ':') {
80 is_double_colon = true;
81 index++;
82 }
83
84 StringPiece rest = line.substr(index);
Shinichiro Hamaji2928f462015-06-23 20:24:53 +090085 size_t term_index = rest.find_first_of("=;");
Shinichiro Hamajic4f76622016-06-30 13:05:10 +090086 string buf;
Shinichiro Hamaji2928f462015-06-23 20:24:53 +090087 if ((term_index != string::npos && rest[term_index] == '=') ||
88 (term_index == string::npos && term == '=')) {
89 if (term_index == string::npos)
90 term_index = rest.size();
Shinichiro Hamajic4f76622016-06-30 13:05:10 +090091 // "test: =foo" is questionable but a valid rule definition (not a
92 // target specific variable).
93 // See https://github.com/google/kati/issues/83
94 if (term_index == 0) {
Dan Willemsen3ce083f2017-10-11 22:17:48 -070095 KATI_WARN_LOC(loc,
96 "defining a target which starts with `=', "
Dan Willemsene41c7552017-02-22 14:31:16 -080097 "which is not probably what you meant");
Shinichiro Hamajic4f76622016-06-30 13:05:10 +090098 buf = line.as_string();
99 if (term)
100 buf += term;
101 buf += after_term_fn();
102 line = buf;
103 rest = line.substr(index);
104 term_index = string::npos;
105 } else {
106 rule_var->outputs.swap(outputs);
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700107 ParseAssignStatement(rest, term_index, &rule_var->lhs, &rule_var->rhs,
108 &rule_var->op);
Shinichiro Hamajic4f76622016-06-30 13:05:10 +0900109 *out_rule = NULL;
110 return;
111 }
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900112 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900113
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900114 Rule* rule = new Rule();
115 *out_rule = rule;
116 rule->loc = loc;
117 rule->is_double_colon = is_double_colon;
118 if (is_first_pattern) {
119 rule->output_patterns.swap(outputs);
120 } else {
121 rule->outputs.swap(outputs);
122 }
Shinichiro Hamaji2928f462015-06-23 20:24:53 +0900123 if (term_index != string::npos && term != ';') {
124 CHECK(rest[term_index] == ';');
125 // TODO: Maybe better to avoid Intern here?
126 rule->cmds.push_back(
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900127 NewLiteral(Intern(TrimLeftSpace(rest.substr(term_index + 1))).str()));
Shinichiro Hamaji2928f462015-06-23 20:24:53 +0900128 rest = rest.substr(0, term_index);
129 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900130
131 index = rest.find(':');
132 if (index == string::npos) {
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900133 ParseInputs(rule, rest);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900134 return;
135 }
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900136
137 if (is_first_pattern) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800138 ERROR_LOC(loc, "*** mixed implicit and normal rules: deprecated syntax");
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900139 }
140
141 StringPiece second = rest.substr(0, index);
Dan Willemsen3ce083f2017-10-11 22:17:48 -0700142 StringPiece third = rest.substr(index + 1);
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900143
144 for (StringPiece tok : WordScanner(second)) {
Shinichiro Hamajifcbadb22016-01-26 16:38:52 +0900145 tok = TrimLeadingCurdir(tok);
Shinichiro Hamaji138c4d82015-09-28 13:53:46 +0900146 for (Symbol output : rule->outputs) {
147 if (!Pattern(tok).Match(output.str())) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800148 WARN_LOC(loc, "target `%s' doesn't match the target pattern",
149 output.c_str());
Shinichiro Hamaji138c4d82015-09-28 13:53:46 +0900150 }
151 }
152
Shinichiro Hamaji2e23e4a2015-06-26 07:33:16 +0900153 rule->output_patterns.push_back(Intern(tok));
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900154 }
155
156 if (rule->output_patterns.empty()) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800157 ERROR_LOC(loc, "*** missing target pattern.");
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900158 }
159 if (rule->output_patterns.size() > 1) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800160 ERROR_LOC(loc, "*** multiple target patterns.");
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900161 }
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900162 if (!IsPatternRule(rule->output_patterns[0].str())) {
Dan Willemsene41c7552017-02-22 14:31:16 -0800163 ERROR_LOC(loc, "*** target pattern contains no '%%'.");
Shinichiro Hamaji9b16bda2015-06-19 14:25:17 +0900164 }
165 ParseInputs(rule, third);
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900166}
167
168string Rule::DebugString() const {
169 vector<string> v;
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900170 v.push_back(StringPrintf("outputs=[%s]", JoinSymbols(outputs, ",").c_str()));
171 v.push_back(StringPrintf("inputs=[%s]", JoinSymbols(inputs, ",").c_str()));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900172 if (!order_only_inputs.empty()) {
173 v.push_back(StringPrintf("order_only_inputs=[%s]",
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900174 JoinSymbols(order_only_inputs, ",").c_str()));
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900175 }
Shinichiro Hamaji2e23e4a2015-06-26 07:33:16 +0900176 if (!output_patterns.empty()) {
177 v.push_back(StringPrintf("output_patterns=[%s]",
Shinichiro Hamajie7992752015-06-29 18:38:35 +0900178 JoinSymbols(output_patterns, ",").c_str()));
Shinichiro Hamaji2e23e4a2015-06-26 07:33:16 +0900179 }
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900180 if (is_double_colon)
181 v.push_back("is_double_colon");
182 if (is_suffix_rule)
183 v.push_back("is_suffix_rule");
Shinichiro Hamaji776ca302015-06-06 03:52:48 +0900184 if (!cmds.empty()) {
185 v.push_back(StringPrintf("cmds=[%s]", JoinValues(cmds, ",").c_str()));
186 }
187 return JoinStrings(v, " ");
188}