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