This commit is contained in:
Kovid Goyal 2021-03-24 18:38:20 +05:30
commit 79e1fe3fce
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
2 changed files with 22 additions and 4 deletions

View File

@ -228,9 +228,12 @@ General Program Mode
times_div_expr ::= unary_op_expr [ times_div_op unary_op_expr ]*
times_div_op ::= '*' | '/'
unary_op_expr ::= [ add_sub_op unary_op_expr ]* | expression
expression ::= identifier | constant | function | assignment |
expression ::= identifier | constant | function | assignment | field_reference |
if_expression | for_expression | '(' expression_list ')'
identifier ::= sequence of letters or ``_`` characters
field_reference ::= '$' [ '$' ] [ '#' ] identifier
identifier ::= id_start [ id_rest ]*
id_start ::= letter | underscore
id_rest ::= id_start | digit
constant ::= " string " | ' string ' | number
function ::= identifier '(' expression_list [ ',' expression_list ]* ')'
assignment ::= identifier '=' top_expression
@ -256,7 +259,7 @@ is 3.
The operator precedence (order of evaluation) specified by the above grammar, from highest to lowest is:
* Function calls, constants, parenthesized expressions, statement expressions, assignment expressions.
* Function calls, constants, parenthesized expressions, statement expressions, assignment expressions, field references.
* Unary plus (``+``) and minus (``-``). These operators evaluate right to left. These and all the other arithmetic operators return integers if the expression results in a fractional part equal to zero. Example: if an expression returns ``3.0`` it is changed to ``3``.
* Multiply (``*``) and divide (``/``). These operators are associative and evaluate left to right. Use parentheses if you want to change the order of evaluation.
* Add (``+``) and subtract (``-``). These operators are associative and evaluate left to right.
@ -265,6 +268,15 @@ The operator precedence (order of evaluation) specified by the above grammar, fr
* Logical and (``&&``). This operator returns '1' if both the left-hand and right-hand expressions are True, or the empty string ``''`` if either is False. It is associative, evaluates left to right, and does `short-circuiting <https://chortle.ccsu.edu/java5/Notes/chap40/ch40_2.html>`_.
* Logical or (``||``). This operator returns ``'1'`` if either the left-hand or right-hand expression is True, or ``''`` if both are False. It is associative, evaluates left to right, and does short-circuiting. The operator is an inclusive or, returning '1' if both the left- and right-hand expressions are True.
**Field References**
A ``field_reference`` evaluates to the value of the metadata field named by lookup key that follows the ``$`` or ``$$``. Using ``$`` is equivalent to using the ``field()`` function. Using ``$$`` is equivalent to using the ``raw_field`` function. Examples::
* $authors ==> field('authors')
* $#genre ==> field('#genre')
* $$pubdate ==> raw_field('pubdate')
* $$#my_int ==> raw_field('#my_int')
**If Expressions**
``If`` expressions first evaluate the ``condition``, which is True if it evaluates to anything other than the empty string. If the ``condition`` is True then the ``expression_list`` in the ``then`` clause is evaluated. If it is False then the ``expression_list`` in the ``elif`` or ``else`` clause is evaluated if present. The ``elif`` and ``else`` parts are optional. The words ``if``, ``then``, ``elif``, ``else``, and ``fi`` are reserved; you cannot use them as identifier names. You can put newlines and white space wherever they make sense. The ``condition`` is a ``top_expression`` not an ``expression_list``; semicolons are not allowed. The ``expression_lists`` are semicolon-separated sequences of template language top_expressions. An ``if`` expression returns the result of the last ``top_expression`` in the evaluated ``expression_list``, or '' if no expression list was evaluated.

View File

@ -578,8 +578,13 @@ class _Parser(object):
if self.token_is_for():
return self.for_expression()
if self.token_is_id():
# We have an identifier. Determine if it is a function
id_ = self.token()
# We have an identifier. Check if it is a field reference
if len(id_) > 1 and id_[0] == '$':
if id_[1] == '$':
return RawFieldNode(ConstantNode(id_[2:]))
return FieldNode(ConstantNode(id_[1:]))
# Determine if it is a function
if not self.token_op_is_lparen():
if self.token_op_is_equals():
# classic assignment statement
@ -992,6 +997,7 @@ class TemplateFormatter(string.Formatter):
(r'(\|\||&&|!)', lambda x,t: (_Parser.LEX_OP, t)), # noqa
(r'[(),=;:\+\-*/]', lambda x,t: (_Parser.LEX_OP, t)), # noqa
(r'-?[\d\.]+', lambda x,t: (_Parser.LEX_CONST, t)), # noqa
(r'\$\$?#?\w+', lambda x,t: (_Parser.LEX_ID, t)), # noqa
(r'\$', lambda x,t: (_Parser.LEX_ID, t)), # noqa
(r'\w+', lambda x,t: (_Parser.LEX_ID, t)), # noqa
(r'".*?((?<!\\)")', lambda x,t: (_Parser.LEX_CONST, t[1:-1])), # noqa