• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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