• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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