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 #include <regex>
11 #include <unordered_set>
12 #include "util/options.h"
13
14 namespace OHOS {
15 namespace HDI {
GetStdlibInclusions(HeaderFile::HeaderFileSet & headerFiles)16 void CppCodeEmitter::GetStdlibInclusions(HeaderFile::HeaderFileSet& headerFiles)
17 {
18 bool includeString = false;
19 bool includeList = false;
20 bool includeMap = false;
21 bool includeSmq = false;
22
23 const AST::TypeStringMap& types = ast_->GetTypes();
24 for (const auto& pair : types) {
25 AutoPtr<ASTType> type = pair.second;
26 switch (type->GetTypeKind()) {
27 case TypeKind::TYPE_STRING: {
28 if (!includeString) {
29 headerFiles.emplace(HeaderFile(HeaderFileType::CPP_STD_HEADER_FILE, "string"));
30 includeString = true;
31 }
32 break;
33 }
34 case TypeKind::TYPE_ARRAY:
35 case TypeKind::TYPE_LIST: {
36 if (!includeList) {
37 headerFiles.emplace(HeaderFile(HeaderFileType::CPP_STD_HEADER_FILE, "vector"));
38 includeList = true;
39 }
40 break;
41 }
42 case TypeKind::TYPE_MAP: {
43 if (!includeMap) {
44 headerFiles.emplace(HeaderFile(HeaderFileType::CPP_STD_HEADER_FILE, "map"));
45 includeMap = true;
46 }
47 break;
48 }
49 case TypeKind::TYPE_SMQ: {
50 if (!includeSmq) {
51 headerFiles.emplace(HeaderFile(HeaderFileType::OTHER_MODULES_HEADER_FILE, "hdi_smq"));
52 includeSmq = true;
53 }
54 }
55 default:
56 break;
57 }
58 }
59 }
60
GetImportInclusions(HeaderFile::HeaderFileSet & headerFiles)61 void CppCodeEmitter::GetImportInclusions(HeaderFile::HeaderFileSet& headerFiles)
62 {
63 for (const auto& importPair : ast_->GetImports()) {
64 AutoPtr<AST> importAst = importPair.second;
65 String fileName = PackageToFilePath(importAst->GetFullName());
66 headerFiles.emplace(HeaderFile(HeaderFileType::OWN_MODULE_HEADER_FILE, fileName));
67 }
68 }
69
EmitInterfaceMethodParameter(const AutoPtr<ASTParameter> & param,StringBuilder & sb,const String & prefix)70 void CppCodeEmitter::EmitInterfaceMethodParameter(const AutoPtr<ASTParameter>& param, StringBuilder& sb,
71 const String& prefix)
72 {
73 sb.Append(prefix).AppendFormat(param->EmitCppParameter());
74 }
75
EmitLicense(StringBuilder & sb)76 void CppCodeEmitter::EmitLicense(StringBuilder& sb)
77 {
78 if (ast_->GetLicense().IsEmpty()) {
79 return;
80 }
81 sb.Append(ast_->GetLicense()).Append("\n\n");
82 }
83
EmitHeadMacro(StringBuilder & sb,const String & fullName)84 void CppCodeEmitter::EmitHeadMacro(StringBuilder& sb, const String& fullName)
85 {
86 String macroName = MacroName(fullName);
87 sb.Append("#ifndef ").Append(macroName).Append("\n");
88 sb.Append("#define ").Append(macroName).Append("\n");
89 }
90
EmitTailMacro(StringBuilder & sb,const String & fullName)91 void CppCodeEmitter::EmitTailMacro(StringBuilder& sb, const String& fullName)
92 {
93 String macroName = MacroName(fullName);
94 sb.Append("#endif // ").Append(macroName);
95 }
96
EmitHeadExternC(StringBuilder & sb)97 void CppCodeEmitter::EmitHeadExternC(StringBuilder& sb)
98 {
99 sb.Append("#ifdef __cplusplus\n");
100 sb.Append("extern \"C\" {\n");
101 sb.Append("#endif /* __cplusplus */\n");
102 }
103
EmitTailExternC(StringBuilder & sb)104 void CppCodeEmitter::EmitTailExternC(StringBuilder& sb)
105 {
106 sb.Append("#ifdef __cplusplus\n");
107 sb.Append("}\n");
108 sb.Append("#endif /* __cplusplus */\n");
109 }
110
isVersion(const String & name)111 bool CppCodeEmitter::isVersion(const String& name)
112 {
113 std::regex rVer("[V|v][0-9]+_[0-9]+");
114 return std::regex_match(name.string(), rVer);
115 }
116
EmitCppNameSpaceVec(const String & namespaceStr)117 std::vector<String> CppCodeEmitter::EmitCppNameSpaceVec(const String& namespaceStr)
118 {
119 std::vector<String> result;
120 std::vector<String> namespaceVec = namespaceStr.Split(".");
121 bool findVersion = false;
122
123 String rootPackage = Options::GetInstance().GetRootPackage(namespaceStr);
124 size_t rootPackageNum = rootPackage.Split(".").size();
125
126 for (size_t i = 0; i < namespaceVec.size(); i++) {
127 String name;
128 if (i < rootPackageNum) {
129 name = namespaceVec[i].ToUpperCase();
130 } else if (!findVersion && isVersion(namespaceVec[i])) {
131 name = namespaceVec[i].Replace('v', 'V');
132 findVersion = true;
133 } else {
134 if (findVersion) {
135 name = namespaceVec[i];
136 } else {
137 name = PascalName(namespaceVec[i]);
138 }
139 }
140
141 result.emplace_back(name);
142 }
143 return result;
144 }
145
EmitPackageToNameSpace(const String & packageName)146 String CppCodeEmitter::EmitPackageToNameSpace(const String& packageName)
147 {
148 if (packageName.IsEmpty()) {
149 return packageName;
150 }
151
152 StringBuilder nameSpaceStr;
153 std::vector<String> namespaceVec = EmitCppNameSpaceVec(packageName);
154 for (auto nameIter = namespaceVec.begin(); nameIter != namespaceVec.end(); nameIter++) {
155 nameSpaceStr.Append(*nameIter);
156 if (nameIter != namespaceVec.end() - 1) {
157 nameSpaceStr.Append("::");
158 }
159 }
160
161 return nameSpaceStr.ToString();
162 }
163
EmitBeginNamespace(StringBuilder & sb)164 void CppCodeEmitter::EmitBeginNamespace(StringBuilder& sb)
165 {
166 std::vector<String> cppNamespaceVec = EmitCppNameSpaceVec(interface_->GetNamespace()->ToString());
167 for (const auto& nspace : cppNamespaceVec) {
168 sb.AppendFormat("namespace %s {\n", nspace.string());
169 }
170 }
171
EmitEndNamespace(StringBuilder & sb)172 void CppCodeEmitter::EmitEndNamespace(StringBuilder& sb)
173 {
174 std::vector<String> cppNamespaceVec = EmitCppNameSpaceVec(interface_->GetNamespace()->ToString());
175
176 for (auto nspaceIter = cppNamespaceVec.rbegin(); nspaceIter != cppNamespaceVec.rend(); nspaceIter++) {
177 sb.AppendFormat("} // %s\n", nspaceIter->string());
178 }
179 }
180
EmitUsingNamespace(StringBuilder & sb)181 void CppCodeEmitter::EmitUsingNamespace(StringBuilder& sb)
182 {
183 sb.Append("using namespace OHOS;\n");
184 EmitImportUsingNamespace(sb);
185 }
186
EmitNamespace(const String & packageName)187 String CppCodeEmitter::EmitNamespace(const String& packageName)
188 {
189 if (packageName.IsEmpty()) {
190 return packageName;
191 }
192
193 int index = packageName.LastIndexOf('.');
194 return index > 0 ? packageName.Substring(0, index) : packageName;
195 }
196
EmitImportUsingNamespace(StringBuilder & sb)197 void CppCodeEmitter::EmitImportUsingNamespace(StringBuilder& sb)
198 {
199 using StringSet = std::unordered_set<String, StringHashFunc, StringEqualFunc>;
200 StringSet namespaceSet;
201 String selfNameSpace = EmitPackageToNameSpace(EmitNamespace(ast_->GetFullName()));
202
203 for (const auto& importPair : ast_->GetImports()) {
204 AutoPtr<AST> import = importPair.second;
205 String nameSpace = EmitPackageToNameSpace(EmitNamespace(import->GetFullName()));
206 if (nameSpace.Equals(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 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.string());
223 }
224 }
225
EmitWriteMethodParameter(const AutoPtr<ASTParameter> & param,const String & parcelName,StringBuilder & sb,const String & prefix)226 void CppCodeEmitter::EmitWriteMethodParameter(const AutoPtr<ASTParameter>& param, const String& parcelName,
227 StringBuilder& sb, const 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 String & parcelName,bool initVariable,StringBuilder & sb,const String & prefix)233 void CppCodeEmitter::EmitReadMethodParameter(const AutoPtr<ASTParameter>& param, const String& parcelName,
234 bool initVariable, StringBuilder& sb, const String& prefix)
235 {
236 AutoPtr<ASTType> type = param->GetType();
237 type->EmitCppReadVar(parcelName, param->GetName(), sb, prefix, initVariable);
238 }
239
EmitLocalVariable(const AutoPtr<ASTParameter> & param,StringBuilder & sb,const String & prefix)240 void CppCodeEmitter::EmitLocalVariable(const AutoPtr<ASTParameter>& param, StringBuilder& sb, const String& prefix)
241 {
242 sb.Append(prefix).Append(param->EmitCppLocalVar()).Append("\n");
243 }
244
MacroName(const String & name)245 String CppCodeEmitter::MacroName(const String& name)
246 {
247 if (name.IsEmpty()) {
248 return name;
249 }
250
251 String macro = name.Replace('.', '_').ToUpperCase() + "_H";
252 return macro;
253 }
254
SpecificationParam(StringBuilder & paramSb,const String & prefix)255 String CppCodeEmitter::SpecificationParam(StringBuilder& paramSb, const String& prefix)
256 {
257 int maxLineLen = 120;
258 int replaceLen = 2;
259 String paramStr = paramSb.ToString();
260 int preIndex = 0;
261 int curIndex = 0;
262
263 String insertStr = String::Format("\n%s", prefix.string());
264 for (; curIndex < paramStr.GetLength(); curIndex++) {
265 if (curIndex == maxLineLen && preIndex > 0) {
266 paramStr.Replace(preIndex, replaceLen, ",");
267 paramStr.insert(preIndex + 1, insertStr);
268 } else {
269 if (paramStr[curIndex] == ',') {
270 preIndex = curIndex;
271 }
272 }
273 }
274 return paramStr;
275 }
276 } // namespace HDI
277 } // namespace OHOS