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
25using namespace std;
26
28 DyndepFile* dyndep_file)
29 : Parser(state, file_reader)
30 , dyndep_file_(dyndep_file) {
31}
32
33bool 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: {
52 lexer_.UnreadToken();
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
95bool 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
101bool 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;
139 if (lexer_.PeekToken(Lexer::PIPE)) {
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;
168 if (lexer_.PeekToken(Lexer::PIPE)) {
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.
180 if (lexer_.PeekToken(Lexer::PIPE2))
181 return lexer_.Error("order-only inputs not supported", err);
182
183 if (!ExpectToken(Lexer::NEWLINE, err))
184 return false;
185
186 if (lexer_.PeekToken(Lexer::INDENT)) {
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_
bool ParseLet(std::string *key, EvalString *val, std::string *err)
DyndepFile * dyndep_file_
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
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
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
Parser(State *state, FileReader *file_reader)
Definition parser.h:27
Lexer lexer_
Definition parser.h:41
Global state (file status) for a single run.
Definition state.h:95
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