/* * Copyright (c) 2021-2022 Huawei Device Co., Ltd. * * HDF is dual licensed: you can use it either under the terms of * the GPL, or the BSD license, at your option. * See the LICENSE file in the root of this repository for complete details. */ #include "parser/parser.h" #include #include "ast/ast_array_type.h" #include "ast/ast_enum_type.h" #include "ast/ast_list_type.h" #include "ast/ast_map_type.h" #include "ast/ast_parameter.h" #include "ast/ast_sequenceable_type.h" #include "ast/ast_smq_type.h" #include "ast/ast_struct_type.h" #include "ast/ast_union_type.h" #include "util/logger.h" #include "util/string_builder.h" #define RE_DIGIT "[0-9]+" #define RE_IDENTIFIER "[a-zA-Z_][a-zA-Z0-9_]*" #define RE_PACKAGE_NUM 3 #define RE_PACKAGE_INDEX 0 #define RE_PACKAGE_MAJOR_VER_INDEX 1 #define RE_PACKAGE_MINOR_VER_INDEX 2 namespace OHOS { namespace HDI { static const std::regex rePackage(RE_IDENTIFIER "(?:\\." RE_IDENTIFIER ")*\\.[V|v]" "(" RE_DIGIT ")_(" RE_DIGIT ")"); static const std::regex reImport( RE_IDENTIFIER "(?:\\." RE_IDENTIFIER ")*\\.[V|v]" RE_DIGIT "_" RE_DIGIT "." RE_IDENTIFIER); bool Parser::Parse(const std::vector &sourceFiles) { for (const auto &file : sourceFiles) { if (!ParseOne(file)) { return false; } } return true; } bool Parser::ParseOne(const String &sourceFile) { if (!Reset(sourceFile)) { return false; } bool ret = ParseFile(); ret = CheckIntegrity() && ret; ret = AddAst(ast_) && ret; if (!ret || !errors_.empty()) { ShowError(); return false; } return true; } bool Parser::Reset(const String &sourceFile) { bool ret = lexer_.Reset(sourceFile); if (!ret) { Logger::E(TAG, "Fail to open file '%s'.", sourceFile.string()); return false; } errors_.clear(); ast_ = nullptr; return true; } bool Parser::ParseFile() { ast_ = new AST(); ast_->SetIdlFile(lexer_.GetFilePath()); ast_->SetLicense(ParseLicense()); if (!ParsePackage()) { return false; } if (!ParseImports()) { return false; } if (!ParseTypeDecls()) { return false; } SetAstFileType(); return true; } String Parser::ParseLicense() { Token token = lexer_.PeekToken(false); if (token.kind_ == TokenType::COMMENT_BLOCK) { lexer_.GetToken(false); return token.value_; } return String(""); } bool Parser::ParsePackage() { Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::PACKAGE) { LogError(token, String::Format("expected 'package' before '%s' token", token.value_.string())); return false; } lexer_.GetToken(); token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected name of package before '%s' token", token.value_.string())); lexer_.SkipToken(TokenType::SEMICOLON); return false; } String packageName = token.value_; lexer_.GetToken(); token = lexer_.PeekToken(); if (token.kind_ != TokenType::SEMICOLON) { LogError(token, String::Format("expected ';' before '%s' token", token.value_.string())); return false; } lexer_.GetToken(); if (packageName.IsEmpty()) { LogError(String("package name is not expected.")); return false; } else if (!CheckPackageName(lexer_.GetFilePath(), packageName)) { LogError(String::Format( "package name '%s' does not match file apth '%s'.", packageName.string(), lexer_.GetFilePath().string())); return false; } if (!ParserPackageInfo(packageName)) { LogError(String::Format("parse package '%s' infomation failed.", packageName.string())); return false; } return true; } bool Parser::ParserPackageInfo(const String &packageName) { std::cmatch result; if (!std::regex_match(packageName.string(), result, rePackage)) { return false; } if (result.size() < RE_PACKAGE_NUM) { return false; } ast_->SetPackageName(result.str(RE_PACKAGE_INDEX).c_str()); size_t majorVersion = std::atoi(result.str(RE_PACKAGE_MAJOR_VER_INDEX).c_str()); size_t minorVersion = std::atoi(result.str(RE_PACKAGE_MINOR_VER_INDEX).c_str()); ast_->SetVersion(majorVersion, minorVersion); return true; } bool Parser::ParseImports() { Token token = lexer_.PeekToken(); while (token.kind_ == TokenType::IMPORT || token.kind_ == TokenType::SEQ) { TokenType kind = token.kind_; lexer_.GetToken(); token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected identifier before '%s' token", token.value_.string())); lexer_.SkipToken(TokenType::SEMICOLON); token = lexer_.PeekToken(); continue; } if (kind == TokenType::IMPORT) { ParseImportInfo(); } else { ParseSequenceableInfo(); } lexer_.GetToken(); token = lexer_.PeekToken(); if (token.kind_ != TokenType::SEMICOLON) { LogError(token, String::Format("expected ';' before '%s'.", token.value_.string())); return false; } lexer_.GetToken(); token = lexer_.PeekToken(); } return true; } void Parser::ParseImportInfo() { Token token = lexer_.PeekToken(); String importName = token.value_; if (importName.IsEmpty()) { LogError(token, String::Format("import name is empty")); return; } if (!CheckImport(importName)) { LogError(token, String::Format("import name is illegal")); return; } auto iter = allAsts_.find(importName); AutoPtr importAst = (iter != allAsts_.end()) ? iter->second : nullptr; if (importAst == nullptr) { LogError(token, String::Format("can not find idl file from import name '%s'", importName.string())); return; } AutoPtr interfaceType = importAst->GetInterfaceDef(); if (interfaceType != nullptr) { interfaceType->SetSerializable(true); } if (!ast_->AddImport(importAst)) { LogError(token, String::Format("multiple import of '%s'", importName.string())); return; } } void Parser::ParseSequenceableInfo() { Token token = lexer_.PeekToken(); String seqName = token.value_; if (seqName.IsEmpty()) { LogError(token, String::Format("sequenceable name is empty")); return; } AutoPtr seqType = new ASTSequenceableType(); int index = seqName.LastIndexOf('.'); if (index != -1) { seqType->SetName(seqName.Substring(index + 1)); seqType->SetNamespace(ast_->ParseNamespace(seqName.Substring(0, index + 1))); } else { seqType->SetName(seqName); } AutoPtr seqAst = new AST(); seqAst->SetFullName(seqName); seqAst->AddSequenceableDef(seqType); seqAst->SetAStFileType(ASTFileType::AST_SEQUENCEABLE); ast_->AddImport(seqAst); AddAst(seqAst); } bool Parser::ParseTypeDecls() { Token token = lexer_.PeekToken(); while (token.kind_ != TokenType::END_OF_FILE) { switch (token.kind_) { case TokenType::BRACKETS_LEFT: ParseAttribute(); break; case TokenType::INTERFACE: ParseInterface(); break; case TokenType::ENUM: ParseEnumDeclaration(); break; case TokenType::STRUCT: ParseStructDeclaration(); break; case TokenType::UNION: ParseUnionDeclaration(); break; default: LogError(token, String::Format("'%s' is not expected", token.value_.string())); lexer_.SkipToken(TokenType::SEMICOLON); break; } token = lexer_.PeekToken(); } return true; } void Parser::ParseAttribute() { AttrSet attrs = ParseAttributeInfo(); Token token = lexer_.PeekToken(); switch (token.kind_) { case TokenType::INTERFACE: ParseInterface(attrs); break; case TokenType::ENUM: ParseEnumDeclaration(attrs); break; case TokenType::STRUCT: ParseStructDeclaration(attrs); break; case TokenType::UNION: ParseUnionDeclaration(attrs); break; default: LogError(token, String::Format("'%s' is not expected", token.value_.string())); lexer_.SkipToken(token.kind_); break; } } AttrSet Parser::ParseAttributeInfo() { AttrSet attrs; Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACKETS_LEFT) { LogError(token, String::Format("expected '[' before '%s' token", token.value_.string())); lexer_.SkipToken(token.kind_); return attrs; } lexer_.GetToken(); token = lexer_.PeekToken(); while (token.kind_ != TokenType::BRACKETS_RIGHT && token.kind_ != TokenType::END_OF_FILE) { if (!AprseAttrUnit(attrs)) { return attrs; } token = lexer_.PeekToken(); if (token.kind_ == TokenType::COMMA) { lexer_.GetToken(); token = lexer_.PeekToken(); continue; } if (token.kind_ == TokenType::BRACKETS_RIGHT) { lexer_.GetToken(); break; } else { LogError(token, String::Format("expected ',' or ']' before '%s' token", token.value_.string())); lexer_.SkipToken(TokenType::BRACKETS_RIGHT); break; } } return attrs; } bool Parser::AprseAttrUnit(AttrSet &attrs) { Token token = lexer_.PeekToken(); switch (token.kind_) { case TokenType::FULL: case TokenType::LITE: case TokenType::CALLBACK: case TokenType::ONEWAY: { if (attrs.find(token) != attrs.end()) { LogError(token, String::Format("Duplicate declared attributes '%s'", token.value_.string())); } else { attrs.insert(token); } lexer_.GetToken(); break; } default: LogError(token, String::Format("'%s' is a illegal attribute", token.value_.string())); lexer_.SkipToken(TokenType::BRACKETS_RIGHT); return false; } return true; } void Parser::ParseInterface(const AttrSet &attrs) { AutoPtr interfaceType = new ASTInterfaceType; AutoPtr astAttr = ParseInfAttrInfo(attrs); interfaceType->SetAttribute(astAttr); lexer_.GetToken(); Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected interface name before '%s' token", token.value_.string())); } else { interfaceType->SetName(token.value_); interfaceType->SetNamespace(ast_->ParseNamespace(ast_->GetFullName())); interfaceType->SetLicense(ast_->GetLicense()); if (!token.value_.Equals(ast_->GetName())) { LogError(token, String::Format("interface name '%s' is not equal idl file name", token.value_.string())); } lexer_.GetToken(); } ParseInterfaceBody(interfaceType); ast_->AddInterfaceDef(interfaceType); } AutoPtr Parser::ParseInfAttrInfo(const AttrSet &attrs) { AutoPtr infAttr = new ASTInfAttr; for (const auto &attr : attrs) { switch (attr.kind_) { case TokenType::FULL: infAttr->isFull_ = true; break; case TokenType::LITE: infAttr->isLite_ = true; break; case TokenType::CALLBACK: infAttr->isCallback_ = true; break; case TokenType::ONEWAY: infAttr->isOneWay_ = true; break; default: LogError(attr, String::Format("illegal attribute of interface")); break; } } return infAttr; } void Parser::ParseInterfaceBody(const AutoPtr &interface) { Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_LEFT) { LogError(token, String::Format("expected '{' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } token = lexer_.PeekToken(); while (token.kind_ != TokenType::BRACES_RIGHT && token.kind_ != TokenType::END_OF_FILE) { interface->AddMethod(ParseMethod()); token = lexer_.PeekToken(); } token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_RIGHT) { LogError(token, String::Format("expected '{' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } interface->AddVersionMethod(CreateGetVersionMethod()); } AutoPtr Parser::ParseMethod() { AutoPtr method = new ASTMethod(); method->SetAttribute(ParseMethodAttr()); Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected method name before '%s' token", token.value_.string())); } else { method->SetName(token.value_); lexer_.GetToken(); } ParseMethodParamList(method); token = lexer_.PeekToken(); if (token.kind_ != TokenType::SEMICOLON) { LogError(token, String::Format("expected ';' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } return method; } AutoPtr Parser::ParseMethodAttr() { AutoPtr attr = new ASTMethodAttr(); Token token = lexer_.PeekToken(); if (token.kind_ == TokenType::ID) { return attr; } if (token.kind_ != TokenType::BRACKETS_LEFT) { LogError(token, String::Format("expected '[' before '%s' token", token.value_.string())); lexer_.SkipUntilToken(TokenType::ID); return attr; } lexer_.GetToken(); token = lexer_.PeekToken(); while (token.kind_ != TokenType::BRACKETS_RIGHT) { switch (token.kind_) { case TokenType::FULL: attr->isFull_ = true; break; case TokenType::LITE: attr->isLite_ = true; break; case TokenType::ONEWAY: attr->isOneWay_ = true; break; default: LogError(token, String::Format("expected attribute before '%s' token", token.value_.string())); lexer_.SkipUntilToken(TokenType::BRACKETS_RIGHT); return attr; } lexer_.GetToken(); token = lexer_.PeekToken(); if (token.kind_ == TokenType::BRACKETS_RIGHT) { lexer_.GetToken(); break; } if (token.kind_ != TokenType::COMMA) { LogError(token, String::Format("expected ',' before '%s' token", token.value_.string())); lexer_.SkipUntilToken(TokenType::BRACKETS_RIGHT); return attr; } lexer_.GetToken(); token = lexer_.PeekToken(); } return attr; } AutoPtr Parser::CreateGetVersionMethod() { AutoPtr method = new ASTMethod(); method->SetName("GetVersion"); AutoPtr type = ast_->FindType("unsigned int"); if (type == nullptr) { type = new ASTUintType(); } AutoPtr majorParam = new ASTParameter("majorVer", ParamAttr::PARAM_OUT, type); AutoPtr minorParam = new ASTParameter("minorVer", ParamAttr::PARAM_OUT, type); method->AddParameter(majorParam); method->AddParameter(minorParam); return method; } void Parser::ParseMethodParamList(const AutoPtr &method) { Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::PARENTHESES_LEFT) { LogError(token, String::Format("expected '(' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } token = lexer_.PeekToken(); if (token.kind_ == TokenType::PARENTHESES_RIGHT) { lexer_.GetToken(); return; } while (token.kind_ != TokenType::PARENTHESES_RIGHT && token.kind_ != TokenType::END_OF_FILE) { method->AddParameter(ParseParam()); token = lexer_.PeekToken(); if (token.kind_ == TokenType::COMMA) { lexer_.GetToken(); token = lexer_.PeekToken(); if (token.kind_ == TokenType::PARENTHESES_RIGHT) { LogError(token, String::Format("")); } continue; } if (token.kind_ == TokenType::PARENTHESES_RIGHT) { lexer_.GetToken(); break; } else { LogError(token, String::Format("expected ',' or ')' before '%s' token", token.value_.string())); lexer_.SkipToken(TokenType::PARENTHESES_RIGHT); break; } } } AutoPtr Parser::ParseParam() { AutoPtr paramAttr = ParseParamAttr(); AutoPtr paramType = ParseType(); String paramName = ""; Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected param name before '%s' token", token.value_.string())); } else { paramName = token.value_; lexer_.GetToken(); } return new ASTParameter(paramName, paramAttr, paramType); } AutoPtr Parser::ParseParamAttr() { AutoPtr attr = new ASTParamAttr(ParamAttr::PARAM_IN); Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACKETS_LEFT) { LogError(token, String::Format("expected '[' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } token = lexer_.PeekToken(); if (token.kind_ == TokenType::IN) { attr->value_ = ParamAttr::PARAM_IN; lexer_.GetToken(); } else if (token.kind_ == TokenType::OUT) { attr->value_ = ParamAttr::PARAM_OUT; lexer_.GetToken(); } else { LogError(token, String::Format("expected 'in' or 'out' attribute before '%s' token", token.value_.string())); } token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACKETS_RIGHT) { LogError(token, String::Format("expected ']' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } return attr; } AutoPtr Parser::ParseType() { AutoPtr type = nullptr; Token token = lexer_.PeekToken(); switch (token.kind_) { case TokenType::BOOLEAN: case TokenType::BYTE: case TokenType::SHORT: case TokenType::INT: case TokenType::LONG: case TokenType::STRING: case TokenType::FLOAT: case TokenType::DOUBLE: case TokenType::FD: type = ast_->FindType(token.value_); lexer_.GetToken(); break; case TokenType::UNSIGNED: type = ParseUnsignedType(); break; case TokenType::LIST: type = ParseListType(); break; case TokenType::MAP: type = ParseMapType(); break; case TokenType::SMQ: type = ParseSmqType(); case TokenType::ENUM: case TokenType::STRUCT: case TokenType::UNION: case TokenType::ID: case TokenType::SEQ: type = ParseUserDefType(); break; default: LogError(token, String::Format("'%s' of type is illegal", token.value_.string())); return nullptr; } if (type == nullptr) { LogError(token, String::Format("this type was note declared in this scope")); } if (!CheckType(token, type)) { return nullptr; } if (lexer_.PeekToken().kind_ == TokenType::BRACKETS_LEFT) { type = ParseArrayType(type); } return type; } AutoPtr Parser::ParseUnsignedType() { AutoPtr type = nullptr; String namePrefix = lexer_.GetToken().value_; Token token = lexer_.PeekToken(); switch (token.kind_) { case TokenType::CHAR: case TokenType::SHORT: case TokenType::INT: case TokenType::LONG: type = ast_->FindType(namePrefix + " " + token.value_); lexer_.GetToken(); break; default: LogError(token, String::Format("'unsigned %s' was not declared in the idl file", token.value_.string())); break; } return type; } AutoPtr Parser::ParseArrayType(const AutoPtr &elementType) { lexer_.GetToken(); // '[' Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACKETS_RIGHT) { LogError(token, String::Format("expected ']' before '%s' token", token.value_.string())); return nullptr; } lexer_.GetToken(); // ']' if (elementType == nullptr) { return nullptr; } AutoPtr arrayType = new ASTArrayType(); arrayType->SetElementType(elementType); AutoPtr type = ast_->FindType(arrayType->ToString()); if (type == nullptr) { ast_->AddType(arrayType.Get()); type = arrayType.Get(); } return type; } AutoPtr Parser::ParseListType() { lexer_.GetToken(); // List Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ANGLE_BRACKETS_LEFT) { LogError(token, String::Format("expected '<' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); // '<' } AutoPtr type = ParseType(); // element type if (type == nullptr) { lexer_.SkipToken(TokenType::ANGLE_BRACKETS_RIGHT); return nullptr; } token = lexer_.PeekToken(); if (token.kind_ != TokenType::ANGLE_BRACKETS_RIGHT) { LogError(token, String::Format("expected '>' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); // '>' } AutoPtr list = new ASTListType(); list->SetElementType(type); AutoPtr ret = ast_->FindType(list->ToString()); if (ret == nullptr) { ast_->AddType(list.Get()); ret = list.Get(); } return ret; } AutoPtr Parser::ParseMapType() { lexer_.GetToken(); // 'Map' Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ANGLE_BRACKETS_LEFT) { LogError(token, String::Format("expected '<' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); // '<' } AutoPtr keyType = ParseType(); // key type if (keyType == nullptr) { LogError(token, String::Format("key type '%s' is illegal", token.value_.string())); lexer_.SkipToken(TokenType::ANGLE_BRACKETS_RIGHT); return nullptr; } token = lexer_.PeekToken(); if (token.kind_ != TokenType::COMMA) { LogError(token, String::Format("expected ',' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); // ',' } AutoPtr valueType = ParseType(); if (valueType == nullptr) { LogError(token, String::Format("key type '%s' is illegal", token.value_.string())); lexer_.SkipToken(TokenType::ANGLE_BRACKETS_RIGHT); return nullptr; } token = lexer_.PeekToken(); if (token.kind_ != TokenType::ANGLE_BRACKETS_RIGHT) { LogError(token, String::Format("expected '>' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } AutoPtr map = new ASTMapType(); map->SetKeyType(keyType); map->SetValueType(valueType); AutoPtr ret = ast_->FindType(map->ToString()); if (ret == nullptr) { ast_->AddType(map.Get()); ret = map.Get(); } return ret; } AutoPtr Parser::ParseSmqType() { lexer_.GetToken(); // 'SharedMemQueue' Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ANGLE_BRACKETS_LEFT) { LogError(token, String::Format("expected '<' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); // '<' } AutoPtr InnerType = ParseType(); if (InnerType == nullptr) { lexer_.SkipToken(TokenType::ANGLE_BRACKETS_RIGHT); return nullptr; } token = lexer_.PeekToken(); if (token.kind_ != TokenType::ANGLE_BRACKETS_RIGHT) { LogError(token, String::Format("expected '>' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); // '>' } AutoPtr type = new ASTSmqType(); type->SetInnerType(InnerType); AutoPtr ret = ast_->FindType(type->ToString()); if (ret == nullptr) { ast_->AddType(type.Get()); ret = type.Get(); } return ret; } AutoPtr Parser::ParseUserDefType() { Token token = lexer_.GetToken(); if (token.kind_ == TokenType::ID) { return ast_->FindType(token.value_); } String typePrefix = token.value_; token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected identifier before '%s' token", token.value_.string())); return nullptr; } else { lexer_.GetToken(); } String typeName = typePrefix + " " + token.value_; AutoPtr type = ast_->FindType(typeName); if (type != nullptr) { ast_->AddType(type); } return type; } void Parser::ParseEnumDeclaration(const AttrSet &attrs) { AutoPtr enumType = new ASTEnumType; enumType->SetAttribute(ParseUserDefTypeAttr(attrs)); lexer_.GetToken(); Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected enum type name before '%s' token", token.value_.string())); } else { lexer_.GetToken(); enumType->SetName(token.value_); } token = lexer_.PeekToken(); if (token.kind_ == TokenType::COLON || token.kind_ == TokenType::BRACES_LEFT) { enumType->SetBaseType(ParseEnumBaseType()); } else { LogError(token, String::Format("expected ':' or '{' before '%s' token", token.value_.string())); } ParserEnumMember(enumType); token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_RIGHT) { LogError(token, String::Format("expected '}' before '%s' token", token.value_.string())); return; } else { lexer_.GetToken(); } token = lexer_.PeekToken(); if (token.kind_ != TokenType::SEMICOLON) { LogError(token, String::Format("expected ';' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } ast_->AddTypeDefinition(enumType.Get()); } AutoPtr Parser::ParseEnumBaseType() { AutoPtr baseType = nullptr; Token token = lexer_.PeekToken(); if (token.kind_ == TokenType::COLON) { lexer_.GetToken(); token = lexer_.PeekToken(); baseType = ParseType(); if (baseType == nullptr) { return nullptr; } switch (baseType->GetTypeKind()) { case TypeKind::TYPE_BYTE: case TypeKind::TYPE_SHORT: case TypeKind::TYPE_INT: case TypeKind::TYPE_LONG: case TypeKind::TYPE_UCHAR: case TypeKind::TYPE_USHORT: case TypeKind::TYPE_UINT: case TypeKind::TYPE_ULONG: break; default: LogError(token, String::Format("illegal base type of enum", baseType->ToString().string())); return nullptr; } token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_LEFT) { LogError(token, String::Format("expected '{' before '%s' token", token.value_.string())); } lexer_.GetToken(); } else { lexer_.GetToken(); AutoPtr baseType = ast_->FindType("int"); } return baseType; } void Parser::ParserEnumMember(const AutoPtr &enumType) { Token token = lexer_.PeekToken(); while (token.kind_ == TokenType::ID) { AutoPtr enumValue = new ASTEnumValue(token.value_); lexer_.GetToken(); token = lexer_.PeekToken(); if (token.kind_ == TokenType::ASSIGN) { lexer_.GetToken(); token = lexer_.PeekToken(); enumValue->SetExprValue(ParseExpr()); } enumValue->SetType(enumType->GetBaseType()); enumType->AddMember(enumValue); token = lexer_.PeekToken(); if (token.kind_ == TokenType::COMMA) { lexer_.GetToken(); token = lexer_.PeekToken(); continue; } if (token.kind_ != TokenType::BRACES_RIGHT) { LogError(token, String::Format("expected ',' or '}' before '%s' token", token.value_.string())); } } } void Parser::ParseStructDeclaration(const AttrSet &attrs) { AutoPtr structType = new ASTStructType; structType->SetAttribute(ParseUserDefTypeAttr(attrs)); lexer_.GetToken(); Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected struct name before '%s' token", token.value_.string())); } else { structType->SetName(token.value_); lexer_.GetToken(); } token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_LEFT) { LogError(token, String::Format("expected '{' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } ParseStructMember(structType); token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_RIGHT) { LogError(token, String::Format("expected '}' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } token = lexer_.PeekToken(); if (token.kind_ != TokenType::SEMICOLON) { LogError(token, String::Format("expected ';' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } ast_->AddTypeDefinition(structType.Get()); } void Parser::ParseStructMember(const AutoPtr &structType) { Token token = lexer_.PeekToken(); while (token.kind_ != TokenType::BRACES_RIGHT && token.kind_ != TokenType::END_OF_FILE) { AutoPtr memberType = ParseType(); if (memberType == nullptr) { lexer_.SkipToken(TokenType::SEMICOLON); token = lexer_.PeekToken(); continue; } String typeName = memberType->ToString(); token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected member name before '%s' token", token.value_.string())); lexer_.SkipToken(TokenType::SEMICOLON); token = lexer_.PeekToken(); continue; } lexer_.GetToken(); String memberName = token.value_; structType->AddMember(memberType, memberName); token = lexer_.PeekToken(); if (token.kind_ == TokenType::SEMICOLON) { lexer_.GetToken(); token = lexer_.PeekToken(); continue; } if (token.kind_ != TokenType::BRACES_RIGHT) { LogError(token, String::Format("expected ',' or '}' before '%s' token", token.value_.string())); } } } void Parser::ParseUnionDeclaration(const AttrSet &attrs) { AutoPtr unionType = new ASTUnionType; unionType->SetAttribute(ParseUserDefTypeAttr(attrs)); lexer_.GetToken(); Token token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected struct name before '%s' token", token.value_.string())); } else { unionType->SetName(token.value_); lexer_.GetToken(); } token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_LEFT) { LogError(token, String::Format("expected '{' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } ParseUnionMember(unionType); token = lexer_.PeekToken(); if (token.kind_ != TokenType::BRACES_RIGHT) { LogError(token, String::Format("expected '}' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } token = lexer_.PeekToken(); if (token.kind_ != TokenType::SEMICOLON) { LogError(token, String::Format("expected ';' before '%s' token", token.value_.string())); } else { lexer_.GetToken(); } ast_->AddTypeDefinition(unionType.Get()); } void Parser::ParseUnionMember(const AutoPtr &unionType) { Token token = lexer_.PeekToken(); while (token.kind_ != TokenType::BRACES_RIGHT && token.kind_ != TokenType::END_OF_FILE) { AutoPtr memberType = ParseType(); if (memberType == nullptr) { lexer_.SkipToken(TokenType::SEMICOLON); token = lexer_.PeekToken(); continue; } String typeName = memberType->ToString(); token = lexer_.PeekToken(); if (token.kind_ != TokenType::ID) { LogError(token, String::Format("expected member name before '%s' token", token.value_.string())); lexer_.SkipToken(TokenType::SEMICOLON); token = lexer_.PeekToken(); continue; } lexer_.GetToken(); String memberName = token.value_; if (!AddUnionMember(unionType, memberType, memberName)) { LogError(token, String::Format("union not support this type or name of member duplicate '%s'", token.value_.string())); } token = lexer_.PeekToken(); if (token.kind_ == TokenType::SEMICOLON) { lexer_.GetToken(); token = lexer_.PeekToken(); continue; } if (token.kind_ != TokenType::BRACES_RIGHT) { LogError(token, String::Format("expected ',' or '}' before '%s' token", token.value_.string())); } } } bool Parser::AddUnionMember(const AutoPtr &unionType, const AutoPtr &type, const String &name) { for (size_t i = 0; i < unionType->GetMemberNumber(); i++) { String memberName = unionType->GetMemberName(i); if (name.Equals(memberName)) { return false; } } if ((type->GetTypeKind() < TypeKind::TYPE_BOOLEAN || type->GetTypeKind() > TypeKind::TYPE_ULONG) && (type->GetTypeKind() < TypeKind::TYPE_ENUM || type->GetTypeKind() > TypeKind::TYPE_UNION)) { return false; } unionType->AddMember(type, name); return true; } AutoPtr Parser::ParseUserDefTypeAttr(const AttrSet &attrs) { AutoPtr attribute = new ASTTypeAttr(); for (const auto &token : attrs) { switch (token.kind_) { case TokenType::FULL: attribute->isFull_ = true; break; case TokenType::LITE: attribute->isLite_ = true; break; default: LogError(token, String::Format("invalid attribute '%s' for type decl", token.value_.string())); break; } } return attribute; } AutoPtr Parser::ParseExpr() { return ParseAndExpr(); } AutoPtr Parser::ParseAndExpr() { AutoPtr left = ParseXorExpr(); Token token = lexer_.PeekToken(); while (token.kind_ == TokenType::AND) { lexer_.GetToken(); AutoPtr expr = new ASTBinaryExpr; expr->op_ = BinaryOpKind::AND; expr->lExpr_ = left; expr->rExpr_ = ParseXorExpr(); left = expr.Get(); token = lexer_.PeekToken(); } return left; } AutoPtr Parser::ParseXorExpr() { AutoPtr left = ParseOrExpr(); Token token = lexer_.PeekToken(); while (token.kind_ == TokenType::XOR) { lexer_.GetToken(); AutoPtr expr = new ASTBinaryExpr; expr->op_ = BinaryOpKind::XOR; expr->lExpr_ = left; expr->rExpr_ = ParseOrExpr(); left = expr.Get(); token = lexer_.PeekToken(); } return left; } AutoPtr Parser::ParseOrExpr() { AutoPtr left = ParseShiftExpr(); Token token = lexer_.PeekToken(); while (token.kind_ == TokenType::OR) { lexer_.GetToken(); AutoPtr expr = new ASTBinaryExpr; expr->op_ = BinaryOpKind::OR; expr->lExpr_ = left; expr->rExpr_ = ParseShiftExpr(); left = expr.Get(); token = lexer_.PeekToken(); } return left; } AutoPtr Parser::ParseShiftExpr() { AutoPtr left = ParseAddExpr(); Token token = lexer_.PeekToken(); while (token.kind_ == TokenType::LEFT_SHIFT || token.kind_ == TokenType::RIGHT_SHIFT) { lexer_.GetToken(); BinaryOpKind op = (token.kind_ == TokenType::LEFT_SHIFT) ? BinaryOpKind::LSHIFT : BinaryOpKind::RSHIFT; AutoPtr expr = new ASTBinaryExpr; expr->op_ = op; expr->lExpr_ = left; expr->rExpr_ = ParseAddExpr(); left = expr.Get(); token = lexer_.PeekToken(); } return left; } AutoPtr Parser::ParseAddExpr() { AutoPtr left = ParseMulExpr(); Token token = lexer_.PeekToken(); while (token.kind_ == TokenType::ADD || token.kind_ == TokenType::SUB) { lexer_.GetToken(); BinaryOpKind op = (token.kind_ == TokenType::ADD) ? BinaryOpKind::ADD : BinaryOpKind::SUB; AutoPtr expr = new ASTBinaryExpr; expr->op_ = op; expr->lExpr_ = left; expr->rExpr_ = ParseMulExpr(); left = expr.Get(); token = lexer_.PeekToken(); } return left; } AutoPtr Parser::ParseMulExpr() { AutoPtr left = ParseUnaryExpr(); Token token = lexer_.PeekToken(); while ( token.kind_ == TokenType::STAR || token.kind_ == TokenType::SLASH || token.kind_ == TokenType::PERCENT_SIGN) { lexer_.GetToken(); BinaryOpKind op = BinaryOpKind::MUL; if (token.kind_ == TokenType::SLASH) { op = BinaryOpKind::DIV; } else if (token.kind_ == TokenType::PERCENT_SIGN) { op = BinaryOpKind::MOD; } AutoPtr expr = new ASTBinaryExpr; expr->op_ = op; expr->lExpr_ = left; expr->rExpr_ = ParseUnaryExpr(); left = expr.Get(); token = lexer_.PeekToken(); } return left; } AutoPtr Parser::ParseUnaryExpr() { Token token = lexer_.PeekToken(); switch (token.kind_) { case TokenType::ADD: case TokenType::SUB: case TokenType::TILDE: { lexer_.GetToken(); AutoPtr expr = new ASTUnaryExpr; expr->op_ = UnaryOpKind::PLUS; if (token.kind_ == TokenType::SUB) { expr->op_ = UnaryOpKind::MINUS; } else if (token.kind_ == TokenType::TILDE) { expr->op_ = UnaryOpKind::TILDE; } expr->expr_ = ParseUnaryExpr(); return expr.Get(); } default: return ParsePrimaryExpr(); } } AutoPtr Parser::ParsePrimaryExpr() { Token token = lexer_.PeekToken(); switch (token.kind_) { case TokenType::PARENTHESES_LEFT: { lexer_.GetToken(); AutoPtr expr = ParseExpr(); token = lexer_.PeekToken(); if (token.kind_ != TokenType::PARENTHESES_RIGHT) { LogError(token, String::Format("expected ')' before %s token", token.value_.string())); } else { lexer_.GetToken(); expr->isParenExpr = true; } return expr; } case TokenType::NUM: return ParseNumExpr(); default: LogError(token, String::Format("this expression is not supported")); lexer_.SkipUntilToken(TokenType::COMMA); return nullptr; } } AutoPtr Parser::ParseNumExpr() { Token token = lexer_.GetToken(); AutoPtr expr = new ASTNumExpr; expr->value_ = token.value_; return expr.Get(); } bool Parser::CheckType(const Token &token, const AutoPtr &type) { if (type == nullptr) { return false; } if (Options::GetInstance().GetTargetLanguage().Equals("c")) { if (type->IsSequenceableType()) { LogError(token, String::Format("The sequenceable type is not supported by c language.")); return false; } if (type->IsSmqType()) { LogError(token, String::Format("The smq type is not supported by c language.")); return false; } if (Options::GetInstance().DoGenerateKernelCode()) { switch (type->GetTypeKind()) { case TypeKind::TYPE_FLOAT: case TypeKind::TYPE_DOUBLE: case TypeKind::TYPE_FILEDESCRIPTOR: case TypeKind::TYPE_INTERFACE: LogError(token, String::Format("The '%s' type is not supported by c language.", type->ToString().string())); break; default: break; } } } else if (Options::GetInstance().GetTargetLanguage().Equals("java")) { switch (type->GetTypeKind()) { case TypeKind::TYPE_UCHAR: case TypeKind::TYPE_USHORT: case TypeKind::TYPE_UINT: case TypeKind::TYPE_ULONG: case TypeKind::TYPE_ENUM: case TypeKind::TYPE_STRUCT: case TypeKind::TYPE_UNION: case TypeKind::TYPE_SMQ: case TypeKind::TYPE_UNKNOWN: LogError(token, String::Format("The '%s' type is not supported by java language.", type->ToString().string())); return false; default: break; } } return true; } void Parser::SetAstFileType() { if (ast_->GetInterfaceDef() != nullptr) { if (ast_->GetInterfaceDef()->IsCallback()) { ast_->SetAStFileType(ASTFileType::AST_ICALLBACK); } else { ast_->SetAStFileType(ASTFileType::AST_IFACE); } } else { ast_->SetAStFileType(ASTFileType::AST_TYPES); } } bool Parser::CheckIntegrity() { if (ast_ == nullptr) { LogError(String("ast is nullptr.")); return false; } if (ast_->GetName().IsEmpty()) { LogError(String("ast's name is empty.")); return false; } if (ast_->GetPackageName().IsEmpty()) { LogError(String("ast's package name is empty.")); return false; } switch (ast_->GetASTFileType()) { case ASTFileType::AST_IFACE: { return CheckInterfaceAst(); } case ASTFileType::AST_ICALLBACK: { return CheckCallbackAst(); } case ASTFileType::AST_SEQUENCEABLE: { LogError(String("it's impossible that ast is sequenceable.")); return false; } case ASTFileType::AST_TYPES: { if (ast_->GetInterfaceDef() != nullptr) { LogError(String("custom ast cannot has interface.")); return false; } break; } default: break; } return true; } bool Parser::CheckInterfaceAst() { AutoPtr interface = ast_->GetInterfaceDef(); if (interface == nullptr) { LogError(String("ast's interface is empty.")); return false; } if (ast_->GetTypeDefinitionNumber() > 0) { LogError(String("interface ast cannot has custom types.")); return false; } if (interface->GetMethodNumber() == 0) { LogError(String("interface ast has no method.")); return false; } return true; } bool Parser::CheckCallbackAst() { AutoPtr interface = ast_->GetInterfaceDef(); if (interface == nullptr) { LogError(String("ast's interface is empty.")); return false; } if (!interface->IsCallback()) { LogError(String("ast is callback, but ast's interface is not callback.")); return false; } return true; } /* * For example * filePath: ./ohos/interface/foo/v1_0/IFoo.idl * package OHOS.Hdi.foo.v1_0; */ bool Parser::CheckPackageName(const String &filePath, const String &packageName) { String pkgToPath = Options::GetInstance().GetPackagePath(packageName); int index = filePath.LastIndexOf(File::separator); if (index == -1) { return false; } String parentDir = filePath.Substring(0, index); return parentDir.Equals(pkgToPath); } bool Parser::CheckImport(const String &importName) { if (!std::regex_match(importName.string(), reImport)) { LogError(String::Format("invalid impirt name '%s'", importName.string())); return false; } String idlFilePath = Options::GetInstance().GetImportFilePath(importName); if (!File::CheckValid(idlFilePath)) { LogError(String::Format("can not import '%s'", idlFilePath.string())); return false; } return true; } bool Parser::AddAst(const AutoPtr &ast) { if (ast == nullptr) { LogError(String("ast is nullptr.")); return false; } allAsts_[ast->GetFullName()] = ast; return true; } void Parser::LogError(const String &message) { errors_.push_back(message); } void Parser::LogError(const Token &token, const String &message) { errors_.push_back(String::Format("[%s] error:%s", LocInfo(token).string(), message.string())); } void Parser::ShowError() { for (const auto &errMsg : errors_) { Logger::E(TAG, "%s", errMsg.string()); } } } // namespace HDI } // namespace OHOS