Methodology

Grammar definition methodology


General

There are five aspects that are important in TQL (and ADL) language specification. The first three has to do with Syntax:

1. Expansion: grammar rules that say one expression/component can be "expanded" into other expression(s)/component(s)

2. Containment (nesting): the nested XML/JSON tree structure for TQL components (e.g. Task "contains" Input, Invoke and Output)

3. Sequence: how the symbols are used in the correct sequence to generate meaningful expressions/components

The other two are about Semantics:

4. Semantics: what do the words/phrases mean and what value can they take as variables

5. Semantical hierarchy (System types): the inheritance relationship of system-defined types (such as Atom, String, Number, etc.)

#1 and #2 are systematically defined in the grammar definition, using containment graphs (like a tree). Containment graphs are read from top to down. The grammar itself does not confine the sequence between different child components of the same parent. However, there are places where different sequence will result in different execution of the code.

Since TQL (and ADL) is syntax free (currently supporting both XML and JSON), #3 (the sequence) mostly follows general XML grammar rules, and is self-explanatory. In places where there are TQL-specific rules, they are documented using the standard Railroad graph (with blue lines). Railroad graphs are read from left to right. Note that the language compiler does not make any distinction between XML elements and attributes. That is, any XML attribute can be given as an element and any element with text value can be given as an attribute.

#4 is documented in the grammar modifier tables.

#5 is documented in system defined types.


Legends & Notations

Terminal nodes are instances of the specified non-terminal used as an XML tag/container with the specified name.

Modifiers are terminal symbols (e.g."String", "Integer", "Duration" etc.) of a corresponding type.

Non-terminals and Non-terminal Modifiers are replaced by groups of terminal nodes or modifiers according to the production rules.

All terminals may contain any other content (e.g. TP parameters etc.). Such content is not governed by this grammar.


Function calls

Since this grammar is using the type system, some of the tag names are defined as function calls to current index API (e.g. fun.SubtypeOf(<type inheritance predicate>)). Such call is supposed to return a list of type names satisfying given predicate and one of them used as an actual tag name. Type predicates are logical expressions on type inheritance chains. For example (DataFacet and not.ThingFacet) means all types which inherit from DataFacet, but not from ThingFacet (this is because ThingFacet itself inherits from DataFacet and all descendants of DataFacet would also include all descendants of ThingFacet so we explicitly exclude them). It is assumed, that returned type lists will be relative to the current environment/scope. That is, only types defined in the scope of a current project need to be evaluated, as opposed to all types known to the system across all projects and all type repositories.

Cardinality

These are defined as 0..1, 1..1, 0..m, 1..m. Sometimes when multiples (>1) of the same child component structure are iterated under the same parent, the A-Stack recognizes their sequence of appearance and execute accordingly. For example, three Invokes within the same Task will be invoked sequentially to each other based on their order of appearance in the definition. In such cases, the cardinality is shown as [0..m] or [1..m].


Modifiers

TQL Modifiers can be written either as XML Elements or XML Attributes. The two are equivalent.