• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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     if (outDir.size() > SIZE_MAX) {
118         return "";
119     }
120     std::string outPath = StringHelper::EndWith(outDir, SEPARATOR) ? outDir.substr(0, outDir.size() - 1) : outDir;
121     std::string subPackage = Options::GetInstance().GetSubPackage(ast_->GetPackageName());
122     std::string subPath = StringHelper::Replace(subPackage, '.', SEPARATOR);
123     if (subPath.empty()) {
124         return File::AdapterPath(StringHelper::Format("%s/", outPath.c_str(), subPath.c_str()));
125     } else {
126         return File::AdapterPath(StringHelper::Format("%s/%s/", outPath.c_str(), subPath.c_str()));
127     }
128 }
129 
PackageToFilePath(const std::string & packageName) const130 std::string CodeEmitter::PackageToFilePath(const std::string &packageName) const
131 {
132     std::vector<std::string> packageVec = StringHelper::Split(Options::GetInstance().GetSubPackage(packageName), ".");
133     StringBuilder filePath;
134     for (auto iter = packageVec.begin(); iter != packageVec.end(); iter++) {
135         filePath.Append(FileName(*iter));
136         if (iter != packageVec.end() - 1) {
137             filePath.Append(SEPARATOR);
138         }
139     }
140 
141     return filePath.ToString();
142 }
143 
InterfaceToFilePath(const std::string & interfaceName) const144 std::string CodeEmitter::InterfaceToFilePath(const std::string &interfaceName) const
145 {
146     std::string fullName = interfaceName;
147     if (StringHelper::EndWith(fullName, "]")) {
148         fullName = fullName.substr(0, fullName.find("["));
149     }
150     size_t index = fullName.rfind(".");
151     std::string prefix = fullName.substr(0, index + 1);
152     std::string suffix = fullName.substr(index + 1);
153     std::string fileName = prefix + (StringHelper::StartWith(suffix, "I") ? suffix.substr(1) : suffix) + "Proxy";
154     return PackageToFilePath(fileName);
155 }
156 
EmitMethodCmdID(const AutoPtr<ASTMethod> & method)157 std::string CodeEmitter::EmitMethodCmdID(const AutoPtr<ASTMethod> &method)
158 {
159     return StringHelper::Format("CMD_%s_%s%s",
160         ConstantName(baseName_).c_str(), ConstantName(method->GetName()).c_str(),
161         method->GetMethodIdentifier().c_str());
162 }
163 
EmitInterfaceMethodCommands(StringBuilder & sb,const std::string & prefix)164 void CodeEmitter::EmitInterfaceMethodCommands(StringBuilder &sb, const std::string &prefix)
165 {
166     sb.Append(prefix).AppendFormat("enum {\n");
167     sb.Append(prefix + TAB).Append(EmitMethodCmdID(interface_->GetVersionMethod())).Append(" = 0,\n");
168     int i = 0;
169     for (const auto &method : interface_->GetMethodsBySystem(Options::GetInstance().GetSystemLevel())) {
170         sb.Append(prefix + TAB).Append(EmitMethodCmdID(method)).AppendFormat(" = %d", i + 1).Append(",\n");
171         i++;
172     }
173     sb.Append(prefix).Append("};\n");
174 }
175 
EmitVersionHeaderName(const std::string & name) const176 std::string CodeEmitter::EmitVersionHeaderName(const std::string &name) const
177 {
178     return StringHelper::Format("v%u_%u/%s", ast_->GetMajorVer(), ast_->GetMinorVer(), FileName(name).c_str());
179 }
180 
EmitLogTagMacro(StringBuilder & sb,const std::string & name) const181 void CodeEmitter::EmitLogTagMacro(StringBuilder &sb, const std::string &name) const
182 {
183     sb.AppendFormat("#define HDF_LOG_TAG    %s\n", name.c_str());
184 }
185 
ConstantName(const std::string & name) const186 std::string CodeEmitter::ConstantName(const std::string &name) const
187 {
188     if (name.empty()) {
189         return name;
190     }
191 
192     StringBuilder sb;
193 
194     for (size_t i = 0; i < name.size(); i++) {
195         char c = name[i];
196         if (isupper(c) != 0) {
197             if (i > 1) {
198                 sb.Append('_');
199             }
200             sb.Append(c);
201         } else {
202             sb.Append(toupper(c));
203         }
204     }
205 
206     return sb.ToString();
207 }
208 
PascalName(const std::string & name) const209 std::string CodeEmitter::PascalName(const std::string &name) const
210 {
211     if (name.empty()) {
212         return name;
213     }
214 
215     StringBuilder sb;
216     for (size_t i = 0; i < name.size(); i++) {
217         char c = name[i];
218         if (i == 0) {
219             if (islower(c)) {
220                 c = toupper(c);
221             }
222             sb.Append(c);
223         } else {
224             if (c == '_') {
225                 continue;
226             }
227 
228             if (islower(c) && name[i - 1] == '_') {
229                 c = toupper(c);
230             }
231             sb.Append(c);
232         }
233     }
234 
235     return sb.ToString();
236 }
237 
FileName(const std::string & name) const238 std::string CodeEmitter::FileName(const std::string &name) const
239 {
240     if (name.empty()) {
241         return name;
242     }
243 
244     StringBuilder sb;
245     for (size_t i = 0; i < name.size(); i++) {
246         char c = name[i];
247         if (isupper(c) != 0) {
248             // 2->Index of the last char array.
249             if (i > 1) {
250                 sb.Append('_');
251             }
252             sb.Append(tolower(c));
253         } else {
254             sb.Append(c);
255         }
256     }
257 
258     return sb.ToString();
259 }
260 
GetUtilMethods(UtilMethodMap & methods)261 void CodeEmitter::GetUtilMethods(UtilMethodMap &methods)
262 {
263     // get util methods
264     (void)methods;
265 }
266 
EmitUtilMethods(StringBuilder & sb,const std::string & prefix,const UtilMethodMap & methods,bool isDecl)267 void CodeEmitter::EmitUtilMethods(
268     StringBuilder &sb, const std::string &prefix, const UtilMethodMap &methods, bool isDecl)
269 {
270     // generator util methods
271     for (const auto &methodPair : methods) {
272         if (!isDecl) {
273             sb.Append("\n");
274         }
275         methodPair.second(sb, "", prefix, isDecl);
276     }
277 }
278 
EmitInterfaceBuffSizeMacro(StringBuilder & sb) const279 void CodeEmitter::EmitInterfaceBuffSizeMacro(StringBuilder &sb) const
280 {
281     sb.AppendFormat("#ifndef %s\n", MAX_BUFF_SIZE_MACRO);
282     sb.AppendFormat("#define %s (%s)\n", MAX_BUFF_SIZE_MACRO, MAX_BUFF_SIZE_VALUE);
283     sb.Append("#endif\n\n");
284 
285     sb.AppendFormat("#ifndef %s\n", CHECK_VALUE_RETURN_MACRO);
286     sb.AppendFormat("#define %s(lv, compare, rv, ret) do { \\\n", CHECK_VALUE_RETURN_MACRO);
287     sb.Append(TAB).Append("if ((lv) compare (rv)) { \\\n");
288     sb.Append(TAB).Append(TAB).Append("return ret; \\\n");
289     sb.Append(TAB).Append("} \\\n");
290     sb.Append("} while (false)\n");
291     sb.Append("#endif\n\n");
292 
293     sb.AppendFormat("#ifndef %s\n", CHECK_VALUE_RET_GOTO_MACRO);
294     sb.AppendFormat("#define %s(lv, compare, rv, ret, value, table) do { \\\n", CHECK_VALUE_RET_GOTO_MACRO);
295     sb.Append(TAB).Append("if ((lv) compare (rv)) { \\\n");
296     sb.Append(TAB).Append(TAB).Append("ret = value; \\\n");
297     sb.Append(TAB).Append(TAB).Append("goto table; \\\n");
298     sb.Append(TAB).Append("} \\\n");
299     sb.Append("} while (false)\n");
300     sb.Append("#endif\n");
301 }
302 } // namespace HDI
303 } // namespace OHOS
304