Home | History | Annotate | Download | only in kati
      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 
     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 
     44 bool IsPatternRule(StringPiece s) {
     45   return s.find('%') != string::npos;
     46 }
     47 
     48 }  // namespace
     49 
     50 Rule::Rule()
     51     : is_double_colon(false),
     52       is_suffix_rule(false),
     53       cmd_lineno(0) {
     54 }
     55 
     56 void ParseRule(Loc& loc, StringPiece line, char term,
     57                Rule** out_rule, RuleVarAssignment* rule_var) {
     58   size_t index = line.find(':');
     59   if (index == string::npos) {
     60     ERROR("%s:%d: *** missing separator.", LOCF(loc));
     61   }
     62 
     63   StringPiece first = line.substr(0, index);
     64   vector<Symbol> outputs;
     65   for (StringPiece tok : WordScanner(first)) {
     66     outputs.push_back(Intern(TrimLeadingCurdir(tok)));
     67   }
     68 
     69   const bool is_first_pattern = (
     70       !outputs.empty() && IsPatternRule(outputs[0].str()));
     71   for (size_t i = 1; i < outputs.size(); i++) {
     72     if (IsPatternRule(outputs[i].str()) != is_first_pattern) {
     73       ERROR("%s:%d: *** mixed implicit and normal rules: deprecated syntax",
     74             LOCF(loc));
     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   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();
     91     rule_var->outputs.swap(outputs);
     92     ParseAssignStatement(rest, term_index,
     93                          &rule_var->lhs, &rule_var->rhs, &rule_var->op);
     94     *out_rule = NULL;
     95     return;
     96   }
     97 
     98   Rule* rule = new Rule();
     99   *out_rule = rule;
    100   rule->loc = loc;
    101   rule->is_double_colon = is_double_colon;
    102   if (is_first_pattern) {
    103     rule->output_patterns.swap(outputs);
    104   } else {
    105     rule->outputs.swap(outputs);
    106   }
    107   if (term_index != string::npos && term != ';') {
    108     CHECK(rest[term_index] == ';');
    109     // TODO: Maybe better to avoid Intern here?
    110     rule->cmds.push_back(
    111         NewLiteral(Intern(TrimLeftSpace(rest.substr(term_index + 1))).str()));
    112     rest = rest.substr(0, term_index);
    113   }
    114 
    115   index = rest.find(':');
    116   if (index == string::npos) {
    117     ParseInputs(rule, rest);
    118     return;
    119   }
    120 
    121   if (is_first_pattern) {
    122     ERROR("%s:%d: *** mixed implicit and normal rules: deprecated syntax",
    123           LOCF(loc));
    124   }
    125 
    126   StringPiece second = rest.substr(0, index);
    127   StringPiece third = rest.substr(index+1);
    128 
    129   for (StringPiece tok : WordScanner(second)) {
    130     tok = TrimLeadingCurdir(tok);
    131     for (Symbol output : rule->outputs) {
    132       if (!Pattern(tok).Match(output.str())) {
    133         WARN("%s:%d: target `%s' doesn't match the target pattern",
    134              LOCF(loc), output.c_str());
    135       }
    136     }
    137 
    138     rule->output_patterns.push_back(Intern(tok));
    139   }
    140 
    141   if (rule->output_patterns.empty()) {
    142     ERROR("%s:%d: *** missing target pattern.", LOCF(loc));
    143   }
    144   if (rule->output_patterns.size() > 1) {
    145     ERROR("%s:%d: *** multiple target patterns.", LOCF(loc));
    146   }
    147   if (!IsPatternRule(rule->output_patterns[0].str())) {
    148     ERROR("%s:%d: *** target pattern contains no '%%'.", LOCF(loc));
    149   }
    150   ParseInputs(rule, third);
    151 }
    152 
    153 string Rule::DebugString() const {
    154   vector<string> v;
    155   v.push_back(StringPrintf("outputs=[%s]", JoinSymbols(outputs, ",").c_str()));
    156   v.push_back(StringPrintf("inputs=[%s]", JoinSymbols(inputs, ",").c_str()));
    157   if (!order_only_inputs.empty()) {
    158     v.push_back(StringPrintf("order_only_inputs=[%s]",
    159                              JoinSymbols(order_only_inputs, ",").c_str()));
    160   }
    161   if (!output_patterns.empty()) {
    162     v.push_back(StringPrintf("output_patterns=[%s]",
    163                              JoinSymbols(output_patterns, ",").c_str()));
    164   }
    165   if (is_double_colon)
    166     v.push_back("is_double_colon");
    167   if (is_suffix_rule)
    168     v.push_back("is_suffix_rule");
    169   if (!cmds.empty()) {
    170     v.push_back(StringPrintf("cmds=[%s]", JoinValues(cmds, ",").c_str()));
    171   }
    172   return JoinStrings(v, " ");
    173 }
    174