• 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")) && !(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