1 /*
2 * Copyright (c) 2021-2022 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/code_emitter.h"
10
11 #include <cctype>
12
13 #include "util/file.h"
14 #include "util/options.h"
15
16 namespace OHOS {
17 namespace HDI {
OutPut(const AutoPtr<AST> & ast,const std::string & targetDirectory,GenMode mode)18 bool CodeEmitter::OutPut(const AutoPtr<AST> &ast, const std::string &targetDirectory, GenMode mode)
19 {
20 if (!Reset(ast, targetDirectory, mode)) {
21 return false;
22 }
23
24 EmitCode();
25 return true;
26 }
27
Reset(const AutoPtr<AST> & ast,const std::string & targetDirectory,GenMode mode)28 bool CodeEmitter::Reset(const AutoPtr<AST> &ast, const std::string &targetDirectory, GenMode mode)
29 {
30 if (ast == nullptr || targetDirectory.empty()) {
31 return false;
32 }
33
34 CleanData();
35
36 mode_ = mode;
37 ast_ = ast;
38 if (ast_->GetASTFileType() == ASTFileType::AST_IFACE || ast_->GetASTFileType() == ASTFileType::AST_ICALLBACK) {
39 interface_ = ast_->GetInterfaceDef();
40 interfaceName_ = interface_->GetName();
41 interfaceFullName_ = interface_->GetNamespace()->ToString() + interfaceName_;
42 baseName_ = StringHelper::StartWith(interfaceName_, "I") ? interfaceName_.substr(1) : interfaceName_;
43 proxyName_ = baseName_ + "Proxy";
44 proxyFullName_ = interface_->GetNamespace()->ToString() + proxyName_;
45
46 stubName_ = baseName_ + "Stub";
47 stubFullName_ = interface_->GetNamespace()->ToString() + stubName_;
48
49 implName_ = baseName_ + "Service";
50 implFullName_ = interface_->GetNamespace()->ToString() + implName_;
51 } else if (ast_->GetASTFileType() == ASTFileType::AST_TYPES) {
52 baseName_ = ast_->GetName();
53 } else if (ast_->GetASTFileType() == ASTFileType::AST_SEQUENCEABLE) {
54 baseName_ = ast_->GetName();
55 }
56
57 majorVerName_ = StringHelper::Format("%s_MAJOR_VERSION", ConstantName(interfaceName_).c_str());
58 minorVerName_ = StringHelper::Format("%s_MINOR_VERSION", ConstantName(interfaceName_).c_str());
59
60 std::string prefix = StringHelper::Format("%c%s", tolower(baseName_[0]), baseName_.substr(1).c_str());
61 dataParcelName_ = prefix + "Data";
62 replyParcelName_ = prefix + "Reply";
63 optionName_ = prefix + "Option";
64 errorCodeName_ = prefix + "Ret";
65 flagOfSetMemName_ = prefix + "MemSet";
66
67 if (!ResolveDirectory(targetDirectory)) {
68 return false;
69 }
70
71 return true;
72 }
73
CleanData()74 void CodeEmitter::CleanData()
75 {
76 ast_ = nullptr;
77 interface_ = nullptr;
78 directory_ = "";
79 interfaceName_ = "";
80 interfaceFullName_ = "";
81 baseName_ = "";
82 proxyName_ = "";
83 proxyFullName_ = "";
84 stubName_ = "";
85 stubFullName_ = "";
86 implName_ = "";
87 implFullName_ = "";
88 dataParcelName_ = "";
89 replyParcelName_ = "";
90 optionName_ = "";
91 errorCodeName_ = "";
92 }
93
NeedFlag(const AutoPtr<ASTMethod> & method) const94 bool CodeEmitter::NeedFlag(const AutoPtr<ASTMethod> &method) const
95 {
96 for (size_t i = 0; i < method->GetParameterNumber(); i++) {
97 AutoPtr<ASTParameter> param = method->GetParameter(i);
98 AutoPtr<ASTType> type = param->GetType();
99 if (param->GetAttribute() == ParamAttr::PARAM_OUT &&
100 (type->IsStringType() || type->IsArrayType() || type->IsListType())) {
101 return true;
102 }
103 }
104 return false;
105 }
106
107 /*
108 * -r option: -r ohos.hdi:./drivers/interface
109 * outDir: ./out
110 * package: ohos.hdi.foo.v1_0
111 * subPackage: foo.v1_0
112 * subPath: foo/v1_0
113 * GenPath: ./out/foo/v1_0/
114 */
GetFileParentPath(const std::string & outDir) const115 std::string CodeEmitter::GetFileParentPath(const std::string &outDir) const
116 {
117 std::string outPath = StringHelper::EndWith(outDir, SEPARATOR) ? outDir.substr(0, outDir.size() - 1) : outDir;
118 std::string subPackage = Options::GetInstance().GetSubPackage(ast_->GetPackageName());
119 std::string subPath = StringHelper::Replace(subPackage, '.', SEPARATOR);
120 if (subPath.empty()) {
121 return File::AdapterPath(StringHelper::Format("%s/", outPath.c_str(), subPath.c_str()));
122 } else {
123 return File::AdapterPath(StringHelper::Format("%s/%s/", outPath.c_str(), subPath.c_str()));
124 }
125 }
126
PackageToFilePath(const std::string & packageName) const127 std::string CodeEmitter::PackageToFilePath(const std::string &packageName) const
128 {
129 std::vector<std::string> packageVec = StringHelper::Split(Options::GetInstance().GetSubPackage(packageName), ".");
130 StringBuilder filePath;
131 for (auto iter = packageVec.begin(); iter != packageVec.end(); iter++) {
132 filePath.Append(FileName(*iter));
133 if (iter != packageVec.end() - 1) {
134 filePath.Append(SEPARATOR);
135 }
136 }
137
138 return filePath.ToString();
139 }
140
InterfaceToFilePath(const std::string & interfaceName) const141 std::string CodeEmitter::InterfaceToFilePath(const std::string &interfaceName) const
142 {
143 std::string fullName = interfaceName;
144 if (StringHelper::EndWith(fullName, "]")) {
145 fullName = fullName.substr(0, fullName.find("["));
146 }
147 size_t index = fullName.rfind(".");
148 std::string prefix = fullName.substr(0, index + 1);
149 std::string suffix = fullName.substr(index + 1);
150 std::string fileName = prefix + (StringHelper::StartWith(suffix, "I") ? suffix.substr(1) : suffix) + "Proxy";
151 return PackageToFilePath(fileName);
152 }
153
EmitMethodCmdID(const AutoPtr<ASTMethod> & method)154 std::string CodeEmitter::EmitMethodCmdID(const AutoPtr<ASTMethod> &method)
155 {
156 return StringHelper::Format("CMD_%s_%s", ConstantName(baseName_).c_str(), ConstantName(method->GetName()).c_str());
157 }
158
EmitInterfaceMethodCommands(StringBuilder & sb,const std::string & prefix)159 void CodeEmitter::EmitInterfaceMethodCommands(StringBuilder &sb, const std::string &prefix)
160 {
161 sb.Append(prefix).AppendFormat("enum {\n");
162 sb.Append(prefix + TAB).Append(EmitMethodCmdID(interface_->GetVersionMethod())).Append(" = 0,\n");
163 int i = 0;
164 for (const auto &method : interface_->GetMethodsBySystem(Options::GetInstance().GetSystemLevel())) {
165 sb.Append(prefix + TAB).Append(EmitMethodCmdID(method)).AppendFormat(" = %d", i + 1).Append(",\n");
166 i++;
167 }
168 sb.Append(prefix).Append("};\n");
169 }
170
EmitVersionHeaderName(const std::string & name) const171 std::string CodeEmitter::EmitVersionHeaderName(const std::string &name) const
172 {
173 return StringHelper::Format("v%u_%u/%s", ast_->GetMajorVer(), ast_->GetMinorVer(), FileName(name).c_str());
174 }
175
EmitLogTagMacro(StringBuilder & sb,const std::string & name) const176 void CodeEmitter::EmitLogTagMacro(StringBuilder &sb, const std::string &name) const
177 {
178 sb.AppendFormat("#define HDF_LOG_TAG %s\n", name.c_str());
179 }
180
ConstantName(const std::string & name) const181 std::string CodeEmitter::ConstantName(const std::string &name) const
182 {
183 if (name.empty()) {
184 return name;
185 }
186
187 StringBuilder sb;
188
189 for (size_t i = 0; i < name.size(); i++) {
190 char c = name[i];
191 if (isupper(c) != 0) {
192 if (i > 1) {
193 sb.Append('_');
194 }
195 sb.Append(c);
196 } else {
197 sb.Append(toupper(c));
198 }
199 }
200
201 return sb.ToString();
202 }
203
PascalName(const std::string & name) const204 std::string CodeEmitter::PascalName(const std::string &name) const
205 {
206 if (name.empty()) {
207 return name;
208 }
209
210 StringBuilder sb;
211 for (size_t i = 0; i < name.size(); i++) {
212 char c = name[i];
213 if (i == 0) {
214 if (islower(c)) {
215 c = toupper(c);
216 }
217 sb.Append(c);
218 } else {
219 if (c == '_') {
220 continue;
221 }
222
223 if (islower(c) && name[i - 1] == '_') {
224 c = toupper(c);
225 }
226 sb.Append(c);
227 }
228 }
229
230 return sb.ToString();
231 }
232
FileName(const std::string & name) const233 std::string CodeEmitter::FileName(const std::string &name) const
234 {
235 if (name.empty()) {
236 return name;
237 }
238
239 StringBuilder sb;
240 for (size_t i = 0; i < name.size(); i++) {
241 char c = name[i];
242 if (isupper(c) != 0) {
243 // 2->Index of the last char array.
244 if (i > 1) {
245 sb.Append('_');
246 }
247 sb.Append(tolower(c));
248 } else {
249 sb.Append(c);
250 }
251 }
252
253 return sb.ToString();
254 }
255
GetUtilMethods(UtilMethodMap & methods)256 void CodeEmitter::GetUtilMethods(UtilMethodMap &methods)
257 {
258 // get util methods
259 (void)methods;
260 }
261
EmitUtilMethods(StringBuilder & sb,const std::string & prefix,const UtilMethodMap & methods,bool isDecl)262 void CodeEmitter::EmitUtilMethods(
263 StringBuilder &sb, const std::string &prefix, const UtilMethodMap &methods, bool isDecl)
264 {
265 // generator util methods
266 for (const auto &methodPair : methods) {
267 if (!isDecl) {
268 sb.Append("\n");
269 }
270 methodPair.second(sb, "", prefix, isDecl);
271 }
272 }
273
EmitInterfaceBuffSizeMacro(StringBuilder & sb) const274 void CodeEmitter::EmitInterfaceBuffSizeMacro(StringBuilder &sb) const
275 {
276 sb.AppendFormat("#ifndef %s\n", MAX_BUFF_SIZE_MACRO);
277 sb.AppendFormat("#define %s (%s)\n", MAX_BUFF_SIZE_MACRO, MAX_BUFF_SIZE_VALUE);
278 sb.Append("#endif\n\n");
279
280 sb.AppendFormat("#ifndef %s\n", CHECK_VALUE_RETURN_MACRO);
281 sb.AppendFormat("#define %s(lv, compare, rv, ret) do { \\\n", CHECK_VALUE_RETURN_MACRO);
282 sb.Append(TAB).Append("if ((lv) compare (rv)) { \\\n");
283 sb.Append(TAB).Append(TAB).Append("return ret; \\\n");
284 sb.Append(TAB).Append("} \\\n");
285 sb.Append("} while (false)\n");
286 sb.Append("#endif\n\n");
287
288 sb.AppendFormat("#ifndef %s\n", CHECK_VALUE_RET_GOTO_MACRO);
289 sb.AppendFormat("#define %s(lv, compare, rv, ret, value, table) do { \\\n", CHECK_VALUE_RET_GOTO_MACRO);
290 sb.Append(TAB).Append("if ((lv) compare (rv)) { \\\n");
291 sb.Append(TAB).Append(TAB).Append("ret = value; \\\n");
292 sb.Append(TAB).Append(TAB).Append("goto table; \\\n");
293 sb.Append(TAB).Append("} \\\n");
294 sb.Append("} while (false)\n");
295 sb.Append("#endif\n");
296 }
297 } // namespace HDI
298 } // namespace OHOS
299