Commit ea17ab16 authored by Stefan Behnel's avatar Stefan Behnel

generalise C type specific string formatting

parent 010ca805
......@@ -3012,7 +3012,7 @@ class FormattedValueNode(ExprNode):
# value ExprNode The expression itself
# conversion_char str or None Type conversion (!s, !r, !a, or none)
# format_spec JoinedStrNode or None Format string passed to __format__
# c_format_spec str or None Formatting that can be done at the C level
# c_format_spec str or None If not None, formatting can be done at the C level
subexprs = ['value', 'format_spec']
......@@ -3033,26 +3033,23 @@ class FormattedValueNode(ExprNode):
def analyse_types(self, env):
self.value = self.value.analyse_types(env)
if not self.format_spec or self.format_spec.is_string_literal:
c_format_spec = self.format_spec.value if self.format_spec else None
c_format_spec = self.format_spec.value if self.format_spec else self.value.type.default_format_spec
if self.value.type.can_coerce_to_pystring(env, format_spec=c_format_spec):
if c_format_spec is None and self.value.type.is_int:
c_format_spec = 'd'
self.c_format_spec = c_format_spec
if self.format_spec:
self.format_spec = self.format_spec.analyse_types(env).coerce_to_pyobject(env)
if not self.c_format_spec:
if self.c_format_spec is None:
self.value = self.value.coerce_to_pyobject(env)
return self
def generate_result_code(self, code):
if self.c_format_spec and not self.value.type.is_pyobject:
convert_func = self.value.type.to_pystring_function(code)
code.putln("%s = %s(%s, '%s'); %s" % (
if self.c_format_spec is not None and not self.value.type.is_pyobject:
convert_func_call = self.value.type.convert_to_pystring(
self.value.result(), code, self.c_format_spec)
code.putln("%s = %s; %s" % (
self.result(),
convert_func,
self.value.result(),
self.c_format_spec,
convert_func_call,
code.error_goto_if_null(self.result(), self.pos)))
code.put_gotref(self.py_result())
return
......
......@@ -26,6 +26,7 @@ class BaseType(object):
# List of attribute names of any subtypes
subtypes = []
_empty_declaration = None
default_format_spec = None
def can_coerce_to_pyobject(self, env):
return False
......@@ -33,6 +34,9 @@ class BaseType(object):
def can_coerce_to_pystring(self, env, format_spec=None):
return False
def convert_to_pystring(self, cvalue, code, format_spec=None):
raise NotImplementedError("C types that support string formatting must override this method")
def cast_code(self, expr_code):
return "((%s)%s)" % (self.empty_declaration_code(), expr_code)
......@@ -1624,6 +1628,7 @@ class CIntType(CNumericType):
to_py_function = None
from_py_function = None
to_pyunicode_utility = None
default_format_spec = 'd'
exception_value = -1
def can_coerce_to_pyobject(self, env):
......@@ -1634,7 +1639,7 @@ class CIntType(CNumericType):
return False
return True
def to_pystring_function(self, code):
def convert_to_pystring(self, cvalue, code, format_spec=None):
if self.to_pyunicode_utility is None:
utility_code_name = "__Pyx_PyUnicode_From_" + self.specialization_name()
to_pyunicode_utility = TempitaUtilityCode.load_cached(
......@@ -1645,7 +1650,7 @@ class CIntType(CNumericType):
else:
utility_code_name, to_pyunicode_utility = self.to_pyunicode_utility
code.globalstate.use_utility_code(to_pyunicode_utility)
return utility_code_name
return "%s(%s, '%s')" % (utility_code_name, cvalue, format_spec or 'd')
def create_to_py_utility_code(self, env):
if type(self).to_py_function is None:
......@@ -1762,12 +1767,15 @@ class CBIntType(CIntType):
to_py_function = "__Pyx_PyBool_FromLong"
from_py_function = "__Pyx_PyObject_IsTrue"
exception_check = 1 # for C++ bool
exception_check = 1 # for C++ bool
default_format_spec = ''
def can_coerce_to_pystring(self, env, format_spec=None):
return not format_spec
return not format_spec or super(CBIntType, self).can_coerce_to_pystring(env, format_spec)
def to_pystring_function(self, code):
def convert_to_pystring(self, cvalue, code, format_spec=None):
if format_spec:
return super(CBIntType, self).convert_to_pystring(cvalue, code, format_spec)
# NOTE: no caching here as the string constant cnames depend on the current module
utility_code_name = "__Pyx_PyUnicode_FromBInt_" + self.specialization_name()
to_pyunicode_utility = TempitaUtilityCode.load_cached(
......@@ -1777,7 +1785,7 @@ class CBIntType(CIntType):
"TO_PY_FUNCTION": utility_code_name,
})
code.globalstate.use_utility_code(to_pyunicode_utility)
return utility_code_name
return "%s(%s)" % (utility_code_name, cvalue)
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
......
......@@ -656,7 +656,7 @@ static CYTHON_INLINE PyObject* {{TO_PY_FUNCTION}}({{TYPE}} value, char format_ch
/////////////// CBIntToPyUnicode.proto ///////////////
#define {{TO_PY_FUNCTION}}(value, format_char) \
#define {{TO_PY_FUNCTION}}(value) \
((value) ? __Pyx_NewRef({{TRUE_CONST}}) : __Pyx_NewRef({{FALSE_CONST}}))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment