• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
DyndepParser(State * state,FileReader * file_reader,DyndepFile * dyndep_file)25 DyndepParser::DyndepParser(State* state, FileReader* file_reader,
26                            DyndepFile* dyndep_file)
27     : Parser(state, file_reader)
28     , dyndep_file_(dyndep_file) {
29 }
30 
Parse(const string & filename,const string & input,string * err)31 bool DyndepParser::Parse(const string& filename, const string& input,
32                          string* err) {
33   lexer_.Start(filename, input);
34 
35   // Require a supported ninja_dyndep_version value immediately so
36   // we can exit before encountering any syntactic surprises.
37   bool haveDyndepVersion = false;
38 
39   for (;;) {
40     Lexer::Token token = lexer_.ReadToken();
41     switch (token) {
42     case Lexer::BUILD: {
43       if (!haveDyndepVersion)
44         return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
45       if (!ParseEdge(err))
46         return false;
47       break;
48     }
49     case Lexer::IDENT: {
50       lexer_.UnreadToken();
51       if (haveDyndepVersion)
52         return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
53                             err);
54       if (!ParseDyndepVersion(err))
55         return false;
56       haveDyndepVersion = true;
57       break;
58     }
59     case Lexer::ERROR:
60       return lexer_.Error(lexer_.DescribeLastError(), err);
61     case Lexer::TEOF:
62       if (!haveDyndepVersion)
63         return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
64       return true;
65     case Lexer::NEWLINE:
66       break;
67     default:
68       return lexer_.Error(string("unexpected ") + Lexer::TokenName(token),
69                           err);
70     }
71   }
72   return false;  // not reached
73 }
74 
ParseDyndepVersion(string * err)75 bool DyndepParser::ParseDyndepVersion(string* err) {
76   string name;
77   EvalString let_value;
78   if (!ParseLet(&name, &let_value, err))
79     return false;
80   if (name != "ninja_dyndep_version") {
81     return lexer_.Error("expected 'ninja_dyndep_version = ...'", err);
82   }
83   string version = let_value.Evaluate(&env_);
84   int major, minor;
85   ParseVersion(version, &major, &minor);
86   if (major != 1 || minor != 0) {
87     return lexer_.Error(
88       string("unsupported 'ninja_dyndep_version = ") + version + "'", err);
89     return false;
90   }
91   return true;
92 }
93 
ParseLet(string * key,EvalString * value,string * err)94 bool DyndepParser::ParseLet(string* key, EvalString* value, string* err) {
95   if (!lexer_.ReadIdent(key))
96     return lexer_.Error("expected variable name", err);
97   if (!ExpectToken(Lexer::EQUALS, err))
98     return false;
99   if (!lexer_.ReadVarValue(value, err))
100     return false;
101   return true;
102 }
103 
ParseEdge(string * err)104 bool DyndepParser::ParseEdge(string* err) {
105   // Parse one explicit output.  We expect it to already have an edge.
106   // We will record its dynamically-discovered dependency information.
107   Dyndeps* dyndeps = NULL;
108   {
109     EvalString out0;
110     if (!lexer_.ReadPath(&out0, err))
111       return false;
112     if (out0.empty())
113       return lexer_.Error("expected path", err);
114 
115     string path = out0.Evaluate(&env_);
116     string path_err;
117     uint64_t slash_bits;
118     if (!CanonicalizePath(&path, &slash_bits, &path_err))
119       return lexer_.Error(path_err, err);
120     Node* node = state_->LookupNode(path);
121     if (!node || !node->in_edge())
122       return lexer_.Error("no build statement exists for '" + path + "'", err);
123     Edge* edge = node->in_edge();
124     std::pair<DyndepFile::iterator, bool> res =
125       dyndep_file_->insert(DyndepFile::value_type(edge, Dyndeps()));
126     if (!res.second)
127       return lexer_.Error("multiple statements for '" + path + "'", err);
128     dyndeps = &res.first->second;
129   }
130 
131   // Disallow explicit outputs.
132   {
133     EvalString out;
134     if (!lexer_.ReadPath(&out, err))
135       return false;
136     if (!out.empty())
137       return lexer_.Error("explicit outputs not supported", err);
138   }
139 
140   // Parse implicit outputs, if any.
141   vector<EvalString> outs;
142   if (lexer_.PeekToken(Lexer::PIPE)) {
143     for (;;) {
144       EvalString out;
145       if (!lexer_.ReadPath(&out, err))
146         return err;
147       if (out.empty())
148         break;
149       outs.push_back(out);
150     }
151   }
152 
153   if (!ExpectToken(Lexer::COLON, err))
154     return false;
155 
156   string rule_name;
157   if (!lexer_.ReadIdent(&rule_name) || rule_name != "dyndep")
158     return lexer_.Error("expected build command name 'dyndep'", err);
159 
160   // Disallow explicit inputs.
161   {
162     EvalString in;
163     if (!lexer_.ReadPath(&in, err))
164       return false;
165     if (!in.empty())
166       return lexer_.Error("explicit inputs not supported", err);
167   }
168 
169   // Parse implicit inputs, if any.
170   vector<EvalString> ins;
171   if (lexer_.PeekToken(Lexer::PIPE)) {
172     for (;;) {
173       EvalString in;
174       if (!lexer_.ReadPath(&in, err))
175         return err;
176       if (in.empty())
177         break;
178       ins.push_back(in);
179     }
180   }
181 
182   // Disallow order-only inputs.
183   if (lexer_.PeekToken(Lexer::PIPE2))
184     return lexer_.Error("order-only inputs not supported", err);
185 
186   if (!ExpectToken(Lexer::NEWLINE, err))
187     return false;
188 
189   if (lexer_.PeekToken(Lexer::INDENT)) {
190     string key;
191     EvalString val;
192     if (!ParseLet(&key, &val, err))
193       return false;
194     if (key != "restat")
195       return lexer_.Error("binding is not 'restat'", err);
196     string value = val.Evaluate(&env_);
197     dyndeps->restat_ = !value.empty();
198   }
199 
200   dyndeps->implicit_inputs_.reserve(ins.size());
201   for (vector<EvalString>::iterator i = ins.begin(); i != ins.end(); ++i) {
202     string path = i->Evaluate(&env_);
203     string path_err;
204     uint64_t slash_bits;
205     if (!CanonicalizePath(&path, &slash_bits, &path_err))
206       return lexer_.Error(path_err, err);
207     Node* n = state_->GetNode(path, slash_bits);
208     dyndeps->implicit_inputs_.push_back(n);
209   }
210 
211   dyndeps->implicit_outputs_.reserve(outs.size());
212   for (vector<EvalString>::iterator i = outs.begin(); i != outs.end(); ++i) {
213     string path = i->Evaluate(&env_);
214     string path_err;
215     uint64_t slash_bits;
216     if (!CanonicalizePath(&path, &slash_bits, &path_err))
217       return lexer_.Error(path_err, err);
218     Node* n = state_->GetNode(path, slash_bits);
219     dyndeps->implicit_outputs_.push_back(n);
220   }
221 
222   return true;
223 }
224