func.cc revision 0d8e79b7753a89ac6beaf638a535ec63f1941444
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 "func.h" 18 19#include <glob.h> 20#include <limits.h> 21#include <stdio.h> 22#include <stdlib.h> 23 24#include <algorithm> 25#include <iterator> 26#include <memory> 27#include <unordered_map> 28 29#include "ast.h" 30#include "eval.h" 31#include "log.h" 32#include "parser.h" 33#include "stats.h" 34#include "strutil.h" 35#include "symtab.h" 36#include "var.h" 37 38namespace { 39 40void PatsubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 41 shared_ptr<string> pat_str = args[0]->Eval(ev); 42 shared_ptr<string> repl = args[1]->Eval(ev); 43 shared_ptr<string> str = args[2]->Eval(ev); 44 WordWriter ww(s); 45 Pattern pat(*pat_str); 46 for (StringPiece tok : WordScanner(*str)) { 47 ww.MaybeAddWhitespace(); 48 pat.AppendSubst(tok, *repl, s); 49 } 50} 51 52void StripFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 53 shared_ptr<string> str = args[0]->Eval(ev); 54 WordWriter ww(s); 55 for (StringPiece tok : WordScanner(*str)) { 56 ww.Write(tok); 57 } 58} 59 60void SubstFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 61 shared_ptr<string> pat = args[0]->Eval(ev); 62 shared_ptr<string> repl = args[1]->Eval(ev); 63 shared_ptr<string> str = args[2]->Eval(ev); 64 size_t index = 0; 65 while (index < str->size()) { 66 size_t found = str->find(*pat, index); 67 if (found == string::npos) 68 break; 69 AppendString(StringPiece(*str).substr(index, found - index), s); 70 AppendString(*repl, s); 71 index = found + pat->size(); 72 } 73 AppendString(StringPiece(*str).substr(index), s); 74} 75 76void FindstringFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 77 shared_ptr<string> find = args[0]->Eval(ev); 78 shared_ptr<string> in = args[1]->Eval(ev); 79 if (in->find(*find) != string::npos) 80 AppendString(*find, s); 81} 82 83void FilterFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 84 shared_ptr<string> pat_buf = args[0]->Eval(ev); 85 shared_ptr<string> text = args[1]->Eval(ev); 86 vector<Pattern> pats; 87 for (StringPiece pat : WordScanner(*pat_buf)) { 88 pats.push_back(Pattern(pat)); 89 } 90 WordWriter ww(s); 91 for (StringPiece tok : WordScanner(*text)) { 92 for (const Pattern& pat : pats) { 93 if (pat.Match(tok)) { 94 ww.Write(tok); 95 break; 96 } 97 } 98 } 99} 100 101void FilterOutFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 102 shared_ptr<string> pat_buf = args[0]->Eval(ev); 103 shared_ptr<string> text = args[1]->Eval(ev); 104 vector<Pattern> pats; 105 for (StringPiece pat : WordScanner(*pat_buf)) { 106 pats.push_back(Pattern(pat)); 107 } 108 WordWriter ww(s); 109 for (StringPiece tok : WordScanner(*text)) { 110 bool matched = false; 111 for (const Pattern& pat : pats) { 112 if (pat.Match(tok)) { 113 matched = true; 114 break; 115 } 116 } 117 if (!matched) 118 ww.Write(tok); 119 } 120} 121 122void SortFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 123 shared_ptr<string> list = args[0]->Eval(ev); 124 vector<StringPiece> toks; 125 WordScanner(*list).Split(&toks); 126 sort(toks.begin(), toks.end()); 127 WordWriter ww(s); 128 StringPiece prev; 129 for (StringPiece tok : toks) { 130 if (prev != tok) { 131 ww.Write(tok); 132 prev = tok; 133 } 134 } 135} 136 137static int GetNumericValueForFunc(const string& buf) { 138 StringPiece s = TrimLeftSpace(buf); 139 char* end; 140 long n = strtol(s.data(), &end, 10); 141 if (n < 0 || n == LONG_MAX || s.data() + s.size() != end) { 142 return -1; 143 } 144 return n; 145} 146 147void WordFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 148 shared_ptr<string> n_str = args[0]->Eval(ev); 149 int n = GetNumericValueForFunc(*n_str); 150 if (n < 0) { 151 ev->Error(StringPrintf( 152 "*** non-numeric first argument to `word' function: '%s'.", 153 n_str->c_str())); 154 } 155 if (n == 0) { 156 ev->Error("*** first argument to `word' function must be greater than 0."); 157 } 158 159 shared_ptr<string> text = args[1]->Eval(ev); 160 for (StringPiece tok : WordScanner(*text)) { 161 n--; 162 if (n == 0) { 163 AppendString(tok, s); 164 break; 165 } 166 } 167} 168 169void WordlistFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 170 shared_ptr<string> s_str = args[0]->Eval(ev); 171 int si = GetNumericValueForFunc(*s_str); 172 if (si < 0) { 173 ev->Error(StringPrintf( 174 "*** non-numeric first argument to `wordlist' function: '%s'.", 175 s_str->c_str())); 176 } 177 if (si == 0) { 178 ev->Error(StringPrintf( 179 "*** invalid first argument to `wordlist' function: %s`", 180 s_str->c_str())); 181 } 182 183 shared_ptr<string> e_str = args[1]->Eval(ev); 184 int ei = GetNumericValueForFunc(*e_str); 185 if (ei < 0) { 186 ev->Error(StringPrintf( 187 "*** non-numeric second argument to `wordlist' function: '%s'.", 188 e_str->c_str())); 189 } 190 191 shared_ptr<string> text = args[2]->Eval(ev); 192 int i = 0; 193 WordWriter ww(s); 194 for (StringPiece tok : WordScanner(*text)) { 195 i++; 196 if (si <= i && i <= ei) { 197 ww.Write(tok); 198 } 199 } 200} 201 202void WordsFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 203 shared_ptr<string> text = args[0]->Eval(ev); 204 WordScanner ws(*text); 205 int n = 0; 206 for (auto iter = ws.begin(); iter != ws.end(); ++iter) 207 n++; 208 char buf[32]; 209 sprintf(buf, "%d", n); 210 *s += buf; 211} 212 213void FirstwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 214 shared_ptr<string> text = args[0]->Eval(ev); 215 for (StringPiece tok : WordScanner(*text)) { 216 AppendString(tok, s); 217 return; 218 } 219} 220 221void LastwordFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 222 shared_ptr<string> text = args[0]->Eval(ev); 223 StringPiece last; 224 for (StringPiece tok : WordScanner(*text)) { 225 last = tok; 226 } 227 AppendString(last, s); 228} 229 230void JoinFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 231 shared_ptr<string> list1 = args[0]->Eval(ev); 232 shared_ptr<string> list2 = args[1]->Eval(ev); 233 WordScanner ws1(*list1); 234 WordScanner ws2(*list2); 235 WordWriter ww(s); 236 for (WordScanner::Iterator iter1 = ws1.begin(), iter2 = ws2.begin(); 237 iter1 != ws1.end() && iter2 != ws2.end(); 238 ++iter1, ++iter2) { 239 ww.Write(*iter1); 240 // Use |AppendString| not to append extra ' '. 241 AppendString(*iter2, s); 242 } 243} 244 245void WildcardFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 246 COLLECT_STATS("func wildcard time"); 247 shared_ptr<string> pat = args[0]->Eval(ev); 248 if (ev->avoid_io()) { 249 *s += "$(/bin/ls -d "; 250 *s += *pat; 251 *s += " 2> /dev/null)"; 252 return; 253 } 254 255 WordWriter ww(s); 256 vector<const char*> files; 257 for (StringPiece tok : WordScanner(*pat)) { 258 ScopedTerminator st(tok); 259 // TODO: Make this faster by not always using glob. 260 files.clear(); 261 glob_t gl; 262 glob(tok.data(), GLOB_NOSORT, NULL, &gl); 263 for (size_t i = 0; i < gl.gl_pathc; i++) { 264 files.push_back(gl.gl_pathv[i]); 265 } 266 sort(files.begin(), files.end(), 267 [](const char* a, const char* b) { 268 return strcmp(a, b) < 0; 269 }); 270 for (const char* file : files) { 271 ww.Write(file); 272 } 273 274 globfree(&gl); 275 } 276} 277 278void DirFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 279 shared_ptr<string> text = args[0]->Eval(ev); 280 WordWriter ww(s); 281 for (StringPiece tok : WordScanner(*text)) { 282 ww.Write(Dirname(tok)); 283 s->push_back('/'); 284 } 285} 286 287void NotdirFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 288 shared_ptr<string> text = args[0]->Eval(ev); 289 WordWriter ww(s); 290 for (StringPiece tok : WordScanner(*text)) { 291 if (tok == "/") { 292 ww.Write(STRING_PIECE("")); 293 } else { 294 ww.Write(Basename(tok)); 295 } 296 } 297} 298 299void SuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 300 shared_ptr<string> text = args[0]->Eval(ev); 301 WordWriter ww(s); 302 for (StringPiece tok : WordScanner(*text)) { 303 StringPiece suf = GetExt(tok); 304 if (!suf.empty()) 305 ww.Write(suf); 306 } 307} 308 309void BasenameFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 310 shared_ptr<string> text = args[0]->Eval(ev); 311 WordWriter ww(s); 312 for (StringPiece tok : WordScanner(*text)) { 313 ww.Write(StripExt(tok)); 314 } 315} 316 317void AddsuffixFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 318 shared_ptr<string> suf = args[0]->Eval(ev); 319 shared_ptr<string> text = args[1]->Eval(ev); 320 WordWriter ww(s); 321 for (StringPiece tok : WordScanner(*text)) { 322 ww.Write(tok); 323 *s += *suf; 324 } 325} 326 327void AddprefixFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 328 shared_ptr<string> pre = args[0]->Eval(ev); 329 shared_ptr<string> text = args[1]->Eval(ev); 330 WordWriter ww(s); 331 for (StringPiece tok : WordScanner(*text)) { 332 ww.Write(*pre); 333 AppendString(tok, s); 334 } 335} 336 337void RealpathFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 338 shared_ptr<string> text = args[0]->Eval(ev); 339 if (ev->avoid_io()) { 340 *s += "KATI_TODO(realpath)"; 341 return; 342 } 343 344 WordWriter ww(s); 345 for (StringPiece tok : WordScanner(*text)) { 346 ScopedTerminator st(tok); 347 char buf[PATH_MAX]; 348 if (realpath(tok.data(), buf)) 349 *s += buf; 350 } 351} 352 353void AbspathFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 354 shared_ptr<string> text = args[0]->Eval(ev); 355 WordWriter ww(s); 356 string buf; 357 for (StringPiece tok : WordScanner(*text)) { 358 AbsPath(tok, &buf); 359 ww.Write(buf); 360 } 361} 362 363void IfFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 364 shared_ptr<string> cond = args[0]->Eval(ev); 365 if (cond->empty()) { 366 if (args.size() > 2) 367 args[2]->Eval(ev, s); 368 } else { 369 args[1]->Eval(ev, s); 370 } 371} 372 373void AndFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 374 shared_ptr<string> cond; 375 for (Value* a : args) { 376 cond = a->Eval(ev); 377 if (cond->empty()) 378 return; 379 } 380 if (cond.get()) { 381 *s += *cond; 382 } 383} 384 385void OrFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 386 for (Value* a : args) { 387 shared_ptr<string> cond = a->Eval(ev); 388 if (!cond->empty()) { 389 *s += *cond; 390 return; 391 } 392 } 393} 394 395void ValueFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 396 shared_ptr<string> var_name = args[0]->Eval(ev); 397 Var* var = ev->LookupVar(Intern(*var_name)); 398 AppendString(var->String().as_string(), s); 399} 400 401void EvalFunc(const vector<Value*>& args, Evaluator* ev, string*) { 402 // TODO: eval leaks everything... for now. 403 //shared_ptr<string> text = args[0]->Eval(ev); 404 string* text = new string; 405 args[0]->Eval(ev, text); 406 vector<AST*> asts; 407 Parse(*text, ev->loc(), &asts); 408 for (AST* ast : asts) { 409 LOG("%s", ast->DebugString().c_str()); 410 ast->Eval(ev); 411 //delete ast; 412 } 413} 414 415void ShellFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 416 COLLECT_STATS("func shell time"); 417 shared_ptr<string> cmd = args[0]->Eval(ev); 418 if (ev->avoid_io()) { 419 *s += "$("; 420 *s += *cmd; 421 *s += ")"; 422 return; 423 } 424 425 LOG("ShellFunc: %s", cmd->c_str()); 426 string out; 427 // TODO: Handle $(SHELL). 428 FILE* fp = popen(cmd->c_str(), "r"); 429 while (true) { 430 char buf[4096]; 431 size_t r = fread(buf, 1, 4096, fp); 432 out.append(buf, buf+r); 433 if (r == 0) { 434 fclose(fp); 435 break; 436 } 437 } 438 439 while (out[out.size()-1] == '\n') 440 out.pop_back(); 441 for (size_t i = 0; i < out.size(); i++) { 442 if (out[i] == '\n') 443 out[i] = ' '; 444 } 445 *s += out; 446} 447 448void CallFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 449 static const char* tmpvar_names[] = { 450 "0", "1", "2", "3", "4", "5", "6", "7", "8", "9" 451 }; 452 453 shared_ptr<string> func_name = args[0]->Eval(ev); 454 Var* func = ev->LookupVar(Intern(*func_name)); 455 vector<unique_ptr<SimpleVar>> av; 456 for (size_t i = 1; i < args.size(); i++) { 457 unique_ptr<SimpleVar> s( 458 new SimpleVar(args[i]->Eval(ev), VarOrigin::AUTOMATIC)); 459 av.push_back(move(s)); 460 } 461 vector<unique_ptr<ScopedVar>> sv; 462 for (size_t i = 1; i < args.size(); i++) { 463 sv.push_back(move(unique_ptr<ScopedVar>( 464 new ScopedVar(ev->mutable_vars(), 465 Intern(tmpvar_names[i]), av[i-1].get())))); 466 } 467 func->Eval(ev, s); 468} 469 470void ForeachFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 471 shared_ptr<string> varname = args[0]->Eval(ev); 472 shared_ptr<string> list = args[1]->Eval(ev); 473 WordWriter ww(s); 474 for (StringPiece tok : WordScanner(*list)) { 475 unique_ptr<SimpleVar> v(new SimpleVar( 476 make_shared<string>(tok.data(), tok.size()), VarOrigin::AUTOMATIC)); 477 ScopedVar sv(ev->mutable_vars(), Intern(*varname), v.get()); 478 ww.MaybeAddWhitespace(); 479 args[2]->Eval(ev, s); 480 } 481} 482 483void OriginFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 484 shared_ptr<string> var_name = args[0]->Eval(ev); 485 Var* var = ev->LookupVar(Intern(*var_name)); 486 *s += GetOriginStr(var->Origin()); 487} 488 489void FlavorFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 490 shared_ptr<string> var_name = args[0]->Eval(ev); 491 Var* var = ev->LookupVar(Intern(*var_name)); 492 *s += var->Flavor(); 493} 494 495void InfoFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 496 shared_ptr<string> a = args[0]->Eval(ev); 497 if (ev->avoid_io()) { 498 *s += "KATI_TODO(info)"; 499 return; 500 } 501 printf("%s\n", a->c_str()); 502 fflush(stdout); 503} 504 505void WarningFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 506 shared_ptr<string> a = args[0]->Eval(ev); 507 if (ev->avoid_io()) { 508 *s += "KATI_TODO(warning)"; 509 return; 510 } 511 printf("%s:%d: %s\n", LOCF(ev->loc()), a->c_str()); 512 fflush(stdout); 513} 514 515void ErrorFunc(const vector<Value*>& args, Evaluator* ev, string* s) { 516 shared_ptr<string> a = args[0]->Eval(ev); 517 if (ev->avoid_io()) { 518 *s += "KATI_TODO(error)"; 519 return; 520 } 521 ev->Error(StringPrintf("*** %s.", a->c_str())); 522} 523 524FuncInfo g_func_infos[] = { 525 { "patsubst", &PatsubstFunc, 3, 3, false, false }, 526 { "strip", &StripFunc, 1, 1, false, false }, 527 { "subst", &SubstFunc, 3, 3, false, false }, 528 { "findstring", &FindstringFunc, 2, 2, false, false }, 529 { "filter", &FilterFunc, 2, 2, false, false }, 530 { "filter-out", &FilterOutFunc, 2, 2, false, false }, 531 { "sort", &SortFunc, 1, 1, false, false }, 532 { "word", &WordFunc, 2, 2, false, false }, 533 { "wordlist", &WordlistFunc, 3, 3, false, false }, 534 { "words", &WordsFunc, 1, 1, false, false }, 535 { "firstword", &FirstwordFunc, 1, 1, false, false }, 536 { "lastword", &LastwordFunc, 1, 1, false, false }, 537 538 { "join", &JoinFunc, 2, 2, false, false }, 539 { "wildcard", &WildcardFunc, 1, 1, false, false }, 540 { "dir", &DirFunc, 1, 1, false, false }, 541 { "notdir", &NotdirFunc, 1, 1, false, false }, 542 { "suffix", &SuffixFunc, 1, 1, false, false }, 543 { "basename", &BasenameFunc, 1, 1, false, false }, 544 { "addsuffix", &AddsuffixFunc, 2, 2, false, false }, 545 { "addprefix", &AddprefixFunc, 2, 2, false, false }, 546 { "realpath", &RealpathFunc, 1, 1, false, false }, 547 { "abspath", &AbspathFunc, 1, 1, false, false }, 548 549 { "if", &IfFunc, 3, 2, false, true }, 550 { "and", &AndFunc, 0, 0, true, false }, 551 { "or", &OrFunc, 0, 0, true, false }, 552 553 { "value", &ValueFunc, 1, 1, false, false }, 554 { "eval", &EvalFunc, 1, 1, false, false }, 555 { "shell", &ShellFunc, 1, 1, false, false }, 556 { "call", &CallFunc, 0, 0, false, false }, 557 { "foreach", &ForeachFunc, 3, 3, false, false }, 558 559 { "origin", &OriginFunc, 1, 1, false, false }, 560 { "flavor", &FlavorFunc, 1, 1, false, false }, 561 562 { "info", &InfoFunc, 1, 1, false, false }, 563 { "warning", &WarningFunc, 1, 1, false, false }, 564 { "error", &ErrorFunc, 1, 1, false, false }, 565}; 566 567unordered_map<StringPiece, FuncInfo*>* g_func_info_map; 568 569} // namespace 570 571void InitFuncTable() { 572 g_func_info_map = new unordered_map<StringPiece, FuncInfo*>; 573 for (size_t i = 0; i < sizeof(g_func_infos) / sizeof(g_func_infos[0]); i++) { 574 FuncInfo* fi = &g_func_infos[i]; 575 bool ok = g_func_info_map->emplace(fi->name, fi).second; 576 CHECK(ok); 577 } 578} 579 580void QuitFuncTable() { 581 delete g_func_info_map; 582} 583 584FuncInfo* GetFuncInfo(StringPiece name) { 585 auto found = g_func_info_map->find(name); 586 if (found == g_func_info_map->end()) 587 return NULL; 588 return found->second; 589} 590