Files
langkit/langkit/c_api.py
Pierre-Marie de Rodat 145c81d3d4 C API: preserve type names that start with lowercase
TN: QB10-018
2017-11-10 16:52:31 +01:00

121 lines
3.9 KiB
Python

from __future__ import absolute_import, division, print_function
import re
from langkit import names
from langkit.diagnostics import check_source_language
from langkit.language_api import AbstractAPISettings
class CAPIType(object):
"""
C API generation helper: encapsulate the logic of C types formatting.
"""
def __init__(self, c_api_settings, name, external=False):
"""Create a stub for a C API type.
:param CAPISettings c_api_settings: API settings to use for this type.
:param name: The name for the type. Can be either a Name or a
lower-case formatted name.
:type name: str|names.Name
:param bool external: Whether this type is already declared outside the
C API. For instance: "int" is external, but "node" is not.
"""
self.c_api_settings = c_api_settings
self.external = external
# Make private the following in order to avoid accidental use of these
# instead of the properties.
self._name = (name if isinstance(name, names.Name) else
names.Name(name))
@property
def name(self):
"""Return the C name for this type, properly wrapped if needed."""
# All names we define as part of the C API must be wrapped so that they
# don't conflict with "external" names. Keep "external" ones untouched
# since we don't control them.
return (self._name if self.external else
self.c_api_settings.get_name(self._name))
class CAPISettings(AbstractAPISettings):
"""Convenient container for C API generation settings.
The convention is to make instances for this class available to templates
as `capi`."""
LIB_NAME_RE = re.compile('[a-zA-Z][a-zA-Z0-9_-]+')
def __init__(self, ctx, symbol_prefix=''):
"""
Create C API generation settings.
:param CompileCtx ctx: Compile context for this C API.
:param str symbol_prefix: Valid C identifier used as a prefix for all
top-level declarations in the generated C API. Empty string (default)
if no prefix is needed.
"""
self.context = ctx
self.symbol_prefix = symbol_prefix
@property
def lib_name(self):
"""
Name of the generated library, generated from the context's lib_name.
This will be used to build the name of header files, library (static
and shared object) files, etc. It must be a valid C identifier with the
exception that dashes ("-") are allowed. Case matters (but you still
choose it).
"""
lib_name = self.context.lib_name.lower
check_source_language(
self.LIB_NAME_RE.match(lib_name),
'Invalid library name: {}'.format(lib_name)
)
return lib_name
#
# Helpers for templates
#
@property
def shared_object_basename(self):
"""
Return the basename to use for the shared object.
In order to get the fullname, format the following string::
lib{shared_object_basename}.{extension}
`extension` must be "so" on Linux, "dll" on Windows, etc.
"""
basename = self.lib_name.lower()
return basename[3:] if basename.startswith('lib') else basename
@property
def header_guard_id(self):
return self.lib_name.upper().replace('-', '_')
def get_name(self, name):
"""
Wrap `name` as a top-level scope symbol.
:type name: Name|basestring
:rtype: str
"""
if isinstance(name, basestring):
name = names.Name(name)
return names.Name('{}_{}'.format(self.symbol_prefix, name.base_name)
if self.symbol_prefix else name).lower
def get_enum_alternative(self, type_name, alt_name, suffix):
return self.get_name(
names.Name('{}_{}'.format(type_name.base_name,
alt_name.base_name)))