1 /*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
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
16 #include "parser/parser.h"
17 #include <cstdio>
18 #include "ast/ast_array_type.h"
19 #include "ast/ast_list_type.h"
20 #include "ast/ast_map_type.h"
21 #include "ast/ast_parameter.h"
22 #include "ast/ast_sequenceable_type.h"
23 #include "util/logger.h"
24 #include "util/string_builder.h"
25
26 namespace OHOS {
27 namespace Idl {
28 const char* Parser::TAG = "Parser";
29
Parser(const Options & options)30 Parser::Parser(const Options& options)
31 : options_(options)
32 {}
33
Parse(const String & sourceFile)34 bool Parser::Parse(const String& sourceFile)
35 {
36 bool ret = lexer_.OpenSourceFile(sourceFile);
37 if (!ret) {
38 Logger::E(TAG, "Fail to open file \"%s\".", sourceFile.string());
39 return false;
40 }
41 ret = ParseFile();
42 ret = CheckIntegrity() && ret;
43 if (!ret) {
44 ShowError();
45 return false;
46 }
47 if (options_.DoDumpAST()) {
48 String astStr = module_->Dump("");
49 printf("%s\n", astStr.string());
50 }
51 return ret;
52 }
53
ParseFile()54 bool Parser::ParseFile()
55 {
56 bool ret = true;
57
58 module_ = new ASTModule();
59 module_->SetIdlFile(lexer_.GetSourceFile()->GetPath());
60
61 ParseLicense();
62
63 Token token;
64 while ((token = lexer_.PeekToken()) != Token::END_OF_FILE) {
65 switch (token) {
66 case Token::BRACKETS_LEFT:
67 case Token::INTERFACE:
68 ret = ParseInterface() && ret;
69 continue;
70 case Token::SEQUENCEABLE:
71 ret = ParseSequenceable() && ret;
72 continue;
73 case Token::COMMENT_LINE:
74 lexer_.GetToken();
75 continue;
76 default:
77 LogError(token, String::Format("%s is not expected.", lexer_.DumpToken().string()));
78 lexer_.GetToken();
79 ret = false;
80 continue;
81 }
82 }
83 lexer_.GetToken();
84
85 return ret;
86 }
87
ParseLicense()88 bool Parser::ParseLicense()
89 {
90 Token token = lexer_.PeekToken(false);
91 if (token != Token::COMMENT_BLOCK) {
92 return false;
93 }
94
95 lexer_.GetToken(false);
96
97 module_->SetLicense(lexer_.GetComment());
98
99 return true;
100 }
101
ParseInterface()102 bool Parser::ParseInterface()
103 {
104 bool ret = true;
105 bool hasProperties = false;
106 bool oneway = false;
107 Token token = lexer_.GetToken();
108 if (token == Token::BRACKETS_LEFT) {
109 token = lexer_.PeekToken();
110 if (token != Token::ONEWAY) {
111 LogError(Token::IDENTIFIER,
112 String::Format("\"%s\" is an illegal interface property.", lexer_.DumpToken().string()));
113 if (token != Token::BRACKETS_RIGHT) {
114 lexer_.SkipCurrentLine(Lexer::TokenToChar(Token::BRACKETS_RIGHT));
115 }
116 ret = false;
117 }
118 lexer_.GetToken();
119 oneway = true;
120 hasProperties = true;
121 token = lexer_.PeekToken();
122 if (token != Token::BRACKETS_RIGHT) {
123 LogError(Token::IDENTIFIER, String("\"]\" is expected."));
124 while (token != Token::BRACKETS_RIGHT && token != Token::INTERFACE && token != Token::END_OF_FILE) {
125 lexer_.GetToken();
126 token = lexer_.PeekToken();
127 }
128 ret = false;
129 } else {
130 lexer_.GetToken();
131 }
132
133 token = lexer_.PeekToken();
134 if (token != Token::INTERFACE) {
135 LogError(Token::IDENTIFIER, String("\"interface\" is expected."));
136 ret = false;
137 } else {
138 lexer_.GetToken();
139 }
140 }
141 String interfaceFullName;
142 token = lexer_.PeekToken();
143 if (token != Token::IDENTIFIER) {
144 LogError(token, String::Format("%s is not expected.", lexer_.DumpToken().string()));
145 lexer_.SkipCurrentLine();
146 return false;
147 } else {
148 lexer_.GetToken();
149 interfaceFullName = lexer_.GetIdentifier();
150 token = lexer_.PeekToken();
151 }
152 if (token != Token::SEMICOLON && token != Token::BRACES_LEFT) {
153 LogError(token, String::Format("%s is not expected.", lexer_.DumpToken().string()));
154 lexer_.SkipCurrentLine();
155 return false;
156 }
157
158 if (interfaceFullName.IsEmpty()) {
159 LogError(Token::IDENTIFIER, String("Interface name is expected."));
160 return false;
161 } else if (!IsValidTypeName(interfaceFullName)) {
162 LogError(Token::IDENTIFIER, String::Format("Interface name \"%s\" is illegal.", interfaceFullName.string()));
163 return false;
164 } else if (interfaceFullName.IndexOf(".") == -1) {
165 if (!(options_.GetTargetLanguage().Equals("ts")) && !(options_.GetTargetLanguage().Equals("rust"))) {
166 LogError(Token::IDENTIFIER, String::Format("Interface name \"%s\" does not have namespace.",
167 interfaceFullName.string()));
168 return false;
169 }
170 }
171
172 AutoPtr<ASTInterfaceType> interface = new ASTInterfaceType();
173 parsingInterface_ = interface;
174 int index = interfaceFullName.LastIndexOf('.');
175 if (index != -1) {
176 interface->SetName(interfaceFullName.Substring(index + 1));
177 interface->SetNamespace(module_->ParseNamespace(interfaceFullName.Substring(0, index + 1)));
178 } else {
179 interface->SetName(interfaceFullName);
180 interface->SetNamespace(NameSpaceEmpty());
181 }
182
183 // read ';'
184 lexer_.GetToken();
185 if (token == Token::SEMICOLON) {
186 if (hasProperties) {
187 LogError(Token::IDENTIFIER, String("Interface forward declaration should not have properties."));
188 return false;
189 }
190 interface->SetExternal(true);
191 module_->AddInterface(interface);
192 return true;
193 } else {
194 if (!interface->GetName().Equals(module_->GetName())) {
195 LogError(Token::IDENTIFIER, String::Format("Module name \"%s\" is not equal to interface name \"%s\".",
196 module_->GetName().string(), interface->GetName().string()));
197 return false;
198 }
199
200 interface->SetLicense(module_->GetLicense());
201 interface->SetOneway(oneway);
202
203 while (token != Token::BRACES_RIGHT && token != Token::END_OF_FILE) {
204 ret = ParseMethod(interface) && ret;
205 token = lexer_.PeekToken();
206 }
207
208 if (token != Token::BRACES_RIGHT) {
209 ret = false;
210 } else {
211 lexer_.GetToken();
212 module_->AddInterface(interface);
213 }
214
215 return ret;
216 }
217 }
218
ParseMethod(ASTInterfaceType * interface)219 bool Parser::ParseMethod(ASTInterfaceType* interface)
220 {
221 bool ret = true;
222 bool oneway = false;
223 Token token;
224
225 token = lexer_.PeekToken();
226 if (token == Token::BRACKETS_LEFT) {
227 lexer_.GetToken();
228 token = lexer_.PeekToken();
229 if (token != Token::ONEWAY) {
230 LogError(Token::IDENTIFIER, String::Format("\"%s\" is an illegal method property.",
231 lexer_.DumpToken().string()));
232
233 if (token != Token::BRACKETS_RIGHT) {
234 lexer_.SkipCurrentLine(Lexer::TokenToChar(Token::BRACKETS_RIGHT));
235 }
236 ret = false;
237 }
238 lexer_.GetToken();
239
240 oneway = true;
241
242 token = lexer_.PeekToken();
243 if (token != Token::BRACKETS_RIGHT) {
244 LogError(Token::IDENTIFIER, String("\"]\" is expected."));
245 ret = false;
246 } else {
247 lexer_.GetToken();
248 }
249 }
250 AutoPtr<ASTType> type = ParseType();
251 if (type == nullptr) {
252 token = lexer_.PeekToken();
253 if (token != Token::BRACES_RIGHT) {
254 // jump over colon
255 lexer_.GetToken();
256 while (token != Token::SEMICOLON && token != Token::END_OF_FILE) {
257 token = lexer_.PeekToken();
258 if (token == Token::BRACES_RIGHT) {
259 break;
260 }
261 lexer_.GetToken();
262 }
263 }
264 return false;
265 }
266 if (interface->IsOneway()) {
267 if (!type->IsVoidType()) {
268 LogError(token, String("void return type expected in oneway interface."));
269 return false;
270 }
271 }
272 token = lexer_.PeekToken();
273 if (token != Token::IDENTIFIER) {
274 LogError(token, String("Method name is expected."));
275 if (token != Token::BRACES_RIGHT) {
276 // jump over colon
277 lexer_.GetToken();
278 while (token != Token::SEMICOLON && token != Token::END_OF_FILE) {
279 token = lexer_.PeekToken();
280 if (token == Token::BRACES_RIGHT) {
281 break;
282 }
283 lexer_.GetToken();
284 }
285 }
286 return false;
287 }
288 token = lexer_.GetToken();
289
290 AutoPtr<ASTMethod> method = new ASTMethod();
291 method->SetName(lexer_.GetIdentifier());
292 method->SetOneway(oneway);
293 method->SetReturnType(type);
294 if (method->IsOneway()) {
295 if (!method->GetReturnType()->IsVoidType()) {
296 LogError(token, String("void return type expected in oneway method."));
297 return false;
298 }
299 }
300 token = lexer_.PeekToken();
301 if (token != Token::PARENTHESES_LEFT) {
302 LogError(token, String("\"(\" is expected."));
303 if (token != Token::BRACES_RIGHT) {
304 // jump over colon
305 lexer_.GetToken();
306 while (token != Token::SEMICOLON && token != Token::END_OF_FILE) {
307 token = lexer_.PeekToken();
308 if (token == Token::BRACES_RIGHT) {
309 break;
310 }
311 lexer_.GetToken();
312 }
313 }
314 return false;
315 }
316 token = lexer_.GetToken();
317
318 token = lexer_.PeekToken();
319 while (token != Token::PARENTHESES_RIGHT && token != Token::END_OF_FILE) {
320 ret = ParseParameter(method) && ret;
321 token = lexer_.PeekToken();
322 if (token == Token::COMMA) {
323 lexer_.GetToken();
324 token = lexer_.PeekToken();
325 }
326 }
327
328 if (interface->IsOneway() || method->IsOneway()) {
329 for (size_t i = 0; i< method->GetParameterNumber(); i++) {
330 auto parameter = method->GetParameter(i);
331 if (parameter->IsOutParameter()) {
332 LogError(token, String("out parameter type not expected in oneway method."));
333 return false;
334 }
335 }
336 }
337 lexer_.GetToken();
338 if (!ret) {
339 lexer_.SkipCurrentLine();
340 return false;
341 }
342
343 token = lexer_.PeekToken();
344 if (token != Token::SEMICOLON) {
345 LogError(token, String("\";\" is expected."));
346 if (token != Token::BRACES_RIGHT) {
347 lexer_.SkipCurrentLine(Lexer::TokenToChar(Token::BRACES_RIGHT));
348 }
349 return false;
350 }
351 lexer_.GetToken();
352
353 interface->AddMethod(method);
354
355 return ret;
356 }
357
ParseParameter(ASTMethod * method)358 bool Parser::ParseParameter(ASTMethod* method)
359 {
360 Token token = lexer_.PeekToken();
361 if (token != Token::BRACKETS_LEFT) {
362 LogError(token, String("\"[\" is expected."));
363 // jump to ',' or ')'
364 while (token != Token::COMMA && token != Token::PARENTHESES_RIGHT && token != Token::END_OF_FILE) {
365 lexer_.GetToken();
366 token = lexer_.PeekToken();
367 }
368 return false;
369 }
370 lexer_.GetToken();
371
372 AutoPtr<ASTParameter> parameter = new ASTParameter();
373
374 token = lexer_.PeekToken();
375 while (token != Token::BRACKETS_RIGHT && token != Token::END_OF_FILE) {
376 switch (token) {
377 case Token::IN:
378 lexer_.GetToken();
379 parameter->SetInParameter(true);
380 break;
381 case Token::OUT:
382 lexer_.GetToken();
383 parameter->SetOutParameter(true);
384 break;
385 case Token::INOUT:
386 lexer_.GetToken();
387 parameter->SetInParameter(true);
388 parameter->SetOutParameter(true);
389 break;
390 default:
391 LogError(token, String("\"in\" or \"out\" or \"inout\" is expected."));
392 break;
393 }
394 token = lexer_.PeekToken();
395 if (token == Token::COMMA) {
396 lexer_.GetToken();
397 token = lexer_.PeekToken();
398 continue;
399 }
400 if (token != Token::BRACKETS_RIGHT) {
401 LogError(token, String("\",\" or \"]\" is expected."));
402 // jump to ',' or ')'
403 while (token != Token::COMMA && token != Token::PARENTHESES_RIGHT && token != Token::END_OF_FILE) {
404 lexer_.GetToken();
405 token = lexer_.PeekToken();
406 }
407 return false;
408 }
409 }
410 // read ']'
411 lexer_.GetToken();
412
413 AutoPtr<ASTType> type = ParseType();
414 if (type == nullptr) {
415 // jump to ',' or ')'
416 while (token != Token::COMMA && token != Token::PARENTHESES_RIGHT && token != Token::END_OF_FILE) {
417 lexer_.GetToken();
418 token = lexer_.PeekToken();
419 }
420 return false;
421 }
422
423 token = lexer_.PeekToken();
424 if (token != Token::IDENTIFIER) {
425 LogError(token, String("Parameter name is expected."));
426 // jump to ',' or ')'
427 while (token != Token::COMMA && token != Token::PARENTHESES_RIGHT && token != Token::END_OF_FILE) {
428 lexer_.GetToken();
429 token = lexer_.PeekToken();
430 }
431 return false;
432 }
433 lexer_.GetToken();
434
435 parameter->SetName(lexer_.GetIdentifier());
436 parameter->SetType(type);
437 method->AddParameter(parameter);
438
439 return true;
440 }
441
ParseType()442 AutoPtr<ASTType> Parser::ParseType()
443 {
444 AutoPtr<ASTType> type;
445
446 Token token = lexer_.PeekToken();
447 if (IsPrimitiveType(token)) {
448 lexer_.GetToken();
449 type = module_->FindType(lexer_.DumpToken());
450 } else if (token == Token::LIST) {
451 type = ParseList();
452 } else if (token == Token::MAP) {
453 type = ParseMap();
454 } else if (token == Token::IDENTIFIER) {
455 lexer_.GetToken();
456 if (parsingInterface_ != nullptr &&
457 parsingInterface_->GetName().Equals(lexer_.GetIdentifier())) {
458 type = parsingInterface_.Get();
459 } else {
460 type = module_->FindType(lexer_.GetIdentifier());
461 }
462 } else {
463 LogError(token, String("Type name is expected."));
464 return nullptr;
465 }
466
467 if (type == nullptr || type.Get() == nullptr) {
468 LogError(token, String::Format("Type \"%s\" was not declared in the module.", lexer_.DumpToken().string()));
469 return nullptr;
470 }
471
472 token = lexer_.PeekToken();
473 if (token == Token::BRACKETS_LEFT) {
474 lexer_.GetToken();
475 token = lexer_.PeekToken();
476 if (token != Token::BRACKETS_RIGHT) {
477 LogError(token, String("\"]\" is expected."));
478 return nullptr;
479 }
480 lexer_.GetToken();
481
482 AutoPtr<ASTArrayType> arrayType = new ASTArrayType();
483 arrayType->SetElementType(type);
484
485 type = module_->FindType(arrayType->ToString());
486 if (type == nullptr) {
487 module_->AddType(arrayType);
488 type = static_cast<ASTType*>(arrayType.Get());
489 }
490 }
491
492 return type;
493 }
494
ParseList()495 AutoPtr<ASTType> Parser::ParseList()
496 {
497 lexer_.GetToken();
498
499 Token token = lexer_.PeekToken();
500 if (token != Token::ANGLE_BRACKETS_LEFT) {
501 LogError(token, String("\"<\" is expected."));
502 return nullptr;
503 }
504 lexer_.GetToken();
505
506 AutoPtr<ASTType> type = ParseType();
507 if (type == nullptr) {
508 lexer_.SkipCurrentLine('>');
509 return nullptr;
510 }
511
512 token = lexer_.PeekToken();
513 if (token != Token::ANGLE_BRACKETS_RIGHT) {
514 LogError(token, String("\">\" is expected."));
515 return nullptr;
516 }
517 lexer_.GetToken();
518
519 AutoPtr<ASTListType> list = new ASTListType();
520 list->SetElementType(type);
521
522 AutoPtr<ASTType> ret = module_->FindType(list->ToString());
523 if (ret == nullptr) {
524 module_->AddType(list);
525 ret = list.Get();
526 }
527
528 return ret;
529 }
530
ParseMap()531 AutoPtr<ASTType> Parser::ParseMap()
532 {
533 lexer_.GetToken();
534
535 Token token = lexer_.PeekToken();
536 if (token != Token::ANGLE_BRACKETS_LEFT) {
537 LogError(token, String("\"<\" is expected."));
538 return nullptr;
539 }
540 lexer_.GetToken();
541
542 AutoPtr<ASTType> keyType = ParseType();
543 if (keyType == nullptr) {
544 lexer_.SkipCurrentLine('>');
545 return nullptr;
546 }
547
548 token = lexer_.PeekToken();
549 if (token != Token::COMMA) {
550 LogError(token, String("\",\" is expected."));
551 return nullptr;
552 }
553 lexer_.GetToken();
554
555 AutoPtr<ASTType> valueType = ParseType();
556 if (valueType == nullptr) {
557 lexer_.SkipCurrentLine('>');
558 return nullptr;
559 }
560
561 token = lexer_.PeekToken();
562 if (token != Token::ANGLE_BRACKETS_RIGHT) {
563 LogError(token, String("\">\" is expected."));
564 return nullptr;
565 }
566 lexer_.GetToken();
567
568 AutoPtr<ASTMapType> map = new ASTMapType();
569 map->SetKeyType(keyType);
570 map->SetValueType(valueType);
571
572 AutoPtr<ASTType> ret = module_->FindType(map->ToString());
573 if (ret == nullptr) {
574 module_->AddType(map);
575 ret = map.Get();
576 }
577
578 return ret;
579 }
580
ParseSequenceable()581 bool Parser::ParseSequenceable()
582 {
583 lexer_.GetToken();
584
585 String classFullName;
586
587 Token token = lexer_.PeekToken();
588 if (token != Token::IDENTIFIER) {
589 LogError(token, String::Format("%s is not expected.", lexer_.DumpToken().string()));
590 lexer_.SkipCurrentLine();
591 return false;
592 } else {
593 lexer_.GetToken();
594 classFullName = lexer_.GetIdentifier();
595 token = lexer_.PeekToken();
596 }
597
598 if (token != Token::SEMICOLON) {
599 LogError(token, String::Format("%s is not expected.", lexer_.DumpToken().string()));
600 lexer_.SkipCurrentLine();
601 return false;
602 }
603
604 // read ';'
605 lexer_.GetToken();
606
607 if (classFullName.IsEmpty()) {
608 LogError(Token::IDENTIFIER, String("Class name is expected."));
609 return false;
610 } else if (!IsValidTypeName(classFullName)) {
611 LogError(Token::IDENTIFIER, String::Format("Class name \"%s\" is illegal.", classFullName.string()));
612 return false;
613 }
614
615 AutoPtr<ASTSequenceableType> sequenceable = new ASTSequenceableType();
616 int index = classFullName.LastIndexOf('.');
617 if (index != -1) {
618 sequenceable->SetName(classFullName.Substring(index + 1));
619 sequenceable->SetNamespace(module_->ParseNamespace(classFullName.Substring(0, index + 1)));
620 } else {
621 sequenceable->SetName(classFullName);
622 sequenceable->SetNamespace(NameSpaceEmpty());
623 }
624 module_->AddSequenceable(sequenceable);
625
626 return true;
627 }
628
CheckIntegrity()629 bool Parser::CheckIntegrity()
630 {
631 bool definedInterface = false;
632 int interfaceNumber = module_->GetInterfaceNumber();
633 for (int i = 0; i < interfaceNumber; i++) {
634 if (!module_->GetInterface(i)->IsExternal()) {
635 definedInterface = true;
636 break;
637 }
638 }
639 if (!definedInterface) {
640 LogError(Token::UNKNOWN, String("An interface is not defined."));
641 return false;
642 }
643
644 return true;
645 }
646
IsValidTypeName(const String & typeName)647 bool Parser::IsValidTypeName(const String& typeName)
648 {
649 if (typeName[0] == '.') {
650 return false;
651 }
652
653 if (typeName[typeName.GetLength() - 1] == '.') {
654 return false;
655 }
656
657 return true;
658 }
659
LogError(Token token,const String & message)660 void Parser::LogError(Token token, const String& message)
661 {
662 AutoPtr<ErrorInfo> error = new ErrorInfo();
663
664 String sourceFile = lexer_.GetSourceFile()->GetPath();
665 #ifdef __MINGW32__
666 error->file_ = sourceFile.Substring(sourceFile.LastIndexOf('\\') + 1);
667 #else
668 error->file_ = sourceFile.Substring(sourceFile.LastIndexOf('/') + 1);
669 #endif
670 error->lineNo_ = lexer_.GetTokenLineNumber();
671 error->columnNo_ = lexer_.GetTokenColumnNumber();
672 error->message_ = message;
673
674 if (errors_ == nullptr) {
675 errors_ = error;
676 } else {
677 ErrorInfo* pos = errors_;
678 while (pos->next_ != nullptr) {
679 pos = pos->next_;
680 }
681 pos->next_ = error;
682 }
683 }
684
ShowError()685 void Parser::ShowError()
686 {
687 ErrorInfo* error = errors_;
688 while (error != nullptr) {
689 Logger::E(TAG, "%s[line %d, column %d] %s", error->file_.string(),
690 error->lineNo_, error->columnNo_, error->message_.string());
691 error = error->next_;
692 }
693 }
694
NameSpaceEmpty()695 AutoPtr<ASTNamespace> Parser::NameSpaceEmpty()
696 {
697 AutoPtr<ASTNamespace> currNspace = nullptr;
698 currNspace = module_->FindNamespace("");
699 if (currNspace == nullptr) {
700 currNspace = new ASTNamespace("");
701 module_->AddNamespace(currNspace);
702 }
703 return currNspace;
704 }
705 } // namespace Idl
706 } // namespace OHOS
707