1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include <memory>
10
11 #include "file.h"
12 #include "logger.h"
13 #include "parser.h"
14
15 using namespace OHOS::Hardware;
16
Parse()17 bool Parser::Parse()
18 {
19 srcQueue_.push_back(Option::Instance().GetSourceName());
20 std::list<std::shared_ptr<Ast>> astList;
21
22 while (!srcQueue_.empty()) {
23 std::list<std::string> includeList;
24 auto oneAst = ParseOne(srcQueue_.front(), includeList);
25 if (oneAst == nullptr) {
26 return false;
27 }
28
29 astList.push_back(oneAst);
30 srcQueue_.pop_front();
31 srcQueue_.splice(srcQueue_.begin(), includeList);
32 }
33
34 astList.push_back(astList.front());
35 astList.pop_front();
36 ast_ = astList.front();
37 astList.pop_front();
38
39 if (!ast_->Merge(astList)) {
40 Logger().Debug() << "failed to merge ast";
41 return false;
42 }
43 if (!astList.empty()) {
44 ast_->Dump("merged");
45 }
46
47 if (ast_->GetAstRoot() == nullptr) {
48 Logger().Error() << Option::Instance().GetSourceName() << ": Empty hcs file";
49 return false;
50 }
51
52 if (!ast_->Expand()) {
53 return false;
54 }
55 return true;
56 }
57
ParseOne(const std::string & src,std::list<std::string> & includeList)58 std::shared_ptr<Ast> Parser::ParseOne(const std::string &src, std::list<std::string> &includeList)
59 {
60 if (!lexer_.Initialize(src)) {
61 return nullptr;
62 }
63
64 if (!lexer_.Lex(current_)) {
65 return nullptr;
66 }
67
68 if (current_ == INCLUDE && !ProcessInclude(includeList)) {
69 return nullptr;
70 }
71
72 std::shared_ptr<AstObject> rootNode = nullptr;
73 if (current_ == ROOT) {
74 auto preToken = current_;
75 preToken.type = LITERAL;
76 preToken.strval = "root";
77 rootNode = ParseNode(preToken);
78 if (rootNode == nullptr) {
79 return nullptr;
80 }
81 } else if (current_ != EOF) {
82 Logger().Error() << lexer_ << "syntax error, expect root node of end of file";
83 return nullptr;
84 }
85
86 if (!lexer_.Lex(current_) || current_ != EOF) {
87 Logger().Error() << lexer_ << "syntax error, expect EOF";
88 return nullptr;
89 }
90
91 auto oneAst = std::make_shared<Ast>(rootNode);
92 oneAst->Dump(*lexer_.GetSourceName());
93
94 return oneAst;
95 }
96
ProcessInclude(std::list<std::string> & includeList)97 bool Parser::ProcessInclude(std::list<std::string> &includeList)
98 {
99 do {
100 if (!lexer_.Lex(current_) || current_ != STRING) {
101 Logger().Error() << lexer_ << "syntax error, expect include path after ’#include‘";
102 return false;
103 }
104
105 auto includePath = current_.strval;
106 if (includePath.empty()) {
107 Logger().Error() << lexer_ << "include invalid file: \'" << includePath << '\'';
108 return false;
109 }
110 if (includePath[0] != '/') {
111 auto currentSrc = srcQueue_.front();
112 auto currentSrcDir = Util::File::GetDir(currentSrc);
113 includePath = currentSrcDir.append(includePath);
114 }
115
116 auto includeAbsPath = Util::File::AbsPath(includePath);
117 if (includeAbsPath.empty()) {
118 Logger().Error() << lexer_ << "include invalid file: \'" << current_.strval << '\'';
119 return false;
120 }
121
122 includeList.push_back(includeAbsPath);
123
124 if (!lexer_.Lex(current_)) {
125 return false;
126 }
127
128 if (current_ == INCLUDE) {
129 continue;
130 }
131
132 break;
133 } while (true);
134
135 return true;
136 }
137
ParseNode(Token & name,bool bracesStart)138 std::shared_ptr<AstObject> Parser::ParseNode(Token &name, bool bracesStart)
139 {
140 /* bracesStart: if true, current is '{' , else need to read next token and check with '}' */
141 if (!bracesStart) {
142 if (!lexer_.Lex(current_) || current_ != '{') {
143 Logger().Error() << lexer_ << "syntax error, node miss '{'";
144 return nullptr;
145 }
146 }
147
148 auto node = std::make_shared<ConfigNode>(name, NODE_NOREF, "");
149 std::shared_ptr<AstObject> child;
150 while (lexer_.Lex(current_) && current_ != '}') {
151 switch (current_.type) {
152 case TEMPLATE:
153 child = ParseTemplate();
154 break;
155 case LITERAL:
156 child = ParseNodeAndTerm();
157 break;
158 default:
159 Logger().Error() << lexer_ << "syntax error, except '}' or TEMPLATE or LITERAL for node '"
160 << name.strval << '\'';
161 return nullptr;
162 }
163 if (child == nullptr) {
164 return nullptr;
165 }
166
167 node->AddChild(child);
168 }
169
170 if (current_ != '}') {
171 Logger().Error() << lexer_ << "syntax error, node miss '}'";
172 return nullptr;
173 }
174 return node;
175 }
176
ParseTerm(Token & name)177 std::shared_ptr<AstObject> Parser::ParseTerm(Token &name)
178 {
179 if (!lexer_.Lex(current_)) {
180 Logger().Error() << lexer_ << "syntax error, miss value of config term";
181 return nullptr;
182 }
183 auto term = std::make_shared<ConfigTerm>(name, nullptr);
184 switch (current_.type) {
185 case STRING:
186 term->AddChild(std::make_shared<AstObject>("", PARSEROP_STRING, current_.strval, current_));
187 break;
188 case NUMBER:
189 term->AddChild(std::make_shared<AstObject>("", PARSEROP_UINT64, current_.numval, current_));
190 break;
191 case '[': {
192 std::shared_ptr<AstObject> list = ParseArray();
193 if (list == nullptr) {
194 return nullptr;
195 } else {
196 term->AddChild(list);
197 }
198 break;
199 }
200 case '&':
201 if (!lexer_.Lex(current_) || (current_ != LITERAL && current_ != REF_PATH)) {
202 Logger().Error() << lexer_ << "syntax error, invalid config term definition";
203 return nullptr;
204 }
205 term->AddChild(std::make_shared<AstObject>("", PARSEROP_NODEREF, current_.strval, current_));
206 break;
207 case DELETE:
208 term->AddChild(std::make_shared<AstObject>("", PARSEROP_DELETE, current_.strval, current_));
209 break;
210 default:
211 Logger().Error() << lexer_ << "syntax error, invalid config term definition";
212 return nullptr;
213 }
214
215 if (!lexer_.Lex(current_) || current_ != ';') {
216 Logger().Error() << lexer_ << "syntax error, miss ';'";
217 return nullptr;
218 }
219
220 return term;
221 }
222
ParseTemplate()223 std::shared_ptr<AstObject> Parser::ParseTemplate()
224 {
225 if (!lexer_.Lex(current_) || current_ != LITERAL) {
226 Logger().Error() << lexer_ << "syntax error, template miss name";
227 return nullptr;
228 }
229
230 auto name = current_;
231 auto node = ParseNode(name, false);
232 if (node == nullptr) {
233 return node;
234 }
235
236 ConfigNode::CastFrom(node)->SetNodeType(NODE_TEMPLATE);
237 return node;
238 }
239
ParseNodeAndTerm()240 std::shared_ptr<AstObject> Parser::ParseNodeAndTerm()
241 {
242 auto name = current_;
243 if (!lexer_.Lex(current_)) {
244 Logger().Error() << lexer_ << "syntax error, broken term or node";
245 return nullptr;
246 }
247
248 switch (current_.type) {
249 case '=':
250 return ParseTerm(name);
251 case '{':
252 return ParseNode(name, true);
253 case ':':
254 if (lexer_.Lex(current_)) {
255 return ParseNodeWithRef(name);
256 }
257 Logger().Error() << lexer_ << "syntax error, unknown node reference type";
258 break;
259 default:
260 Logger().Error() << lexer_ << "syntax error, except '=' or '{' or ':'";
261 break;
262 }
263
264 return nullptr;
265 }
266
ParseNodeWithRef(Token name)267 std::shared_ptr<AstObject> Parser::ParseNodeWithRef(Token name)
268 {
269 std::shared_ptr<AstObject> node;
270 switch (current_.type) {
271 case REF_PATH:
272 case LITERAL:
273 return ParseNodeCopy(name);
274 case '&':
275 return ParseNodeRef(name);
276 case DELETE:
277 return ParseNodeDelete(name);
278 case ':':
279 return ParseNodeInherit(name);
280 default:
281 Logger().Error() << lexer_ << "syntax error, unknown node type";
282 break;
283 }
284
285 return node;
286 }
287
288 /* started with NodePath on gramme : LITERAL ':' NodePath '{' ConfigTermList '}'*/
ParseNodeCopy(Token & name)289 std::shared_ptr<AstObject> Parser::ParseNodeCopy(Token &name)
290 {
291 auto nodePath = current_.strval;
292
293 auto node = ParseNode(name);
294 if (node == nullptr) {
295 return nullptr;
296 }
297
298 auto nodeCopy = ConfigNode::CastFrom(node);
299 nodeCopy->SetNodeType(NODE_COPY);
300 nodeCopy->SetRefPath(nodePath);
301
302 return node;
303 }
304
305 /* started with & on gramme : LITERAL ':' '&' NodePath '{' ConfigTermList '}'*/
ParseNodeRef(Token & name)306 std::shared_ptr<AstObject> Parser::ParseNodeRef(Token &name)
307 {
308 if (!lexer_.Lex(current_) || (current_ != LITERAL && current_ != REF_PATH)) {
309 Logger().Error() << lexer_ << "syntax error, miss node reference path";
310 return nullptr;
311 }
312 auto refPath = current_.strval;
313 auto node = ParseNode(name);
314 if (node == nullptr) {
315 return nullptr;
316 }
317
318 auto configNode = ConfigNode::CastFrom(node);
319 configNode->SetNodeType(NODE_REF);
320 configNode->SetRefPath(refPath);
321 return node;
322 }
323
324 /* started with DELETE on gramme : LITERAL ':' DELETE '{' ConfigTermList '}'*/
ParseNodeDelete(Token & name)325 std::shared_ptr<AstObject> Parser::ParseNodeDelete(Token &name)
326 {
327 auto node = ParseNode(name);
328 if (node == nullptr) {
329 return nullptr;
330 }
331
332 /* maybe drop node context is better */
333 auto configNode = ConfigNode::CastFrom(node);
334 configNode->SetNodeType(NODE_DELETE);
335 return node;
336 }
337
338 /* started with 2th ':' on gramme : LITERAL ':' ':' NodePath '{' ConfigTermList '}'*/
ParseNodeInherit(Token & name)339 std::shared_ptr<AstObject> Parser::ParseNodeInherit(Token &name)
340 {
341 if (!lexer_.Lex(current_) || (current_ != LITERAL && current_ != REF_PATH)) {
342 Logger().Error() << lexer_ << "syntax error, miss node inherit path";
343 return nullptr;
344 }
345
346 auto inheritPath = current_.strval;
347
348 auto node = ParseNode(name);
349 if (node == nullptr) {
350 return nullptr;
351 }
352
353 auto configNode = ConfigNode::CastFrom(node);
354 configNode->SetNodeType(NODE_INHERIT);
355 configNode->SetRefPath(inheritPath);
356
357 return node;
358 }
359
ParseArray()360 std::shared_ptr<AstObject> Parser::ParseArray()
361 {
362 auto array = std::make_shared<ConfigArray>(current_);
363 int32_t arrayType = 0;
364
365 while (lexer_.Lex(current_) && current_ != ']') {
366 if (current_.type == STRING) {
367 array->AddChild(std::make_shared<AstObject>("", PARSEROP_STRING, current_.strval, current_));
368 } else if (current_.type == NUMBER) {
369 array->AddChild(std::make_shared<AstObject>("", PARSEROP_UINT64, current_.numval, current_));
370 } else {
371 Logger().Error() << lexer_ << "syntax error, except STRING or NUMBER in array";
372 return nullptr;
373 }
374
375 if (arrayType == 0) {
376 arrayType = current_.type;
377 } else if (arrayType != current_.type) {
378 Logger().Error() << lexer_ << "syntax error, not allow mix type array";
379 return nullptr;
380 }
381
382 if (lexer_.Lex(current_)) {
383 if (current_ == ',') {
384 continue;
385 } else if (current_ == ']') {
386 break;
387 } else {
388 Logger().Error() << lexer_ << "syntax error, except ',' or ']'";
389 return nullptr;
390 }
391 }
392 return std::shared_ptr<AstObject>();
393 }
394
395 if (current_ != ']') {
396 Logger().Error() << lexer_ << "syntax error, miss ']' at end of array";
397 return nullptr;
398 }
399
400 return array;
401 }
402
GetAst()403 std::shared_ptr<Ast> Parser::GetAst()
404 {
405 return ast_;
406 }
407