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     return StringHelper::Format("v%u_%u/%s", ast_->GetMajorVer(), ast_->GetMinorVer(), FileName(name).c_str());
124 }
125 
EmitLogTagMacro(StringBuilder & sb,const std::string & name) const126 void CodeEmitter::EmitLogTagMacro(StringBuilder &sb, const std::string &name) const
127 {
128     sb.AppendFormat("#define HDF_LOG_TAG    %s\n", name.c_str());
129 }
130 
ConstantName(const std::string & name) const131 std::string CodeEmitter::ConstantName(const std::string &name) const
132 {
133     StringBuilder sb;
134 
135     if (name.empty()) {
136         return name;
137     }
138 
139     for (size_t i = 0; i < name.size(); i++) {
140         char c = name[i];
141         if (isupper(c) != 0) {
142             if (i > 1) {
143                 sb.Append('_');
144             }
145             sb.Append(c);
146         } else {
147             sb.Append(toupper(c));
148         }
149     }
150 
151     return sb.ToString();
152 }
153 
PascalName(const std::string & name) const154 std::string CodeEmitter::PascalName(const std::string &name) const
155 {
156     if (name.empty()) {
157         return name;
158     }
159 
160     StringBuilder sb;
161     for (size_t i = 0; i < name.size(); i++) {
162         char c = name[i];
163         if (i == 0) {
164             if (islower(c)) {
165                 c = toupper(c);
166             }
167             sb.Append(c);
168         } else {
169             if (c == '_') {
170                 continue;
171             }
172 
173             if (islower(c) && name[i - 1] == '_') {
174                 c = toupper(c);
175             }
176             sb.Append(c);
177         }
178     }
179 
180     return sb.ToString();
181 }
182 
FileName(const std::string & name) const183 std::string CodeEmitter::FileName(const std::string &name) const
184 {
185     if (name.empty()) {
186         return name;
187     }
188 
189     StringBuilder sb;
190     for (size_t i = 0; i < name.size(); i++) {
191         char c = name[i];
192         if (isupper(c) != 0) {
193             // 2->Index of the last char array.
194             if ((i > 1) && (name[i - 1] != '.') && (name[i - 2] != '.')) {
195                 sb.Append('_');
196             }
197             sb.Append(tolower(c));
198         } else {
199             sb.Append(c);
200         }
201     }
202 
203     return StringHelper::Replace(sb.ToString(), '.', '/');
204 }
205 
GetNamespace(const std::string & fpnp) const206 std::string CodeEmitter::GetNamespace(const std::string &fpnp) const
207 {
208     size_t pos = fpnp.find("..");
209     if (pos == std::string::npos) {
210         return fpnp;
211     }
212 
213     return fpnp.substr(pos + strlen(".."));
214 }
215 
EmitHeadMacro(StringBuilder & sb,const std::string & fullName) const216 void CodeEmitter::EmitHeadMacro(StringBuilder &sb, const std::string &fullName) const
217 {
218     std::string macroName = MacroName(fullName);
219     sb.Append("#ifndef ").Append(macroName).Append("\n");
220     sb.Append("#define ").Append(macroName).Append("\n");
221 }
222 
EmitTailMacro(StringBuilder & sb,const std::string & fullName) const223 void CodeEmitter::EmitTailMacro(StringBuilder &sb, const std::string &fullName) const
224 {
225     std::string macroName = MacroName(fullName);
226     sb.Append("#endif // ").Append(macroName.c_str()).Append("\n\n");
227 }
228 
EmitHeadExternC(StringBuilder & sb) const229 void CodeEmitter::EmitHeadExternC(StringBuilder &sb) const
230 {
231     sb.Append("#ifdef __cplusplus\n");
232     sb.Append("extern \"C\" {\n");
233     sb.Append("#endif /* __cplusplus */\n");
234 }
235 
EmitTailExternC(StringBuilder & sb) const236 void CodeEmitter::EmitTailExternC(StringBuilder &sb) const
237 {
238     sb.Append("#ifdef __cplusplus\n");
239     sb.Append("}\n");
240     sb.Append("#endif /* __cplusplus */\n");
241 }
242 
MacroName(const std::string & name) const243 std::string CodeEmitter::MacroName(const std::string &name) const
244 {
245     if (name.empty()) {
246         return name;
247     }
248 
249     std::string macro = StringHelper::StrToUpper(StringHelper::Replace(name, '.', '_')) + "_H";
250     return macro;
251 }
252 } // namespace Idl
253 } // namespace OHOS
254