• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2023 Huawei Device Co., Ltd.
3  *
4  * HDF is dual licensed: you can use it either under the terms of
5  * the GPL, or the BSD license, at your option.
6  * See the LICENSE file in the root of this repository for complete details.
7  */
8 
9 #include "codegen/cpp_code_emitter.h"
10 
11 #include <regex>
12 #include <unordered_set>
13 
14 #include "util/options.h"
15 
16 #include "util/logger.h"
17 
18 namespace OHOS {
19 namespace HDI {
GetStdlibInclusions(HeaderFile::HeaderFileSet & headerFiles)20 void CppCodeEmitter::GetStdlibInclusions(HeaderFile::HeaderFileSet &headerFiles)
21 {
22     const AST::TypeStringMap &types = ast_->GetTypes();
23     for (const auto &pair : types) {
24         AutoPtr<ASTType> type = pair.second;
25         switch (type->GetTypeKind()) {
26             case TypeKind::TYPE_STRING: {
27                 headerFiles.emplace(HeaderFileType::CPP_STD_HEADER_FILE, "string");
28                 break;
29             }
30             case TypeKind::TYPE_ARRAY:
31             case TypeKind::TYPE_LIST: {
32                 headerFiles.emplace(HeaderFileType::CPP_STD_HEADER_FILE, "vector");
33                 break;
34             }
35             case TypeKind::TYPE_MAP: {
36                 headerFiles.emplace(HeaderFileType::CPP_STD_HEADER_FILE, "map");
37                 break;
38             }
39             case TypeKind::TYPE_SMQ: {
40                 headerFiles.emplace(HeaderFileType::OTHER_MODULES_HEADER_FILE, "base/hdi_smq");
41                 break;
42             }
43             case TypeKind::TYPE_ASHMEM: {
44                 headerFiles.emplace(HeaderFileType::OTHER_MODULES_HEADER_FILE, "ashmem");
45                 break;
46             }
47             case TypeKind::TYPE_NATIVE_BUFFER: {
48                 headerFiles.emplace(HeaderFileType::OTHER_MODULES_HEADER_FILE, "base/native_buffer");
49                 break;
50             }
51             default:
52                 break;
53         }
54     }
55 }
56 
GetImportInclusions(HeaderFile::HeaderFileSet & headerFiles)57 void CppCodeEmitter::GetImportInclusions(HeaderFile::HeaderFileSet &headerFiles)
58 {
59     for (const auto &importPair : ast_->GetImports()) {
60         AutoPtr<AST> importAst = importPair.second;
61         std::string fileName = (importAst->GetASTFileType() == ASTFileType::AST_SEQUENCEABLE) ?
62             PackageToFilePath(importAst->GetName()) :
63             PackageToFilePath(importAst->GetFullName());
64         headerFiles.emplace(HeaderFileType::OWN_MODULE_HEADER_FILE, fileName);
65     }
66 }
67 
EmitInterfaceMethodParameter(const AutoPtr<ASTParameter> & param,StringBuilder & sb,const std::string & prefix) const68 void CppCodeEmitter::EmitInterfaceMethodParameter(
69     const AutoPtr<ASTParameter> &param, StringBuilder &sb, const std::string &prefix) const
70 {
71     sb.Append(prefix).Append(param->EmitCppParameter());
72 }
73 
EmitLicense(StringBuilder & sb)74 void CppCodeEmitter::EmitLicense(StringBuilder &sb)
75 {
76     if (ast_->GetLicense().empty()) {
77         return;
78     }
79     sb.Append(ast_->GetLicense()).Append("\n\n");
80 }
81 
EmitHeadMacro(StringBuilder & sb,const std::string & fullName) const82 void CppCodeEmitter::EmitHeadMacro(StringBuilder &sb, const std::string &fullName) const
83 {
84     std::string macroName = MacroName(fullName);
85     sb.Append("#ifndef ").Append(macroName).Append("\n");
86     sb.Append("#define ").Append(macroName).Append("\n");
87 }
88 
EmitTailMacro(StringBuilder & sb,const std::string & fullName) const89 void CppCodeEmitter::EmitTailMacro(StringBuilder &sb, const std::string &fullName) const
90 {
91     std::string macroName = MacroName(fullName);
92     sb.Append("#endif // ").Append(macroName);
93 }
94 
EmitHeadExternC(StringBuilder & sb) const95 void CppCodeEmitter::EmitHeadExternC(StringBuilder &sb) const
96 {
97     sb.Append("#ifdef __cplusplus\n");
98     sb.Append("extern \"C\" {\n");
99     sb.Append("#endif /* __cplusplus */\n");
100 }
101 
EmitTailExternC(StringBuilder & sb) const102 void CppCodeEmitter::EmitTailExternC(StringBuilder &sb) const
103 {
104     sb.Append("#ifdef __cplusplus\n");
105     sb.Append("}\n");
106     sb.Append("#endif /* __cplusplus */\n");
107 }
108 
IsVersion(const std::string & name) const109 bool CppCodeEmitter::IsVersion(const std::string &name) const
110 {
111     std::regex rVer("[V|v][0-9]+_[0-9]+");
112     return std::regex_match(name.c_str(), rVer);
113 }
114 
EmitCppNameSpaceVec(const std::string & namespaceStr) const115 std::vector<std::string> CppCodeEmitter::EmitCppNameSpaceVec(const std::string &namespaceStr) const
116 {
117     std::vector<std::string> result;
118     std::vector<std::string> namespaceVec = StringHelper::Split(namespaceStr, ".");
119     bool findVersion = false;
120 
121     std::string rootPackage = Options::GetInstance().GetRootPackage(namespaceStr);
122     size_t rootPackageNum = StringHelper::Split(rootPackage, ".").size();
123 
124     for (size_t i = 0; i < namespaceVec.size(); i++) {
125         std::string name;
126         if (i < rootPackageNum) {
127             name = StringHelper::StrToUpper(namespaceVec[i]);
128         } else if (!findVersion && IsVersion(namespaceVec[i])) {
129             name = StringHelper::Replace(namespaceVec[i], 'v', 'V');
130             findVersion = true;
131         } else {
132             if (findVersion) {
133                 name = namespaceVec[i];
134             } else {
135                 name = PascalName(namespaceVec[i]);
136             }
137         }
138 
139         result.emplace_back(name);
140     }
141     return result;
142 }
143 
EmitPackageToNameSpace(const std::string & packageName) const144 std::string CppCodeEmitter::EmitPackageToNameSpace(const std::string &packageName) const
145 {
146     if (packageName.empty()) {
147         return packageName;
148     }
149 
150     StringBuilder nameSpaceStr;
151     std::vector<std::string> namespaceVec = EmitCppNameSpaceVec(packageName);
152     for (auto nameIter = namespaceVec.begin(); nameIter != namespaceVec.end(); nameIter++) {
153         nameSpaceStr.Append(*nameIter);
154         if (nameIter != namespaceVec.end() - 1) {
155             nameSpaceStr.Append("::");
156         }
157     }
158 
159     return nameSpaceStr.ToString();
160 }
161 
EmitBeginNamespace(StringBuilder & sb)162 void CppCodeEmitter::EmitBeginNamespace(StringBuilder &sb)
163 {
164     std::vector<std::string> cppNamespaceVec = EmitCppNameSpaceVec(interface_->GetNamespace()->ToString());
165     for (const auto &nspace : cppNamespaceVec) {
166         sb.AppendFormat("namespace %s {\n", nspace.c_str());
167     }
168 }
169 
EmitEndNamespace(StringBuilder & sb)170 void CppCodeEmitter::EmitEndNamespace(StringBuilder &sb)
171 {
172     std::vector<std::string> cppNamespaceVec = EmitCppNameSpaceVec(interface_->GetNamespace()->ToString());
173 
174     for (std::vector<std::string>::const_reverse_iterator nspaceIter = cppNamespaceVec.rbegin();
175         nspaceIter != cppNamespaceVec.rend(); ++nspaceIter) {
176         sb.AppendFormat("} // %s\n", nspaceIter->c_str());
177     }
178 }
179 
EmitUsingNamespace(StringBuilder & sb)180 void CppCodeEmitter::EmitUsingNamespace(StringBuilder &sb)
181 {
182     sb.Append("using namespace OHOS;\n");
183     sb.Append("using namespace OHOS::HDI;\n");
184     EmitImportUsingNamespace(sb);
185 }
186 
EmitNamespace(const std::string & packageName) const187 std::string CppCodeEmitter::EmitNamespace(const std::string &packageName) const
188 {
189     if (packageName.empty()) {
190         return packageName;
191     }
192 
193     size_t index = packageName.rfind('.');
194     return index != std::string::npos ? StringHelper::SubStr(packageName, 0, index) : packageName;
195 }
196 
EmitImportUsingNamespace(StringBuilder & sb)197 void CppCodeEmitter::EmitImportUsingNamespace(StringBuilder &sb)
198 {
199     using StringSet = std::unordered_set<std::string>;
200     StringSet namespaceSet;
201     std::string selfNameSpace = EmitPackageToNameSpace(EmitNamespace(ast_->GetFullName()));
202 
203     for (const auto &importPair : ast_->GetImports()) {
204         AutoPtr<AST> import = importPair.second;
205         std::string nameSpace = EmitPackageToNameSpace(EmitNamespace(import->GetFullName()));
206         if (nameSpace == selfNameSpace) {
207             continue;
208         }
209         namespaceSet.emplace(nameSpace);
210     }
211 
212     const AST::TypeStringMap &types = ast_->GetTypes();
213     for (const auto &pair : types) {
214         AutoPtr<ASTType> type = pair.second;
215         if (type->GetTypeKind() == TypeKind::TYPE_SMQ ||
216             type->GetTypeKind() == TypeKind::TYPE_NATIVE_BUFFER) {
217             namespaceSet.emplace("OHOS::HDI::Base");
218             break;
219         }
220     }
221 
222     for (const auto &nspace : namespaceSet) {
223         sb.Append("using namespace ").AppendFormat("%s;\n", nspace.c_str());
224     }
225 }
226 
EmitWriteMethodParameter(const AutoPtr<ASTParameter> & param,const std::string & parcelName,StringBuilder & sb,const std::string & prefix) const227 void CppCodeEmitter::EmitWriteMethodParameter(const AutoPtr<ASTParameter> &param,
228     const std::string &parcelName, StringBuilder &sb, const std::string &prefix) const
229 {
230     AutoPtr<ASTType> type = param->GetType();
231     type->EmitCppWriteVar(parcelName, param->GetName(), sb, prefix);
232 }
233 
EmitReadMethodParameter(const AutoPtr<ASTParameter> & param,const std::string & parcelName,bool initVariable,StringBuilder & sb,const std::string & prefix) const234 void CppCodeEmitter::EmitReadMethodParameter(const AutoPtr<ASTParameter> &param, const std::string &parcelName,
235     bool initVariable, StringBuilder &sb, const std::string &prefix) const
236 {
237     AutoPtr<ASTType> type = param->GetType();
238     type->EmitCppReadVar(parcelName, param->GetName(), sb, prefix, initVariable);
239 }
240 
MacroName(const std::string & name) const241 std::string CppCodeEmitter::MacroName(const std::string &name) const
242 {
243     if (name.empty()) {
244         return name;
245     }
246 
247     std::string macro = StringHelper::StrToUpper(StringHelper::Replace(name, '.', '_')) + "_H";
248     return macro;
249 }
250 
SpecificationParam(StringBuilder & paramSb,const std::string & prefix) const251 std::string CppCodeEmitter::SpecificationParam(StringBuilder &paramSb, const std::string &prefix) const
252 {
253     size_t maxLineLen = 120;
254     size_t replaceLen = 2;
255     std::string paramStr = paramSb.ToString();
256     size_t preIndex = 0;
257     size_t curIndex = 0;
258 
259     std::string insertStr = StringHelper::Format("\n%s", prefix.c_str());
260     for (; curIndex < paramStr.size(); curIndex++) {
261         if (curIndex == maxLineLen && preIndex > 0) {
262             StringHelper::Replace(paramStr, preIndex, replaceLen, ",");
263             paramStr.insert(preIndex + 1, insertStr);
264         } else {
265             if (paramStr[curIndex] == ',') {
266                 preIndex = curIndex;
267             }
268         }
269     }
270     return paramStr;
271 }
272 
EmitHeaderNameByInterface(AutoPtr<ASTInterfaceType> interface,const std::string & name)273 std::string CppCodeEmitter::EmitHeaderNameByInterface(AutoPtr<ASTInterfaceType> interface, const std::string &name)
274 {
275     return StringHelper::Format(
276         "v%u_%u/%s", interface->GetMajorVersion(), interface->GetMinorVersion(), FileName(name).c_str());
277 }
278 
EmitDefinitionByInterface(AutoPtr<ASTInterfaceType> interface,const std::string & name) const279 std::string CppCodeEmitter::EmitDefinitionByInterface(
280     AutoPtr<ASTInterfaceType> interface, const std::string &name) const
281 {
282     StringBuilder sb;
283     std::vector<std::string> cppNamespaceVec = EmitCppNameSpaceVec(interface->GetNamespace()->ToString());
284     for (const auto &nspace : cppNamespaceVec) {
285         sb.AppendFormat("%s", nspace.c_str());
286         sb.Append("::");
287     }
288     sb.Append(name.c_str());
289     return sb.ToString();
290 }
291 
GetNameSpaceByInterface(AutoPtr<ASTInterfaceType> interface,const std::string & name)292 std::string CppCodeEmitter::GetNameSpaceByInterface(AutoPtr<ASTInterfaceType> interface, const std::string &name)
293 {
294     std::string value = EmitDefinitionByInterface(interface, name);
295     if (value.empty()) {
296         return "";
297     }
298     size_t index = value.rfind(':');
299     return (index == std::string::npos) ? value.substr(0) : value.substr(0, index + 1);
300 }
301 } // namespace HDI
302 } // namespace OHOS