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> ¶m, 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> ¶m,
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> ¶m, 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 ¶mSb, 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