Skip to content

Filter functions and typedefs by prefix #25

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 7, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 10 additions & 9 deletions Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,16 @@
#include <clang/Tooling/CommonOptionsParser.h>


static llvm::cl::OptionCategory Category("Binding Generator");
static llvm::cl::extrahelp CommonHelp(clang::tooling::CommonOptionsParser::HelpMessage);
static llvm::cl::extrahelp MoreHelp("\nProduce Bindings for scala native. Please specify lib name wit parameter name\n");
static llvm::cl::opt<std::string> LibName("name", llvm::cl::cat(Category));
static llvm::cl::opt<std::string> StdHeaders("stdHeaders", llvm::cl::cat(Category));
static llvm::cl::opt<bool> PrintHeadersLocation ("location", llvm::cl::cat(Category));


int main(int argc, char *argv[]) {
llvm::cl::OptionCategory Category("Binding Generator");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

❤️ less global variables

llvm::cl::extrahelp CommonHelp(clang::tooling::CommonOptionsParser::HelpMessage);
llvm::cl::extrahelp MoreHelp("\nProduce Bindings for scala native. Please specify lib name with parameter name\n");

llvm::cl::opt<std::string> LibName("name", llvm::cl::cat(Category));
llvm::cl::opt<std::string> StdHeaders("std-headers", llvm::cl::cat(Category));
llvm::cl::opt<bool> PrintHeadersLocation("location", llvm::cl::cat(Category));
llvm::cl::opt<std::string> ExcludePrefix("exclude-prefix", llvm::cl::cat(Category));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Eventually it would be nice to support multiple values.


clang::tooling::CommonOptionsParser op(argc, (const char**)argv, Category);
clang::tooling::ClangTool Tool(op.getCompilations(), op.getSourcePathList());

Expand Down Expand Up @@ -40,7 +41,7 @@ int main(int argc, char *argv[]) {
llvm::outs() << location.c_str();
}
} else {
ir.generate();
ir.generate(ExcludePrefix.getValue());
llvm::outs() << ir;
}
llvm::outs().flush();
Expand Down
18 changes: 18 additions & 0 deletions Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,5 +79,23 @@ static inline void trim(std::string &s) {
rtrim(s);
}

/**
* @return true if str starts with given prefix
*/
static inline bool startsWith(const std::string &str, const std::string &prefix) {
return str.substr(0, prefix.size()) == prefix;
}

/**
* @return true if checkedType uses type
* example: checkedType = native.Ptr[struct_A], type = struct_A
*/
static inline bool typeUsesOtherType(const std::string &checkedType, const std::string &type) {
// TODO: find better way to check it
return checkedType == type ||
checkedType == "native.Ptr[" + type + "]" ||
startsWith(checkedType, "native.CArray[" + type + ", ");
}


#endif // UTILS_H
16 changes: 16 additions & 0 deletions ir/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,19 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) {
<< " = native.extern\n";
return s;
}

bool Function::usesType(const std::string &type) const {
if (typeUsesOtherType(retType, type)) {
return true;
}
for (const auto &parameter : parameters) {
if (typeUsesOtherType(parameter.getType(), type)) {
return true;
}
}
return false;
}

std::string Function::getName() const {
return name;
}
4 changes: 4 additions & 0 deletions ir/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ class Function {

friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func);

bool usesType(const std::string &type) const;

std::string getName() const;

private:
std::string name;
std::vector<Parameter> parameters;
Expand Down
62 changes: 61 additions & 1 deletion ir/IR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,9 @@ void IR::generateTypeDefs() {
}
}

void IR::generate() {
void IR::generate(const std::string &excludePrefix) {
if (!generated) {
filterDeclarations(excludePrefix);
generateTypeDefs();
generated = true;
}
Expand All @@ -137,3 +138,62 @@ bool IR::hasHelperMethods() const {
bool IR::hasEnums() const {
return !enums.empty();
}

void IR::filterDeclarations(const std::string &excludePrefix) {
if (excludePrefix.empty()) {
return;
}

filterTypeDefs(excludePrefix);

filterFunctions(excludePrefix);
}

void IR::filterTypeDefs(const std::string &excludePrefix) {
for (auto it = typeDefs.begin(); it != typeDefs.end();) {
TypeDef &typeDef = *it;
if (startsWith(typeDef.getName(), excludePrefix) &&
typeIsUsedOnlyInTypeDefs(typeDef.getName())) {
/* remove this typedef and replace aliases with actual type */
replaceTypeInTypeDefs(typeDef.getName(), typeDef.getType());
it = typeDefs.erase(it);
} else {
++it;
}
}
}

void IR::replaceTypeInTypeDefs(const std::string &oldType, const std::string &newType) {
for (auto &typeDef : typeDefs) {
if (typeDef.getType() == oldType) {
typeDef.setType(newType);
}
}
}

void IR::filterFunctions(const std::string &excludePrefix) {
for (auto it = functions.begin(); it != functions.end();) {
Function &function = *it;
if (startsWith(function.getName(), excludePrefix)) {
it = functions.erase(it);
} else {
it++;
}
}
}

template<typename T>
bool IR::isTypeUsed(const std::vector<T> &declarations, const std::string &type) {
for (const auto &decl : declarations) {
if (decl.usesType(type)) {
return true;
}
}
return false;
}

bool IR::typeIsUsedOnlyInTypeDefs(std::string type) {
return !(isTypeUsed(functions, type) ||
isTypeUsed(structs, type) ||
isTypeUsed(unions, type));
}
49 changes: 48 additions & 1 deletion ir/IR.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class IR {

friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir);

void generate();
void generate(const std::string &excludePrefix);

private:

Expand All @@ -49,6 +49,53 @@ class IR {
*/
bool hasHelperMethods() const;

/**
* Remove functions that start with given prefix.
*
* Replace typedef by underlying type if it starts with given prefix
* and it is used only in other typedefs.
*
* Example:
* @code
* type __int32_t = native.CInt
* type __darwin_pid_t = __int32_t
* type pid_t = __darwin_pid_t
* @endcode
*
* Becomes:
* @code
* type pid_t = native.CInt
* @endcode
*
*/
void filterDeclarations(const std::string &excludePrefix);

/**
* Remove all typedefs that start with given prefix.
*/
void filterTypeDefs(const std::string &excludePrefix);

/**
* Find all typedefs that use oldType and replace it with newType.
*/
void replaceTypeInTypeDefs(const std::string &oldType, const std::string &newType);

/**
* Remove functions with names that start with excludePrefix.
*/
void filterFunctions(const std::string &excludePrefix);

/**
* @return true if given type is used only in typedefs.
*/
bool typeIsUsedOnlyInTypeDefs(std::string type);

/**
* @return true if type is used in one of given declarations.
*/
template<typename T>
bool isTypeUsed(const std::vector<T> &declarations, const std::string &type);

std::string libName;
std::vector<Function> functions;
std::vector<TypeDef> typeDefs;
Expand Down
36 changes: 29 additions & 7 deletions ir/Struct.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,19 @@ Field::Field(std::string name, std::string type)
StructOrUnion::StructOrUnion(std::string name, std::vector<Field> fields)
: name(std::move(name)), fields(std::move(fields)) {}

std::string StructOrUnion::getName() const {
return name;
}

bool StructOrUnion::usesType(const std::string &type) const {
for (const auto &field : fields) {
if (typeUsesOtherType(field.getType(), type)) {
return true;
}
}
return false;
}

Struct::Struct(std::string name, std::vector<Field> fields, uint64_t typeSize)
: StructOrUnion(std::move(name), std::move(fields)), typeSize(typeSize) {}

Expand Down Expand Up @@ -38,8 +51,8 @@ std::string Struct::generateHelperClass() const {
return "";
}
std::stringstream s;
std::string newName = "struct_" + name;
s << " implicit class " << newName << "_ops(val p: native.Ptr[struct_" << name << "])"
std::string type = getType();
s << " implicit class " << type << "_ops(val p: native.Ptr[" << type << "])"
<< " extends AnyVal {\n";
int fieldIndex = 0;
for (const auto &field : fields) {
Expand All @@ -56,8 +69,8 @@ std::string Struct::generateHelperClass() const {
s << " }\n\n";

/* makes struct instantiation easier */
s << " def " << newName + "()(implicit z: native.Zone): native.Ptr[" + newName + "]"
<< " = native.alloc[" + newName + "]\n";
s << " def " << type + "()(implicit z: native.Zone): native.Ptr[" + type + "]"
<< " = native.alloc[" + type + "]\n";

return s.str();
}
Expand All @@ -66,18 +79,23 @@ bool Struct::hasHelperMethods() const {
return !fields.empty() && fields.size() < SCALA_NATIVE_MAX_STRUCT_FIELDS;
}

std::string Struct::getType() const {
return "struct_" + name;
}

Union::Union(std::string name,
std::vector<Field> members, uint64_t maxSize)
: StructOrUnion(std::move(name), std::move(members)), maxSize(maxSize) {}

TypeDef Union::generateTypeDef() const {
return TypeDef("union_" + name, "native.CArray[Byte, " + uint64ToScalaNat(maxSize) + "]");
return TypeDef(getType(), "native.CArray[Byte, " + uint64ToScalaNat(maxSize) + "]");
}

std::string Union::generateHelperClass() const {
std::stringstream s;
s << " implicit class union_" << name << "_pos"
<< "(val p: native.Ptr[union_" << name << "]) extends AnyVal {\n";
std::string type = getType();
s << " implicit class " << type << "_pos"
<< "(val p: native.Ptr[" << type << "]) extends AnyVal {\n";
for (const auto &field : fields) {
if (!field.getName().empty()) {
std::string getter = handleReservedWords(field.getName());
Expand All @@ -93,3 +111,7 @@ std::string Union::generateHelperClass() const {
s << " }\n";
return s.str();
}

std::string Union::getType() const {
return "union_" + name;
}
17 changes: 15 additions & 2 deletions ir/Struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,30 @@ class StructOrUnion {

virtual std::string generateHelperClass() const = 0;

std::string getName() const;

virtual std::string getType() const = 0;

/**
* @return true if at leas one field has given type
*/
bool usesType(const std::string &type) const;

protected:
std::string name; // names of structs and unions are not empty
std::vector<Field> fields;
};

class Struct : StructOrUnion {
class Struct : public StructOrUnion {
public:
Struct(std::string name, std::vector<Field> fields, uint64_t typeSize);

TypeDef generateTypeDef() const override;

std::string generateHelperClass() const override;

std::string getType() const override;

/**
* @return true if helper methods will be generated for this struct
*/
Expand All @@ -46,14 +57,16 @@ class Struct : StructOrUnion {
uint64_t typeSize;
};

class Union : StructOrUnion {
class Union : public StructOrUnion {
public:
Union(std::string name, std::vector<Field> members, uint64_t maxSize);

TypeDef generateTypeDef() const override;

std::string generateHelperClass() const override;

std::string getType() const override;

private:
uint64_t maxSize;
};
Expand Down
4 changes: 4 additions & 0 deletions ir/TypeAndName.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@ std::string TypeAndName::getType() const {
std::string TypeAndName::getName() const {
return name;
}

void TypeAndName::setType(std::string type) {
this->type = std::move(type);
}
2 changes: 2 additions & 0 deletions ir/TypeAndName.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ class TypeAndName {

std::string getType() const;

void setType(std::string name);

std::string getName() const;

protected:
Expand Down
4 changes: 4 additions & 0 deletions ir/TypeDef.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const TypeDef &typeDef) {
s << " type " + handleReservedWords(typeDef.name) + " = " + typeDef.getType() + "\n";
return s;
}

bool TypeDef::usesType(const std::string &type) const {
return typeUsesOtherType(this->type, type);
}
4 changes: 3 additions & 1 deletion ir/TypeDef.h
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
#include <llvm/Support/raw_ostream.h>


class TypeDef : TypeAndName {
class TypeDef : public TypeAndName {
public:
TypeDef(std::string name, std::string type);

friend llvm::raw_ostream &operator <<(llvm::raw_ostream &s, const TypeDef &type);

bool usesType(const std::string &type) const;
};


Expand Down
Loading