import ctypes
import os
from dataclasses import dataclass
from typing import Optional, Tuple
from .structures import ASTNode, GenericSlice, NodeParam
from .translation_unit import TranslationUnitPtr
_lib_instance: Optional[ctypes.CDLL] = None
@dataclass
class FunctionSignature:
name: str
return_type: Optional[type]
arg_types: Tuple[type, ...]
lib_functions = [
FunctionSignature("createTranslationUnit", TranslationUnitPtr, (ctypes.c_char_p,)),
FunctionSignature("createTranslationUnitFromSource", TranslationUnitPtr, (ctypes.c_char_p,)),
FunctionSignature("getTranslationUnitNodesCount", ctypes.c_size_t, (TranslationUnitPtr,)),
FunctionSignature("getTranslationUnitNodes", GenericSlice, (TranslationUnitPtr,)),
FunctionSignature("getTranslationUnitRootNodes", GenericSlice, (TranslationUnitPtr,)),
FunctionSignature("getTranslationUnitNodeFromIndex", ASTNode,
(TranslationUnitPtr, ctypes.c_uint32)),
FunctionSignature("getTranslationUnitTokensCount", ctypes.c_size_t, (TranslationUnitPtr,)),
FunctionSignature("getTranslationUnitTokens", GenericSlice, (TranslationUnitPtr,)),
FunctionSignature("getTranslationUnitErrorsCount", ctypes.c_size_t, (TranslationUnitPtr,)),
FunctionSignature("getTranslationUnitErrors", GenericSlice, (TranslationUnitPtr,)),
FunctionSignature("getTranslationUnitSource", GenericSlice, (TranslationUnitPtr,)),
FunctionSignature("freeTranslationUnit", None, (TranslationUnitPtr,)),
FunctionSignature("getNodeSpelling", GenericSlice, (TranslationUnitPtr, ASTNode)),
FunctionSignature("getNodeSource", GenericSlice, (TranslationUnitPtr, ctypes.c_uint32)),
FunctionSignature("getNodeType", ASTNode, (TranslationUnitPtr, ASTNode)),
FunctionSignature("getNodeAlign", GenericSlice, (TranslationUnitPtr, ASTNode)),
FunctionSignature("getNodeBody", GenericSlice, (TranslationUnitPtr, ASTNode)),
FunctionSignature("getNodeParamsCount", ctypes.c_size_t, (TranslationUnitPtr, ASTNode)),
FunctionSignature("getNodeParams", ctypes.c_size_t,
(TranslationUnitPtr, ASTNode, ctypes.POINTER(NodeParam), ctypes.c_size_t)),
FunctionSignature("isNodeExtern", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodeExport", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodePublic", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodeConst", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodeContainer", ctypes.c_bool, (ASTNode,)),
FunctionSignature("isNodeStruct", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodeUnion", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodeOpaque", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodeEnum", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
FunctionSignature("isNodeErrorUnion", ctypes.c_bool, (TranslationUnitPtr, ASTNode)),
]
def get_lib_ext() -> str:
from sys import platform # pylint: disable=import-outside-toplevel
exts = {"win32": "dll", "darwin": "dylib", "linux": "so"}
if ext := exts.get(platform):
return ext
raise ValueError(f"Invalid platform: '{platform}'.")
[docs]
def init_native_library(lib_dir: Optional[str] = None) -> None:
global _lib_instance # pylint: disable=global-statement
if _lib_instance is not None:
return
lib_ext: str = get_lib_ext()
path = lib_dir or os.path.join(os.path.dirname(os.path.realpath(__file__)), "native")
ctypes_lib = ctypes.CDLL(f"{path}/clib.{lib_ext}")
for func in lib_functions:
lib_func = getattr(ctypes_lib, func.name)
setattr(lib_func, "argtypes", func.arg_types)
setattr(lib_func, "restype", func.return_type)
_lib_instance = ctypes_lib
[docs]
def get_native_library(lib_dir: Optional[str] = None) -> ctypes.CDLL:
if _lib_instance is None:
init_native_library(lib_dir)
assert _lib_instance is not None, "Failed to load native library."
return _lib_instance