diff --git a/bindgen/CMakeLists.txt b/bindgen/CMakeLists.txt index 3a88246..150d40d 100644 --- a/bindgen/CMakeLists.txt +++ b/bindgen/CMakeLists.txt @@ -54,6 +54,16 @@ add_executable(bindgen ir/Variable.h ir/PossibleVarDefine.cpp ir/PossibleVarDefine.h + ir/types/Type.cpp + ir/types/Type.h + ir/types/PrimitiveType.cpp + ir/types/PrimitiveType.h + ir/types/PointerType.cpp + ir/types/PointerType.h + ir/types/FunctionPointerType.cpp + ir/types/FunctionPointerType.h + ir/types/ArrayType.cpp + ir/types/ArrayType.h ) set_target_properties(bindgen diff --git a/bindgen/CycleDetection.h b/bindgen/CycleDetection.h index b2d76ef..6304060 100644 --- a/bindgen/CycleDetection.h +++ b/bindgen/CycleDetection.h @@ -10,25 +10,35 @@ class CycleDetection { private: TypeTranslator &tpeTransl; - bool contains(std::string &k) { return !!dependencies.count(k); } + bool contains(const std::string &k) const { + return dependencies.count(k) != 0; + } public: std::map> dependencies; - CycleDetection(TypeTranslator &tpeTransl_) + + explicit CycleDetection(TypeTranslator &tpeTransl_) : tpeTransl(tpeTransl_), dependencies{} {} - void AddDependcy(std::string name, const clang::QualType &qtpe) { + void AddDependency(const std::string &name, const clang::QualType &qtpe) { - // TODO: function pointer + if (qtpe->isFunctionPointerType()) { + // TODO: function pointer + /* type translator cannot translate function type */ + return; + } if (qtpe->isPointerType()) { - const clang::PointerType *ptr = - qtpe.getTypePtr()->getAs(); - AddDependcy(name, ptr->getPointeeType()); + const auto *ptr = qtpe.getTypePtr()->getAs(); + AddDependency(name, ptr->getPointeeType()); return; } - std::string qtpeString = tpeTransl.Translate(qtpe); + Type *type = tpeTransl.translate(qtpe); + std::string qtpeString = type->str(); + if (type->canBeDeallocated()) { + delete type; + } // Add the dependence of qtpe if (contains(qtpeString)) { @@ -39,7 +49,7 @@ class CycleDetection { dependencies[name].insert(qtpeString); } - bool isCyclic(std::string &name) { + bool isCyclic(const std::string &name) { if (contains(name)) { if (dependencies[name].count(name) != 0) { return true; diff --git a/bindgen/TypeTranslator.cpp b/bindgen/TypeTranslator.cpp index e8b301c..6d80eae 100644 --- a/bindgen/TypeTranslator.cpp +++ b/bindgen/TypeTranslator.cpp @@ -1,7 +1,10 @@ #include "TypeTranslator.h" #include "Utils.h" +#include "ir/types/FunctionPointerType.h" +#include "ir/types/PointerType.h" -TypeTranslator::TypeTranslator(clang::ASTContext *ctx_) : ctx(ctx_), typeMap() { +TypeTranslator::TypeTranslator(clang::ASTContext *ctx_, IR &ir) + : ctx(ctx_), ir(ir), typeMap() { // Native Types typeMap["void"] = "Unit"; @@ -27,38 +30,24 @@ TypeTranslator::TypeTranslator(clang::ASTContext *ctx_) : ctx(ctx_), typeMap() { typeMap["char32_t"] = "native.CChar32"; typeMap["float"] = "native.CFloat"; typeMap["double"] = "native.CDouble"; - typeMap["void*"] = "native.Ptr[Byte]"; } -std::string -TypeTranslator::TranslateFunctionPointer(const clang::QualType &qtpe, - const std::string *avoid) { - const clang::PointerType *ptr = - qtpe.getTypePtr()->getAs(); +Type *TypeTranslator::translateFunctionPointer(const clang::QualType &qtpe, + const std::string *avoid) { + const auto *ptr = qtpe.getTypePtr()->getAs(); const clang::QualType &inner = ptr->getPointeeType(); if (inner->isFunctionProtoType()) { - const clang::FunctionProtoType *fc = - inner->getAs(); - std::string ret = Translate(fc->getReturnType(), avoid); - std::string params = ""; - int counter = 0; + const auto *fc = inner->getAs(); + Type *returnType = translate(fc->getReturnType(), avoid); + std::vector parametersTypes; for (const clang::QualType ¶m : fc->param_types()) { - params += Translate(param, avoid); - params += ", "; - counter++; + parametersTypes.push_back(translate(param, avoid)); } - std::string variad = ""; - - if (fc->isVariadic()) { - counter++; - variad = "native.CVararg, "; - } - - return std::string("native.CFunctionPtr") + std::to_string(counter) + - "[" + params + variad + ret + "]"; + return new FunctionPointerType(returnType, parametersTypes, + fc->isVariadic()); } else { llvm::errs() << "Unsupported function pointer type: " @@ -68,111 +57,111 @@ TypeTranslator::TranslateFunctionPointer(const clang::QualType &qtpe, } } -std::string TypeTranslator::TranslatePointer(const clang::QualType &pte, - const std::string *avoid) { +Type *TypeTranslator::translatePointer(const clang::QualType &pte, + const std::string *avoid) { if (pte->isBuiltinType()) { const clang::BuiltinType *as = pte->getAs(); // Take care of void* if (as->getKind() == clang::BuiltinType::Void) { - return "native.Ptr[Byte]"; + return new PointerType(new PrimitiveType("Byte")); } // Take care of char* if (as->getKind() == clang::BuiltinType::Char_S || as->getKind() == clang::BuiltinType::SChar) { - return "native.CString"; + // TODO: new PointerType(new PrimitiveType("native.CChar")) + return new PrimitiveType("native.CString"); } } - return std::string("native.Ptr[") + Translate(pte, avoid) + - std::string("]"); + return new PointerType(translate(pte, avoid)); } -std::string -TypeTranslator::TranslateStructOrUnion(const clang::QualType &qtpe) { - if (qtpe->hasUnnamedOrLocalType()) { - // TODO: Verify that the local part is not a problem - uint64_t size = ctx->getTypeSize(qtpe); - return "native.CArray[Byte, " + uint64ToScalaNat(size) + "]"; - } - +Type * +TypeTranslator::translateStructOrUnionOrEnum(const clang::QualType &qtpe) { std::string name = qtpe.getUnqualifiedType().getAsString(); - // TODO: do it properly - size_t f = name.find(std::string("struct __dirstream")); - if (f != std::string::npos) { - return std::string("native.CArray[Byte, Digit[_3, Digit[_2, _0]]]"); - } - - f = name.find(" "); - if (f != std::string::npos) { - return name.replace(f, std::string(" ").length(), "_"); + auto it = aliasesMap.find(name); + if (it != aliasesMap.end()) { + /* name contains space: struct . + * Use type alias instead struct type */ + return (*it).second; } - return name; + /* type has typedef alias */ + return ir.getTypeDefWithName(name); } -std::string TypeTranslator::TranslateEnum(const clang::QualType &qtpe) { - std::string name = qtpe.getUnqualifiedType().getAsString(); - size_t f = name.find(" "); - if (f != std::string::npos) { - return name.replace(f, std::string(" ").length(), "_"); +Type *TypeTranslator::translateStructOrUnion(const clang::QualType &qtpe) { + if (qtpe->hasUnnamedOrLocalType()) { + // TODO: Verify that the local part is not a problem + uint64_t size = ctx->getTypeSize(qtpe); + return new ArrayType(new PrimitiveType("Byte"), size); } - return name; + + return translateStructOrUnionOrEnum(qtpe); } -std::string -TypeTranslator::TranslateConstantArray(const clang::ConstantArrayType *ar, - const std::string *avoid) { +Type *TypeTranslator::translateConstantArray(const clang::ConstantArrayType *ar, + const std::string *avoid) { const uint64_t size = ar->getSize().getZExtValue(); - const std::string nat = uint64ToScalaNat(size); - return "native.CArray[" + Translate(ar->getElementType(), avoid) + ", " + - nat + "]"; + return new ArrayType(translate(ar->getElementType(), avoid), size); } -std::string TypeTranslator::Translate(const clang::QualType &qtpe, - const std::string *avoid) { +Type *TypeTranslator::translate(const clang::QualType &qtpe, + const std::string *avoid) { const clang::Type *tpe = qtpe.getTypePtr(); if (typeEquals(tpe, avoid)) { // This is a type that we want to avoid the usage. - //Êxample: A struct that has a pointer to itself + // Êxample: A struct that has a pointer to itself uint64_t size = ctx->getTypeSize(tpe); - return "native.CArray[Byte, " + uint64ToScalaNat(size) + "]"; + return new ArrayType(new PrimitiveType("Byte"), size); } if (tpe->isFunctionPointerType()) { - return TranslateFunctionPointer(qtpe, avoid); + return translateFunctionPointer(qtpe, avoid); } else if (tpe->isPointerType()) { - return TranslatePointer( + return translatePointer( tpe->getAs()->getPointeeType(), avoid); - } else if (qtpe->isStructureType() || qtpe->isUnionType()) { - return handleReservedWords(TranslateStructOrUnion(qtpe)); + } else if (qtpe->isStructureType()) { + return translateStructOrUnion(qtpe); + + } else if (qtpe->isUnionType()) { + return translateStructOrUnion(qtpe); } else if (qtpe->isEnumeralType()) { - return TranslateEnum(qtpe); + return translateStructOrUnionOrEnum(qtpe); } else if (qtpe->isConstantArrayType()) { - return TranslateConstantArray(ctx->getAsConstantArrayType(qtpe), avoid); + return translateConstantArray(ctx->getAsConstantArrayType(qtpe), avoid); } else if (qtpe->isArrayType()) { - return TranslatePointer(ctx->getAsArrayType(qtpe)->getElementType(), + return translatePointer(ctx->getAsArrayType(qtpe)->getElementType(), avoid); } else { auto found = typeMap.find(qtpe.getUnqualifiedType().getAsString()); if (found != typeMap.end()) { - return handleReservedWords(found->second); + return new PrimitiveType(found->second); } else { - // TODO: Properly handle non-default types - return handleReservedWords(qtpe.getUnqualifiedType().getAsString()); + return ir.getTypeDefWithName( + qtpe.getUnqualifiedType().getAsString()); } } } -void TypeTranslator::AddTranslation(std::string from, std::string to) { - typeMap[from] = to; +void TypeTranslator::addAlias(std::string cName, Type *type) { + aliasesMap[cName] = type; +} + +std::string TypeTranslator::getTypeFromTypeMap(std::string cType) { + auto it = typeMap.find(cType); + if (it != typeMap.end()) { + return (*it).second; + } + return ""; } diff --git a/bindgen/TypeTranslator.h b/bindgen/TypeTranslator.h index efa77fc..415ce60 100644 --- a/bindgen/TypeTranslator.h +++ b/bindgen/TypeTranslator.h @@ -1,17 +1,11 @@ #pragma once -#include -#include +#include "ir/IR.h" #include class TypeTranslator { - private: - clang::ASTContext *ctx; - std::map typeMap; - public: - explicit TypeTranslator(clang::ASTContext *ctx); - void AddTranslation(std::string from, std::string to); + TypeTranslator(clang::ASTContext *ctx, IR &ir); /** * @brief Translate the qualified type from c to a scala type @@ -20,14 +14,36 @@ class TypeTranslator { * structs, unions, ... * @return the type translated */ - std::string Translate(const clang::QualType &tpe, - const std::string * = nullptr); - std::string TranslateFunctionPointer(const clang::QualType &qtpe, - const std::string *avoid); - std::string TranslatePointer(const clang::QualType &pointee, + Type *translate(const clang::QualType &tpe, const std::string * = nullptr); + + void addAlias(std::string cName, Type *type); + + std::string getTypeFromTypeMap(std::string cType); + + private: + clang::ASTContext *ctx; + IR &ir; + + /** + * Primitive types + */ + std::map typeMap; + + /** + * Maps C struct, union or enum name to Type alias + */ + std::map aliasesMap; + + Type *translateStructOrUnionOrEnum(const clang::QualType &qtpe); + + Type *translateStructOrUnion(const clang::QualType &qtpe); + + Type *translateFunctionPointer(const clang::QualType &qtpe, + const std::string *avoid); + + Type *translatePointer(const clang::QualType &pointee, + const std::string *avoid); + + Type *translateConstantArray(const clang::ConstantArrayType *ar, const std::string *avoid); - std::string TranslateStructOrUnion(const clang::QualType &qtpe); - std::string TranslateEnum(const clang::QualType &qtpe); - std::string TranslateConstantArray(const clang::ConstantArrayType *ar, - const std::string *avoid); }; diff --git a/bindgen/Utils.h b/bindgen/Utils.h index 9e32681..4e73ebd 100644 --- a/bindgen/Utils.h +++ b/bindgen/Utils.h @@ -3,6 +3,7 @@ #include +#include "ir/types/Type.h" #include #include #include @@ -94,15 +95,4 @@ static inline bool startsWith(const std::string &str, 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 diff --git a/bindgen/defines/DefineFinder.cpp b/bindgen/defines/DefineFinder.cpp index a8fc4d9..3ef7067 100644 --- a/bindgen/defines/DefineFinder.cpp +++ b/bindgen/defines/DefineFinder.cpp @@ -1,4 +1,5 @@ #include "DefineFinder.h" +#include "../ir/types/PrimitiveType.h" #include #include @@ -41,14 +42,15 @@ void DefineFinder::MacroDefined(const clang::Token ¯oNameTok, clang::Token stringToken = (*tokens)[0]; std::string literal(stringToken.getLiteralData(), stringToken.getLength()); - ir.addLiteralDefine(macroName, "c" + literal, "native.CString"); + ir.addLiteralDefine(macroName, "c" + literal, + new PrimitiveType("native.CString")); } else if (tokens->size() == 1 && (*tokens)[0].getKind() == clang::tok::identifier) { // token might be a variable std::string varName = (*tokens)[0].getIdentifierInfo()->getName(); ir.addPossibleVarDefine(macroName, varName); } - std::free(tokens); + delete tokens; } } @@ -68,13 +70,13 @@ DefineFinder::expandDefine(const clang::MacroDirective &md) { std::vector *newTokens = expandDefine( *pp.getLocalMacroDirective(token.getIdentifierInfo())); if (!newTokens) { - std::free(expandedTokens); + delete expandedTokens; return nullptr; } for (const auto &newToken : *newTokens) { (*expandedTokens).push_back(newToken); } - std::free(newTokens); + delete newTokens; } else { (*expandedTokens).push_back(token); } @@ -118,16 +120,16 @@ void DefineFinder::addNumericConstantDefine(const std::string ¯oName, type = "native.CLongLong"; /* must fit into Scala integer type */ - if (getTypeOfIntegerLiteral(parser, literal, positive).empty()) { - type = ""; + if (!integerFitsIntoType(parser, positive)) { + type.clear(); } } else if (parser.isLong) { /* literal has `L` ending */ type = "native.CLong"; /* must fit into Scala integer type */ - if (getTypeOfIntegerLiteral(parser, literal, positive).empty()) { - type = ""; + if (!integerFitsIntoType(parser, positive)) { + type.clear(); } } else { type = getTypeOfIntegerLiteral(parser, literal, positive); @@ -150,7 +152,7 @@ void DefineFinder::addNumericConstantDefine(const std::string ¯oName, if (!positive) { scalaLiteral = "-" + scalaLiteral; } - ir.addLiteralDefine(macroName, scalaLiteral, type); + ir.addLiteralDefine(macroName, scalaLiteral, new PrimitiveType(type)); } } diff --git a/bindgen/ir/Enum.cpp b/bindgen/ir/Enum.cpp index 6fae352..22cdb0b 100644 --- a/bindgen/ir/Enum.cpp +++ b/bindgen/ir/Enum.cpp @@ -1,5 +1,4 @@ #include "Enum.h" -#include Enumerator::Enumerator(std::string name, int64_t value) : name(std::move(name)), value(value) {} @@ -10,38 +9,38 @@ int64_t Enumerator::getValue() { return value; } Enum::Enum(std::string name, std::string type, std::vector enumerators) - : name(std::move(name)), type(std::move(type)), + : PrimitiveType(std::move(type)), name(std::move(name)), enumerators(std::move(enumerators)) {} bool Enum::isAnonymous() const { return name.empty(); } -TypeDef Enum::generateTypeDef() const { +TypeDef *Enum::generateTypeDef() { assert(!isAnonymous()); - return TypeDef(getTypeName(), type); + return new TypeDef("enum_" + name, this); } llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Enum &e) { for (auto enumerator : e.enumerators) { std::string enumeratorName; if (!e.name.empty()) { - enumeratorName = e.getTypeName() + "_" + enumerator.getName(); + enumeratorName = "enum_" + e.name + "_" + enumerator.getName(); } else { enumeratorName = "enum_" + enumerator.getName(); } s << " final val " << enumeratorName; std::string type; if (e.isAnonymous()) { - type = e.type; + type = e.getType(); } else { - type = e.getTypeName(); + type = "enum_" + e.name; } s << ": " << type << " = " << std::to_string(enumerator.getValue()); - if (e.type == "native.CLong") { + if (e.getType() == "native.CLong") { s << "L"; - } else if (e.type == "native.CUnsignedInt") { + } else if (e.getType() == "native.CUnsignedInt") { s << ".toUInt"; - } else if (e.type == "native.CUnsignedLong") { + } else if (e.getType() == "native.CUnsignedLong") { s << "L.toULong"; } s << "\n"; @@ -49,7 +48,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Enum &e) { return s; } -std::string Enum::getTypeName() const { - assert(!isAnonymous()); - return "enum_" + name; -} +std::string Enum::getName() const { return name; } + +bool Enum::canBeDeallocated() const { return false; } diff --git a/bindgen/ir/Enum.h b/bindgen/ir/Enum.h index 6bf8c42..5f97915 100644 --- a/bindgen/ir/Enum.h +++ b/bindgen/ir/Enum.h @@ -2,8 +2,7 @@ #define SCALA_NATIVE_BINDGEN_ENUM_H #include "TypeDef.h" -#include -#include +#include "types/PrimitiveType.h" #include class Enumerator { @@ -19,22 +18,23 @@ class Enumerator { int64_t value; }; -class Enum { +class Enum : public PrimitiveType { public: Enum(std::string name, std::string type, std::vector enumerators); bool isAnonymous() const; - TypeDef generateTypeDef() const; + TypeDef *generateTypeDef(); - std::string getTypeName() const; + std::string getName() const; friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Enum &e); + bool canBeDeallocated() const override; + private: std::string name; // might be empty - std::string type; std::vector enumerators; }; diff --git a/bindgen/ir/Function.cpp b/bindgen/ir/Function.cpp index 32abefb..e6db20a 100644 --- a/bindgen/ir/Function.cpp +++ b/bindgen/ir/Function.cpp @@ -1,13 +1,13 @@ #include "Function.h" #include "../Utils.h" -Parameter::Parameter(std::string name, std::string type) - : TypeAndName(std::move(name), std::move(type)) {} +Parameter::Parameter(std::string name, Type *type) + : TypeAndName(std::move(name), type) {} -Function::Function(std::string name, std::vector parameters, - std::string retType, bool isVariadic) +Function::Function(const std::string &name, std::vector parameters, + Type *retType, bool isVariadic) : name(name), scalaName(name), parameters(std::move(parameters)), - retType(std::move(retType)), isVariadic(isVariadic) {} + retType(retType), isVariadic(isVariadic) {} llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) { if (func.scalaName != func.name) { @@ -16,8 +16,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) { s << " def " << handleReservedWords(func.scalaName) << "("; std::string sep = ""; for (const auto ¶m : func.parameters) { - s << sep << handleReservedWords(param.getName()) << ": " - << param.getType(); + s << sep << handleReservedWords(param->getName()) << ": " + << param->getType()->str(); sep = ", "; } if (func.isVariadic) { @@ -25,16 +25,16 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func) { * the comma is fine */ s << ", " << func.getVarargsParameterName() << ": native.CVararg*"; } - s << "): " << func.retType << " = native.extern\n"; + s << "): " << func.retType->str() << " = native.extern\n"; return s; } -bool Function::usesType(const std::string &type) const { - if (typeUsesOtherType(retType, type)) { +bool Function::usesType(Type *type) const { + if (retType == type) { return true; } for (const auto ¶meter : parameters) { - if (typeUsesOtherType(parameter.getType(), type)) { + if (parameter->getType() == type) { return true; } } @@ -54,7 +54,7 @@ std::string Function::getVarargsParameterName() const { bool Function::existsParameterWithName(const std::string ¶meterName) const { for (const auto ¶meter : parameters) { - if (parameter.getName() == parameterName) { + if (parameter->getName() == parameterName) { return true; } } @@ -64,3 +64,19 @@ bool Function::existsParameterWithName(const std::string ¶meterName) const { void Function::setScalaName(std::string scalaName) { this->scalaName = std::move(scalaName); } + +void Function::deallocateTypesThatAreNotInIR() { + if (retType->canBeDeallocated()) { + delete retType; + } + + for (const auto ¶meter : parameters) { + parameter->deallocateTypesThatAreNotInIR(); + } +} + +Function::~Function() { + for (const auto ¶meter : parameters) { + delete parameter; + } +} diff --git a/bindgen/ir/Function.h b/bindgen/ir/Function.h index b18b7ff..d549921 100644 --- a/bindgen/ir/Function.h +++ b/bindgen/ir/Function.h @@ -8,23 +8,27 @@ class Parameter : public TypeAndName { public: - Parameter(std::string name, std::string type); + Parameter(std::string name, Type *type); }; class Function { public: - Function(std::string name, std::vector parameters, - std::string retType, bool isVariadic); + Function(const std::string &name, std::vector parameters, + Type *retType, bool isVariadic); + + ~Function(); friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const Function &func); - bool usesType(const std::string &type) const; + bool usesType(Type *type) const; std::string getName() const; void setScalaName(std::string scalaName); + void deallocateTypesThatAreNotInIR(); + private: std::string getVarargsParameterName() const; @@ -32,8 +36,8 @@ class Function { std::string name; // real name of the function std::string scalaName; // not empty - std::vector parameters; - std::string retType; + std::vector parameters; + Type *retType; bool isVariadic; }; diff --git a/bindgen/ir/IR.cpp b/bindgen/ir/IR.cpp index 85ec92f..27569ef 100644 --- a/bindgen/ir/IR.cpp +++ b/bindgen/ir/IR.cpp @@ -6,45 +6,55 @@ IR::IR(std::string libName, std::string linkName, std::string objectName, : libName(std::move(libName)), linkName(std::move(linkName)), objectName(std::move(objectName)), packageName(std::move(packageName)) {} -void IR::addFunction(std::string name, std::vector parameters, - std::string retType, bool isVariadic) { - functions.emplace_back(std::move(name), std::move(parameters), - std::move(retType), isVariadic); +void IR::addFunction(std::string name, std::vector parameters, + Type *retType, bool isVariadic) { + functions.push_back( + new Function(name, std::move(parameters), retType, isVariadic)); } -void IR::addTypeDef(std::string name, std::string type) { - typeDefs.emplace_back(std::move(name), std::move(type)); +void IR::addTypeDef(std::string name, Type *type) { + typeDefs.push_back(new TypeDef(std::move(name), type)); } -void IR::addEnum(std::string name, std::string type, - std::vector enumerators) { - enums.emplace_back(std::move(name), std::move(type), - std::move(enumerators)); +Type *IR::addEnum(std::string name, const std::string &type, + std::vector enumerators) { + Enum *e = new Enum(std::move(name), type, std::move(enumerators)); + enums.push_back(e); + if (!e->isAnonymous()) { + typeDefs.push_back(e->generateTypeDef()); + return typeDefs.back(); + } + return nullptr; } -void IR::addStruct(std::string name, std::vector fields, - uint64_t typeSize) { - structs.emplace_back(std::move(name), std::move(fields), typeSize); +Type *IR::addStruct(std::string name, std::vector fields, + uint64_t typeSize) { + Struct *s = new Struct(std::move(name), std::move(fields), typeSize); + structs.push_back(s); + typeDefs.push_back(s->generateTypeDef()); + return typeDefs.back(); } -void IR::addUnion(std::string name, std::vector fields, - uint64_t maxSize) { - unions.emplace_back(std::move(name), std::move(fields), maxSize); +Type *IR::addUnion(std::string name, std::vector fields, + uint64_t maxSize) { + Union *u = new Union(std::move(name), std::move(fields), maxSize); + unions.push_back(u); + typeDefs.push_back(u->generateTypeDef()); + return typeDefs.back(); } -void IR::addLiteralDefine(std::string name, std::string literal, - std::string type) { - literalDefines.emplace_back(std::move(name), std::move(literal), - std::move(type)); +void IR::addLiteralDefine(std::string name, std::string literal, Type *type) { + literalDefines.push_back( + new LiteralDefine(std::move(name), std::move(literal), type)); } void IR::addPossibleVarDefine(const std::string ¯oName, const std::string &varName) { - possibleVarDefines.emplace_back(macroName, varName); + possibleVarDefines.push_back(new PossibleVarDefine(macroName, varName)); } void IR::addVarDefine(std::string name, Variable *variable) { - varDefines.emplace_back(name, variable); + varDefines.push_back(new VarDefine(std::move(name), variable)); } bool IR::libObjEmpty() const { @@ -75,15 +85,15 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) { << "object " << objectName << " {\n"; for (const auto &typeDef : ir.typeDefs) { - s << typeDef; + s << *typeDef; } for (const auto &varDefine : ir.varDefines) { - s << varDefine; + s << *varDefine; } for (const auto &func : ir.functions) { - s << func; + s << *func; } s << "}\n\n"; @@ -92,7 +102,7 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) { if (!ir.literalDefines.empty()) { s << "object " << ir.libName << "Defines {\n"; for (const auto &literalDefine : ir.literalDefines) { - s << literalDefine; + s << *literalDefine; } s << "}\n\n"; } @@ -106,8 +116,8 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) { unsigned long enumeratorsCount = ir.enums.size(); for (unsigned long i = 0; i < enumeratorsCount; i++) { - auto &e = ir.enums[i]; - s << e; + auto e = ir.enums[i]; + s << *e; if (i < enumeratorsCount - 1) { s << "\n"; // space between groups of enums } @@ -120,11 +130,11 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) { s << "object " << ir.libName << "Helpers {\n"; for (const auto &st : ir.structs) { - s << "\n" << st.generateHelperClass(); + s << "\n" << st->generateHelperClass(); } for (const auto &u : ir.unions) { - s << "\n" << u.generateHelperClass(); + s << "\n" << u->generateHelperClass(); } s << "}\n\n"; @@ -133,25 +143,10 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir) { return s; } -void IR::generateTypeDefs() { - for (const auto &e : enums) { - if (!e.isAnonymous()) { // enum might be anon - typeDefs.push_back(e.generateTypeDef()); - } - } - for (const auto &s : structs) { - typeDefs.push_back(s.generateTypeDef()); - } - for (const auto &u : unions) { - typeDefs.push_back(u.generateTypeDef()); - } -} - void IR::generate(const std::string &excludePrefix) { if (!generated) { setScalaNames(); filterDeclarations(excludePrefix); - generateTypeDefs(); generated = true; } } @@ -163,15 +158,13 @@ bool IR::hasHelperMethods() const { } for (const auto &s : structs) { - if (s.hasHelperMethods()) { + if (s->hasHelperMethods()) { return true; } } return false; } -bool IR::hasEnums() const { return !enums.empty(); } - void IR::filterDeclarations(const std::string &excludePrefix) { if (excludePrefix.empty()) { return; @@ -188,11 +181,11 @@ void IR::filterDeclarations(const std::string &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())) { + TypeDef *typeDef = *it; + if (startsWith(typeDef->getName(), excludePrefix) && + typeIsUsedOnlyInTypeDefs(typeDef)) { /* remove this typedef and replace aliases with actual type */ - replaceTypeInTypeDefs(typeDef.getName(), typeDef.getType()); + replaceTypeInTypeDefs(typeDef, typeDef->getType()); it = typeDefs.erase(it); } else { ++it; @@ -200,27 +193,25 @@ void IR::filterTypeDefs(const std::string &excludePrefix) { } } -void IR::replaceTypeInTypeDefs(const std::string &oldType, - const std::string &newType) { +void IR::replaceTypeInTypeDefs(Type *oldType, Type *newType) { for (auto &typeDef : typeDefs) { - if (typeDef.getType() == oldType) { - typeDef.setType(newType); + if (typeDef->getType() == oldType) { + typeDef->setType(newType); } } } template -bool IR::isTypeUsed(const std::vector &declarations, - const std::string &type) { - for (const auto &decl : declarations) { - if (decl.usesType(type)) { +bool IR::isTypeUsed(const std::vector &declarations, Type *type) { + for (const auto decl : declarations) { + if (decl->usesType(type)) { return true; } } return false; } -bool IR::typeIsUsedOnlyInTypeDefs(std::string type) { +bool IR::typeIsUsedOnlyInTypeDefs(Type *type) { return !(isTypeUsed(functions, type) || isTypeUsed(structs, type) || isTypeUsed(unions, type)); } @@ -230,20 +221,20 @@ void IR::setScalaNames() { * should happen here */ for (auto &function : functions) { - if (function.getName() == "native") { + if (function->getName() == "native") { std::string scalaName = "nativeFunc"; int i = 0; while (existsFunctionWithName(scalaName)) { scalaName = "nativeFunc" + std::to_string(i++); } - function.setScalaName(scalaName); + function->setScalaName(scalaName); } } } bool IR::existsFunctionWithName(std::string functionName) { for (const auto &function : functions) { - if (function.getName() == functionName) { + if (function->getName() == functionName) { return true; } } @@ -260,8 +251,8 @@ template void IR::filterByPrefix(std::vector &declarations, const std::string &excludePrefix) { for (auto it = declarations.begin(); it != declarations.end();) { - auto &declaration = *it; - if (startsWith(declaration.getName(), excludePrefix)) { + T declaration = *it; + if (startsWith(declaration->getName(), excludePrefix)) { it = declarations.erase(it); } else { it++; @@ -272,8 +263,8 @@ void IR::filterByPrefix(std::vector &declarations, template void IR::filterByName(std::vector &declarations, const std::string &name) { for (auto it = declarations.begin(); it != declarations.end();) { - auto &declaration = *it; - if (declaration.getName() == name) { + T declaration = *it; + if (declaration->getName() == name) { it = declarations.erase(it); } else { it++; @@ -283,21 +274,62 @@ void IR::filterByName(std::vector &declarations, const std::string &name) { std::string IR::getDefineForVar(const std::string &varName) const { for (const auto &varDefine : possibleVarDefines) { - if (varDefine.getVariableName() == varName) { - return varDefine.getName(); + if (varDefine->getVariableName() == varName) { + return varDefine->getName(); } } return ""; } -Variable *IR::addVariable(const std::string &name, const std::string &type) { +Variable *IR::addVariable(const std::string &name, Type *type) { Variable *variable = new Variable(name, type); variables.push_back(variable); return variable; } +TypeDef *IR::getTypeDefWithName(const std::string &name) { + return getDeclarationWithName(typeDefs, name); +} + +template +T IR::getDeclarationWithName(std::vector &declarations, + const std::string &name) { + for (auto it = declarations.begin(), end = declarations.end(); it != end; + ++it) { + T declaration = (*it); + if (declaration->getName() == name) { + return declaration; + } + } + return nullptr; +} + IR::~IR() { - for (auto variable : variables) { - std::free(variable); + deallocateTypesThatAreNotInIR(functions); + deallocateTypesThatAreNotInIR(typeDefs); + deallocateTypesThatAreNotInIR(structs); + deallocateTypesThatAreNotInIR(unions); + deallocateTypesThatAreNotInIR(variables); + + clearVector(functions); + clearVector(typeDefs); + clearVector(structs); + clearVector(unions); + clearVector(enums); + clearVector(literalDefines); + clearVector(possibleVarDefines); + clearVector(variables); + clearVector(varDefines); +} + +template void IR::clearVector(std::vector v) { + for (const auto &e : v) { + delete e; + } +} + +template void IR::deallocateTypesThatAreNotInIR(std::vector v) { + for (const auto &e : v) { + e->deallocateTypesThatAreNotInIR(); } } diff --git a/bindgen/ir/IR.h b/bindgen/ir/IR.h index f2716b4..4bf5206 100644 --- a/bindgen/ir/IR.h +++ b/bindgen/ir/IR.h @@ -14,34 +14,42 @@ */ class IR { public: - explicit IR(std::string libName, std::string linkName, - std::string objectName, std::string packageName); + IR(std::string libName, std::string linkName, std::string objectName, + std::string packageName); ~IR(); - void addFunction(std::string name, std::vector parameters, - std::string, bool isVariadic); + void addFunction(std::string name, std::vector parameters, + Type *retType, bool isVariadic); - void addTypeDef(std::string name, std::string type); + void addTypeDef(std::string name, Type *type); - void addEnum(std::string name, std::string type, - std::vector enumerators); + /** + * @return type alias for the enum + */ + Type *addEnum(std::string name, const std::string &type, + std::vector enumerators); - void addStruct(std::string name, std::vector fields, - uint64_t typeSize); + /** + * @return type alias for the struct + */ + Type *addStruct(std::string name, std::vector fields, + uint64_t typeSize); - void addUnion(std::string name, std::vector fields, - uint64_t maxSize); + /** + * @return type alias for the union + */ + Type *addUnion(std::string name, std::vector fields, + uint64_t maxSize); - void addLiteralDefine(std::string name, std::string literal, - std::string type); + void addLiteralDefine(std::string name, std::string literal, Type *type); void addPossibleVarDefine(const std::string ¯oName, const std::string &varName); void addVarDefine(std::string name, Variable *variable); - Variable *addVariable(const std::string &name, const std::string &type); + Variable *addVariable(const std::string &name, Type *type); /** * @return true if there are no functions, types, @@ -49,8 +57,6 @@ class IR { */ bool libObjEmpty() const; - bool hasEnums() const; - friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const IR &ir); void generate(const std::string &excludePrefix); @@ -63,12 +69,9 @@ class IR { */ std::string getDefineForVar(const std::string &varName) const; - private: - /** - * Generates type defs for enums, structs and unions - */ - void generateTypeDefs(); + TypeDef *getTypeDefWithName(const std::string &name); + private: /** * @return true if helper methods will be generated for this library */ @@ -103,20 +106,18 @@ class IR { /** * Find all typedefs that use oldType and replace it with newType. */ - void replaceTypeInTypeDefs(const std::string &oldType, - const std::string &newType); + void replaceTypeInTypeDefs(Type *oldType, Type *newType); /** * @return true if given type is used only in typedefs. */ - bool typeIsUsedOnlyInTypeDefs(std::string type); + bool typeIsUsedOnlyInTypeDefs(Type *type); /** * @return true if type is used in one of given declarations. */ template - bool isTypeUsed(const std::vector &declarations, - const std::string &type); + bool isTypeUsed(const std::vector &declarations, Type *type); void setScalaNames(); @@ -129,17 +130,25 @@ class IR { template void filterByName(std::vector &declarations, const std::string &name); + template + T getDeclarationWithName(std::vector &declarations, + const std::string &name); + + template void clearVector(std::vector v); + + template void deallocateTypesThatAreNotInIR(std::vector v); + std::string libName; // name of the library std::string linkName; // name of the library to link with std::string objectName; // name of Scala object - std::vector functions; - std::vector typeDefs; - std::vector structs; - std::vector unions; - std::vector enums; - std::vector literalDefines; - std::vector possibleVarDefines; - std::vector varDefines; + std::vector functions; + std::vector typeDefs; + std::vector structs; + std::vector unions; + std::vector enums; + std::vector literalDefines; + std::vector possibleVarDefines; + std::vector varDefines; std::vector variables; bool generated = false; // generate type defs only once std::string packageName; diff --git a/bindgen/ir/LiteralDefine.cpp b/bindgen/ir/LiteralDefine.cpp index 7a9da3a..62eb0ec 100644 --- a/bindgen/ir/LiteralDefine.cpp +++ b/bindgen/ir/LiteralDefine.cpp @@ -1,16 +1,17 @@ #include "LiteralDefine.h" -LiteralDefine::LiteralDefine(std::string name, std::string literal, - std::string type) - : Define(std::move(name)), literal(std::move(literal)), - type(std::move(type)) {} +LiteralDefine::LiteralDefine(std::string name, std::string literal, Type *type) + : Define(std::move(name)), literal(std::move(literal)), type(type) {} llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const LiteralDefine &literalDefine) { - s << " val " << literalDefine.name; - if (!literalDefine.type.empty()) { - s << ": " << literalDefine.type; - } - s << " = " << literalDefine.literal << "\n"; + s << " val " << literalDefine.name << ": " << literalDefine.type->str() + << " = " << literalDefine.literal << "\n"; return s; } + +void LiteralDefine::deallocateTypesThatAreNotInIR() { + if (type->canBeDeallocated()) { + delete type; + } +} diff --git a/bindgen/ir/LiteralDefine.h b/bindgen/ir/LiteralDefine.h index bb6b76f..c1e5d48 100644 --- a/bindgen/ir/LiteralDefine.h +++ b/bindgen/ir/LiteralDefine.h @@ -2,18 +2,21 @@ #define SCALA_NATIVE_BINDGEN_LITERALDEFINE_H #include "Define.h" +#include "types/Type.h" #include class LiteralDefine : public Define { public: - LiteralDefine(std::string name, std::string literal, std::string type); + LiteralDefine(std::string name, std::string literal, Type *type); friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const LiteralDefine &literalDefine); + void deallocateTypesThatAreNotInIR(); + private: std::string literal; - std::string type; + Type *type; }; #endif // SCALA_NATIVE_BINDGEN_LITERALDEFINE_H diff --git a/bindgen/ir/Struct.cpp b/bindgen/ir/Struct.cpp index 55911cb..2292c57 100644 --- a/bindgen/ir/Struct.cpp +++ b/bindgen/ir/Struct.cpp @@ -1,49 +1,43 @@ #include "Struct.h" #include "../Utils.h" +#include "types/ArrayType.h" +#include "types/PrimitiveType.h" #include +#include -Field::Field(std::string name, std::string type) - : TypeAndName(std::move(name), std::move(type)) {} +Field::Field(std::string name, Type *type) + : TypeAndName(std::move(name), type) {} -StructOrUnion::StructOrUnion(std::string name, std::vector fields) +StructOrUnion::StructOrUnion(std::string name, std::vector fields) : name(std::move(name)), fields(std::move(fields)) {} std::string StructOrUnion::getName() const { return name; } -bool StructOrUnion::usesType(const std::string &type) const { +StructOrUnion::~StructOrUnion() { for (const auto &field : fields) { - if (typeUsesOtherType(field.getType(), type)) { - return true; - } + delete field; + } +} + +void StructOrUnion::deallocateTypesThatAreNotInIR() { + for (const auto &field : fields) { + field->deallocateTypesThatAreNotInIR(); } - return false; } -Struct::Struct(std::string name, std::vector fields, uint64_t typeSize) +Struct::Struct(std::string name, std::vector fields, uint64_t typeSize) : StructOrUnion(std::move(name), std::move(fields)), typeSize(typeSize) {} -TypeDef Struct::generateTypeDef() const { +TypeDef *Struct::generateTypeDef() { if (fields.size() < SCALA_NATIVE_MAX_STRUCT_FIELDS) { - return TypeDef("struct_" + name, "native.CStruct" + - std::to_string(fields.size()) + - "[" + getFieldsTypes() + "]"); + return new TypeDef(getAliasType(), this); } else { // There is no easy way to represent it as a struct in scala native, // have to represent it as an array and then Add helpers to help with // its manipulation - return TypeDef("struct_" + name, "native.CArray[Byte, " + - uint64ToScalaNat(typeSize) + "]"); - } -} - -std::string Struct::getFieldsTypes() const { - std::stringstream s; - std::string sep = ""; - for (const auto &field : fields) { - s << sep << field.getType(); - sep = ", "; + return new TypeDef(getAliasType(), + new ArrayType(new PrimitiveType("Byte"), typeSize)); } - return s.str(); } std::string Struct::generateHelperClass() const { @@ -52,19 +46,20 @@ std::string Struct::generateHelperClass() const { return ""; } std::stringstream s; - std::string type = getType(); + std::string type = getAliasType(); s << " implicit class " << type << "_ops(val p: native.Ptr[" << type << "])" << " extends AnyVal {\n"; int fieldIndex = 0; for (const auto &field : fields) { - if (!field.getName().empty()) { - std::string getter = handleReservedWords(field.getName()); - std::string setter = handleReservedWords(field.getName(), "_="); - std::string ftype = field.getType(); - s << " def " << getter << ": " << ftype << " = !p._" + if (!field->getName().empty()) { + std::string getter = handleReservedWords(field->getName()); + std::string setter = handleReservedWords(field->getName(), "_="); + Type *ftype = field->getType(); + s << " def " << getter << ": " << ftype->str() << " = !p._" << std::to_string(fieldIndex + 1) << "\n" - << " def " << setter << "(value: " + ftype + "):Unit = !p._" + << " def " << setter + << "(value: " + ftype->str() + "):Unit = !p._" << std::to_string(fieldIndex + 1) << " = value\n"; } fieldIndex++; @@ -83,35 +78,64 @@ bool Struct::hasHelperMethods() const { return !fields.empty() && fields.size() < SCALA_NATIVE_MAX_STRUCT_FIELDS; } -std::string Struct::getType() const { return "struct_" + name; } +std::string Struct::getAliasType() const { return "struct_" + name; } + +std::string Struct::str() const { + std::stringstream ss; + ss << "native.CStruct" << std::to_string(fields.size()) << "["; -Union::Union(std::string name, std::vector members, uint64_t maxSize) - : StructOrUnion(std::move(name), std::move(members)), maxSize(maxSize) {} + std::string sep = ""; + for (const auto &field : fields) { + ss << sep << field->getType()->str(); + sep = ", "; + } -TypeDef Union::generateTypeDef() const { - return TypeDef(getType(), - "native.CArray[Byte, " + uint64ToScalaNat(maxSize) + "]"); + ss << "]"; + return ss.str(); +} + +bool Struct::usesType(Type *type) const { + if (this == type) { + return true; + } + for (const auto &field : fields) { + if (field->getType() == type) { + return true; + } + } + return false; } +bool Struct::canBeDeallocated() const { return false; } + +Union::Union(std::string name, std::vector fields, uint64_t maxSize) + : StructOrUnion(std::move(name), std::move(fields)), + ArrayType(new PrimitiveType("Byte"), maxSize) {} + +TypeDef *Union::generateTypeDef() { return new TypeDef(getTypeAlias(), this); } + std::string Union::generateHelperClass() const { std::stringstream s; - std::string type = getType(); + std::string type = getTypeAlias(); 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()); - std::string setter = handleReservedWords(field.getName(), "_="); - std::string ftype = field.getType(); - s << " def " << getter << ": native.Ptr[" << ftype - << "] = p.cast[native.Ptr[" << ftype << "]]\n"; - - s << " def " << setter << "(value: " << ftype - << "): Unit = !p.cast[native.Ptr[" << ftype << "]] = value\n"; + if (!field->getName().empty()) { + std::string getter = handleReservedWords(field->getName()); + std::string setter = handleReservedWords(field->getName(), "_="); + Type *ftype = field->getType(); + s << " def " << getter << ": native.Ptr[" << ftype->str() + << "] = p.cast[native.Ptr[" << ftype->str() << "]]\n"; + + s << " def " << setter << "(value: " << ftype->str() + << "): Unit = !p.cast[native.Ptr[" << ftype->str() + << "]] = value\n"; } } s << " }\n"; return s.str(); } -std::string Union::getType() const { return "union_" + name; } +std::string Union::getTypeAlias() const { return "union_" + name; } + +bool Union::canBeDeallocated() const { return false; } diff --git a/bindgen/ir/Struct.h b/bindgen/ir/Struct.h index 20daff1..59c802f 100644 --- a/bindgen/ir/Struct.h +++ b/bindgen/ir/Struct.h @@ -3,6 +3,7 @@ #include "TypeAndName.h" #include "TypeDef.h" +#include "types/ArrayType.h" #include #include @@ -10,65 +11,66 @@ class Field : public TypeAndName { public: - Field(std::string name, std::string type); + Field(std::string name, Type *type); }; class StructOrUnion { public: - StructOrUnion(std::string name, std::vector fields); + StructOrUnion(std::string name, std::vector fields); - virtual TypeDef generateTypeDef() const = 0; + ~StructOrUnion(); + + virtual TypeDef *generateTypeDef() = 0; 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; + void deallocateTypesThatAreNotInIR(); protected: - std::string name; // names of structs and unions are not empty - std::vector fields; + std::string name; + std::vector fields; }; -class Struct : public StructOrUnion { +class Struct : public StructOrUnion, public Type { public: - Struct(std::string name, std::vector fields, uint64_t typeSize); + Struct(std::string name, std::vector fields, uint64_t typeSize); - TypeDef generateTypeDef() const override; + TypeDef *generateTypeDef() override; std::string generateHelperClass() const override; - std::string getType() const override; + std::string getAliasType() const; /** * @return true if helper methods will be generated for this struct */ bool hasHelperMethods() const; - private: - std::string getFieldsTypes() const; + bool usesType(Type *type) const override; + + std::string str() const override; + bool canBeDeallocated() const override; + + private: /* type size is needed if number of fields is bigger than 22 */ uint64_t typeSize; }; -class Union : public StructOrUnion { +class Union : public StructOrUnion, public ArrayType { public: - Union(std::string name, std::vector members, uint64_t maxSize); + Union(std::string name, std::vector fields, uint64_t maxSize); - TypeDef generateTypeDef() const override; + TypeDef *generateTypeDef() override; std::string generateHelperClass() const override; - std::string getType() const override; + bool canBeDeallocated() const override; private: - uint64_t maxSize; + std::string getTypeAlias() const; }; #endif // SCALA_NATIVE_BINDGEN_STRUCT_H diff --git a/bindgen/ir/TypeAndName.cpp b/bindgen/ir/TypeAndName.cpp index a74bfac..30a838e 100644 --- a/bindgen/ir/TypeAndName.cpp +++ b/bindgen/ir/TypeAndName.cpp @@ -1,10 +1,16 @@ #include "TypeAndName.h" -TypeAndName::TypeAndName(std::string name, std::string type) - : name(std::move(name)), type(std::move(type)) {} +TypeAndName::TypeAndName(std::string name, Type *type) + : name(std::move(name)), type(type) {} -std::string TypeAndName::getType() const { return type; } +Type *TypeAndName::getType() const { return type; } std::string TypeAndName::getName() const { return name; } -void TypeAndName::setType(std::string type) { this->type = std::move(type); } +void TypeAndName::setType(Type *type) { this->type = type; } + +void TypeAndName::deallocateTypesThatAreNotInIR() { + if (type->canBeDeallocated()) { + delete type; + } +} diff --git a/bindgen/ir/TypeAndName.h b/bindgen/ir/TypeAndName.h index e152b33..581fc1e 100644 --- a/bindgen/ir/TypeAndName.h +++ b/bindgen/ir/TypeAndName.h @@ -1,6 +1,7 @@ #ifndef SCALA_NATIVE_BINDGEN_TYPEANDNAME_H #define SCALA_NATIVE_BINDGEN_TYPEANDNAME_H +#include "types/Type.h" #include /** @@ -9,17 +10,19 @@ */ class TypeAndName { public: - TypeAndName(std::string name, std::string type); + TypeAndName(std::string name, Type *type); - std::string getType() const; + Type *getType() const; - void setType(std::string name); + void setType(Type *name); std::string getName() const; + void deallocateTypesThatAreNotInIR(); + protected: std::string name; - std::string type; + Type *type; }; #endif // SCALA_NATIVE_BINDGEN_TYPEANDNAME_H diff --git a/bindgen/ir/TypeDef.cpp b/bindgen/ir/TypeDef.cpp index cc324b7..e98b9ba 100644 --- a/bindgen/ir/TypeDef.cpp +++ b/bindgen/ir/TypeDef.cpp @@ -1,15 +1,19 @@ #include "TypeDef.h" #include "../Utils.h" -TypeDef::TypeDef(std::string name, std::string type) - : TypeAndName(std::move(name), std::move(type)) {} +TypeDef::TypeDef(std::string name, Type *type) + : TypeAndName(std::move(name), type) {} llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const TypeDef &typeDef) { s << " type " + handleReservedWords(typeDef.name) + " = " + - typeDef.getType() + "\n"; + typeDef.getType()->str() + "\n"; return s; } -bool TypeDef::usesType(const std::string &type) const { - return typeUsesOtherType(this->type, type); +bool TypeDef::usesType(Type *type) const { + return this == type || this->type == type; } + +std::string TypeDef::str() const { return handleReservedWords(name); } + +bool TypeDef::canBeDeallocated() const { return false; } diff --git a/bindgen/ir/TypeDef.h b/bindgen/ir/TypeDef.h index 8f552b4..a301efc 100644 --- a/bindgen/ir/TypeDef.h +++ b/bindgen/ir/TypeDef.h @@ -5,14 +5,18 @@ #include #include -class TypeDef : public TypeAndName { +class TypeDef : public TypeAndName, public Type { public: - TypeDef(std::string name, std::string type); + TypeDef(std::string name, Type *type); friend llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const TypeDef &type); - bool usesType(const std::string &type) const; + bool usesType(Type *type) const override; + + std::string str() const override; + + bool canBeDeallocated() const override; }; #endif // SCALA_NATIVE_BINDGEN_TYPEDEF_H diff --git a/bindgen/ir/VarDefine.cpp b/bindgen/ir/VarDefine.cpp index 64628bb..75e8597 100644 --- a/bindgen/ir/VarDefine.cpp +++ b/bindgen/ir/VarDefine.cpp @@ -7,6 +7,6 @@ llvm::raw_ostream &operator<<(llvm::raw_ostream &s, const VarDefine &varDefine) { s << " @name(\"" << varDefine.variable->getName() << "\")\n" << " val " << varDefine.getName() << ": " - << varDefine.variable->getType() << " = native.extern\n"; + << varDefine.variable->getType()->str() << " = native.extern\n"; return s; } diff --git a/bindgen/ir/Variable.cpp b/bindgen/ir/Variable.cpp index 9cc46b8..fbb67ba 100644 --- a/bindgen/ir/Variable.cpp +++ b/bindgen/ir/Variable.cpp @@ -1,4 +1,4 @@ #include "Variable.h" -Variable::Variable(const std::string &name, const std::string &type) +Variable::Variable(const std::string &name, Type *type) : TypeAndName(name, type) {} diff --git a/bindgen/ir/Variable.h b/bindgen/ir/Variable.h index 0be207b..34d01f6 100644 --- a/bindgen/ir/Variable.h +++ b/bindgen/ir/Variable.h @@ -5,7 +5,7 @@ class Variable : public TypeAndName { public: - Variable(const std::string &name, const std::string &type); + Variable(const std::string &name, Type *type); }; #endif // SCALA_NATIVE_BINDGEN_VARIABLE_H diff --git a/bindgen/ir/types/ArrayType.cpp b/bindgen/ir/types/ArrayType.cpp new file mode 100644 index 0000000..014d50b --- /dev/null +++ b/bindgen/ir/types/ArrayType.cpp @@ -0,0 +1,20 @@ +#include "ArrayType.h" +#include "../../Utils.h" + +ArrayType::ArrayType(Type *elementsType, uint64_t size) + : size(size), elementsType(elementsType) {} + +std::string ArrayType::str() const { + return "native.CArray[" + elementsType->str() + ", " + + uint64ToScalaNat(size) + "]"; +} + +bool ArrayType::usesType(Type *type) const { + return this == type || elementsType == type; +} + +ArrayType::~ArrayType() { + if (elementsType->canBeDeallocated()) { + delete elementsType; + } +} diff --git a/bindgen/ir/types/ArrayType.h b/bindgen/ir/types/ArrayType.h new file mode 100644 index 0000000..72c9f7e --- /dev/null +++ b/bindgen/ir/types/ArrayType.h @@ -0,0 +1,21 @@ +#ifndef SCALA_NATIVE_BINDGEN_ARRAYTYPE_H +#define SCALA_NATIVE_BINDGEN_ARRAYTYPE_H + +#include "Type.h" + +class ArrayType : public Type { + public: + ArrayType(Type *elementsType, uint64_t size); + + ~ArrayType() override; + + bool usesType(Type *type) const override; + + std::string str() const override; + + private: + const uint64_t size; + Type *elementsType; +}; + +#endif // SCALA_NATIVE_BINDGEN_ARRAYTYPE_H diff --git a/bindgen/ir/types/FunctionPointerType.cpp b/bindgen/ir/types/FunctionPointerType.cpp new file mode 100644 index 0000000..cd82eac --- /dev/null +++ b/bindgen/ir/types/FunctionPointerType.cpp @@ -0,0 +1,50 @@ +#include "FunctionPointerType.h" +#include + +FunctionPointerType::FunctionPointerType( + Type *returnType, const std::vector ¶metersTypes, + bool isVariadic) + : returnType(returnType), parametersTypes(parametersTypes), + isVariadic(isVariadic) {} + +std::string FunctionPointerType::str() const { + std::stringstream ss; + ss << "native.CFunctionPtr" << parametersTypes.size() << "["; + + for (const auto ¶meterType : parametersTypes) { + ss << parameterType->str() << ", "; + } + + if (isVariadic) { + ss << "native.CVararg, "; + } + ss << returnType->str() << "]"; + return ss.str(); +} + +bool FunctionPointerType::usesType(Type *type) const { + if (this == type) { + return true; + } + if (returnType == type) { + return true; + } + + for (auto parameterType : parametersTypes) { + if (parameterType == type) { + return true; + } + } + return false; +} + +FunctionPointerType::~FunctionPointerType() { + if (returnType->canBeDeallocated()) { + delete returnType; + } + for (const auto ¶meterType : parametersTypes) { + if (parameterType->canBeDeallocated()) { + delete parameterType; + } + } +} diff --git a/bindgen/ir/types/FunctionPointerType.h b/bindgen/ir/types/FunctionPointerType.h new file mode 100644 index 0000000..ad7749d --- /dev/null +++ b/bindgen/ir/types/FunctionPointerType.h @@ -0,0 +1,25 @@ +#ifndef SCALA_NATIVE_BINDGEN_FUNCTIONPOINTERTYPE_H +#define SCALA_NATIVE_BINDGEN_FUNCTIONPOINTERTYPE_H + +#include "Type.h" +#include + +class FunctionPointerType : public Type { + public: + FunctionPointerType(Type *returnType, + const std::vector ¶metersTypes, + bool isVariadic); + + ~FunctionPointerType() override; + + bool usesType(Type *type) const override; + + std::string str() const override; + + private: + Type *returnType; + std::vector parametersTypes; + bool isVariadic; +}; + +#endif // SCALA_NATIVE_BINDGEN_FUNCTIONPOINTERTYPE_H diff --git a/bindgen/ir/types/PointerType.cpp b/bindgen/ir/types/PointerType.cpp new file mode 100644 index 0000000..7361228 --- /dev/null +++ b/bindgen/ir/types/PointerType.cpp @@ -0,0 +1,20 @@ +#include "PointerType.h" + +PointerType::PointerType(Type *type) : type(type) {} + +std::string PointerType::str() const { + return "native.Ptr[" + type->str() + "]"; +} + +bool PointerType::usesType(Type *type) const { + if (this == type) { + return true; + } + return this->type == type; +} + +PointerType::~PointerType() { + if (type->canBeDeallocated()) { + delete type; + } +} diff --git a/bindgen/ir/types/PointerType.h b/bindgen/ir/types/PointerType.h new file mode 100644 index 0000000..d8914b5 --- /dev/null +++ b/bindgen/ir/types/PointerType.h @@ -0,0 +1,20 @@ +#ifndef SCALA_NATIVE_BINDGEN_POINTERTYPE_H +#define SCALA_NATIVE_BINDGEN_POINTERTYPE_H + +#include "Type.h" + +class PointerType : public Type { + public: + explicit PointerType(Type *type); + + ~PointerType() override; + + bool usesType(Type *type) const override; + + std::string str() const override; + + private: + Type *type; +}; + +#endif // SCALA_NATIVE_BINDGEN_POINTERTYPE_H diff --git a/bindgen/ir/types/PrimitiveType.cpp b/bindgen/ir/types/PrimitiveType.cpp new file mode 100644 index 0000000..67a1031 --- /dev/null +++ b/bindgen/ir/types/PrimitiveType.cpp @@ -0,0 +1,15 @@ +#include "PrimitiveType.h" +#include "../../Utils.h" + +PrimitiveType::PrimitiveType(std::string type) : type(std::move(type)) {} + +std::string PrimitiveType::str() const { return handleReservedWords(type); } + +std::string PrimitiveType::getType() const { return type; } + +bool PrimitiveType::usesType(Type *type) const { + if (this == type) { + return true; + } + return str() == type->str(); +} diff --git a/bindgen/ir/types/PrimitiveType.h b/bindgen/ir/types/PrimitiveType.h new file mode 100644 index 0000000..042d4f6 --- /dev/null +++ b/bindgen/ir/types/PrimitiveType.h @@ -0,0 +1,24 @@ +#ifndef SCALA_NATIVE_BINDGEN_SIMPLETYPE_H +#define SCALA_NATIVE_BINDGEN_SIMPLETYPE_H + +#include "Type.h" +#include + +/** + * For example native.CInt + */ +class PrimitiveType : public Type { + public: + explicit PrimitiveType(std::string type); + + std::string getType() const; + + bool usesType(Type *type) const override; + + std::string str() const override; + + private: + std::string type; +}; + +#endif // SCALA_NATIVE_BINDGEN_SIMPLETYPE_H diff --git a/bindgen/ir/types/Type.cpp b/bindgen/ir/types/Type.cpp new file mode 100644 index 0000000..daf2488 --- /dev/null +++ b/bindgen/ir/types/Type.cpp @@ -0,0 +1,9 @@ +#include "Type.h" + +std::string Type::str() const { return ""; } + +bool Type::usesType(Type *type) const { return false; } + +bool Type::canBeDeallocated() const { return true; } + +Type::~Type() = default; diff --git a/bindgen/ir/types/Type.h b/bindgen/ir/types/Type.h new file mode 100644 index 0000000..b4c0eef --- /dev/null +++ b/bindgen/ir/types/Type.h @@ -0,0 +1,27 @@ +#ifndef SCALA_NATIVE_BINDGEN_TYPE_H +#define SCALA_NATIVE_BINDGEN_TYPE_H + +#include + +/** + * Base class for types. + */ +class Type { + public: + virtual ~Type(); + + virtual std::string str() const; + + virtual bool usesType(Type *type) const; + + /** + * Instances of Enum, Struct, Union and TypeDef are stored in IR so they are + * deallocated in IR destructor. + * All other instances of Type are *not* shared between multiple objects and + * can be deallocated in containing object. + * @return true if instance can be deallocated. + */ + virtual bool canBeDeallocated() const; +}; + +#endif // SCALA_NATIVE_BINDGEN_TYPE_H diff --git a/bindgen/visitor/TreeConsumer.h b/bindgen/visitor/TreeConsumer.h index e9e174e..380c4eb 100644 --- a/bindgen/visitor/TreeConsumer.h +++ b/bindgen/visitor/TreeConsumer.h @@ -1,15 +1,8 @@ #pragma once #include "../Utils.h" -#include "TreeVisitor.h" - #include "../ir/IR.h" -#include -#include -#include -#include -#include -#include +#include "TreeVisitor.h" class TreeConsumer : public clang::ASTConsumer { private: diff --git a/bindgen/visitor/TreeVisitor.cpp b/bindgen/visitor/TreeVisitor.cpp index 0bedcf0..be35f7f 100644 --- a/bindgen/visitor/TreeVisitor.cpp +++ b/bindgen/visitor/TreeVisitor.cpp @@ -1,5 +1,4 @@ #include "TreeVisitor.h" -#include "../Utils.h" HeaderManager headerMan; @@ -7,9 +6,8 @@ std::set locations; bool TreeVisitor::VisitFunctionDecl(clang::FunctionDecl *func) { std::string funcName = func->getNameInfo().getName().getAsString(); - std::string retType = - handleReservedWords(typeTranslator.Translate(func->getReturnType())); - std::vector parameters; + Type *retType = typeTranslator.translate(func->getReturnType()); + std::vector parameters; int anonCounter = 0; @@ -21,12 +19,12 @@ bool TreeVisitor::VisitFunctionDecl(clang::FunctionDecl *func) { pname = "anonymous" + std::to_string(anonCounter++); } - std::string ptype = - handleReservedWords(typeTranslator.Translate(parm->getType())); - parameters.emplace_back(pname, ptype); + Type *ptype = typeTranslator.translate(parm->getType()); + parameters.emplace_back(new Parameter(pname, ptype)); } - ir.addFunction(funcName, parameters, retType, func->isVariadic()); + ir.addFunction(funcName, std::move(parameters), retType, + func->isVariadic()); return true; } @@ -34,7 +32,7 @@ bool TreeVisitor::VisitFunctionDecl(clang::FunctionDecl *func) { bool TreeVisitor::VisitTypedefDecl(clang::TypedefDecl *tpdef) { std::string name = tpdef->getName(); - cycleDetection.AddDependcy(name, tpdef->getUnderlyingType()); + cycleDetection.AddDependency(name, tpdef->getUnderlyingType()); if (cycleDetection.isCyclic(name)) { llvm::errs() << "Error: " << name << " is cyclic\n"; llvm::errs() << name << "\n"; @@ -45,8 +43,7 @@ bool TreeVisitor::VisitTypedefDecl(clang::TypedefDecl *tpdef) { llvm::errs().flush(); } - std::string type = handleReservedWords( - typeTranslator.Translate(tpdef->getUnderlyingType())); + Type *type = typeTranslator.translate(tpdef->getUnderlyingType()); ir.addTypeDef(name, type); return true; } @@ -58,11 +55,6 @@ bool TreeVisitor::VisitEnumDecl(clang::EnumDecl *enumdecl) { name = enumdecl->getTypedefNameForAnonDecl()->getNameAsString(); } - if (!name.empty()) { - // Replace "enum x" with enum_x in scala - typeTranslator.AddTranslation("enum " + name, "enum_" + name); - } - std::vector enumerators; for (const clang::EnumConstantDecl *en : enumdecl->enumerators()) { @@ -70,8 +62,13 @@ bool TreeVisitor::VisitEnumDecl(clang::EnumDecl *enumdecl) { enumerators.emplace_back(en->getNameAsString(), value); } - ir.addEnum(name, typeTranslator.Translate(enumdecl->getIntegerType()), - enumerators); + std::string scalaType = typeTranslator.getTypeFromTypeMap( + enumdecl->getIntegerType().getUnqualifiedType().getAsString()); + + Type *alias = ir.addEnum(name, scalaType, std::move(enumerators)); + if (alias != nullptr) { + typeTranslator.addAlias("enum " + name, alias); + } return true; } @@ -100,24 +97,22 @@ bool TreeVisitor::VisitRecordDecl(clang::RecordDecl *record) { } void TreeVisitor::handleUnion(clang::RecordDecl *record, std::string name) { - // Replace "union x" with union_x in scala - typeTranslator.AddTranslation("union " + name, "union_" + name); - uint64_t maxSize = 0; - std::vector fields; + std::vector fields; for (const clang::FieldDecl *field : record->fields()) { uint64_t sizeInBytes = astContext->getTypeSize(field->getType()) / 8; maxSize = std::max(maxSize, sizeInBytes); std::string fname = field->getNameAsString(); - std::string ftype = handleReservedWords( - typeTranslator.Translate(field->getType(), &name)); + Type *ftype = typeTranslator.translate(field->getType(), &name); - fields.emplace_back(fname, ftype); + fields.push_back(new Field(fname, ftype)); } - ir.addUnion(name, fields, maxSize); + Type *alias = ir.addUnion(name, std::move(fields), maxSize); + + typeTranslator.addAlias("union " + name, alias); } void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) { @@ -130,18 +125,14 @@ void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) { llvm::errs().flush(); } - // Replace "struct x" with struct_x in scala - typeTranslator.AddTranslation("struct " + name, newName); - int fieldCnt = 0; - std::vector fields; + std::vector fields; for (const clang::FieldDecl *field : record->fields()) { - std::string ftype = handleReservedWords( - typeTranslator.Translate(field->getType(), &name)); - fields.emplace_back(field->getNameAsString(), ftype); + Type *ftype = typeTranslator.translate(field->getType(), &name); + fields.push_back(new Field(field->getNameAsString(), ftype)); - cycleDetection.AddDependcy(newName, field->getType()); + cycleDetection.AddDependency(newName, field->getType()); fieldCnt++; } @@ -156,15 +147,17 @@ void TreeVisitor::handleStruct(clang::RecordDecl *record, std::string name) { llvm::errs().flush(); } - ir.addStruct(name, fields, - astContext->getTypeSize(record->getTypeForDecl())); + Type *alias = + ir.addStruct(name, std::move(fields), + astContext->getTypeSize(record->getTypeForDecl())); + + typeTranslator.addAlias("struct " + name, alias); } bool TreeVisitor::VisitVarDecl(clang::VarDecl *varDecl) { if (!varDecl->isThisDeclarationADefinition()) { std::string variableName = varDecl->getName().str(); - std::string type = - handleReservedWords(typeTranslator.Translate(varDecl->getType())); + Type *type = typeTranslator.translate(varDecl->getType()); Variable *variable = ir.addVariable(variableName, type); /* check if there is a macro for the variable. * Macros were saved by DefineFinder */ diff --git a/bindgen/visitor/TreeVisitor.h b/bindgen/visitor/TreeVisitor.h index 56302ce..85a48c9 100644 --- a/bindgen/visitor/TreeVisitor.h +++ b/bindgen/visitor/TreeVisitor.h @@ -4,13 +4,7 @@ #include "../HeaderManager.h" #include "../TypeTranslator.h" #include "../ir/IR.h" -#include -#include -#include #include -#include -#include -#include #include extern HeaderManager headerMan; @@ -30,7 +24,7 @@ class TreeVisitor : public clang::RecursiveASTVisitor { public: TreeVisitor(clang::CompilerInstance *CI, IR &ir) - : astContext(&(CI->getASTContext())), typeTranslator(astContext), + : astContext(&(CI->getASTContext())), typeTranslator(astContext, ir), cycleDetection(typeTranslator), ir(ir) {} virtual bool VisitFunctionDecl(clang::FunctionDecl *func); diff --git a/tests/samples/PrivateMembers.scala b/tests/samples/PrivateMembers.scala index 5eb05e3..dfc9ace 100644 --- a/tests/samples/PrivateMembers.scala +++ b/tests/samples/PrivateMembers.scala @@ -8,15 +8,15 @@ import scala.scalanative.native._ object PrivateMembers { type pid_t = native.CInt type __private_type = native.CInt - type privateStructWithTypedef = struct_privateStructWithTypedef - type privateStructWithTypedefPtr = native.Ptr[struct_privateStructWithTypedef] - type enum___privateEnum = native.CUnsignedInt - type enum_enumWithPrivateMembers = native.CUnsignedInt type struct_structWithPrivateType = native.CStruct2[native.CInt, __private_type] + type union___unionWithPrivateName = native.CArray[Byte, native.Nat._4] type struct_structWithPrivateStruct = native.CStruct1[native.Ptr[struct_structWithPrivateType]] type struct_normalStruct = native.CStruct1[native.CInt] + type enum___privateEnum = native.CUnsignedInt + type enum_enumWithPrivateMembers = native.CUnsignedInt type struct_privateStructWithTypedef = native.CStruct1[native.Ptr[__private_type]] - type union___unionWithPrivateName = native.CArray[Byte, native.Nat._4] + type privateStructWithTypedef = struct_privateStructWithTypedef + type privateStructWithTypedefPtr = native.Ptr[struct_privateStructWithTypedef] def getTypeThatUsesPrivateTypes(): pid_t = native.extern def getPrivateType(): native.Ptr[__private_type] = native.extern def usesPrivateUnion(anonymous0: union___unionWithPrivateName): Unit = native.extern diff --git a/tests/samples/ReservedWords.scala b/tests/samples/ReservedWords.scala index ec72616..45a94bc 100644 --- a/tests/samples/ReservedWords.scala +++ b/tests/samples/ReservedWords.scala @@ -8,14 +8,14 @@ import scala.scalanative.native._ object ReservedWords { type `match` = native.CInt type `var` = native.CArray[`match`, native.Nat._5] + type struct_object = native.CStruct2[`match`, native.CInt] type `object` = struct_object type `type` = struct_object + type union_lazy = native.CArray[Byte, native.Nat.Digit[native.Nat._1, native.Nat._6]] type `lazy` = union_lazy type `def` = `match` - type `finally` = struct_finally - type struct_object = native.CStruct2[`match`, native.CInt] type struct_finally = native.CStruct2[`def`, `lazy`] - type union_lazy = native.CArray[Byte, native.Nat.Digit[native.Nat._1, native.Nat._6]] + type `finally` = struct_finally def `with`(`sealed`: `match`, `implicit`: native.Ptr[`match`], `forSome`: `lazy`): `type` = native.extern def `implicit`(`type`: native.Ptr[`finally`]): `match` = native.extern def _1(): Unit = native.extern diff --git a/tests/samples/Struct.scala b/tests/samples/Struct.scala index 6e5e5d2..f466d78 100644 --- a/tests/samples/Struct.scala +++ b/tests/samples/Struct.scala @@ -6,8 +6,8 @@ import scala.scalanative.native._ @native.link("bindgentests") @native.extern object Struct { - type point_s = native.Ptr[struct_point] type struct_point = native.CStruct2[native.CInt, native.CInt] + type point_s = native.Ptr[struct_point] def getPoint(): native.Ptr[struct_point] = native.extern } diff --git a/tests/samples/Typedef.scala b/tests/samples/Typedef.scala index 1b23a5a..b23f5b1 100644 --- a/tests/samples/Typedef.scala +++ b/tests/samples/Typedef.scala @@ -6,12 +6,12 @@ import scala.scalanative.native._ @native.link("bindgentests") @native.extern object Typedef { + type enum_days = native.CUnsignedInt + type enum_toggle_e = native.CUnsignedInt type toggle_e = enum_toggle_e type int2int = native.CFunctionPtr1[native.CInt, native.CInt] type day2string = native.CFunctionPtr1[enum_days, native.CString] type toggle = native.CFunctionPtr1[toggle_e, Unit] - type enum_days = native.CUnsignedInt - type enum_toggle_e = native.CUnsignedInt } import Typedef._