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 "expr.h" 18 19 #include <vector> 20 21 #include "eval.h" 22 #include "func.h" 23 #include "log.h" 24 #include "stringprintf.h" 25 #include "strutil.h" 26 #include "var.h" 27 28 Evaluable::Evaluable() {} 29 30 Evaluable::~Evaluable() {} 31 32 string Evaluable::Eval(Evaluator* ev) const { 33 string s; 34 Eval(ev, &s); 35 return s; 36 } 37 38 Value::Value() {} 39 40 Value::~Value() {} 41 42 string Value::DebugString() const { 43 if (static_cast<const Value*>(this)) { 44 return NoLineBreak(DebugString_()); 45 } 46 return "(null)"; 47 } 48 49 class Literal : public Value { 50 public: 51 explicit Literal(StringPiece s) : s_(s) {} 52 53 StringPiece val() const { return s_; } 54 55 virtual void Eval(Evaluator* ev, string* s) const override { 56 ev->CheckStack(); 57 s->append(s_.begin(), s_.end()); 58 } 59 60 virtual bool IsLiteral() const override { return true; } 61 virtual StringPiece GetLiteralValueUnsafe() const override { return s_; } 62 63 virtual string DebugString_() const override { return s_.as_string(); } 64 65 private: 66 StringPiece s_; 67 }; 68 69 class Expr : public Value { 70 public: 71 Expr() {} 72 73 virtual ~Expr() { 74 for (Value* v : vals_) { 75 delete v; 76 } 77 } 78 79 // Takes the ownership of |v|. 80 void AddValue(Value* v) { vals_.push_back(v); } 81 82 virtual void Eval(Evaluator* ev, string* s) const override { 83 ev->CheckStack(); 84 for (Value* v : vals_) { 85 v->Eval(ev, s); 86 } 87 } 88 89 virtual string DebugString_() const override { 90 string r; 91 for (Value* v : vals_) { 92 if (r.empty()) { 93 r += "Expr("; 94 } else { 95 r += ", "; 96 } 97 r += v->DebugString(); 98 } 99 if (!r.empty()) 100 r += ")"; 101 return r; 102 } 103 104 virtual Value* Compact() override { 105 if (vals_.size() != 1) { 106 return this; 107 } 108 Value* r = vals_[0]; 109 vals_.clear(); 110 delete this; 111 return r; 112 } 113 114 private: 115 vector<Value*> vals_; 116 }; 117 118 class SymRef : public Value { 119 public: 120 explicit SymRef(Symbol n) : name_(n) {} 121 virtual ~SymRef() {} 122 123 virtual void Eval(Evaluator* ev, string* s) const override { 124 ev->CheckStack(); 125 Var* v = ev->LookupVar(name_); 126 v->Used(ev, name_); 127 v->Eval(ev, s); 128 } 129 130 virtual string DebugString_() const override { 131 return StringPrintf("SymRef(%s)", name_.c_str()); 132 } 133 134 private: 135 Symbol name_; 136 }; 137 138 class VarRef : public Value { 139 public: 140 explicit VarRef(Value* n) : name_(n) {} 141 virtual ~VarRef() { delete name_; } 142 143 virtual void Eval(Evaluator* ev, string* s) const override { 144 ev->CheckStack(); 145 ev->IncrementEvalDepth(); 146 const string&& name = name_->Eval(ev); 147 ev->DecrementEvalDepth(); 148 Symbol sym = Intern(name); 149 Var* v = ev->LookupVar(sym); 150 v->Used(ev, sym); 151 v->Eval(ev, s); 152 } 153 154 virtual string DebugString_() const override { 155 return StringPrintf("VarRef(%s)", name_->DebugString().c_str()); 156 } 157 158 private: 159 Value* name_; 160 }; 161 162 class VarSubst : public Value { 163 public: 164 explicit VarSubst(Value* n, Value* p, Value* s) 165 : name_(n), pat_(p), subst_(s) {} 166 virtual ~VarSubst() { 167 delete name_; 168 delete pat_; 169 delete subst_; 170 } 171 172 virtual void Eval(Evaluator* ev, string* s) const override { 173 ev->CheckStack(); 174 ev->IncrementEvalDepth(); 175 const string&& name = name_->Eval(ev); 176 Symbol sym = Intern(name); 177 Var* v = ev->LookupVar(sym); 178 const string&& pat_str = pat_->Eval(ev); 179 const string&& subst = subst_->Eval(ev); 180 ev->DecrementEvalDepth(); 181 v->Used(ev, sym); 182 const string&& value = v->Eval(ev); 183 WordWriter ww(s); 184 Pattern pat(pat_str); 185 for (StringPiece tok : WordScanner(value)) { 186 ww.MaybeAddWhitespace(); 187 pat.AppendSubstRef(tok, subst, s); 188 } 189 } 190 191 virtual string DebugString_() const override { 192 return StringPrintf("VarSubst(%s:%s=%s)", name_->DebugString().c_str(), 193 pat_->DebugString().c_str(), 194 subst_->DebugString().c_str()); 195 } 196 197 private: 198 Value* name_; 199 Value* pat_; 200 Value* subst_; 201 }; 202 203 class Func : public Value { 204 public: 205 explicit Func(FuncInfo* fi) : fi_(fi) {} 206 207 ~Func() { 208 for (Value* a : args_) 209 delete a; 210 } 211 212 virtual void Eval(Evaluator* ev, string* s) const override { 213 ev->CheckStack(); 214 LOG("Invoke func %s(%s)", name(), JoinValues(args_, ",").c_str()); 215 ev->IncrementEvalDepth(); 216 fi_->func(args_, ev, s); 217 ev->DecrementEvalDepth(); 218 } 219 220 virtual string DebugString_() const override { 221 return StringPrintf("Func(%s %s)", fi_->name, 222 JoinValues(args_, ",").c_str()); 223 } 224 225 void AddArg(Value* v) { args_.push_back(v); } 226 227 const char* name() const { return fi_->name; } 228 int arity() const { return fi_->arity; } 229 int min_arity() const { return fi_->min_arity; } 230 bool trim_space() const { return fi_->trim_space; } 231 bool trim_right_space_1st() const { return fi_->trim_right_space_1st; } 232 233 private: 234 FuncInfo* fi_; 235 vector<Value*> args_; 236 }; 237 238 static char CloseParen(char c) { 239 switch (c) { 240 case '(': 241 return ')'; 242 case '{': 243 return '}'; 244 } 245 return 0; 246 } 247 248 static size_t SkipSpaces(StringPiece s, const char* terms) { 249 for (size_t i = 0; i < s.size(); i++) { 250 char c = s[i]; 251 if (strchr(terms, c)) 252 return i; 253 if (!isspace(c)) { 254 if (c != '\\') 255 return i; 256 char n = s.get(i + 1); 257 if (n != '\r' && n != '\n') 258 return i; 259 } 260 } 261 return s.size(); 262 } 263 264 bool ShouldHandleComments(ParseExprOpt opt) { 265 return opt != ParseExprOpt::DEFINE && opt != ParseExprOpt::COMMAND; 266 } 267 268 void ParseFunc(const Loc& loc, 269 Func* f, 270 StringPiece s, 271 size_t i, 272 char* terms, 273 size_t* index_out) { 274 terms[1] = ','; 275 terms[2] = '\0'; 276 i += SkipSpaces(s.substr(i), terms); 277 if (i == s.size()) { 278 *index_out = i; 279 return; 280 } 281 282 int nargs = 1; 283 while (true) { 284 if (f->arity() && nargs >= f->arity()) { 285 terms[1] = '\0'; // Drop ','. 286 } 287 288 if (f->trim_space()) { 289 for (; i < s.size(); i++) { 290 if (isspace(s[i])) 291 continue; 292 if (s[i] == '\\') { 293 char c = s.get(i + 1); 294 if (c == '\r' || c == '\n') 295 continue; 296 } 297 break; 298 } 299 } 300 const bool trim_right_space = 301 (f->trim_space() || (nargs == 1 && f->trim_right_space_1st())); 302 size_t n; 303 Value* v = ParseExprImpl(loc, s.substr(i), terms, ParseExprOpt::FUNC, &n, 304 trim_right_space); 305 // TODO: concatLine??? 306 f->AddArg(v); 307 i += n; 308 if (i == s.size()) { 309 ERROR_LOC(loc, 310 "*** unterminated call to function '%s': " 311 "missing '%c'.", 312 f->name(), terms[0]); 313 } 314 nargs++; 315 if (s[i] == terms[0]) { 316 i++; 317 break; 318 } 319 i++; // Should be ','. 320 if (i == s.size()) 321 break; 322 } 323 324 if (nargs <= f->min_arity()) { 325 ERROR_LOC(loc, 326 "*** insufficient number of arguments (%d) to function `%s'.", 327 nargs - 1, f->name()); 328 } 329 330 *index_out = i; 331 return; 332 } 333 334 Value* ParseDollar(const Loc& loc, StringPiece s, size_t* index_out) { 335 CHECK(s.size() >= 2); 336 CHECK(s[0] == '$'); 337 CHECK(s[1] != '$'); 338 339 char cp = CloseParen(s[1]); 340 if (cp == 0) { 341 *index_out = 2; 342 return new SymRef(Intern(s.substr(1, 1))); 343 } 344 345 char terms[] = {cp, ':', ' ', 0}; 346 for (size_t i = 2;;) { 347 size_t n; 348 Value* vname = 349 ParseExprImpl(loc, s.substr(i), terms, ParseExprOpt::NORMAL, &n); 350 i += n; 351 if (s[i] == cp) { 352 *index_out = i + 1; 353 if (vname->IsLiteral()) { 354 Literal* lit = static_cast<Literal*>(vname); 355 Symbol sym = Intern(lit->val()); 356 if (g_flags.enable_kati_warnings) { 357 size_t found = sym.str().find_first_of(" ({"); 358 if (found != string::npos) { 359 KATI_WARN_LOC(loc, "*warning*: variable lookup with '%c': %.*s", 360 sym.str()[found], SPF(s)); 361 } 362 } 363 Value* r = new SymRef(sym); 364 delete lit; 365 return r; 366 } 367 return new VarRef(vname); 368 } 369 370 if (s[i] == ' ' || s[i] == '\\') { 371 // ${func ...} 372 if (vname->IsLiteral()) { 373 Literal* lit = static_cast<Literal*>(vname); 374 if (FuncInfo* fi = GetFuncInfo(lit->val())) { 375 delete lit; 376 Func* func = new Func(fi); 377 ParseFunc(loc, func, s, i + 1, terms, index_out); 378 return func; 379 } else { 380 KATI_WARN_LOC(loc, "*warning*: unknown make function '%.*s': %.*s", 381 SPF(lit->val()), SPF(s)); 382 } 383 } 384 385 // Not a function. Drop ' ' from |terms| and parse it 386 // again. This is inefficient, but this code path should be 387 // rarely used. 388 delete vname; 389 terms[2] = 0; 390 i = 2; 391 continue; 392 } 393 394 if (s[i] == ':') { 395 terms[2] = '\0'; 396 terms[1] = '='; 397 size_t n; 398 Value* pat = 399 ParseExprImpl(loc, s.substr(i + 1), terms, ParseExprOpt::NORMAL, &n); 400 i += 1 + n; 401 if (s[i] == cp) { 402 Expr* v = new Expr; 403 v->AddValue(vname); 404 v->AddValue(new Literal(":")); 405 v->AddValue(pat); 406 *index_out = i + 1; 407 return new VarRef(v); 408 } 409 410 terms[1] = '\0'; 411 Value* subst = 412 ParseExprImpl(loc, s.substr(i + 1), terms, ParseExprOpt::NORMAL, &n); 413 i += 1 + n; 414 *index_out = i + 1; 415 return new VarSubst(vname->Compact(), pat, subst); 416 } 417 418 // GNU make accepts expressions like $((). See unmatched_paren*.mk 419 // for detail. 420 size_t found = s.find(cp); 421 if (found != string::npos) { 422 KATI_WARN_LOC(loc, "*warning*: unmatched parentheses: %.*s", SPF(s)); 423 *index_out = s.size(); 424 return new SymRef(Intern(s.substr(2, found - 2))); 425 } 426 ERROR_LOC(loc, "*** unterminated variable reference."); 427 } 428 } 429 430 Value* ParseExprImpl(const Loc& loc, 431 StringPiece s, 432 const char* terms, 433 ParseExprOpt opt, 434 size_t* index_out, 435 bool trim_right_space) { 436 if (s.get(s.size() - 1) == '\r') 437 s.remove_suffix(1); 438 439 Expr* r = new Expr; 440 size_t b = 0; 441 char save_paren = 0; 442 int paren_depth = 0; 443 size_t i; 444 for (i = 0; i < s.size(); i++) { 445 char c = s[i]; 446 if (terms && strchr(terms, c) && !save_paren) { 447 break; 448 } 449 450 // Handle a comment. 451 if (!terms && c == '#' && ShouldHandleComments(opt)) { 452 if (i > b) 453 r->AddValue(new Literal(s.substr(b, i - b))); 454 bool was_backslash = false; 455 for (; i < s.size() && !(s[i] == '\n' && !was_backslash); i++) { 456 was_backslash = !was_backslash && s[i] == '\\'; 457 } 458 *index_out = i; 459 return r->Compact(); 460 } 461 462 if (c == '$') { 463 if (i + 1 >= s.size()) { 464 break; 465 } 466 467 if (i > b) 468 r->AddValue(new Literal(s.substr(b, i - b))); 469 470 if (s[i + 1] == '$') { 471 r->AddValue(new Literal(StringPiece("$"))); 472 i += 1; 473 b = i + 1; 474 continue; 475 } 476 477 if (terms && strchr(terms, s[i + 1])) { 478 *index_out = i + 1; 479 return r->Compact(); 480 } 481 482 size_t n; 483 Value* v = ParseDollar(loc, s.substr(i), &n); 484 i += n; 485 b = i; 486 i--; 487 r->AddValue(v); 488 continue; 489 } 490 491 if ((c == '(' || c == '{') && opt == ParseExprOpt::FUNC) { 492 char cp = CloseParen(c); 493 if (terms && terms[0] == cp) { 494 paren_depth++; 495 save_paren = cp; 496 terms++; 497 } else if (cp == save_paren) { 498 paren_depth++; 499 } 500 continue; 501 } 502 503 if (c == save_paren) { 504 paren_depth--; 505 if (paren_depth == 0) { 506 terms--; 507 save_paren = 0; 508 } 509 } 510 511 if (c == '\\' && i + 1 < s.size() && opt != ParseExprOpt::COMMAND) { 512 char n = s[i + 1]; 513 if (n == '\\') { 514 i++; 515 continue; 516 } 517 if (n == '#' && ShouldHandleComments(opt)) { 518 r->AddValue(new Literal(s.substr(b, i - b))); 519 i++; 520 b = i; 521 continue; 522 } 523 if (n == '\r' || n == '\n') { 524 if (terms && strchr(terms, ' ')) { 525 break; 526 } 527 if (i > b) { 528 r->AddValue(new Literal(TrimRightSpace(s.substr(b, i - b)))); 529 } 530 r->AddValue(new Literal(StringPiece(" "))); 531 // Skip the current escaped newline 532 i += 2; 533 if (n == '\r' && s.get(i) == '\n') 534 i++; 535 // Then continue skipping escaped newlines, spaces, and tabs 536 for (; i < s.size(); i++) { 537 if (s[i] == '\\' && (s.get(i + 1) == '\r' || s.get(i + 1) == '\n')) { 538 i++; 539 continue; 540 } 541 if (s[i] != ' ' && s[i] != '\t') { 542 break; 543 } 544 } 545 b = i; 546 i--; 547 } 548 } 549 } 550 551 if (i > b) { 552 StringPiece rest = s.substr(b, i - b); 553 if (trim_right_space) 554 rest = TrimRightSpace(rest); 555 if (!rest.empty()) 556 r->AddValue(new Literal(rest)); 557 } 558 *index_out = i; 559 return r->Compact(); 560 } 561 562 Value* ParseExpr(const Loc& loc, StringPiece s, ParseExprOpt opt) { 563 size_t n; 564 return ParseExprImpl(loc, s, NULL, opt, &n); 565 } 566 567 string JoinValues(const vector<Value*>& vals, const char* sep) { 568 vector<string> val_strs; 569 for (Value* v : vals) { 570 val_strs.push_back(v->DebugString()); 571 } 572 return JoinStrings(val_strs, sep); 573 } 574 575 Value* NewExpr2(Value* v1, Value* v2) { 576 Expr* e = new Expr(); 577 e->AddValue(v1); 578 e->AddValue(v2); 579 return e; 580 } 581 582 Value* NewExpr3(Value* v1, Value* v2, Value* v3) { 583 Expr* e = new Expr(); 584 e->AddValue(v1); 585 e->AddValue(v2); 586 e->AddValue(v3); 587 return e; 588 } 589 590 Value* NewLiteral(StringPiece s) { 591 return new Literal(s); 592 } 593