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 :ref:`go-decoding-gohcl` and :ref:`go-decoding-hcldec` 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.
.. go:currentpackage:: hcl
.. go:type:: 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.
As we saw in :ref:`go-decoding-hcldec`, HCL represents values using an underlying library called :go:pkg:`cty`. When defining variables, their values must be given as :go:type:`cty.Value` values.
A full description of the types and value constructors in :go:pkg:`cty` is in the reference documentation. Variables in HCL are defined by assigning values into a map from string names to :go:type:`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"
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 :go:pkg:`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 :go:pkg:`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 configuration formats to avoid user
confusion.
You can define functions in the Functions
field of :go:type:`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)}!"
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 :go:type:`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.