* @file
*
* This file declares auxiliary methods for Cangjie Native FFI implementation with different targets
*/
#ifndef CANGJIE_SEMA_NATIVE_FFI_UTILS
#define CANGJIE_SEMA_NATIVE_FFI_UTILS
#include "cangjie/AST/Create.h"
#include "cangjie/AST/Match.h"
#include "cangjie/AST/Utils.h"
#include "cangjie/Mangle/BaseMangler.h"
#include "cangjie/Modules/ImportManager.h"
#include "cangjie/Sema/TypeManager.h"
namespace Cangjie::Native::FFI {
constexpr std::string_view NSSTRING_CLASS_IDENT = "NSString";
constexpr std::string_view NSOBJECT_CLASS_IDENT = "NSObject";
constexpr std::string_view TOSTRING_METHOD_IDENT = "toString";
constexpr std::string_view INIT_IDENT = "init";
using namespace AST;
Generic Config Example:
generic_object_configuration = [
{ name = "GenericClass", type_arguments = ["Int32"]},
{ name = "GenericClass<Int32>", symbols = [
"getValue",
"GenericClass",
"value",
"setValue"
]}
]
*/
struct GenericConfigInfo {
std::string declSymbolName;
std::string declInstName;
std::vector<std::pair<std::string, std::string>> instTypes;
std::unordered_set<std::string> funcNames;
GenericConfigInfo(std::string name, std::string declInstName,
std::vector<std::pair<std::string, std::string>>& insts, std::unordered_set<std::string>& funcs)
: declSymbolName(name), declInstName(declInstName), instTypes(insts), funcNames(funcs)
{
}
};
enum class ArrayOperationKind : uint8_t { CREATE, GET, SET, GET_LENGTH };
OwnedPtr<RefExpr> CreateThisRef(Ptr<Decl> target, Ptr<Ty> ty, Ptr<File> curFile);
OwnedPtr<CallExpr> CreateThisCall(
Decl& target, FuncDecl& baseTarget, Ptr<Ty> funcTy, Ptr<File> curFile, std::vector<OwnedPtr<FuncArg>> args = {});
OwnedPtr<PrimitiveType> CreateUnitType(Ptr<File> curFile);
std::vector<Ptr<Ty>> GetParamTys(FuncParamList& params);
OwnedPtr<RefExpr> CreateSuperRef(Ptr<Decl> target, Ptr<Ty> ty);
OwnedPtr<CallExpr> CreateSuperCall(Decl& target, FuncDecl& baseTarget, Ptr<Ty> funcTy);
ArrayOperationKind GetArrayOperationKind(Decl& decl);
template <typename Ret = Node, typename... Args> std::vector<OwnedPtr<Ret>> Nodes(OwnedPtr<Args>&&... args)
{
std::vector<OwnedPtr<Ret>> nodes;
(nodes.push_back(std::forward<OwnedPtr<Args>>(args)), ...);
return nodes;
}
namespace Details {
template <typename T> void WrapArg(std::vector<OwnedPtr<FuncArg>>* funcArgs, OwnedPtr<T>&& e)
{
CJC_ASSERT(e);
if (auto ptr = As<ASTKind::FUNC_ARG>(e.get())) {
funcArgs->emplace_back(ptr);
} else {
funcArgs->push_back(CreateFuncArg(std::forward<OwnedPtr<T>>(e)));
}
}
}
template <typename T> OwnedPtr<T> WithinFile(OwnedPtr<T> node, Ptr<File> curFile)
{
CJC_NULLPTR_CHECK(curFile);
node->curFile = curFile;
return node;
}
template <typename... Args> OwnedPtr<CallExpr> CreateCall(Ptr<FuncDecl> fd, Ptr<File> curFile, OwnedPtr<Args>&&... args)
{
if (!fd) {
return nullptr;
}
std::vector<OwnedPtr<FuncArg>> funcArgs;
(Details::WrapArg(&funcArgs, std::forward<OwnedPtr<Args>>(args)), ...);
auto funcTy = StaticCast<FuncTy*>(fd->GetTy());
return CreateCallExpr(WithinFile(CreateRefExpr(*fd), curFile), std::move(funcArgs), fd, funcTy->retTy,
CallKind::CALL_DECLARED_FUNCTION);
}
template <typename... Args>
OwnedPtr<CallExpr> CreateMemberCall(OwnedPtr<Expr> receiver, Ptr<FuncDecl> fd, OwnedPtr<Args>&&... args)
{
CJC_NULLPTR_CHECK(receiver);
CJC_NULLPTR_CHECK(fd);
std::vector<OwnedPtr<FuncArg>> funcArgs;
(Details::WrapArg(&funcArgs, std::forward<OwnedPtr<Args>>(args)), ...);
auto funcTy = StaticCast<FuncTy*>(fd->GetTy());
auto ma = CreateMemberAccess(std::move(receiver), *fd);
CopyBasicInfo(ma->baseExpr, ma);
return CreateCallExpr(std::move(ma), std::move(funcArgs), fd, funcTy->retTy, CallKind::CALL_DECLARED_FUNCTION);
}
OwnedPtr<Type> CreateType(Ptr<Ty> ty);
OwnedPtr<Type> CreateFuncType(Ptr<FuncTy> ty);
OwnedPtr<Expr> CreateBoolMatch(
OwnedPtr<Expr> selector, OwnedPtr<Expr> trueBranch, OwnedPtr<Expr> falseBranch, Ptr<Ty> ty);
StructDecl& GetStringDecl(const ImportManager& importManager);
* Returns synthetic lambda call that includes nodes. The result of the call expr is the last node:
*
* {
* node1;
* node2;
* ...
* return noden;
* }()
*/
OwnedPtr<CallExpr> WrapReturningLambdaCall(TypeManager& typeManager, std::vector<OwnedPtr<Node>> nodes);
* Returns lambda expression of nodes returning `Unit`.
*/
OwnedPtr<LambdaExpr> WrapUnitLambdaExpr(TypeManager& typeManager, std::vector<OwnedPtr<Node>> nodes,
std::vector<OwnedPtr<FuncParam>> lambdaParams = {});
OwnedPtr<LambdaExpr> WrapReturningLambdaExpr(
TypeManager& typeManager, std::vector<OwnedPtr<Node>> nodes, std::vector<OwnedPtr<FuncParam>> lambdaParams = {});
* Returns trimmed cangjie library name.
* For a filename in [outputLibPath] matched to "lib{libname}.{ext}" it returns {libname} if [trimmed] = `true`
* and "lib{libname}.{ext}" if [trimmed] = `false`.
* For other cases, it returns [fullPackageName]
*/
std::string GetCangjieLibName(
const std::string& outputLibPath, const std::string& fullPackageName, bool trimmed = true);
std::string GetMangledMethodName(const BaseMangler& mangler, const std::vector<OwnedPtr<FuncParam>>& params,
const std::string& methodName, TypeManager& typeManager, GenericConfigInfo* genericConfig = nullptr);
Ptr<Annotation> GetForeignNameAnnotation(const Decl& decl);
Ptr<Annotation> GetAnnotation(const Decl& decl, AnnotationKind annotationKind);
Ptr<std::string> GetSingleArgumentAnnotationValue(const Decl& target, AnnotationKind annotationKind);
std::string GetObjCMirrorForeignName(const ClassLikeDecl& target);
bool IsObjCGeneratedNSStringCtor(const Decl& target);
bool IsObjCGeneratedNSObjectToString(const Decl& target);
bool IsObjCGeneratedMember(const Decl& target);
bool IsSuperConstructorCall(const CallExpr& call);
bool IsThisConstructorCall(const CallExpr& call);
OwnedPtr<PrimitiveType> GetPrimitiveType(std::string typeName, AST::TypeKind typekind);
OwnedPtr<Type> GetTypeByName(std::string typeStr);
OwnedPtr<Type> GetGenericInstType(const GenericConfigInfo* config, std::string genericName);
OwnedPtr<Type> GetGenericInstType(const GenericConfigInfo* config, const Ptr<Ty>& genericTy, TypeManager& typeManager);
std::string GetGenericActualType(const GenericConfigInfo* config, std::string genericName);
TypeKind GetActualTypeKind(std::string configType);
Ptr<Ty> GetGenericInstTy(const GenericConfigInfo* config, std::string genericName);
Ptr<Ty> GetGenericInstTy(const GenericConfigInfo* config, const Ptr<Ty>& genericTy, TypeManager& typeManager);
Ptr<Ty> GetTyByName(std::string typeStr);
bool IsGenericParam(const Ptr<Ty> ty, const AST::Decl& decl, Native::FFI::GenericConfigInfo* genericConfig);
bool IsVisibalFunc(const FuncDecl& funcDecl, const AST::Decl& decl, Native::FFI::GenericConfigInfo* genericConfig);
bool IsCJMappingGeneric(const Decl& decl);
void SplitAndTrim(std::string str, std::vector<std::string>& types);
std::string JoinVector(const std::vector<std::string>& vec, const std::string& delimiter = "");
void InitGenericConfigs(
const File& file, const AST::Decl* decl, std::vector<GenericConfigInfo*>& genericConfigs, bool& isGenericGlueCode);
* If function param or return param is generic ty, replace it to instance ty by genericConfig.
*/
void ReplaceGenericTyForFunc(Ptr<FuncDecl> funcDecl, GenericConfigInfo* genericConfig, TypeManager& typeManager);
void ReplaceGenericTyForFuncTy(Ptr<Ty> ty, GenericConfigInfo* genericConfig, TypeManager& typeManager);
void GetArgsAndRetGenericActualTyVector(const GenericConfigInfo* config, FuncDecl& ctor,
std::unordered_map<std::string, Ptr<Ty>>& actualTyArgMap, std::vector<Ptr<Ty>>& funcTyParams,
std::vector<OwnedPtr<Type>>& actualPrimitiveType, TypeManager& typeManager);
Ptr<Ty> GetInstantyForGenericTy(
Decl& decl, const std::unordered_map<std::string, Ptr<Ty>>& actualTyArgMap, TypeManager& typeManager);
std::string GetLambdaJavaClassName(LambdaPattern& pattern);
std::string GetLambdaJavaClassName(Ptr<Ty> ty);
std::string GetCjMappingTupleName(const Ty& tupleTy);
ClassDecl& GetExceptionDecl(const ImportManager& importManager);
OwnedPtr<ThrowExpr> CreateThrowExceptionCall(const ImportManager& importManager,
TypeManager& typeManager, const std::string& msg, Ptr<File> curFile);
bool AreParamTypeKindsValid(const FuncDecl& fd, const std::vector<TypeKind>& typeKinds);
}
#endif