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"))) {
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) {
468 LogError(token, String::Format("Type \"%s\" was not declared in the module.", lexer_.DumpToken().string()));
469 }
470
471 token = lexer_.PeekToken();
472 if (token == Token::BRACKETS_LEFT) {
473 lexer_.GetToken();
474 token = lexer_.PeekToken();
475 if (token != Token::BRACKETS_RIGHT) {
476 LogError(token, String("\"]\" is expected."));
477 return nullptr;
478 }
479 lexer_.GetToken();
480
481 AutoPtr<ASTArrayType> arrayType = new ASTArrayType();
482 arrayType->SetElementType(type);
483
484 type = module_->FindType(arrayType->ToString());
485 if (type == nullptr) {
486 module_->AddType(arrayType);
487 type = static_cast<ASTType*>(arrayType.Get());
488 }
489 }
490
491 return type;
492 }
493
ParseList()494 AutoPtr<ASTType> Parser::ParseList()
495 {
496 lexer_.GetToken();
497
498 Token token = lexer_.PeekToken();
499 if (token != Token::ANGLE_BRACKETS_LEFT) {
500 LogError(token, String("\"<\" is expected."));
501 return nullptr;
502 }
503 lexer_.GetToken();
504
505 AutoPtr<ASTType> type = ParseType();
506 if (type == nullptr) {
507 lexer_.SkipCurrentLine('>');
508 return nullptr;
509 }
510
511 token = lexer_.PeekToken();
512 if (token != Token::ANGLE_BRACKETS_RIGHT) {
513 LogError(token, String("\">\" is expected."));
514 return nullptr;
515 }
516 lexer_.GetToken();
517
518 AutoPtr<ASTListType> list = new ASTListType();
519 list->SetElementType(type);
520
521 AutoPtr<ASTType> ret = module_->FindType(list->ToString());
522 if (ret == nullptr) {
523 module_->AddType(list);
524 ret = list.Get();
525 }
526
527 return ret;
528 }
529
ParseMap()530 AutoPtr<ASTType> Parser::ParseMap()
531 {
532 lexer_.GetToken();
533
534 Token token = lexer_.PeekToken();
535 if (token != Token::ANGLE_BRACKETS_LEFT) {
536 LogError(token, String("\"<\" is expected."));
537 return nullptr;
538 }
539 lexer_.GetToken();
540
541 AutoPtr<ASTType> keyType = ParseType();
542 if (keyType == nullptr) {
543 lexer_.SkipCurrentLine('>');
544 return nullptr;
545 }
546
547 token = lexer_.PeekToken();
548 if (token != Token::COMMA) {
549 LogError(token, String("\",\" is expected."));
550 return nullptr;
551 }
552 lexer_.GetToken();
553
554 AutoPtr<ASTType> valueType = ParseType();
555 if (valueType == nullptr) {
556 lexer_.SkipCurrentLine('>');
557 return nullptr;
558 }
559
560 token = lexer_.PeekToken();
561 if (token != Token::ANGLE_BRACKETS_RIGHT) {
562 LogError(token, String("\">\" is expected."));
563 return nullptr;
564 }
565 lexer_.GetToken();
566
567 AutoPtr<ASTMapType> map = new ASTMapType();
568 map->SetKeyType(keyType);
569 map->SetValueType(valueType);
570
571 AutoPtr<ASTType> ret = module_->FindType(map->ToString());
572 if (ret == nullptr) {
573 module_->AddType(map);
574 ret = map.Get();
575 }
576
577 return ret;
578 }
579
ParseSequenceable()580 bool Parser::ParseSequenceable()
581 {
582 lexer_.GetToken();
583
584 String classFullName;
585
586 Token token = lexer_.PeekToken();
587 if (token != Token::IDENTIFIER) {
588 LogError(token, String::Format("%s is not expected.", lexer_.DumpToken().string()));
589 lexer_.SkipCurrentLine();
590 return false;
591 } else {
592 lexer_.GetToken();
593 classFullName = lexer_.GetIdentifier();
594 token = lexer_.PeekToken();
595 }
596
597 if (token != Token::SEMICOLON) {
598 LogError(token, String::Format("%s is not expected.", lexer_.DumpToken().string()));
599 lexer_.SkipCurrentLine();
600 return false;
601 }
602
603 // read ';'
604 lexer_.GetToken();
605
606 if (classFullName.IsEmpty()) {
607 LogError(Token::IDENTIFIER, String("Class name is expected."));
608 return false;
609 } else if (!IsValidTypeName(classFullName)) {
610 LogError(Token::IDENTIFIER, String::Format("Class name \"%s\" is illegal.", classFullName.string()));
611 return false;
612 }
613
614 AutoPtr<ASTSequenceableType> sequenceable = new ASTSequenceableType();
615 int index = classFullName.LastIndexOf('.');
616 if (index != -1) {
617 sequenceable->SetName(classFullName.Substring(index + 1));
618 sequenceable->SetNamespace(module_->ParseNamespace(classFullName.Substring(0, index + 1)));
619 } else {
620 sequenceable->SetName(classFullName);
621 sequenceable->SetNamespace(NameSpaceEmpty());
622 }
623 module_->AddSequenceable(sequenceable);
624
625 return true;
626 }
627
CheckIntegrity()628 bool Parser::CheckIntegrity()
629 {
630 bool definedInterface = false;
631 int interfaceNumber = module_->GetInterfaceNumber();
632 for (int i = 0; i < interfaceNumber; i++) {
633 if (!module_->GetInterface(i)->IsExternal()) {
634 definedInterface = true;
635 break;
636 }
637 }
638 if (!definedInterface) {
639 LogError(Token::UNKNOWN, String("An interface is not defined."));
640 return false;
641 }
642
643 return true;
644 }
645
IsValidTypeName(const String & typeName)646 bool Parser::IsValidTypeName(const String& typeName)
647 {
648 if (typeName[0] == '.') {
649 return false;
650 }
651
652 if (typeName[typeName.GetLength() - 1] == '.') {
653 return false;
654 }
655
656 return true;
657 }
658
LogError(Token token,const String & message)659 void Parser::LogError(Token token, const String& message)
660 {
661 AutoPtr<ErrorInfo> error = new ErrorInfo();
662
663 String sourceFile = lexer_.GetSourceFile()->GetPath();
664 #ifdef __MINGW32__
665 error->file_ = sourceFile.Substring(sourceFile.LastIndexOf('\\') + 1);
666 #else
667 error->file_ = sourceFile.Substring(sourceFile.LastIndexOf('/') + 1);
668 #endif
669 error->lineNo_ = lexer_.GetTokenLineNumber();
670 error->columnNo_ = lexer_.GetTokenColumnNumber();
671 error->message_ = message;
672
673 if (errors_ == nullptr) {
674 errors_ = error;
675 } else {
676 ErrorInfo* pos = errors_;
677 while (pos->next_ != nullptr) {
678 pos = pos->next_;
679 }
680 pos->next_ = error;
681 }
682 }
683
ShowError()684 void Parser::ShowError()
685 {
686 ErrorInfo* error = errors_;
687 while (error != nullptr) {
688 Logger::E(TAG, "%s[line %d, column %d] %s", error->file_.string(),
689 error->lineNo_, error->columnNo_, error->message_.string());
690 error = error->next_;
691 }
692 }
693
NameSpaceEmpty()694 AutoPtr<ASTNamespace> Parser::NameSpaceEmpty()
695 {
696 AutoPtr<ASTNamespace> currNspace = nullptr;
697 currNspace = module_->FindNamespace("");
698 if (currNspace == nullptr) {
699 currNspace = new ASTNamespace("");
700 module_->AddNamespace(currNspace);
701 }
702 return currNspace;
703 }
704 } // namespace Idl
705 } // namespace OHOS
706