Update the various spec documents to include static analysis

Implementing the config loader for Terraform led to the addition of some
special static analysis operations for expressions, separate from the
usual action of evaluating an expression to produce a value.

These operations are useful for building application-specific language
constructs within HCL syntax, and so they are now included as part of the
specification in order to help developers of other applications understand
their behaviors and the implications of using them.
This commit is contained in:
Martin Atkins 2018-03-04 14:35:16 -08:00
parent 5956048526
commit ab87bc9ded
3 changed files with 132 additions and 0 deletions

View File

@ -879,3 +879,45 @@ application, by converting the final template result to string. This is
necessary, for example, if a standalone template is being used to produce
the direct contents of a file, since the result in that case must always be a
string.
## Static Analysis
The HCL static analysis operations are implemented for some expression types
in the native syntax, as described in the following sections.
A goal for static analysis of the native syntax is for the interpretation to
be as consistent as possible with the dynamic evaluation interpretation of
the given expression, though some deviations are intentionally made in order
to maximize the potential for analysis.
### Static List
The tuple construction syntax can be interpreted as a static list. All of
the expression elements given are returned as the static list elements,
with no further interpretation.
### Static Map
The object construction syntax can be interpreted as a static map. All of the
key/value pairs given are returned as the static pairs, with no further
interpretation.
The usual requirement that an attribute name be interpretable as a string
does not apply to this static analyis, allowing callers to provide map-like
constructs with different key types by building on the map syntax.
### Static Call
The function call syntax can be interpreted as a static call. The called
function name is returned verbatim and the given argument expressions are
returned as the static arguments, with no further interpretation.
### Static Traversal
A variable expression and any attached attribute access operations and
constant index operations can be interpreted as a static traversal.
The keywords `true`, `false` and `null` can also be interpreted as
static traversals, behaving as if they were references to variables of those
names, to allow callers to redefine the meaning of those keywords in certain
contexts.

View File

@ -358,3 +358,48 @@ the result must be a number, rather than a string representation of a number:
```json
"${ a + b }"
```
## Static Analysis
The HCL static analysis operations are implemented for JSON values that
represent expressions, as described in the following sections.
Due to the limited expressive power of the JSON syntax alone, use of these
static analyses functions rather than normal expression evaluation is used
as additional context for how a JSON value is to be interpreted, which means
that static analyses can result in a different interpretation of a given
expression than normal evaluation.
### Static List
An expression interpreted as a static list must be a JSON array. Each of the
values in the array is interpreted as an expression and returned.
### Static Map
An expression interpreted as a static map must be a JSON object. Each of the
key/value pairs in the object is presented as a pair of expressions. Since
object property names are always strings, evaluating the key expression with
a non-`nil` evaluation context will evaluate any template sequences given
in the property name.
### Static Call
An expression interpreted as a static call must be a string. The content of
the string is interpreted as a native syntax expression (not a _template_,
unlike normal evaluation) and then the static call analysis is delegated to
that expression.
If the original expression is not a string or its contents cannot be parsed
as a native syntax expression then static call analysis is not supported.
### Static Traversal
An expression interpreted as a static traversal must be a string. The content
of the string is interpreted as a native syntax expression (not a _template_,
unlike normal evaluation) and then static traversal analysis is delegated
to that expression.
If the original expression is not a string or its contents cannot be parsed
as a native syntax expression then static call analysis is not supported.

View File

@ -616,6 +616,48 @@ Two tuple types of the same length unify constructing a new type of the
same length whose elements are the unification of the corresponding elements
in the two input types.
## Static Analysis
In most applications, full expression evaluation is sufficient for understanding
the provided configuration. However, some specialized applications require more
direct access to the physical structures in the expressions, which can for
example allow the construction of new language constructs in terms of the
existing syntax elements.
Since static analysis analyses the physical structure of configuration, the
details will vary depending on syntax. Each syntax must decide which of its
physical structures corresponds to the following analyses, producing error
diagnostics if they are applied to inappropriate expressions.
The following are the required static analysis functions:
* **Static List**: Require list/tuple construction syntax to be used and
return a list of expressions for each of the elements given.
* **Static Map**: Require map/object construction syntax to be used and
return a list of key/value pairs -- both expressions -- for each of
the elements given. The usual constraint that a map key must be a string
must not apply to this analysis, thus allowing applications to interpret
arbitrary keys as they see fit.
* **Static Call**: Require function call syntax to be used and return an
object describing the called function name and a list of expressions
representing each of the call arguments.
* **Static Traversal**: Require a reference to a symbol in the variable
scope and return a description of the path from the root scope to the
accessed attribute or index.
The intent of a calling application using these features is to require a more
rigid interpretation of the configuration than in expression evaluation.
Syntax implementations should make use of the extra contextual information
provided in order to make an intuitive mapping onto the constructs of the
underlying syntax, possibly interpreting the expression slightly differently
than it would be interpreted in normal evaluation.
Each syntax must define which of its expression elements each of the analyses
above applies to, and how those analyses behave given those expression elements.
## Implementation Considerations
Implementations of this specification are free to adopt any strategy that
@ -639,6 +681,9 @@ are implemented separately for each syntax:
* Providing an evaluation function for all possible expressions that produces
a value given an evaluation context.
* Providing the static analysis functionality described above in a manner that
makes sense within the convention of the syntax.
The suggested implementation strategy is to use an implementation language's
closest concept to an _abstract type_, _virtual type_ or _interface type_
to represent both Body and Expression. Each language-specific implementation