Skip to content

Commit

Permalink
Add syntactic sugar for nested for loops
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanhogg committed Dec 10, 2024
1 parent 84edc2c commit 939ff92
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 5 deletions.
34 changes: 34 additions & 0 deletions docs/language.md
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,23 @@ There is actually a more convenient `polar(theta)` function that does the same
thing as `zip(cos(theta), sin(theta))`. Arguably, it would be even neater to
implement a clock face using `!transform rotate=` instead.

Some syntactic sugar is provided to make directly nested loops more readable.
For example:

```flitter
for x in ..N
for y in ..N
for z in ..N
!sphere position=x;y;z size=0.5
```

may be written as the more concise:

```flitter
for x in ..N, y in ..N, z in ..N
!sphere position=x;y;z size=0.5
```

Again, loops may also be used in-line in non-sequence expressions with syntax
borrowed from Python:

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

There is no special syntax for nested in-line loops as these can already be
simply written as:

```flitter
let grid = (x;y) for x in ..N for y in ..N
```

It is worth noting that – following the reversed notation – these loops operate
in the *reverse* order to nested non-inline loops, in that this example is
equivalent to:

```flitter
let grid = ((x;y) for x in ..N) for y in ..N
```

and therefore the *last* loop is outermost.

## Function calling

Functions are called in the normal way, with the name of the function followed
Expand Down
5 changes: 2 additions & 3 deletions examples/bounce.fl
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,5 @@ let SIZE=1080;1080
!light position=0 falloff=1;0;1;0 color=color radius=RADII[i]
-- These additional directional lights are just here to create some
-- reflections on the glass box that lend it more presence
for x in (-1;1)
for y in (-1;1)
!light color=0.01 direction=x;y;0.5+0.1*y-0.05*x
for x in (-1;1), y in (-1;1)
!light color=0.01 direction=x;y;0.5+0.1*y-0.05*x
4 changes: 3 additions & 1 deletion src/flitter/language/grammar.lark
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ let_expression : "let" multiline_bindings sequence -> let
?expression : node _NL
| node _NL _INDENT sequence _DEDENT -> append
| "@" atom [attribute_bindings] _NL [_INDENT sequence _DEDENT] -> template_call
| "for" name_list "in" conditional _NL _INDENT sequence _DEDENT -> loop
| "for" iterators _NL _INDENT sequence _DEDENT -> loop
| "if" conditions ["else" _NL _INDENT sequence _DEDENT] -> if_else
| _EOF -> export

iterators : name_list "in" conditional ("," name_list "in" conditional)* -> tuple

function : "func" NAME _LPAREN parameters _RPAREN _NL _INDENT sequence _DEDENT

parameters : (parameter ("," parameter)*)? -> tuple
Expand Down
7 changes: 6 additions & 1 deletion src/flitter/language/parser.py
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ def inline_if_else(self, then, condition, else_):
def inline_loop(self, body, names, source):
return tree.For(names, source, body)

def loop(self, iterators, expr):
while iterators:
expr = tree.For(iterators[-2], iterators[-1], expr)
iterators = iterators[:-2]
return expr

def call(self, function, args):
args = list(args)
bindings = []
Expand Down Expand Up @@ -120,7 +126,6 @@ def anonymous_function(self, parameters, body):
logical_or = tree.Or
logical_xor = tree.Xor
lookup = tree.Lookup
loop = tree.For
lt = tree.LessThan
modulo = tree.Modulo
multiply = tree.Multiply
Expand Down

0 comments on commit 939ff92

Please sign in to comment.