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 "command.h"
     18 
     19 #include <unordered_map>
     20 #include <unordered_set>
     21 
     22 #include "dep.h"
     23 #include "eval.h"
     24 #include "flags.h"
     25 #include "log.h"
     26 #include "strutil.h"
     27 #include "var.h"
     28 
     29 namespace {
     30 
     31 class AutoVar : public Var {
     32  public:
     33   virtual const char* Flavor() const override {
     34     return "undefined";
     35   }
     36   virtual VarOrigin Origin() const override {
     37     return VarOrigin::AUTOMATIC;
     38   }
     39 
     40   virtual void AppendVar(Evaluator*, Value*) override { CHECK(false); }
     41 
     42   virtual StringPiece String() const override {
     43     ERROR("$(value %s) is not implemented yet", sym_);
     44     return "";
     45   }
     46 
     47   virtual string DebugString() const override {
     48     return string("AutoVar(") + sym_ + ")";
     49   }
     50 
     51  protected:
     52   AutoVar(CommandEvaluator* ce, const char* sym) : ce_(ce), sym_(sym) {}
     53   virtual ~AutoVar() = default;
     54 
     55   CommandEvaluator* ce_;
     56   const char* sym_;
     57 };
     58 
     59 #define DECLARE_AUTO_VAR_CLASS(name)                                    \
     60   class name : public AutoVar {                                         \
     61    public:                                                              \
     62    name(CommandEvaluator* ce, const char* sym)                          \
     63        : AutoVar(ce, sym) {}                                            \
     64    virtual ~name() = default;                                           \
     65    virtual void Eval(Evaluator* ev, string* s) const override;          \
     66   }
     67 
     68 DECLARE_AUTO_VAR_CLASS(AutoAtVar);
     69 DECLARE_AUTO_VAR_CLASS(AutoLessVar);
     70 DECLARE_AUTO_VAR_CLASS(AutoHatVar);
     71 DECLARE_AUTO_VAR_CLASS(AutoPlusVar);
     72 DECLARE_AUTO_VAR_CLASS(AutoStarVar);
     73 DECLARE_AUTO_VAR_CLASS(AutoNotImplementedVar);
     74 
     75 class AutoSuffixDVar : public AutoVar {
     76  public:
     77   AutoSuffixDVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
     78       : AutoVar(ce, sym), wrapped_(wrapped) {
     79   }
     80   virtual ~AutoSuffixDVar() = default;
     81   virtual void Eval(Evaluator* ev, string* s) const override;
     82 
     83  private:
     84   Var* wrapped_;
     85 };
     86 
     87 class AutoSuffixFVar : public AutoVar {
     88  public:
     89   AutoSuffixFVar(CommandEvaluator* ce, const char* sym, Var* wrapped)
     90       : AutoVar(ce, sym), wrapped_(wrapped) {}
     91   virtual ~AutoSuffixFVar() = default;
     92   virtual void Eval(Evaluator* ev, string* s) const override;
     93 
     94  private:
     95   Var* wrapped_;
     96 };
     97 
     98 void AutoAtVar::Eval(Evaluator*, string* s) const {
     99   *s += ce_->current_dep_node()->output.str();
    100 }
    101 
    102 void AutoLessVar::Eval(Evaluator*, string* s) const {
    103   auto& ai = ce_->current_dep_node()->actual_inputs;
    104   if (!ai.empty())
    105     *s += ai[0].str();
    106 }
    107 
    108 void AutoHatVar::Eval(Evaluator*, string* s) const {
    109   unordered_set<StringPiece> seen;
    110   WordWriter ww(s);
    111   for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
    112     if (seen.insert(ai.str()).second)
    113       ww.Write(ai.str());
    114   }
    115 }
    116 
    117 void AutoPlusVar::Eval(Evaluator*, string* s) const {
    118   WordWriter ww(s);
    119   for (Symbol ai : ce_->current_dep_node()->actual_inputs) {
    120     ww.Write(ai.str());
    121   }
    122 }
    123 
    124 void AutoStarVar::Eval(Evaluator*, string* s) const {
    125   const DepNode* n = ce_->current_dep_node();
    126   if (!n->output_pattern.IsValid())
    127     return;
    128   Pattern pat(n->output_pattern.str());
    129   pat.Stem(n->output.str()).AppendToString(s);
    130 }
    131 
    132 void AutoNotImplementedVar::Eval(Evaluator* ev, string*) const {
    133   ev->Error(StringPrintf(
    134       "Automatic variable `$%s' isn't supported yet", sym_));
    135 }
    136 
    137 void AutoSuffixDVar::Eval(Evaluator* ev, string* s) const {
    138   string buf;
    139   wrapped_->Eval(ev, &buf);
    140   WordWriter ww(s);
    141   for (StringPiece tok : WordScanner(buf)) {
    142     ww.Write(Dirname(tok));
    143   }
    144 }
    145 
    146 void AutoSuffixFVar::Eval(Evaluator* ev, string* s) const {
    147   string buf;
    148   wrapped_->Eval(ev, &buf);
    149   WordWriter ww(s);
    150   for (StringPiece tok : WordScanner(buf)) {
    151     ww.Write(Basename(tok));
    152   }
    153 }
    154 
    155 void ParseCommandPrefixes(StringPiece* s, bool* echo, bool* ignore_error) {
    156   *s = TrimLeftSpace(*s);
    157   while (true) {
    158     char c = s->get(0);
    159     if (c == '@') {
    160       *echo = false;
    161     } else if (c == '-') {
    162       *ignore_error = true;
    163     } else if (c == '+') {
    164       // ignore recursion marker
    165     } else {
    166       break;
    167     }
    168     *s = TrimLeftSpace(s->substr(1));
    169   }
    170 }
    171 
    172 }  // namespace
    173 
    174 CommandEvaluator::CommandEvaluator(Evaluator* ev)
    175     : ev_(ev) {
    176 #define INSERT_AUTO_VAR(name, sym) do {                                 \
    177     Var* v = new name(this, sym);                                       \
    178     Intern(sym).SetGlobalVar(v);                                        \
    179     Intern(sym"D").SetGlobalVar(new AutoSuffixDVar(this, sym"D", v));   \
    180     Intern(sym"F").SetGlobalVar(new AutoSuffixFVar(this, sym"F", v));   \
    181   } while (0)
    182   INSERT_AUTO_VAR(AutoAtVar, "@");
    183   INSERT_AUTO_VAR(AutoLessVar, "<");
    184   INSERT_AUTO_VAR(AutoHatVar, "^");
    185   INSERT_AUTO_VAR(AutoPlusVar, "+");
    186   INSERT_AUTO_VAR(AutoStarVar, "*");
    187   // TODO: Implement them.
    188   INSERT_AUTO_VAR(AutoNotImplementedVar, "%");
    189   INSERT_AUTO_VAR(AutoNotImplementedVar, "?");
    190   INSERT_AUTO_VAR(AutoNotImplementedVar, "|");
    191 }
    192 
    193 void CommandEvaluator::Eval(DepNode* n, vector<Command*>* commands) {
    194   ev_->set_loc(n->loc);
    195   ev_->set_current_scope(n->rule_vars);
    196   current_dep_node_ = n;
    197   for (Value* v : n->cmds) {
    198     const string&& cmds_buf = v->Eval(ev_);
    199     StringPiece cmds = cmds_buf;
    200     bool global_echo = !g_flags.is_silent_mode;
    201     bool global_ignore_error = false;
    202     ParseCommandPrefixes(&cmds, &global_echo, &global_ignore_error);
    203     if (cmds == "")
    204       continue;
    205     while (true) {
    206       size_t lf_cnt;
    207       size_t index = FindEndOfLine(cmds, 0, &lf_cnt);
    208       if (index == cmds.size())
    209         index = string::npos;
    210       StringPiece cmd = TrimLeftSpace(cmds.substr(0, index));
    211       cmds = cmds.substr(index + 1);
    212 
    213       bool echo = global_echo;
    214       bool ignore_error = global_ignore_error;
    215       ParseCommandPrefixes(&cmd, &echo, &ignore_error);
    216 
    217       if (!cmd.empty()) {
    218         Command* command = new Command(n->output);
    219         command->cmd = cmd.as_string();
    220         command->echo = echo;
    221         command->ignore_error = ignore_error;
    222         commands->push_back(command);
    223       }
    224       if (index == string::npos)
    225         break;
    226     }
    227     continue;
    228   }
    229 
    230   if (!ev_->delayed_output_commands().empty()) {
    231     vector<Command*> output_commands;
    232     for (const string& cmd : ev_->delayed_output_commands()) {
    233       Command* c = new Command(n->output);
    234       c->cmd = cmd;
    235       c->echo = false;
    236       c->ignore_error = false;
    237       output_commands.push_back(c);
    238     }
    239     // Prepend |output_commands|.
    240     commands->swap(output_commands);
    241     copy(output_commands.begin(), output_commands.end(),
    242          back_inserter(*commands));
    243     ev_->clear_delayed_output_commands();
    244   }
    245 
    246   ev_->set_current_scope(NULL);
    247 }
    248