1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16 #include "codegen/code_emitter.h"
17
18 #include <cctype>
19
20 #include "util/file.h"
21 #include "util/options.h"
22
23 namespace OHOS {
24 namespace Idl {
EmitLicense(StringBuilder & sb)25 void CodeEmitter::EmitLicense(StringBuilder &sb)
26 {
27 if (ast_->GetLicense().empty()) {
28 return;
29 }
30 sb.Append(ast_->GetLicense()).Append("\n\n");
31 }
32
NeedFlag(const AutoPtr<ASTMethod> & method) const33 bool CodeEmitter::NeedFlag(const AutoPtr<ASTMethod> &method) const
34 {
35 for (size_t i = 0; i < method->GetParameterNumber(); i++) {
36 AutoPtr<ASTParameter> param = method->GetParameter(i);
37 if (param == nullptr) {
38 return false;
39 }
40 AutoPtr<ASTType> type = param->GetType();
41 if ((param->GetAttribute() & ASTParamAttr::PARAM_OUT) &&
42 (type->IsStringType() || type->IsArrayType() || type->IsListType())) {
43 return true;
44 }
45 }
46 return false;
47 }
48
49 /*
50 * -r option: -r ohos.hdi:./drivers/interface
51 * outDir: ./out
52 * package: ohos.hdi.foo.v1_0
53 * subPackage: foo.v1_0
54 * subPath: foo/v1_0
55 * GenPath: ./out/foo/v1_0/
56 */
GetFileParentPath(const std::string & outDir) const57 std::string CodeEmitter::GetFileParentPath(const std::string &outDir) const
58 {
59 if (outDir.size() > SIZE_MAX) {
60 return std::string("");
61 }
62 std::string outPath = StringHelper::EndWith(outDir, SEPARATOR) ? outDir.substr(0, outDir.size() - 1) : outDir;
63 std::string subPackage = Options::GetInstance().GetSubPackage(ast_->GetPackageName());
64 std::string subPath = StringHelper::Replace(subPackage, '.', SEPARATOR);
65 if (subPath.empty()) {
66 return File::AdapterPath(StringHelper::Format("%s/", outPath.c_str(), subPath.c_str()));
67 } else {
68 return File::AdapterPath(StringHelper::Format("%s/%s/", outPath.c_str(), subPath.c_str()));
69 }
70 }
71
PackageToFilePath(const std::string & packageName) const72 std::string CodeEmitter::PackageToFilePath(const std::string &packageName) const
73 {
74 std::vector<std::string> packageVec = StringHelper::Split(Options::GetInstance().GetSubPackage(packageName), ".");
75 StringBuilder filePath;
76 for (auto iter = packageVec.begin(); iter != packageVec.end(); iter++) {
77 filePath.Append(FileName(*iter));
78 if (iter != packageVec.end() - 1) {
79 filePath.Append(SEPARATOR);
80 }
81 }
82
83 return filePath.ToString();
84 }
85
InterfaceToFilePath(const std::string & interfaceName) const86 std::string CodeEmitter::InterfaceToFilePath(const std::string &interfaceName) const
87 {
88 std::string fullName = interfaceName;
89 size_t index;
90 if (StringHelper::EndWith(fullName, "]")) {
91 index = fullName.find("[");
92 fullName = fullName.substr(0, index);
93 }
94
95 index = fullName.rfind(".");
96 std::string prefix = fullName.substr(0, index + 1);
97 std::string suffix = fullName.substr(index + 1);
98 std::string fileName = prefix + (StringHelper::StartWith(suffix, "I") ? suffix.substr(1) : suffix) + "Proxy";
99 return PackageToFilePath(fileName);
100 }
101
EmitMethodCmdID(const AutoPtr<ASTMethod> & method)102 std::string CodeEmitter::EmitMethodCmdID(const AutoPtr<ASTMethod> &method)
103 {
104 return StringHelper::Format("CMD_%s_%s%s",
105 ConstantName(baseName_).c_str(), ConstantName(method->GetName()).c_str(),
106 method->GetMethodIdentifier().c_str());
107 }
108
EmitInterfaceMethodCommands(StringBuilder & sb,const std::string & prefix)109 void CodeEmitter::EmitInterfaceMethodCommands(StringBuilder &sb, const std::string &prefix)
110 {
111 sb.Append(prefix).AppendFormat("enum {\n");
112 sb.Append(prefix + TAB).Append(EmitMethodCmdID(interface_->GetVersionMethod())).Append(" = 0,\n");
113 int i = 0;
114 for (const auto &method : interface_->GetMethodsBySystem(Options::GetInstance().GetSystemLevel())) {
115 sb.Append(prefix + TAB).Append(EmitMethodCmdID(method)).AppendFormat(" = %d", i + 1).Append(",\n");
116 i++;
117 }
118 sb.Append(prefix).Append("};\n");
119 }
120
EmitVersionHeaderName(const std::string & name) const121 std::string CodeEmitter::EmitVersionHeaderName(const std::string &name) const
122 {
123 InterfaceType interfaceType = Options::GetInstance().GetInterfaceType();
124 if (interfaceType == InterfaceType::SA) {
125 return StringHelper::Format("%s", FileName(name).c_str());
126 }
127 return StringHelper::Format("v%u_%u/%s", ast_->GetMajorVer(), ast_->GetMinorVer(), FileName(name).c_str());
128 }
129
EmitLogTagMacro(StringBuilder & sb,const std::string & name) const130 void CodeEmitter::EmitLogTagMacro(StringBuilder &sb, const std::string &name) const
131 {
132 sb.AppendFormat("#define HDF_LOG_TAG %s\n", name.c_str());
133 }
134
ConstantName(const std::string & name) const135 std::string CodeEmitter::ConstantName(const std::string &name) const
136 {
137 StringBuilder sb;
138
139 if (name.empty()) {
140 return name;
141 }
142
143 for (size_t i = 0; i < name.size(); i++) {
144 char c = name[i];
145 if (isupper(c) != 0) {
146 if (i > 1) {
147 sb.Append('_');
148 }
149 sb.Append(c);
150 } else {
151 sb.Append(toupper(c));
152 }
153 }
154
155 return sb.ToString();
156 }
157
PascalName(const std::string & name) const158 std::string CodeEmitter::PascalName(const std::string &name) const
159 {
160 if (name.empty()) {
161 return name;
162 }
163
164 StringBuilder sb;
165 for (size_t i = 0; i < name.size(); i++) {
166 char c = name[i];
167 if (i == 0) {
168 if (islower(c)) {
169 c = toupper(c);
170 }
171 sb.Append(c);
172 } else {
173 if (c == '_') {
174 continue;
175 }
176
177 if (islower(c) && name[i - 1] == '_') {
178 c = toupper(c);
179 }
180 sb.Append(c);
181 }
182 }
183
184 return sb.ToString();
185 }
186
FileName(const std::string & name) const187 std::string CodeEmitter::FileName(const std::string &name) const
188 {
189 if (name.empty()) {
190 return name;
191 }
192
193 StringBuilder sb;
194 for (size_t i = 0; i < name.size(); i++) {
195 char c = name[i];
196 if (isupper(c) != 0) {
197 // 2->Index of the last char array.
198 if ((i > 1) && (name[i - 1] != '.') && (name[i - 2] != '.')) {
199 sb.Append('_');
200 }
201 sb.Append(tolower(c));
202 } else {
203 sb.Append(c);
204 }
205 }
206
207 return StringHelper::Replace(sb.ToString(), '.', '/');
208 }
209
GetNamespace(const std::string & fpnp) const210 std::string CodeEmitter::GetNamespace(const std::string &fpnp) const
211 {
212 size_t pos = fpnp.find("..");
213 if (pos == std::string::npos) {
214 return fpnp;
215 }
216
217 return fpnp.substr(pos + strlen(".."));
218 }
219
EmitHeadMacro(StringBuilder & sb,const std::string & fullName) const220 void CodeEmitter::EmitHeadMacro(StringBuilder &sb, const std::string &fullName) const
221 {
222 std::string macroName = MacroName(fullName);
223 sb.Append("#ifndef ").Append(macroName).Append("\n");
224 sb.Append("#define ").Append(macroName).Append("\n");
225 }
226
EmitTailMacro(StringBuilder & sb,const std::string & fullName) const227 void CodeEmitter::EmitTailMacro(StringBuilder &sb, const std::string &fullName) const
228 {
229 std::string macroName = MacroName(fullName);
230 sb.Append("#endif // ").Append(macroName.c_str()).Append("\n\n");
231 }
232
EmitHeadExternC(StringBuilder & sb) const233 void CodeEmitter::EmitHeadExternC(StringBuilder &sb) const
234 {
235 sb.Append("#ifdef __cplusplus\n");
236 sb.Append("extern \"C\" {\n");
237 sb.Append("#endif /* __cplusplus */\n");
238 }
239
EmitTailExternC(StringBuilder & sb) const240 void CodeEmitter::EmitTailExternC(StringBuilder &sb) const
241 {
242 sb.Append("#ifdef __cplusplus\n");
243 sb.Append("}\n");
244 sb.Append("#endif /* __cplusplus */\n");
245 }
246
MacroName(const std::string & name) const247 std::string CodeEmitter::MacroName(const std::string &name) const
248 {
249 if (name.empty()) {
250 return name;
251 }
252
253 std::string macro = StringHelper::StrToUpper(StringHelper::Replace(name, '.', '_')) + "_H";
254 return macro;
255 }
256 } // namespace Idl
257 } // namespace OHOS
258