1 /*
2 * Copyright (c) 2021 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, "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_BUFFER_HANDLE: {
48 headerFiles.emplace(HeaderFileType::OTHER_MODULES_HEADER_FILE, "hdi_buffer_handle");
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)68 void CppCodeEmitter::EmitInterfaceMethodParameter(
69 const AutoPtr<ASTParameter> ¶m, StringBuilder &sb, const std::string &prefix)
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)82 void CppCodeEmitter::EmitHeadMacro(StringBuilder &sb, const std::string &fullName)
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)89 void CppCodeEmitter::EmitTailMacro(StringBuilder &sb, const std::string &fullName)
90 {
91 std::string macroName = MacroName(fullName);
92 sb.Append("#endif // ").Append(macroName);
93 }
94
EmitHeadExternC(StringBuilder & sb)95 void CppCodeEmitter::EmitHeadExternC(StringBuilder &sb)
96 {
97 sb.Append("#ifdef __cplusplus\n");
98 sb.Append("extern \"C\" {\n");
99 sb.Append("#endif /* __cplusplus */\n");
100 }
101
EmitTailExternC(StringBuilder & sb)102 void CppCodeEmitter::EmitTailExternC(StringBuilder &sb)
103 {
104 sb.Append("#ifdef __cplusplus\n");
105 sb.Append("}\n");
106 sb.Append("#endif /* __cplusplus */\n");
107 }
108
isVersion(const std::string & name)109 bool CppCodeEmitter::isVersion(const std::string &name)
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)115 std::vector<std::string> CppCodeEmitter::EmitCppNameSpaceVec(const std::string &namespaceStr)
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)144 std::string CppCodeEmitter::EmitPackageToNameSpace(const std::string &packageName)
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 (auto nspaceIter = cppNamespaceVec.rbegin(); nspaceIter != cppNamespaceVec.rend(); nspaceIter++) {
175 sb.AppendFormat("} // %s\n", nspaceIter->c_str());
176 }
177 }
178
EmitUsingNamespace(StringBuilder & sb)179 void CppCodeEmitter::EmitUsingNamespace(StringBuilder &sb)
180 {
181 sb.Append("using namespace OHOS;\n");
182 sb.Append("using namespace OHOS::HDI;\n");
183 EmitImportUsingNamespace(sb);
184 }
185
EmitNamespace(const std::string & packageName)186 std::string CppCodeEmitter::EmitNamespace(const std::string &packageName)
187 {
188 if (packageName.empty()) {
189 return packageName;
190 }
191
192 size_t index = packageName.rfind('.');
193 return index != std::string::npos ? StringHelper::SubStr(packageName, 0, index) : packageName;
194 }
195
EmitImportUsingNamespace(StringBuilder & sb)196 void CppCodeEmitter::EmitImportUsingNamespace(StringBuilder &sb)
197 {
198 using StringSet = std::unordered_set<std::string>;
199 StringSet namespaceSet;
200 std::string selfNameSpace = EmitPackageToNameSpace(EmitNamespace(ast_->GetFullName()));
201
202 for (const auto &importPair : ast_->GetImports()) {
203 AutoPtr<AST> import = importPair.second;
204 std::string nameSpace = EmitPackageToNameSpace(EmitNamespace(import->GetFullName()));
205 if (nameSpace == selfNameSpace) {
206 continue;
207 }
208 namespaceSet.emplace(nameSpace);
209 }
210
211 const AST::TypeStringMap &types = ast_->GetTypes();
212 for (const auto &pair : types) {
213 AutoPtr<ASTType> type = pair.second;
214 if (type->GetTypeKind() == TypeKind::TYPE_SMQ ||
215 type->GetTypeKind() == TypeKind::TYPE_BUFFER_HANDLE) {
216 namespaceSet.emplace("OHOS::HDI::Base");
217 break;
218 }
219 }
220
221 for (const auto &nspace : namespaceSet) {
222 sb.Append("using namespace ").AppendFormat("%s;\n", nspace.c_str());
223 }
224 }
225
EmitWriteMethodParameter(const AutoPtr<ASTParameter> & param,const std::string & parcelName,StringBuilder & sb,const std::string & prefix)226 void CppCodeEmitter::EmitWriteMethodParameter(
227 const AutoPtr<ASTParameter> ¶m, const std::string &parcelName, StringBuilder &sb, const std::string &prefix)
228 {
229 AutoPtr<ASTType> type = param->GetType();
230 type->EmitCppWriteVar(parcelName, param->GetName(), sb, prefix);
231 }
232
EmitReadMethodParameter(const AutoPtr<ASTParameter> & param,const std::string & parcelName,bool initVariable,StringBuilder & sb,const std::string & prefix)233 void CppCodeEmitter::EmitReadMethodParameter(const AutoPtr<ASTParameter> ¶m, const std::string &parcelName,
234 bool initVariable, StringBuilder &sb, const std::string &prefix)
235 {
236 AutoPtr<ASTType> type = param->GetType();
237 type->EmitCppReadVar(parcelName, param->GetName(), sb, prefix, initVariable);
238 }
239
MacroName(const std::string & name)240 std::string CppCodeEmitter::MacroName(const std::string &name)
241 {
242 if (name.empty()) {
243 return name;
244 }
245
246 std::string macro = StringHelper::StrToUpper(StringHelper::Replace(name, '.', '_')) + "_H";
247 return macro;
248 }
249
SpecificationParam(StringBuilder & paramSb,const std::string & prefix)250 std::string CppCodeEmitter::SpecificationParam(StringBuilder ¶mSb, const std::string &prefix)
251 {
252 size_t maxLineLen = 120;
253 size_t replaceLen = 2;
254 std::string paramStr = paramSb.ToString();
255 size_t preIndex = 0;
256 size_t curIndex = 0;
257
258 std::string insertStr = StringHelper::Format("\n%s", prefix.c_str());
259 for (; curIndex < paramStr.size(); curIndex++) {
260 if (curIndex == maxLineLen && preIndex > 0) {
261 StringHelper::Replace(paramStr, preIndex, replaceLen, ",");
262 paramStr.insert(preIndex + 1, insertStr);
263 } else {
264 if (paramStr[curIndex] == ',') {
265 preIndex = curIndex;
266 }
267 }
268 }
269 return paramStr;
270 }
271 } // namespace HDI
272 } // namespace OHOS