Skip to content

Commit 939ff92

Browse files
committed
Add syntactic sugar for nested for loops
1 parent 84edc2c commit 939ff92

File tree

4 files changed

+45
-5
lines changed

4 files changed

+45
-5
lines changed

docs/language.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -703,6 +703,23 @@ There is actually a more convenient `polar(theta)` function that does the same
703703
thing as `zip(cos(theta), sin(theta))`. Arguably, it would be even neater to
704704
implement a clock face using `!transform rotate=` instead.
705705

706+
Some syntactic sugar is provided to make directly nested loops more readable.
707+
For example:
708+
709+
```flitter
710+
for x in ..N
711+
for y in ..N
712+
for z in ..N
713+
!sphere position=x;y;z size=0.5
714+
```
715+
716+
may be written as the more concise:
717+
718+
```flitter
719+
for x in ..N, y in ..N, z in ..N
720+
!sphere position=x;y;z size=0.5
721+
```
722+
706723
Again, loops may also be used in-line in non-sequence expressions with syntax
707724
borrowed from Python:
708725

@@ -716,6 +733,23 @@ This will evaluate to:
716733
!line points=0;0;1;5;2;10;3;15;4;20
717734
```
718735

736+
There is no special syntax for nested in-line loops as these can already be
737+
simply written as:
738+
739+
```flitter
740+
let grid = (x;y) for x in ..N for y in ..N
741+
```
742+
743+
It is worth noting that – following the reversed notation – these loops operate
744+
in the *reverse* order to nested non-inline loops, in that this example is
745+
equivalent to:
746+
747+
```flitter
748+
let grid = ((x;y) for x in ..N) for y in ..N
749+
```
750+
751+
and therefore the *last* loop is outermost.
752+
719753
## Function calling
720754

721755
Functions are called in the normal way, with the name of the function followed

examples/bounce.fl

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,5 @@ let SIZE=1080;1080
6565
!light position=0 falloff=1;0;1;0 color=color radius=RADII[i]
6666
-- These additional directional lights are just here to create some
6767
-- reflections on the glass box that lend it more presence
68-
for x in (-1;1)
69-
for y in (-1;1)
70-
!light color=0.01 direction=x;y;0.5+0.1*y-0.05*x
68+
for x in (-1;1), y in (-1;1)
69+
!light color=0.01 direction=x;y;0.5+0.1*y-0.05*x

src/flitter/language/grammar.lark

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,12 @@ let_expression : "let" multiline_bindings sequence -> let
3333
?expression : node _NL
3434
| node _NL _INDENT sequence _DEDENT -> append
3535
| "@" atom [attribute_bindings] _NL [_INDENT sequence _DEDENT] -> template_call
36-
| "for" name_list "in" conditional _NL _INDENT sequence _DEDENT -> loop
36+
| "for" iterators _NL _INDENT sequence _DEDENT -> loop
3737
| "if" conditions ["else" _NL _INDENT sequence _DEDENT] -> if_else
3838
| _EOF -> export
3939

40+
iterators : name_list "in" conditional ("," name_list "in" conditional)* -> tuple
41+
4042
function : "func" NAME _LPAREN parameters _RPAREN _NL _INDENT sequence _DEDENT
4143

4244
parameters : (parameter ("," parameter)*)? -> tuple

src/flitter/language/parser.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,12 @@ def inline_if_else(self, then, condition, else_):
7777
def inline_loop(self, body, names, source):
7878
return tree.For(names, source, body)
7979

80+
def loop(self, iterators, expr):
81+
while iterators:
82+
expr = tree.For(iterators[-2], iterators[-1], expr)
83+
iterators = iterators[:-2]
84+
return expr
85+
8086
def call(self, function, args):
8187
args = list(args)
8288
bindings = []
@@ -120,7 +126,6 @@ def anonymous_function(self, parameters, body):
120126
logical_or = tree.Or
121127
logical_xor = tree.Xor
122128
lookup = tree.Lookup
123-
loop = tree.For
124129
lt = tree.LessThan
125130
modulo = tree.Modulo
126131
multiply = tree.Multiply

0 commit comments

Comments
 (0)