8 Rendering

Every node whose bytecode includes a HALT statement MUST define a rendering template.

Templates may be either static or dynamic.

8.1 Dynamic templates

Using placeholders, the content behind MAP calls in the current executing node may be embedded in the template.

Placeholders have the following format:

{{.symbol}}

where symbol is the corresponding argument to MAP.

Note that MAP can only be called on symbols who have a corresponding LOAD on the same level or futher up the stack.

8.1.1 Examples

Consider the following instruction sequence:

LOAD foo 32
MAP foo
HALT

If the template contains the placeholder foo, the contents of that placeholder will be replaced by the cached result of the LOAD foo external symbol.

However:

LOAD foo 32
HALT

This will not work for the same template, because the foo symbol has not been exposed with a MAP call.

LOAD foo 32
MOVE bar
# (bar bytecode follows)
MAP foo
HALT

If the template for the node bar contains the placeholder foo, the contents of that placeholder will be replaced by the cached result of the LOAD foo external symbol.

This works because the MAP is encountered further down the node execution stack than where the LOAD was encountered.

However:

LOAD foo 32
MOVE bar
# (bar bytecode follows)
MAP foo
MOVE baz
# (baz bytecode follows)
HALT

Here, if the template for baz contains the placeholder foo, the execution will fail because the MAP in bar was invalidated by the MOVE to baz.

8.2 Rendering pipeline

The pipeline starts with the loading of the template corresponding to the current execution node.

From there, three branches are possible:

  1. No sink has been defined.
  2. One of the encountered MAP symbols resolves to a sink.
  3. MSINK has been encountered.

If the resulting output from any of these branches is larger than the output size, failure ensues and execution is terminated.

8.2.1 No sink

  1. Expand all placeholders in the template.
  2. Expand all menu items

8.2.2 MAP sink

  1. Expand all non-sink placeholders in the template.
  2. Expand all menu items.
  3. Group sink items up to the remaining output size.
  4. If any item alone exceeds the remaining output size, fail and terminate execution.
  5. If any item together with the lateral navigation menu items exceed the remaining output size, fail and terminate execution.
  6. Check the page navigation index (see Lateral navigation).
  7. Replace sink symbol result with group item corresponding to navigation index.
  8. Expand all sink placeholders in the template.
  9. Expand all menu items (including lateral navigation).

8.3 Multiple-page rendering

As indicated above, multiple-page rendering is activated when a MAP is issued to a symbol that is loaded with 0 size. (LOAD <symbol> 0).

The result is split into rows using newline (0x0a) as separator.

8.3.1 Missing navigation

If no lateral navigation has been activated, any sinks will still be processed.

The sink placeholder will then be replaced with the first item in the group.

8.3.2 Multi-page example

Consider the following instruction sequence:

LOAD foo 8
LOAD bar 16
LOAD baz 0
MAP foo
MAP bar
MAP baz
MOUT to_foo 0
MOUT to_bar 1
MNEXT to_next 11
MPREV to_prev 22
HALT
INCMP foo 0
INCMP bar 1
INCMP > 11
INCMP < 22

... and the following template (14 bytes, without the placeholders, including line break):

This is {{.foo}} and {{.bar}}
{{.baz}}

8.3.2.1 Data accounting

Then consider that the symbols resolve as follows:

symbolreturned valuerendered valuebytes
foofoobarfoobar6
barbarbarbarbarbarbar9
baz
FOO 42
BAR 13
BAZ 666
XYZZY 1984
INKY 1
PINKY 22
BLINKY 333
CLYDE 4444
(deferred)(71)
to_foogo to foo0:go to foo11
to_barvisit the bar1:visit the bar15
to_nextnext page11:next page12
to_prevgo back22:go back10

Given an output size limit of 94, static part of the template (14 bytes). this results in the following render possibilities for the sink content:

navigation casebytes left for sink
no navigation39
next27
previous29
next + previous17

8.3.2.2 Rendering logic

The total sink byte count is 72, whereas the maximum available sink capacity is 39. At least one extra page is needed.

The first page (with next) has 27 bytes available, which covers the 3 first sink items (22 bytes, include line break). This results in the following output:

This is foobar and barbarbar
FOO 42
BAR 13
BAZ 666
0:go to foo
1:visit the bar
11:next page

Any page that is not first page has maximum 29 bytes available. There are 49 bytes left to render from the sink. This means that more pages are needed, and therefore both next and previous are needed, leaving a capacity of 17 bytes. This is only sufficient for the next item (11 bytes, with line break), resulting in the following output:

This is foobar and barbarbar
XYZZY 1984
0:go to foo
1:visit the bar
11:next page
22:go back

For the next page we again compare with the maximum of 29 bytes. There are 38 bytes left to render. Another intermediate page is required, with the two next entries (16 bytes) fitting inside the capacity (17 bytes). The page then looks like this:

This is foobar and barbarbar
INKY 1
PINKY 22
0:go to foo
1:visit the bar
11:next page
22:go back

Lastly, with 22 bytes left to go, we can render within the maximum available space of 29 bytes (only using previous). Thus:

This is foobar and barbarbar
BLINKY 333
CLYDE 4444
0:go to foo
1:visit the bar
22:go back