Ninja
dyndep_parser.cc
Go to the documentation of this file.
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 #include "dyndep_parser.h"
16 
17 #include <vector>
18 
19 #include "dyndep.h"
20 #include "graph.h"
21 #include "state.h"
22 #include "util.h"
23 #include "version.h"
24 
25 using namespace std;
26 
28  DyndepFile* dyndep_file)
29  : Parser(state, file_reader)
30  , dyndep_file_(dyndep_file) {
31 }
32 
33 bool DyndepParser::Parse(const string& filename, const string& input,
34  string* err) {
35  lexer_.Start(filename, input);
36 
37  // Require a supported ninja_dyndep_version value immediately so
38  // we can exit before encountering any syntactic surprises.
39  bool haveDyndepVersion = false;
40 
41  for (;;) {
42  Lexer::Token token = lexer_.ReadToken();
43  switch (token) {
44  case Lexer::BUILD: {
45  if (!haveDyndepVersion)
46  return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
47  if (!ParseEdge(err))
48  return false;
49  break;
50  }
51  case Lexer::IDENT: {
53  if (haveDyndepVersion)
54  return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
55  err);
56  if (!ParseDyndepVersion(err))
57  return false;
58  haveDyndepVersion = true;
59  break;
60  }
61  case Lexer::ERROR:
62  return lexer_.Error(lexer_.DescribeLastError(), err);
63  case Lexer::TEOF:
64  if (!haveDyndepVersion)
65  return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
66  return true;
67  case Lexer::NEWLINE:
68  break;
69  default:
70  return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
71  err);
72  }
73  }
74  return false; // not reached
75 }
76 
78  string name;
79  EvalString let_value;
80  if (!ParseLet(&name, &let_value, err))
81  return false;
82  if (name != "ninja_dyndep_version") {
83  return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
84  }
85  string version = let_value.Evaluate(&env_);
86  int major, minor;
87  ParseVersion(version, &major, &minor);
88  if (major != 1 || minor != 0) {
89  return lexer_.Error(
90  string("unsupported 'ninja_dyndep_version = ") + version + "'", err);
91  }
92  return true;
93 }
94 
95 bool DyndepParser::ParseLet(string* key, EvalString* value, string* err) {
96  if (!lexer_.ReadIdent(key))
97  return lexer_.Error("expected variable name", err);
98  return (ExpectToken(Lexer::EQUALS, err) && lexer_.ReadVarValue(value, err));
99 }
100 
101 bool DyndepParser::ParseEdge(string* err) {
102  // Parse one explicit output. We expect it to already have an edge.
103  // We will record its dynamically-discovered dependency information.
104  Dyndeps* dyndeps = NULL;
105  {
106  EvalString out0;
107  if (!lexer_.ReadPath(&out0, err))
108  return false;
109  if (out0.empty())
110  return lexer_.Error("expected path", err);
111 
112  string path = out0.Evaluate(&env_);
113  if (path.empty())
114  return lexer_.Error("empty path", err);
115  uint64_t slash_bits;
116  CanonicalizePath(&path, &slash_bits);
117  Node* node = state_->LookupNode(path);
118  if (!node || !node->in_edge())
119  return lexer_.Error("no build statement exists for '" + path + "'", err);
120  Edge* edge = node->in_edge();
121  std::pair<DyndepFile::iterator, bool> res =
122  dyndep_file_->insert(DyndepFile::value_type(edge, Dyndeps()));
123  if (!res.second)
124  return lexer_.Error("multiple statements for '" + path + "'", err);
125  dyndeps = &res.first->second;
126  }
127 
128  // Disallow explicit outputs.
129  {
130  EvalString out;
131  if (!lexer_.ReadPath(&out, err))
132  return false;
133  if (!out.empty())
134  return lexer_.Error("explicit outputs not supported", err);
135  }
136 
137  // Parse implicit outputs, if any.
138  vector<EvalString> outs;
140  for (;;) {
141  EvalString out;
142  if (!lexer_.ReadPath(&out, err))
143  return err;
144  if (out.empty())
145  break;
146  outs.push_back(out);
147  }
148  }
149 
150  if (!ExpectToken(Lexer::COLON, err))
151  return false;
152 
153  string rule_name;
154  if (!lexer_.ReadIdent(&rule_name) || rule_name != "dyndep")
155  return lexer_.Error("expected build command name 'dyndep'", err);
156 
157  // Disallow explicit inputs.
158  {
159  EvalString in;
160  if (!lexer_.ReadPath(&in, err))
161  return false;
162  if (!in.empty())
163  return lexer_.Error("explicit inputs not supported", err);
164  }
165 
166  // Parse implicit inputs, if any.
167  vector<EvalString> ins;
169  for (;;) {
170  EvalString in;
171  if (!lexer_.ReadPath(&in, err))
172  return err;
173  if (in.empty())
174  break;
175  ins.push_back(in);
176  }
177  }
178 
179  // Disallow order-only inputs.
181  return lexer_.Error("order-only inputs not supported", err);
182 
183  if (!ExpectToken(Lexer::NEWLINE, err))
184  return false;
185 
187  string key;
188  EvalString val;
189  if (!ParseLet(&key, &val, err))
190  return false;
191  if (key != "restat")
192  return lexer_.Error("binding is not 'restat'", err);
193  string value = val.Evaluate(&env_);
194  dyndeps->restat_ = !value.empty();
195  }
196 
197  dyndeps->implicit_inputs_.reserve(ins.size());
198  for (const EvalString& in : ins) {
199  string path = in.Evaluate(&env_);
200  if (path.empty())
201  return lexer_.Error("empty path", err);
202  uint64_t slash_bits;
203  CanonicalizePath(&path, &slash_bits);
204  Node* n = state_->GetNode(path, slash_bits);
205  dyndeps->implicit_inputs_.push_back(n);
206  }
207 
208  dyndeps->implicit_outputs_.reserve(outs.size());
209  for (const EvalString& out : outs) {
210  string path = out.Evaluate(&env_);
211  if (path.empty())
212  return lexer_.Error("empty path", err);
213  uint64_t slash_bits;
214  CanonicalizePath(&path, &slash_bits);
215  Node* n = state_->GetNode(path, slash_bits);
216  dyndeps->implicit_outputs_.push_back(n);
217  }
218 
219  return true;
220 }
Definition: hash_map.h:26
Store data loaded from one dyndep file.
Definition: dyndep.h:42
bool ParseEdge(std::string *err)
BindingEnv env_
Definition: dyndep_parser.h:44
bool ParseLet(std::string *key, EvalString *val, std::string *err)
DyndepFile * dyndep_file_
Definition: dyndep_parser.h:43
bool ParseDyndepVersion(std::string *err)
bool Parse(const std::string &filename, const std::string &input, std::string *err)
Parse a file, given its contents as a string.
DyndepParser(State *state, FileReader *file_reader, DyndepFile *dyndep_file)
Store dynamically-discovered dependency information for one edge.
Definition: dyndep.h:30
std::vector< Node * > implicit_inputs_
Definition: dyndep.h:34
std::vector< Node * > implicit_outputs_
Definition: dyndep.h:35
bool restat_
Definition: dyndep.h:33
An edge in the dependency graph; links between Nodes using Rules.
Definition: graph.h:175
A tokenized string that contains variable references.
Definition: eval_env.h:35
bool empty() const
Definition: eval_env.h:44
std::string Evaluate(Env *env) const
Definition: eval_env.cc:111
Interface for reading files from disk.
static const char * TokenName(Token t)
Return a human-readable form of a token, used in error messages.
Definition: lexer.cc:75
Token
Definition: lexer.h:32
@ TEOF
Definition: lexer.h:48
@ COLON
Definition: lexer.h:35
@ NEWLINE
Definition: lexer.h:41
@ INDENT
Definition: lexer.h:40
@ ERROR
Definition: lexer.h:33
@ PIPE
Definition: lexer.h:42
@ EQUALS
Definition: lexer.h:37
@ BUILD
Definition: lexer.h:34
@ IDENT
Definition: lexer.h:38
@ PIPE2
Definition: lexer.h:43
bool PeekToken(Token token)
If the next token is token, read it and return true.
Definition: lexer.cc:463
std::string DescribeLastError()
If the last token read was an ERROR token, provide more info or the empty string.
Definition: lexer.cc:106
void UnreadToken()
Rewind to the last read Token.
Definition: lexer.cc:116
void Start(StringPiece filename, StringPiece input)
Start parsing some input.
Definition: lexer.cc:68
Token ReadToken()
Read a Token from the Token enum.
Definition: lexer.cc:120
bool ReadVarValue(EvalString *value, std::string *err)
Read the value side of a var = value line (complete with $escapes).
Definition: lexer.h:86
bool ReadIdent(std::string *out)
Read a simple identifier (a rule or variable name).
Definition: lexer.cc:554
bool ReadPath(EvalString *path, std::string *err)
Read a path (complete with $escapes).
Definition: lexer.h:80
bool Error(const std::string &message, std::string *err)
Construct an error message with context.
Definition: lexer.cc:25
Information about a node in the dependency graph: the file, whether it's dirty, mtime,...
Definition: graph.h:42
Edge * in_edge() const
Definition: graph.h:100
Base class for parsers.
Definition: parser.h:26
State * state_
Definition: parser.h:39
bool ExpectToken(Lexer::Token expected, std::string *err)
If the next token is not expected, produce an error string saying "expected foo, got bar".
Definition: parser.cc:40
Lexer lexer_
Definition: parser.h:41
Global state (file status) for a single run.
Definition: state.h:95
Node * GetNode(StringPiece path, uint64_t slash_bits)
Definition: state.cc:95
Node * LookupNode(StringPiece path) const
Definition: state.cc:104
void CanonicalizePath(string *path, uint64_t *slash_bits)
Definition: util.cc:124
void ParseVersion(const string &version, int *major, int *minor)
Definition: version.cc:25
unsigned long long uint64_t
Definition: win32port.h:29