blueprint-compiler/docs/reference/expressions.rst
James Westman 8c6f8760f7 language: Add expression literals
Add expression literals, so you can set properties of type
Gtk.Expression.
2025-01-04 17:09:57 +00:00

112 lines
4.6 KiB
ReStructuredText

===========
Expressions
===========
Expressions make your user interface code *reactive*. This means when your
application's data changes, the user interface reacts to the change
automatically.
.. code-block:: blueprint
label: bind template.account.username;
/* ^ ^ ^
| creates lookup expressions that are re-evaluated when
| the account's username *or* the account itself changes
|
binds the `label` property to the expression's output
*/
When a value is bound to an expression using the ``bind`` keyword, the binding
monitors all the object properties that are inputs to the expression, and
reevaluates it if any of them change.
This is a powerful tool for ensuring consistency and simplifying your code.
Rather than pushing changes to the user interface wherever they may occur,
you can define your data model with GObject and let GTK take care of the rest.
.. _Syntax Expression:
Expressions
-----------
.. rst-class:: grammar-block
Expression = ( :ref:`ClosureExpression<Syntax ClosureExpression>` | :ref:`Literal<Syntax Literal>` | ( '(' Expression ')' ) ) ( :ref:`LookupExpression<Syntax LookupExpression>` | :ref:`CastExpression<Syntax CastExpression>` )*
.. note::
The grammar above is designed to eliminate `left recursion <https://en.wikipedia.org/wiki/Left_recursion>`_, which can make parsing more complex. In this format, an expression consists of a prefix (such as a literal value or closure invocation) followed by zero or more infix or suffix operators.
Expressions are composed of property lookups and/or closures. Property lookups are the inputs to the expression, and closures provided in application code can perform additional calculations on those inputs.
.. _Syntax LookupExpression:
Lookups
-------
.. rst-class:: grammar-block
LookupExpression = '.' <property::ref:`IDENT<Syntax IDENT>`>
Lookup expressions perform a GObject property lookup on the preceding expression. They are recalculated whenever the property changes, using the `notify signal <https://docs.gtk.org/gobject/signal.Object.notify.html>`_.
The type of a property expression is the type of the property it refers to.
.. _Syntax ClosureExpression:
Closures
--------
.. rst-class:: grammar-block
ClosureExpression = '$' <name::ref:`IDENT<Syntax IDENT>`> '(' ( :ref:`Expression<Syntax Expression>` ),* ')'
Closure expressions allow you to perform additional calculations that aren't supported in blueprint by writing those calculations as application code. These application-defined functions are created in the same way as :ref:`signal handlers<Syntax Signal>`.
Expressions are only reevaluated when their inputs change. Because blueprint doesn't manage a closure's application code, it can't tell what changes might affect the result. Therefore, closures must be *pure*, or deterministic. They may only calculate the result based on their immediate inputs, not properties of their inputs or outside variables.
Blueprint doesn't know the closure's return type, so closure expressions must be cast to the correct return type using a :ref:`cast expression<Syntax CastExpression>`.
.. _Syntax CastExpression:
Casts
-----
.. rst-class:: grammar-block
CastExpression = 'as' '<' :ref:`TypeName<Syntax TypeName>` '>'
Cast expressions allow Blueprint to know the type of an expression when it can't otherwise determine it. This is necessary for closures and for properties of application-defined types.
Example
~~~~~~~
.. code-block:: blueprint
// Cast the result of the closure so blueprint knows it's a string
label: bind $format_bytes(template.file-size) as <string>
.. _Syntax ExprValue:
Expression Values
-----------------
.. rst-class:: grammar-block
ExprValue = 'expr' :ref:`Expression<Syntax Expression>`
Some APIs take *an expression itself*--not its result--as a property value. For example, `Gtk.BoolFilter <https://docs.gtk.org/gtk4/class.BoolFilter.html>`_ has an ``expression`` property of type `Gtk.Expression <https://docs.gtk.org/gtk4/class.Expression.html>`_. This expression is evaluated for every item in a list model to determine whether the item should be filtered.
To define an expression for such a property, use ``expr`` instead of ``bind``. Inside the expression, you can use the ``item`` keyword to refer to the item being evaluated. You must cast the item to the correct type using the ``as`` keyword, and you can only use ``item`` in a property lookup--you may not pass it to a closure.
Example
~~~~~~~
.. code-block:: blueprint
BoolFilter {
expression: expr item as <$UserAccount>.active;
}