Expression Evaluation¶
Each argument attribute in a configuration file is interpreted as an expression. In the HCL native syntax, certain basic expression functionality is always available, such as arithmetic and template strings, and the calling application can extend this by making available specific variables and/or functions via an evaluation context.
We saw in Decoding Into Native Go Values and Decoding With Dynamic Schema some basic
examples of populating an evaluation context to make a variable available.
This section will look more closely at the hcl.EvalContext
type and how
HCL expression evaluation behaves in different cases.
This section does not discuss in detail the expression syntax itself. For more information on that, see the HCL Native Syntax specification.
-
EvalContext
¶ hcl.EvalContext
is the type used to describe the variables and functions available during expression evaluation, if any. Its usage is described in the following sections.
Defining Variables¶
As we saw in Decoding With Dynamic Schema, HCL represents values using an
underlying library called cty
. When defining variables, their values
must be given as cty.Value
values.
A full description of the types and value constructors in cty
is
in the reference documentation.
Variables in HCL are defined by assigning values into a map from string names
to cty.Value
:
ctx := &hcl.EvalContext{
Variables: map[string]cty.Value{
"name": cty.StringVal("Ermintrude"),
"age": cty.NumberIntVal(32),
},
}
If this evaluation context were passed to one of the evaluation functions we saw in previous sections, the user would be able to refer to these variable names in any argument expression appearing in the evaluated portion of configuration:
message = "${name} is ${age} ${age == 1 ? "year" : "years"} old!"
If you place cty
’s object values in the evaluation context, then their
attributes can be referenced using the HCL attribute syntax, allowing for more
complex structures:
ctx := &hcl.EvalContext{
Variables: map[string]cty.Value{
"path": cty.ObjectVal(map[string]cty.Value{
"root": cty.StringVal(rootDir),
"module": cty.StringVal(moduleDir),
"current": cty.StringVal(currentDir),
}),
},
}
source_file = "${path.module}/foo.txt"
Defining Functions¶
Custom functions can be defined by you application to allow users of its
language to transform data in application-specific ways. The underlying
function mechanism is also provided by cty
, allowing you to define
the arguments a given function expects, what value type it will return for
given argument types, etc. The full functions model is described in the
cty
documentation section
Functions System.
There are a number of “standard library” functions
available in a stdlib
package within the cty
repository, avoiding
the need for each application to re-implement basic functions for string
manipulation, list manipulation, etc. It also includes function-shaped versions
of several operations that are native operators in HCL, which should generally
not be exposed as functions in HCL-based configurationf formats to avoid user
confusion.
You can define functions in the Functions
field of hcl.EvalContext
:
ctx := &hcl.EvalContext{
Variables: map[string]cty.Value{
"name": cty.StringVal("Ermintrude"),
},
Functions: map[string]function.Function{
"upper": stdlib.UpperFunc,
"lower": stdlib.LowerFunc,
"min": stdlib.MinFunc,
"max": stdlib.MaxFunc,
"strlen": stdlib.StrlenFunc,
"substr": stdlib.SubstrFunc,
},
}
If this evaluation context were passed to one of the evaluation functions we saw in previous sections, the user would be able to call any of these functions in any argument expression appearing in the evaluated portion of configuration:
message = "HELLO, ${upper(name)}!"
Expression Evaluation Modes¶
HCL uses a different expression evaluation mode depending on the evaluation context provided. In HCL native syntax, evaluation modes are used to provide more relevant error messages. In JSON syntax, which embeds the native expression syntax in strings using “template” syntax, the evaluation mode determines whether strings are evaluated as templates at all.
If the given hcl.EvalContext
is nil
, native syntax expressions
will react to users attempting to refer to variables or functions by producing
errors indicating that these features are not available at all, rather than
by saying that the specific variable or function does not exist. JSON syntax
strings will not be evaluated as templates at all in this mode, making them
function as literal strings.
If the evaluation context is non-nil
but either Variables
or
Functions
within it is nil
, native syntax will similarly produce
“not supported” error messages. JSON syntax strings will parse templates
in this case, but can also generate “not supported” messages if e.g. the
user accesses a variable when the variables map is nil
.
If neither map is nil
, HCL assumes that both variables and functions are
supported and will instead produce error messages stating that the specific
variable or function accessed by the user is not defined.