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 "eval.h"
     18 
     19 #include <errno.h>
     20 #include <string.h>
     21 
     22 #include "expr.h"
     23 #include "file.h"
     24 #include "file_cache.h"
     25 #include "fileutil.h"
     26 #include "parser.h"
     27 #include "rule.h"
     28 #include "stmt.h"
     29 #include "strutil.h"
     30 #include "symtab.h"
     31 #include "var.h"
     32 
     33 Evaluator::Evaluator()
     34     : last_rule_(NULL),
     35       current_scope_(NULL),
     36       avoid_io_(false),
     37       eval_depth_(0) {
     38 }
     39 
     40 Evaluator::~Evaluator() {
     41   // delete vars_;
     42   // for (auto p : rule_vars) {
     43   //   delete p.second;
     44   // }
     45 }
     46 
     47 Var* Evaluator::EvalRHS(Symbol lhs, Value* rhs_v, StringPiece orig_rhs,
     48                         AssignOp op, bool is_override) {
     49   VarOrigin origin = (
     50       (is_bootstrap_ ? VarOrigin::DEFAULT :
     51        is_override ? VarOrigin::OVERRIDE : VarOrigin::FILE));
     52 
     53   Var* rhs = NULL;
     54   bool needs_assign = true;
     55   switch (op) {
     56     case AssignOp::COLON_EQ: {
     57       SimpleVar* sv = new SimpleVar(origin);
     58       rhs_v->Eval(this, sv->mutable_value());
     59       rhs = sv;
     60       break;
     61     }
     62     case AssignOp::EQ:
     63       rhs = new RecursiveVar(rhs_v, origin, orig_rhs);
     64       break;
     65     case AssignOp::PLUS_EQ: {
     66       Var* prev = LookupVarInCurrentScope(lhs);
     67       if (!prev->IsDefined()) {
     68         rhs = new RecursiveVar(rhs_v, origin, orig_rhs);
     69       } else {
     70         prev->AppendVar(this, rhs_v);
     71         rhs = prev;
     72         needs_assign = false;
     73       }
     74       break;
     75     }
     76     case AssignOp::QUESTION_EQ: {
     77       Var* prev = LookupVarInCurrentScope(lhs);
     78       if (!prev->IsDefined()) {
     79         rhs = new RecursiveVar(rhs_v, origin, orig_rhs);
     80       } else {
     81         rhs = prev;
     82         needs_assign = false;
     83       }
     84       break;
     85     }
     86   }
     87 
     88   LOG("Assign: %s=%s", lhs.c_str(), rhs->DebugString().c_str());
     89   if (needs_assign) {
     90     return rhs;
     91   }
     92   return NULL;
     93 }
     94 
     95 void Evaluator::EvalAssign(const AssignStmt* stmt) {
     96   loc_ = stmt->loc();
     97   last_rule_ = NULL;
     98   Symbol lhs = stmt->GetLhsSymbol(this);
     99   if (lhs.empty())
    100     Error("*** empty variable name.");
    101   Var* rhs = EvalRHS(lhs, stmt->rhs, stmt->orig_rhs, stmt->op,
    102                      stmt->directive == AssignDirective::OVERRIDE);
    103   if (rhs)
    104     lhs.SetGlobalVar(rhs);
    105 }
    106 
    107 void Evaluator::EvalRule(const RuleStmt* stmt) {
    108   loc_ = stmt->loc();
    109   last_rule_ = NULL;
    110 
    111   const string&& expr = stmt->expr->Eval(this);
    112   // See semicolon.mk.
    113   if (expr.find_first_not_of(" \t;") == string::npos) {
    114     if (stmt->term == ';')
    115       Error("*** missing rule before commands.");
    116     return;
    117   }
    118 
    119   Rule* rule;
    120   RuleVarAssignment rule_var;
    121   ParseRule(loc_, expr, stmt->term, &rule, &rule_var);
    122 
    123   if (rule) {
    124     if (stmt->term == ';') {
    125       rule->cmds.push_back(stmt->after_term);
    126     }
    127 
    128     LOG("Rule: %s", rule->DebugString().c_str());
    129     rules_.push_back(rule);
    130     last_rule_ = rule;
    131     return;
    132   }
    133 
    134   Symbol lhs = Intern(rule_var.lhs);
    135   for (Symbol output : rule_var.outputs) {
    136     auto p = rule_vars_.emplace(output, nullptr);
    137     if (p.second) {
    138       p.first->second = new Vars;
    139     }
    140 
    141     Value* rhs = stmt->after_term;
    142     if (!rule_var.rhs.empty()) {
    143       Value* lit = NewLiteral(rule_var.rhs);
    144       if (rhs) {
    145         // TODO: We always insert two whitespaces around the
    146         // terminator. Preserve whitespaces properly.
    147         if (stmt->term == ';') {
    148           rhs = NewExpr3(lit, NewLiteral(StringPiece(" ; ")), rhs);
    149         } else {
    150           rhs = NewExpr3(lit, NewLiteral(StringPiece(" = ")), rhs);
    151         }
    152       } else {
    153         rhs = lit;
    154       }
    155     }
    156 
    157     current_scope_ = p.first->second;
    158     Var* rhs_var = EvalRHS(lhs, rhs, StringPiece("*TODO*"), rule_var.op);
    159     if (rhs_var)
    160       current_scope_->Assign(lhs, new RuleVar(rhs_var, rule_var.op));
    161     current_scope_ = NULL;
    162   }
    163 }
    164 
    165 void Evaluator::EvalCommand(const CommandStmt* stmt) {
    166   loc_ = stmt->loc();
    167 
    168   if (!last_rule_) {
    169     vector<Stmt*> stmts;
    170     ParseNotAfterRule(stmt->orig, stmt->loc(), &stmts);
    171     for (Stmt* a : stmts)
    172       a->Eval(this);
    173     return;
    174   }
    175 
    176   last_rule_->cmds.push_back(stmt->expr);
    177   if (last_rule_->cmd_lineno == 0)
    178     last_rule_->cmd_lineno = stmt->loc().lineno;
    179   LOG("Command: %s", stmt->expr->DebugString().c_str());
    180 }
    181 
    182 void Evaluator::EvalIf(const IfStmt* stmt) {
    183   loc_ = stmt->loc();
    184 
    185   bool is_true;
    186   switch (stmt->op) {
    187     case CondOp::IFDEF:
    188     case CondOp::IFNDEF: {
    189       string var_name;
    190       stmt->lhs->Eval(this, &var_name);
    191       Symbol lhs = Intern(TrimRightSpace(var_name));
    192       if (lhs.str().find_first_of(" \t") != string::npos)
    193         Error("*** invalid syntax in conditional.");
    194       Var* v = LookupVarInCurrentScope(lhs);
    195       const string&& s = v->Eval(this);
    196       is_true = (s.empty() == (stmt->op == CondOp::IFNDEF));
    197       break;
    198     }
    199     case CondOp::IFEQ:
    200     case CondOp::IFNEQ: {
    201       const string&& lhs = stmt->lhs->Eval(this);
    202       const string&& rhs = stmt->rhs->Eval(this);
    203       is_true = ((lhs == rhs) == (stmt->op == CondOp::IFEQ));
    204       break;
    205     }
    206     default:
    207       CHECK(false);
    208       abort();
    209   }
    210 
    211   const vector<Stmt*>* stmts;
    212   if (is_true) {
    213     stmts = &stmt->true_stmts;
    214   } else {
    215     stmts = &stmt->false_stmts;
    216   }
    217   for (Stmt* a : *stmts) {
    218     LOG("%s", a->DebugString().c_str());
    219     a->Eval(this);
    220   }
    221 }
    222 
    223 void Evaluator::DoInclude(const string& fname) {
    224   Makefile* mk = MakefileCacheManager::Get()->ReadMakefile(fname);
    225   CHECK(mk->Exists());
    226 
    227   Var* var_list = LookupVar(Intern("MAKEFILE_LIST"));
    228   var_list->AppendVar(this, NewLiteral(Intern(TrimLeadingCurdir(fname)).str()));
    229   for (Stmt* stmt : mk->stmts()) {
    230     LOG("%s", stmt->DebugString().c_str());
    231     stmt->Eval(this);
    232   }
    233 }
    234 
    235 void Evaluator::EvalInclude(const IncludeStmt* stmt) {
    236   loc_ = stmt->loc();
    237   last_rule_ = NULL;
    238 
    239   const string&& pats = stmt->expr->Eval(this);
    240   for (StringPiece pat : WordScanner(pats)) {
    241     ScopedTerminator st(pat);
    242     vector<string>* files;
    243     Glob(pat.data(), &files);
    244 
    245     if (stmt->should_exist) {
    246       if (files->empty()) {
    247         // TOOD: Kati does not support building a missing include file.
    248         Error(StringPrintf("%s: %s", pat.data(), strerror(errno)));
    249       }
    250     }
    251 
    252     for (const string& fname : *files) {
    253       if (!stmt->should_exist && g_flags.ignore_optional_include_pattern &&
    254           Pattern(g_flags.ignore_optional_include_pattern).Match(fname)) {
    255         return;
    256       }
    257       DoInclude(fname);
    258     }
    259   }
    260 }
    261 
    262 void Evaluator::EvalExport(const ExportStmt* stmt) {
    263   loc_ = stmt->loc();
    264   last_rule_ = NULL;
    265 
    266   const string&& exports = stmt->expr->Eval(this);
    267   for (StringPiece tok : WordScanner(exports)) {
    268     size_t equal_index = tok.find('=');
    269     if (equal_index == string::npos) {
    270       exports_[Intern(tok)] = stmt->is_export;
    271     } else if (equal_index == 0 ||
    272                (equal_index == 1 &&
    273                 (tok[0] == ':' || tok[0] == '?' || tok[0] == '+'))) {
    274       // Do not export tokens after an assignment.
    275       break;
    276     } else {
    277       StringPiece lhs, rhs;
    278       AssignOp op;
    279       ParseAssignStatement(tok, equal_index, &lhs, &rhs, &op);
    280       exports_[Intern(lhs)] = stmt->is_export;
    281     }
    282   }
    283 }
    284 
    285 Var* Evaluator::LookupVarGlobal(Symbol name) {
    286   Var* v = name.GetGlobalVar();
    287   if (v->IsDefined())
    288     return v;
    289   used_undefined_vars_.insert(name);
    290   return v;
    291 }
    292 
    293 Var* Evaluator::LookupVar(Symbol name) {
    294   if (current_scope_) {
    295     Var* v = current_scope_->Lookup(name);
    296     if (v->IsDefined())
    297       return v;
    298   }
    299   return LookupVarGlobal(name);
    300 }
    301 
    302 Var* Evaluator::LookupVarInCurrentScope(Symbol name) {
    303   if (current_scope_) {
    304     return current_scope_->Lookup(name);
    305   }
    306   return LookupVarGlobal(name);
    307 }
    308 
    309 string Evaluator::EvalVar(Symbol name) {
    310   return LookupVar(name)->Eval(this);
    311 }
    312 
    313 void Evaluator::Error(const string& msg) {
    314   ERROR("%s:%d: %s", LOCF(loc_), msg.c_str());
    315 }
    316 
    317 unordered_set<Symbol> Evaluator::used_undefined_vars_;
    318