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