Input Specification

ZOTI-Gen structures are specified using:

  • a serialization format (e.g. JSON or YAML) representing the structure of the code blocks, their hierarchy and bindings;

  • an extended Jinja2 template format contained as strings by the code entries of the serialization format.

  • a simpler templated string format to define glue macros in some of the binding entries.

Format Schema

ZOTI-Gen input files are describing code blocks using a serialization format. Similarly to other ZOTI tools, ZOTI-Gen stores modules in a ZOTI-YAML container, hence input files contain the arguments passed to its constructor, among which a preamble object and a document object.

Preamble

Apart from the mandatory module entry containing the qualified name of the current module, ZOTI-Gen preambles need to contain the following entry:

top (string)

the name of the “top” block from which all other blocks are recursively referenced.

Document

A ZOTI-Gen document consists in a list of block entries. Each entry would fill in an equivalent class container hence we use the class API documnentation to document the entry schemas.

block

A block describes a unit of code that might be related to other blocks through bindings and might contain a template. Internally it is represented using a zoti_gen.core.Block class. Blocks are described using the following entries;

name:

(mandatory, string) the unique ID of the block

type:

(Reference) points to an externally-defined library template which would fill in the corresponding entries below, as documented in Template Libraries page.

requirement:

(dict) block prerequisites

label:

(list) label entries, each with a unique name

param:

(dict) generic parameters passed as-is to the template renderer, accessed with the param key.

instance:

(list) other blocks instantiated from this one.

code:

(Template) containing this block’s Code Template. Rendered witn the context:

                    name=comp.name,    # component's name
                    label=comp.label,  # resolved labels
                    param=comp.param,  # parameters
                    placeholder={      # only one placeholder
                        "code": comp.code
                    },
prototype:

(Template) defines this block’s type signature, as provided from a type system. Rendered with the following context:

                    label=comp.label,   # resolved labels
                    param=comp.param,   # parameters
                    placeholder=rinst,  # recursivly-expanded block instances

requirement

Illustrates prerequisites for the parent element. Internally it is represented using a zoti_gen.core.Requirement class. It may contain the following entries:

label

A label is the low-level code equivalent of a ‘port’. Its function is to provide a name which can be used in bindings and glue generation. Internally it is represented using a zoti_gen.core.Label class.

name:

(string) unique ID in the scope of the parent block

glue:

(dict) entries with glue code tailored for various circumstances, provided by the type system and accessible from within the code template using the label.<port_id>.glue key.

usage:

(Template) defines how this label is to be expanded in the code. Provided by the type system. Rendered with the following context:

                        p=key,         # ID of the current label
                        label=labels,  # complete namespace of resolved labels
                        param=params,  # complete namespace of parameters

instance

Refers to another block and (at minimum) triggers its evaluation by the the Rendering engine. It can define an inclusion relation between the parent and the referenced blocks, in which case the referenced one would occupy the space pointed out by a placeholder markup in the parent’s template. Furthermore, the relation between the two blocks can be enforced by a set of bindings that connects the labels and parameters of the two blocks. Internally, aln instance is represented using a zoti_gen.core.Instance class.

To define a block instance within the parent block the following entries might be used:

block:

(Reference) points to an existing (i.e. loaded) block.

placeholder:

(string) the name of the placeholder, as it appears in the parent’s Code Template.

directive:

(list of strings) directive flags passed to the Rendering engine.

bind:

(list) bindings between the labels and parameters of the parent block and those of the referenced block.

usage:

(Template) defines how this block is being instantiated in case it is not expanded inline (e.g., as function call). The template string is defined by the type system. It is rendered with the following contexts, depending on which directive is passed:

  • expand is in directives

                        name=comp.name,    # component's name
                        label=comp.label,  # resolved labels
                        param=comp.param,  # parameters
                        placeholder={      # only one placeholder
                            "code": comp.code
                        },
  • expand is not in directives

                        name=comp.name,    # component's name
                        param=comp.param,  # parameters
                        label=b_labels,    # bounded (parent) labels

bind

A binding between one of the labels or parameters of the parent block and a label or parameter of the referenced block. Internally it is represented using a zoti_gen.core.Bind class. It needs to contain only one of the following entries:

label_to_label:

(dict)

parent:

(str) ID of parent

child:

(str) ID of child

usage:

(Template) rendered with context:

                    p=parent,      # ID of parent
                    label=labels,  # entire namespace of resolved labels
                    param=params,  # entire namespace of parameters
usage_to_label:

(dict)

child:

(str) ID of child

usage:

(Template) rendered with context:

                    label=labels,  # entire namespace of resolved labels
                    param=params,  # entire namespace of parameters
param_to_param:

(dict)

parent:

(str) Parent parameter

child:

(str) Child parameter

value_to_param:

(dict)

value:

(str) Value as simple string

child:

(str) Child parameter

Reference

A reference is an entry pointing to an object by its qualified name and/or path. Since ZOTI-Gen documents are flat (i.e., they consist in a flat list of block descriptions), and the only objects referenced in ZOTI-Gen are blocks, the only access mechanism implemented is referencing by (block) name. Hence, every reference entry will have the following mandatory fields:

module:

(string) the full (dot-separated) name of module containing the referenced block, even if that means the current module.

name:

(string) the name of the referenced block.

For less verbose reference syntax one could check the !ref keyword in the ZOTI-YAML language extension and pre-processor.

Code Template

Code templates are strings with Jinja2 markup commands evaluated in a custom context built from the resolved block specification. Depending on its role in the input specification (see documentation above), each template is evaluated and rendered using a custom context built from resolved information from the interal representation, most usually having the following context fields:

label:

contains a dictionary of all resolved label entries (see Input Specification), both own and passed via bindings, where the keys are the original (specified) names. Each entry contains possibly updated information (i.e., name, usage and glue) reflecting the block’s bindings.

param:

usually contains a merged dictionary with this block’s param entries and the ones passed via bindings.

placeholder:

will contain rendered code blocks for various declared instances (e.g., as inline code or function call) in the current block’s scope.

Apart from the Jinja2 builtin functions, ZOTI-Gen adds the following functions that can be called from within code templates.

static JinjaExtensions.find(json: Dict, path: str) Any[source]

Returns the element with (the dot-separated) path in a json dictionary, where path is specified as a string. E.g.

{# considering the context {'a': None, 'b':{'foo':{'bar': 'baz'}}} #}

{ b | find("foo.bar") }

{# is the same as #}

{ b.foo.bar }

both rendering baz.

static JinjaExtensions.setdefaults(json: Any, defaults: Dict) Dict[source]

For every direct child of the given json element it (possibly recursively) sets the defaults values if undefined. E.g.:

{% set json = {'a': None, 'b':{'foo':'bar'}} %}
{% set defaults = {'foo':'biff', 'baz':'buzz'} %}
{% set example = setdefaults(json, defaults) %}

results in example containing the dictionary

{'a': {'foo':'biff', 'baz':'buzz'}, 'b':{'foo':'bar', 'baz':'buzz'}}
static JinjaExtensions.eval(context: Dict, string: str) str[source]

Renders a Jinja2 string within a context. Useful if both string and context are passed to the current template context.

static JinjaExtensions.error(msg: str, *args) None[source]

Raise an exception from within the template logic.

static JinjaExtensions.getter(context, elem, *args) str[source]

ZOTI-Gen specific formatter that retrieves the type getter macro created by ZOTI-FTN and stored in each label’s glue entry and creates an access expresion based on it:

{{ getter("data.data.LEN") }}

{# is equivalent to #}

{{ label.data.glue.data.LEN._get }}({{ label.data.name }})
static JinjaExtensions.setter(context, elem, *args) str[source]

ZOTI-Gen specific formatter that retrieves the type setter macro created by ZOTI-FTN and stored in each label’s glue entry and creates an access expression based on it:

{{ setter("data.data.c", "i", "x" }}

{# is equivalent to #}

{{ label.data.glue.data.c._set }}({{ label.data.name }}, i, x)