Skip to content

Commit 7009a9b

Browse files
committed
Add new inline append operator
Also some miscellaneous documentation improvements.
1 parent 469968f commit 7009a9b

File tree

4 files changed

+149
-61
lines changed

4 files changed

+149
-61
lines changed

docs/install.md

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -210,11 +210,10 @@ output from non-interactive programs. It also has a specific [effect on how the
210210
physics system runs](physics.md#non-realtime-mode).
211211

212212
`--runtime` *SECONDS*
213-
: Run for a specific period of time and then exit automatically, in seconds
214-
(may be specified as a [time-code](language.md#time-codes)). This is
215-
particularly useful for capturing videos of a specific length unattended. In
216-
`--lockstep` mode, this is a period of the internal frame clock not the wall
217-
clock.
213+
: Run for a specific number of seconds and then exit automatically (may be
214+
specified as a [time-code](language.md#time-codes)). This is particularly
215+
useful for capturing videos of a specific length unattended. In `--lockstep`
216+
mode, this is a period of the internal frame clock not the wall clock.
218217

219218
`--offscreen`
220219
: Requests that all `!window` nodes actually be silently interpreted as
@@ -227,8 +226,7 @@ run just this way), but you should know that the Mesa software rasterizer is
227226
`--opengles`
228227
: This tells *Flitter* to request the OpenGL ES API instead of OpenGL Core. You
229228
can use this on devices that do not support the full OpenGL API, or that are
230-
using a compatibility layer like ANGLE. At the moment, `!canvas` 2D drawing is
231-
not supported on OpenGL ES.
229+
using a compatibility layer like ANGLE.
232230

233231
`--profile`
234232
: Runs the Python profiler around the main loop. See [Profiling](#profiling)
@@ -238,10 +236,12 @@ below for details.
238236
: Turns on logging of **Flitter** virtual machine statistics. This will slow
239237
down the interpreter by quite a lot. The statistics are written out on exit
240238
at the `INFO` logging level, which means you will also need to have at least
241-
`--verbose` logging turned on to see the results. Be wary of interpreting these
242-
statistics: the overhead of doing the timing can make very simple instructions
243-
that are executed millions of times appear to be a larger source of execution
244-
cost than they really are.
239+
`--verbose` logging turned on to see the results. Be wary when interpreting
240+
these statistics: the overhead of doing the timing can make very simple
241+
instructions that are executed millions of times appear to be a larger source
242+
of execution cost than they really are. It is probably most usefully used in
243+
conjunction with `--lockstep` and `--runtime` (see above) to run for a specific
244+
number of frames and compare the statistics of different versions of a program.
245245

246246
## Developing Flitter
247247

docs/language.md

Lines changed: 114 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -75,19 +75,23 @@ The engine-supplied global values are:
7575
- `quantum` - the beats per quantum (usually 4)
7676
- `delta` - the difference between the current value of `beat` and the value
7777
at the last display frame
78-
- `time` - the time that the current frame began execution (either the value
79-
of the high-resolution Python `perf_counter()` timer or a counter beginning
80-
at `0` and incrementing by exactly `1/fps` on each frame in non-realtime
81-
mode)
82-
- `clock` - the current UTC time as a seconds-since-UNIX-epoch value
78+
- `time` - a monotonically increasing timer in seconds; in realtime mode this
79+
is the value of the high-resolution Python `perf_counter()` timer, in
80+
non-realtime mode it is a counter beginning at `0` on the first frame and
81+
incrementing by exactly `1/fps` on each frame
82+
- `clock` - the current UTC time as a seconds-since-UNIX-epoch value; this
83+
value is not guaranteed to be monotonically increasing and will run fast
84+
from the program perspective in non-realtime mode
8385
- `frame` - the current frame number, counting from 0 and increasing by one
84-
for each rendered frame (this will increase by exactly 1 on each program
85-
execution when running in non-realtime mode)
86-
- `fps` - the current target frame-rate of the engine (the `--fps` option)
87-
- `performance` - a value in the range [0.5 .. 2.0] that increases fractionally
88-
if the engine has time to spare and decreases fractionally if it is missing
89-
the target frame rate; this value can be multiplied into variable loads
90-
in the code – e.g., number of things on screen – to maintain frame rate
86+
for each rendered frame
87+
- `fps` - the current target frame-rate of the engine (either set with the
88+
`--fps` option or `%pragma fps`)
89+
- `performance` - a value in the range $[0.5 .. 2.0]$ that increases
90+
fractionally if the engine has time to spare and decreases fractionally if
91+
it is missing the target frame rate; this value can be multiplied into
92+
variable loads in the code – e.g., number of things on screen – to
93+
dynamically increase or reduce the complexity of the scene to match the
94+
target frame rate; in non-realtime mode this value is always `2.0`.
9195
- `realtime` - a `true`/`false` value indicating whether the engine is running
9296
in realtime mode (the default) or not (with the `--lockstep` option)
9397
- `run_time` - the number of seconds that the engine will run for before
@@ -148,21 +152,21 @@ general-purpose formatting and so `"Number ";1` is also a valid string.
148152
`nan`
149153
: The IEEE-754 floating-point "not a number" value
150154

151-
### SI Prefixes
155+
### SI Metric Multipliers ###
152156

153-
**Flitter** supports adding an SI prefix to the end of a number. This is
154-
confusing terminology, but an SI prefix is a prefix to a units suffix.
155-
**Flitter** does *not* support units, so you just end up with the SI prefix
156-
as a suffix. (Confused yet?)
157+
**Flitter** supports adding an SI metric multiplier prefix to the end of a
158+
number. This is slightly confusing terminology, but an SI metric prefix is a
159+
prefix to an SI units suffix. As **Flitter** does *not* support units, you just
160+
end up with the bare SI multiplier as a suffix.
157161

158-
The allowed SI prefixes are:
162+
The supported SI multipliers are:
159163

160164
- `T` – $\times 10^{12}$
161165
- `G` – $\times 10^{9}$
162166
- `M` – $\times 10^{6}$
163167
- `k` – $\times 10^{3}$
164168
- `m` – $\times 10^{-3}$
165-
- `u` – $\times 10^{-6}$ (also `µ`)
169+
- `u` – $\times 10^{-6}$ (also the Unicode `µ` symbol)
166170
- `n` – $\times 10^{-9}$
167171
- `p` – $\times 10^{-12}$
168172

@@ -242,8 +246,8 @@ has been used, then a symbol *cannot* be used to retrieve the value.
242246
### Time codes
243247

244248
In addition to normal literal numbers, as described above, **Flitter** supports
245-
literal *time codes*, which are given as a sequence of hours, minutes and
246-
seconds separated with colon characters (`:`), with the hours being optional
249+
literal *time codes*, which are given as a sequence of integer hours, minutes
250+
and seconds separated with colon characters (`:`), with the hours being optional
247251
and the seconds having an optional decimal fraction. For example:
248252

249253
```flitter
@@ -253,8 +257,9 @@ and the seconds having an optional decimal fraction. For example:
253257
Time codes are converted by the parser into a single-item numeric vector
254258
representing the total number of seconds (*125.3* in the example above).
255259
The hours component may be an arbitrarily large integer value, the minutes
256-
and seconds must be in the range *[0,60)*. Time codes may not be combined with
257-
exponents or SI prefixes, and do not support `_` separators.
260+
and seconds must be in the range *[0,60)*. Leading zeroes are optional. Time
261+
codes may not be combined with exponents or [SI
262+
multipliers](#si-metric-multipliers), and do not support `_` separators.
258263

259264
### Nodes
260265

@@ -306,6 +311,84 @@ appended to a `!window` node, which is the final value of this expression.
306311
Running this program as-is will result in a red window with the title "Hello
307312
world!".
308313

314+
#### Inline append
315+
316+
Although the usual, and most readable, way to indicate appending child nodes
317+
to a parent node is through indentation, there is also an inline append
318+
operator: `<<`. This can be used in `let` bindings, arguments to function
319+
calls, and within parentheses.
320+
321+
For example:
322+
323+
```flitter
324+
let tree = !a << !b << !c
325+
```
326+
327+
binds `tree` to an `!a` node containing a `!b` node containing a `!c` node
328+
(see [Sequence lets](#sequence-let) below for an alternative, probably more
329+
readable, way of achieving this).
330+
331+
Note that the `<<` operator evaluates to the *parent* node. Therefore, the
332+
above example is equivalent to:
333+
334+
```flitter
335+
let tree = !a << (!b << !c)
336+
```
337+
338+
By contrast, the following:
339+
340+
```flitter
341+
let tree = (!a << !b) << !c
342+
```
343+
344+
results in the `!c` node being appended to the `!a` node, and is therefore
345+
equivalent to:
346+
347+
```flitter
348+
let tree = !a << (!b; !c)
349+
```
350+
351+
The inline append operator may also be combined with an indented append block
352+
to collapse chains of nested nodes. The indented block will be appended to the
353+
final node in the chain.
354+
355+
For example:
356+
357+
```flitter
358+
!window size=1920;1080
359+
!adjust tonemap=:aces
360+
!bloom radius=20
361+
!canvas3d
362+
!light color=1 direction=0;0;-1
363+
364+
```
365+
366+
could be collapsed to:
367+
368+
```flitter
369+
!window size=1920;1080
370+
!adjust tonemap=:aces << !bloom radius=20
371+
!canvas3d
372+
!light color=1 direction=0;0;-1
373+
374+
```
375+
376+
which removes one level of indentation and helps to make clear that the
377+
`!adjust` and `!bloom` nodes are a pair of chained filter operations between the
378+
3D canvas and the window. This is particularly useful where three or more
379+
filters are used together and the indentation begins to become unhelpful.
380+
381+
While this example *could* be collapsed even further to:
382+
383+
```flitter
384+
!window size=1920;1080 << !adjust tonemap=:aces << !bloom radius=20 << !canvas3d
385+
!light color=1 direction=0;0;-1
386+
387+
```
388+
389+
this is not recommended usage, as it begins to obscure the structure rather than
390+
clarifying it.
391+
309392
#### Vector Node Operations
310393

311394
As nodes are values, and thus vectors, tag unary-postfix operations,
@@ -586,6 +669,8 @@ ignored. If the vector is shorter, then the the additional names will be bound
586669
to items wrapped around from the start again. If the vector is `null` then all
587670
names will be bound to `null`.
588671

672+
### Sequence let
673+
589674
A let binding may also bind one or more names to the result of evaluating an
590675
indented "body" sequence of expressions. For example:
591676

@@ -598,8 +683,9 @@ let foo=
598683
A let binding of this form may only have one name (or semicolon-separated list
599684
of names for an unpacked vector binding) followed by an `=`, a newline and then
600685
an indented sequence of expressions. This *sequence let* may contain any
601-
multi-line sequence expressions, the same as the body of a function or a loop.
602-
This is particularly useful for binding nested node structures to a name.
686+
multi-line sequence expressions, the same as the body of a function. This
687+
includes [conditionals](#conditionals) and [for loops](#for-loops), and is
688+
particularly useful for binding complex nested node structures to a name.
603689

604690
If a semicolon-separated name list is provided in a sequence let, then the
605691
names will be bound to values following the unpacking logic described above,
@@ -629,9 +715,9 @@ be bound within a non-sequence expression, e.g.:
629715
!foo x=(x*x where x=10)
630716
```
631717

632-
It is good practice, although not always necessary, to surround `where`
633-
expressions with parentheses to make the scope clear. However, note that `where`
634-
has higher precedence than `;` vector composition and so `(x;x*x where x=10)` is
718+
It is good practicealthough not always necessary to surround `where`
719+
expressions with parentheses to make the scope clear. Note that `where` has
720+
higher precedence than `;` vector composition and so `(x;x*x where x=10)` is
635721
equivalent to `x;(x*x where x=10)`.
636722

637723
## Sequences

examples/textures.fl

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -34,20 +34,18 @@ let SIZE=1920;1080
3434

3535
!window size=SIZE
3636
!record filename=(OUTPUT if frame == run_time * fps - 1)
37-
!adjust tonemap=:aces
38-
!bloom radius=hypot(SIZE)/100
39-
!flare
40-
!canvas3d samples=4 viewpoint=0;-25;0 up=0;0;1 near=1 far=100 rotate_y=0.025
41-
!sphere size=20 invert=true emissive_id=:stars rotation=0;0;days/365.256
42-
!group
43-
!light color=0.05
44-
!transform rotate_z=days/365.256
45-
!light color=3 direction=1;0;0
46-
!transform rotate_y=23.44/360 rotate_z=days
47-
!material color_id=:earth emissive_id=:earth_night roughness_id=:earth_reflection
48-
!sphere size=6.371 rotation=0;0;0.25
49-
!material color_id=:earth_cloudmap transparency_id=:earth_cloudmap_transparency
50-
!sphere size=6.421 rotation=0;0;days/14 roughness=0.5
51-
!transform rotate_y=-5.14/360 rotate_z=days/27.322 translate=20;0;0
52-
!material color_id=:moon roughness=0.5
53-
!sphere size=1.7375 rotation=0;(5.14-6.68)/360;0
37+
!adjust tonemap=:aces << !bloom radius=hypot(SIZE)/100 << !flare
38+
!canvas3d samples=4 viewpoint=0;-25;0 up=0;0;1 near=1 far=100 rotate_y=0.025
39+
!sphere size=20 invert=true emissive_id=:stars rotation=0;0;days/365.256
40+
!group
41+
!light color=0.05
42+
!transform rotate_z=days/365.256
43+
!light color=3 direction=1;0;0
44+
!transform rotate_y=23.44/360 rotate_z=days
45+
!material color_id=:earth emissive_id=:earth_night roughness_id=:earth_reflection
46+
!sphere size=6.371 rotation=0;0;0.25
47+
!material color_id=:earth_cloudmap transparency_id=:earth_cloudmap_transparency
48+
!sphere size=6.421 rotation=0;0;days/14 roughness=0.5
49+
!transform rotate_y=-5.14/360 rotate_z=days/27.322 translate=20;0;0
50+
!material color_id=:moon roughness=0.5
51+
!sphere size=1.7375 rotation=0;(5.14-6.68)/360;0

src/flitter/language/grammar.lark

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ parameters : (parameter ("," parameter)*)? -> tuple
3535
parameter : NAME ["=" node] -> binding
3636

3737
?expression : node _NL
38+
| node "<<" _NL? expression -> append
3839
| node _NL _INDENT sequence _DEDENT -> append
3940
| "@" atom [attribute_bindings] _NL [_INDENT sequence _DEDENT] -> template_call
4041
| "for" iterators _NL _INDENT sequence _DEDENT -> loop
@@ -48,6 +49,9 @@ conditions : condition ("elif" condition)* -> tuple
4849

4950
condition : composition _NL _INDENT sequence _DEDENT
5051

52+
?inline_append : node
53+
| node "<<" inline_append -> append
54+
5155
?node : composition
5256
| node TAG -> tag
5357
| node attribute_bindings -> attributes
@@ -60,7 +64,7 @@ multiline_bindings : binding+ _NL (_INDENT (binding+ _NL)+ _DEDENT)? -> tuple
6064

6165
bindings : binding+ -> tuple
6266

63-
binding : name_list "=" composition -> poly_binding
67+
binding : name_list "=" inline_append -> poly_binding
6468

6569
?composition : anonymous
6670
| anonymous (";" anonymous)+ -> sequence
@@ -122,17 +126,17 @@ name_list : NAME (";" NAME)* -> tuple
122126

123127
?call : atom
124128
| call _LPAREN args _RPAREN -> call
125-
| call "[" node "]" -> slice
129+
| call "[" inline_append "]" -> slice
126130

127-
args : node ("," node)* ("," named_arg)* -> tuple
131+
args : inline_append ("," inline_append)* ("," named_arg)* -> tuple
128132
| (named_arg ("," named_arg)*)? -> tuple
129133

130-
named_arg : NAME "=" node -> binding
134+
named_arg : NAME "=" inline_append -> binding
131135

132136
?atom : literal
133137
| NAME -> name
134138
| "$" atom -> lookup
135-
| _LPAREN node _RPAREN
139+
| _LPAREN inline_append _RPAREN
136140

137141
literal : NUMBER
138142
| TIMECODE

0 commit comments

Comments
 (0)