This commit is contained in:
Kovid Goyal 2023-01-06 21:19:12 +05:30
commit c0ff9b11e8
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 52 additions and 1 deletions

View File

@ -610,6 +610,7 @@ In `GPM` the functions described in `Single Function Mode` all require an additi
* ``strlen(value)`` -- Returns the length of the string ``value``.
* ``substr(str, start, end)`` -- returns the ``start``'th through the ``end``'th characters of ``str``. The first character in ``str`` is the zero'th character. If ``end`` is negative, then it indicates that many characters counting from the right. If ``end`` is zero, then it indicates the last character. For example, ``substr('12345', 1, 0)`` returns ``'2345'``, and ``substr('12345', 1, -1)`` returns ``'234'``.
* ``subtract(x, y)`` -- returns ``x - y``. Throws an exception if either ``x`` or ``y`` are not numbers. This function can usually be replaced by the ``-`` operator.
* ``switch_if([test_expression, value_expression,]+ else_expression)`` -- for each ``test_expression, value_expression`` pair, checks if ``test_expression`` is True (non-empty) and if so returns the result of ``value_expression``. If no ``test_expression`` is True then the result of ``else_expression` is returned. You can have as many ``test_expression, value_expressio`` pairs as you want.
* ``today()`` -- return a date+time string for today (now). This value is designed for use in `format_date` or `days_between`, but can be manipulated like any other string. The date is in `ISO <https://en.wikipedia.org/wiki/ISO_8601>`_ date/time format.
* ``template(x)`` -- evaluates ``x`` as a template. The evaluation is done in its own context, meaning that variables are not shared between the caller and the template evaluation.
* ``to_hex(val)`` -- returns the string ``val`` encoded in hex. This is useful when constructing calibre URLs.

View File

@ -55,6 +55,7 @@ class Node:
NODE_LOCAL_FUNCTION_CALL = 29
NODE_RANGE = 30
NODE_SWITCH = 31
NODE_SWITCH_IF = 32
def __init__(self, line_number, name):
self.my_line_number = line_number
@ -289,6 +290,13 @@ class SwitchNode(Node):
self.expression_list = expression_list
class SwitchIfNode(Node):
def __init__(self, line_number, expression_list):
Node.__init__(self, line_number, 'switch_if()')
self.node_type = self.NODE_SWITCH_IF
self.expression_list = expression_list
class ContainsNode(Node):
def __init__(self, line_number, arguments):
Node.__init__(self, line_number, 'contains()')
@ -687,6 +695,8 @@ class _Parser:
lambda ln, args: FirstNonEmptyNode(ln, args)),
'switch': (lambda args: len(args) >= 3 and (len(args) %2) == 0,
lambda ln, args: SwitchNode(ln, args)),
'switch_if': (lambda args: len(args) > 0 and (len(args) %2) == 1,
lambda ln, args: SwitchIfNode(ln, args)),
'assign': (lambda args: len(args) == 2 and len(args[0]) == 1 and args[0][0].node_type == Node.NODE_RVALUE,
lambda ln, args: AssignNode(ln, args[0][0].name, args[1])),
'contains': (lambda args: len(args) == 4,
@ -1303,6 +1313,21 @@ class _Interpreter:
self.break_reporter(prog.node_name, res, prog.line_number)
return res
def do_node_switch_if(self, prog):
for i in range(0, len(prog.expression_list)-1, 2):
tst = self.expr(prog.expression_list[i])
if self.break_reporter:
self.break_reporter("switch_if(): test expr", tst, prog.line_number)
if tst:
res = self.expr(prog.expression_list[i+1])
if self.break_reporter:
self.break_reporter("switch_if(): value expr", res, prog.line_number)
return res
res = self.expr(prog.expression_list[-1])
if (self.break_reporter):
self.break_reporter("switch_if(): default expr", res, prog.line_number)
return res
def do_node_strcat(self, prog):
res = ''.join([self.expr(expr) for expr in prog.expression_list])
if self.break_reporter:
@ -1519,6 +1544,7 @@ class _Interpreter:
Node.NODE_CALL_STORED_TEMPLATE: do_node_stored_template_call,
Node.NODE_FIRST_NON_EMPTY: do_node_first_non_empty,
Node.NODE_SWITCH: do_node_switch,
Node.NODE_SWITCH_IF: do_node_switch_if,
Node.NODE_FOR: do_node_for,
Node.NODE_RANGE: do_node_range,
Node.NODE_GLOBALS: do_node_globals,

View File

@ -667,6 +667,30 @@ class BuiltinSwitch(BuiltinFormatterFunction):
i += 2
class BuiltinSwitchIf(BuiltinFormatterFunction):
name = 'switch_if'
arg_count = -1
category = 'Iterating over values'
__doc__ = doc = _('switch_if([test_expression, value_expression,]+ else_expression) -- '
'for each "test_expression, value_expression" pair, checks if test_expression '
'is True (non-empty) and if so returns the result of value_expression. '
'If no test_expression is True then the result of else_expression is returned. '
'You can have as many "test_expression, value_expression" pairs as you want.')
def evaluate(self, formatter, kwargs, mi, locals, *args):
if (len(args) % 2) != 1:
raise ValueError(_('switch_if requires an odd number of arguments'))
# We shouldn't get here because the function is inlined. However, someone
# might call it directly.
i = 0
while i < len(args):
if i + 1 >= len(args):
return args[i]
if args[i]:
return args[i+1]
i += 2
class BuiltinStrcatMax(BuiltinFormatterFunction):
name = 'strcat_max'
arg_count = -1
@ -2384,7 +2408,7 @@ _formatter_builtins = [
BuiltinSetGlobals(), BuiltinShorten(), BuiltinStrcat(), BuiltinStrcatMax(),
BuiltinStrcmp(), BuiltinStrcmpcase(), BuiltinStrInList(), BuiltinStrlen(), BuiltinSubitems(),
BuiltinSublist(),BuiltinSubstr(), BuiltinSubtract(), BuiltinSwapAroundArticles(),
BuiltinSwapAroundComma(), BuiltinSwitch(),
BuiltinSwapAroundComma(), BuiltinSwitch(), BuiltinSwitchIf(),
BuiltinTemplate(), BuiltinTest(), BuiltinTitlecase(), BuiltinToday(),
BuiltinToHex(), BuiltinTransliterate(), BuiltinUppercase(), BuiltinUrlsFromIdentifiers(),
BuiltinUserCategories(), BuiltinVirtualLibraries(), BuiltinAnnotationCount()