* Copyright (c) 2021-2022 Huawei Device Co., Ltd.
*
* HDF is dual licensed: you can use it either under the terms of
* the GPL, or the BSD license, at your option.
* See the LICENSE file in the root of this repository for complete details.
*/
#include "codegen/code_emitter.h"
#include <cctype>
#include "util/file.h"
#include "util/options.h"
namespace OHOS {
namespace HDI {
bool CodeEmitter::OutPut(const AutoPtr<AST> &ast, const String &targetDirectory, bool isKernelCode)
{
if (!Reset(ast, targetDirectory, isKernelCode)) {
return false;
}
EmitCode();
return true;
}
bool CodeEmitter::Reset(const AutoPtr<AST> &ast, const String &targetDirectory, bool isKernelCode)
{
if (ast == nullptr || targetDirectory.Equals("")) {
return false;
}
CleanData();
isKernelCode_ = isKernelCode;
ast_ = ast;
if (ast_->GetASTFileType() == ASTFileType::AST_IFACE || ast_->GetASTFileType() == ASTFileType::AST_ICALLBACK) {
interface_ = ast_->GetInterfaceDef();
interfaceName_ = interface_->GetName();
interfaceFullName_ = interface_->GetNamespace()->ToString() + interfaceName_;
baseName_ = interfaceName_.StartsWith("I") ? interfaceName_.Substring(1) : interfaceName_;
proxyName_ = baseName_ + "Proxy";
proxyFullName_ = interface_->GetNamespace()->ToString() + proxyName_;
stubName_ = baseName_ + "Stub";
stubFullName_ = interface_->GetNamespace()->ToString() + stubName_;
implName_ = baseName_ + "Service";
implFullName_ = interface_->GetNamespace()->ToString() + implName_;
} else if (ast_->GetASTFileType() == ASTFileType::AST_TYPES) {
baseName_ = ast_->GetName();
} else if (ast_->GetASTFileType() == ASTFileType::AST_SEQUENCEABLE) {
baseName_ = ast_->GetName();
}
majorVerName_ = String::Format("%s_MAJOR_VERSION", ConstantName(interfaceName_).string());
minorVerName_ = String::Format("%s_MINOR_VERSION", ConstantName(interfaceName_).string());
bufferSizeMacroName_ = String::Format("%s_BUFF_MAX_SIZE", ConstantName(baseName_).string());
String prefix = String::Format("%c%s", tolower(baseName_[0]), baseName_.Substring(1).string());
dataParcelName_ = prefix + "Data";
replyParcelName_ = prefix + "Reply";
optionName_ = prefix + "Option";
errorCodeName_ = prefix + "Ret";
flagOfSetMemName_ = prefix + "MemSet";
if (!ResolveDirectory(targetDirectory)) {
return false;
}
return true;
}
void CodeEmitter::CleanData()
{
isKernelCode_ = false;
ast_ = nullptr;
interface_ = nullptr;
directory_ = "";
interfaceName_ = "";
interfaceFullName_ = "";
baseName_ = "";
proxyName_ = "";
proxyFullName_ = "";
stubName_ = "";
stubFullName_ = "";
implName_ = "";
implFullName_ = "";
dataParcelName_ = "";
replyParcelName_ = "";
optionName_ = "";
errorCodeName_ = "";
}
bool CodeEmitter::NeedFlag(const AutoPtr<ASTMethod> &method)
{
for (size_t i = 0; i < method->GetParameterNumber(); i++) {
AutoPtr<ASTParameter> param = method->GetParameter(i);
AutoPtr<ASTType> type = param->GetType();
if (param->GetAttribute() == ParamAttr::PARAM_OUT &&
(type->IsStringType() || type->IsArrayType() || type->IsListType())) {
return true;
}
}
return false;
}
* ForExample:
* -r option: -r ohos.hdi:./drivers/interface
* outDir: ./out
* package: ohos.hdi.foo.v1_0
* subPackage: foo.v1_0
* subPath: foo/v1_0
* GenPath: ./out/foo/v1_0/
*/
String CodeEmitter::GetFileParentPath(const String &outDir)
{
String outPath = outDir.EndsWith(File::separator) ? outDir.Substring(0, outDir.GetLength() - 1) : outDir;
String subPackage = Options::GetInstance().GetSubPackage(ast_->GetPackageName());
String subPath = subPackage.Replace('.', File::separator);
if (subPath.IsEmpty()) {
return File::AdapterPath(String::Format("%s/", outPath.string(), subPath.string()));
} else {
return File::AdapterPath(String::Format("%s/%s/", outPath.string(), subPath.string()));
}
}
String CodeEmitter::PackageToFilePath(const String &packageName)
{
std::vector<String> packageVec = Options::GetInstance().GetSubPackage(packageName).Split(".");
StringBuilder filePath;
for (auto iter = packageVec.begin(); iter != packageVec.end(); iter++) {
filePath.Append(FileName(*iter));
if (iter != packageVec.end() - 1) {
filePath.Append(File::separator);
}
}
return filePath.ToString();
}
String CodeEmitter::EmitMethodCmdID(const AutoPtr<ASTMethod> &method)
{
return String::Format("CMD_%s_%s", ConstantName(baseName_).string(), ConstantName(method->GetName()).string());
}
void CodeEmitter::EmitInterfaceMethodCommands(StringBuilder &sb, const String &prefix)
{
sb.Append(prefix).AppendFormat("enum {\n");
for (size_t i = 0; i < interface_->GetMethodNumber(); i++) {
AutoPtr<ASTMethod> method = interface_->GetMethod(i);
sb.Append(prefix + TAB).Append(EmitMethodCmdID(method)).Append(",\n");
}
sb.Append(prefix + TAB).Append(EmitMethodCmdID(interface_->GetVersionMethod())).Append(",\n");
sb.Append(prefix).Append("};\n");
}
String CodeEmitter::EmitVersionHeaderName(const String &name)
{
return String::Format("v%u_%u/%s", ast_->GetMajorVer(), ast_->GetMinorVer(), FileName(name).string());
}
String CodeEmitter::ConstantName(const String &name)
{
if (name.IsEmpty()) {
return name;
}
StringBuilder sb;
for (int i = 0; i < name.GetLength(); i++) {
char c = name[i];
if (isupper(c) != 0) {
if (i > 1) {
sb.Append('_');
}
sb.Append(c);
} else {
sb.Append(toupper(c));
}
}
return sb.ToString();
}
String CodeEmitter::PascalName(const String &name)
{
if (name.IsEmpty()) {
return name;
}
StringBuilder sb;
for (int i = 0; i < name.GetLength(); i++) {
char c = name[i];
if (i == 0) {
if (islower(c)) {
c = toupper(c);
}
sb.Append(c);
} else {
if (c == '_') {
continue;
}
if (islower(c) && name[i - 1] == '_') {
c = toupper(c);
}
sb.Append(c);
}
}
return sb.ToString();
}
String CodeEmitter::FileName(const String &name)
{
if (name.IsEmpty()) {
return name;
}
StringBuilder sb;
for (int i = 0; i < name.GetLength(); i++) {
char c = name[i];
if (isupper(c) != 0) {
if (i > 1) {
sb.Append('_');
}
sb.Append(tolower(c));
} else {
sb.Append(c);
}
}
return sb.ToString();
}
}
}