• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // 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 
15 // +build ignore
16 
17 #include "rule.h"
18 
19 #include "expr.h"
20 #include "log.h"
21 #include "parser.h"
22 #include "stringprintf.h"
23 #include "strutil.h"
24 #include "symtab.h"
25 
26 namespace {
27 
ParseInputs(Rule * r,StringPiece s)28 static 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     }
35     Symbol input_sym = Intern(TrimLeadingCurdir(input));
36     if (is_order_only) {
37       r->order_only_inputs.push_back(input_sym);
38     } else {
39       r->inputs.push_back(input_sym);
40     }
41   }
42 }
43 
IsPatternRule(StringPiece s)44 bool IsPatternRule(StringPiece s) {
45   return s.find('%') != string::npos;
46 }
47 
48 }  // namespace
49 
Rule()50 Rule::Rule()
51     : is_double_colon(false),
52       is_suffix_rule(false),
53       cmd_lineno(0) {
54 }
55 
ParseRule(Loc & loc,StringPiece line,char term,const function<string ()> & after_term_fn,Rule ** out_rule,RuleVarAssignment * rule_var)56 void ParseRule(Loc& loc, StringPiece line, char term,
57                const function<string()> &after_term_fn,
58                Rule** out_rule, RuleVarAssignment* rule_var) {
59   size_t index = line.find(':');
60   if (index == string::npos) {
61     ERROR_LOC(loc, "*** missing separator.");
62   }
63 
64   StringPiece first = line.substr(0, index);
65   vector<Symbol> outputs;
66   for (StringPiece tok : WordScanner(first)) {
67     outputs.push_back(Intern(TrimLeadingCurdir(tok)));
68   }
69 
70   const bool is_first_pattern = (
71       !outputs.empty() && IsPatternRule(outputs[0].str()));
72   for (size_t i = 1; i < outputs.size(); i++) {
73     if (IsPatternRule(outputs[i].str()) != is_first_pattern) {
74       ERROR_LOC(loc, "*** mixed implicit and normal rules: deprecated syntax");
75     }
76   }
77 
78   bool is_double_colon = false;
79   index++;
80   if (line.get(index) == ':') {
81     is_double_colon = true;
82     index++;
83   }
84 
85   StringPiece rest = line.substr(index);
86   size_t term_index = rest.find_first_of("=;");
87   string buf;
88   if ((term_index != string::npos && rest[term_index] == '=') ||
89       (term_index == string::npos && term == '=')) {
90     if (term_index == string::npos)
91       term_index = rest.size();
92     // "test: =foo" is questionable but a valid rule definition (not a
93     // target specific variable).
94     // See https://github.com/google/kati/issues/83
95     if (term_index == 0) {
96       KATI_WARN_LOC(loc, "defining a target which starts with `=', "
97                     "which is not probably what you meant");
98       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);
107       ParseAssignStatement(rest, term_index,
108                            &rule_var->lhs, &rule_var->rhs, &rule_var->op);
109       *out_rule = NULL;
110       return;
111     }
112   }
113 
114   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   }
123   if (term_index != string::npos && term != ';') {
124     CHECK(rest[term_index] == ';');
125     // TODO: Maybe better to avoid Intern here?
126     rule->cmds.push_back(
127         NewLiteral(Intern(TrimLeftSpace(rest.substr(term_index + 1))).str()));
128     rest = rest.substr(0, term_index);
129   }
130 
131   index = rest.find(':');
132   if (index == string::npos) {
133     ParseInputs(rule, rest);
134     return;
135   }
136 
137   if (is_first_pattern) {
138     ERROR_LOC(loc, "*** mixed implicit and normal rules: deprecated syntax");
139   }
140 
141   StringPiece second = rest.substr(0, index);
142   StringPiece third = rest.substr(index+1);
143 
144   for (StringPiece tok : WordScanner(second)) {
145     tok = TrimLeadingCurdir(tok);
146     for (Symbol output : rule->outputs) {
147       if (!Pattern(tok).Match(output.str())) {
148         WARN_LOC(loc, "target `%s' doesn't match the target pattern",
149                  output.c_str());
150       }
151     }
152 
153     rule->output_patterns.push_back(Intern(tok));
154   }
155 
156   if (rule->output_patterns.empty()) {
157     ERROR_LOC(loc, "*** missing target pattern.");
158   }
159   if (rule->output_patterns.size() > 1) {
160     ERROR_LOC(loc, "*** multiple target patterns.");
161   }
162   if (!IsPatternRule(rule->output_patterns[0].str())) {
163     ERROR_LOC(loc, "*** target pattern contains no '%%'.");
164   }
165   ParseInputs(rule, third);
166 }
167 
DebugString() const168 string Rule::DebugString() const {
169   vector<string> v;
170   v.push_back(StringPrintf("outputs=[%s]", JoinSymbols(outputs, ",").c_str()));
171   v.push_back(StringPrintf("inputs=[%s]", JoinSymbols(inputs, ",").c_str()));
172   if (!order_only_inputs.empty()) {
173     v.push_back(StringPrintf("order_only_inputs=[%s]",
174                              JoinSymbols(order_only_inputs, ",").c_str()));
175   }
176   if (!output_patterns.empty()) {
177     v.push_back(StringPrintf("output_patterns=[%s]",
178                              JoinSymbols(output_patterns, ",").c_str()));
179   }
180   if (is_double_colon)
181     v.push_back("is_double_colon");
182   if (is_suffix_rule)
183     v.push_back("is_suffix_rule");
184   if (!cmds.empty()) {
185     v.push_back(StringPrintf("cmds=[%s]", JoinValues(cmds, ",").c_str()));
186   }
187   return JoinStrings(v, " ");
188 }
189