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:
parent
5956048526
commit
ab87bc9ded
@ -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
|
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
|
the direct contents of a file, since the result in that case must always be a
|
||||||
string.
|
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.
|
||||||
|
@ -358,3 +358,48 @@ the result must be a number, rather than a string representation of a number:
|
|||||||
```json
|
```json
|
||||||
"${ a + b }"
|
"${ 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.
|
||||||
|
|
||||||
|
45
hcl/spec.md
45
hcl/spec.md
@ -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
|
same length whose elements are the unification of the corresponding elements
|
||||||
in the two input types.
|
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
|
## Implementation Considerations
|
||||||
|
|
||||||
Implementations of this specification are free to adopt any strategy that
|
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
|
* Providing an evaluation function for all possible expressions that produces
|
||||||
a value given an evaluation context.
|
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
|
The suggested implementation strategy is to use an implementation language's
|
||||||
closest concept to an _abstract type_, _virtual type_ or _interface type_
|
closest concept to an _abstract type_, _virtual type_ or _interface type_
|
||||||
to represent both Body and Expression. Each language-specific implementation
|
to represent both Body and Expression. Each language-specific implementation
|
||||||
|
Loading…
Reference in New Issue
Block a user