Commit Graph

1232 Commits

Author SHA1 Message Date
Martin Atkins e1e97716f5 hclsyntax: RelativeTraversalExpr walkChildNodes implementation
Unlike ScopeTraversalExpr, this node type _does_ have an expression as its
source and so it must include that expression in an AST walk.
2018-09-25 08:25:42 -07:00
Martin Atkins 2933fec4da hclsyntax: Walk must call Walker.Exit before returning 2018-09-25 08:25:42 -07:00
Radek Simko ffb8e97eb7
Merge pull request #49 from hashicorp/t-hclsyntax-fix
hclsyntax: Add test for 'func()[idx]' syntax
2018-09-21 18:02:03 +01:00
Radek Simko ef3dcd77da
hclsyntax: Add test for parsing of idx'd function calls 2018-09-21 16:13:21 +01:00
Radek Simko def7e926c9
hclsyntax: Fix incorrect positions in tests 2018-09-21 12:04:32 +01:00
Phillip T. George 65a6292f01 Allow strings "true", "false", "1" and "0" to be used where booleans are expected
There is precedent for allowing strings containing digits where numbers are expected,
and so this extends that to also allow for boolean values to be given as strings.

This applies only to callers going through the decoder API. Direct access via the AST
will reflect exactly what was given in the input configuration.
2018-09-06 11:38:39 -07:00
Martin Atkins 864f97c8ab guide: A section on input file naming conventions 2018-09-05 08:26:29 -07:00
Martin Atkins dc326dd882 guide: Update the main title to "HCL Config Language Toolkit"
"HCL Configuration Language" will feel redundant to anyone who thinks
they know what "HCL" is supposed to stand for, even though our docs don't
actually expand the abbreviation at all. This new version is also still
redundant with that interpretation, but at least it emphasizes that it's
a toolkit for creating configuration languages rather than a configuration
language in its own right.
2018-09-05 08:16:17 -07:00
Martin Atkins e78fa0ded2 guide: Guide-type documentation for HCL 2018-09-05 08:10:27 -07:00
Martin Atkins 57c9a676d7 guide: The "Configuration Language Design" section 2018-09-05 08:08:11 -07:00
Martin Atkins 280771fe8a guide: Design Patterns for Complex Systems section 2018-08-31 22:01:43 -07:00
Martin Atkins 495dfc9487 guide: Low-level API section 2018-08-31 07:40:30 -07:00
Martin Atkins d2e7762e9a guide: Expression Evaluation page content 2018-08-28 08:45:24 -07:00
Martin Atkins 50cdb5d614 guide: Stub out some more of the overall guide outline 2018-08-26 10:28:03 -07:00
Martin Atkins b737ad87a3 guide: A section on dynamic decoding using hcldec 2018-08-26 10:03:28 -07:00
Martin Atkins 8cb6e5b959 Prepare to be a Go module 2018-08-25 17:51:36 -07:00
Martin Atkins 3b190b826e guide: Disable the autoapi extension
This extension isn't working well for Go, so we're not using it for now.
2018-08-25 17:06:04 -07:00
Martin Atkins 33120477c7 guide: When running in Read The Docs, get version from its environment
Git isn't available in the Read The Docs build, but we don't actually need
it there anyway because we are told the version number that Read The Docs
thinks it is building.
2018-08-25 17:01:35 -07:00
Martin Atkins c6f6feed76 guide: Start of HCL usage guide
This is guide-style documentation to introduce the different parts of HCL,
as a complement to the reference documentation provided in godoc.
2018-08-25 16:36:05 -07:00
Martin Atkins d754d5a269 hclwrite: Adjust token spacing automatically when writing
Although our underlying parse tree retains all of the token content, it
doesn't necessarily retain all of the spacing information under editing,
and so formatting on save ensures that we'll produce a canonical result
even if some edits have been applied that have changed the expected
alignment of objects, etc.
2018-08-25 12:15:40 -07:00
Martin Atkins ed8144cda1 hcldec: BlockTupleSpec and BlockObjectSpec
When nested attributes are of type cty.DynamicPseudoType, a block spec
that is backed by a cty collection is annoying to use because it requires
all of the blocks to have homogenous types for such attributes.

These new specs are similar to BlockListSpec and BlockMapSpec
respectively, but permit each nested block result to have its own distinct
type.

In return for this flexibility, we lose the ability to predict the exact
type of the result: these specs must just indicate their type as being
cty.DynamicPseudoType themselves, since we need to know how many blocks
there are and what types are inside them before we can know our final
result type.
2018-08-22 12:31:30 -07:00
Martin Atkins b82170e941 hcldec: Handle or forbid cty.DynamicPseudoType attributes in nested blocks
Our BlockList, BlockSet, and BlockMap specs all produce cty collection
values, which require all elements to have a homogeneous type. If the
nested spec contained an attribute of type cty.DynamicPseudoType, that
would create the risk of each element having a different type, which would
previously have caused decoding to panic.

Now we either handle this during decode (BlockList, BlockSet) or forbid
it outright (BlockMap) to prevent that crash. BlockMap could _potentially_
also handle this during decode, but that would require a more significant
reorganization of its implementation than I want to take on right now,
and decoding dynamically-typed values inside collections is an edge case
anyway.
2018-08-22 11:52:40 -07:00
Martin Atkins d6049c2a04 Get ready to be a Go module
However, since this repository is only a temporary home for this module,
the go.mod file carries a warning to that effect. It will move to its more
permanent home as it transitions from experimental to released.
2018-08-17 19:07:38 -07:00
Martin Atkins c79a9bd509 Beginnings of automated test suite for spec compliance.
The test cases are far from complete, but the mechanism is in place.
2018-08-12 18:23:14 -07:00
Martin Atkins ef5c50bb09 hcl/spectests: run the spec testsuite as part of "go test"
Although the spec testsuite and associated harness is designed to be
usable by other implementations of HCL not written in Go, it's convenient
to run it as part of our own "go test" test suite here so there isn't
an additional thing to run on each change.

To achieve this, the new package hcl/spectests will build both hcldec and
hclspecsuite from latest source and then run the latter to execute the
test suite, capturing the output and converting it (sloppily) into
testing.T method calls to produce something vaguely reasonable.

Other than the small amount of "parsing" to make it look in the output
like a normal Go test, there's nothing special going on here and so it's
still valid to run the spec suite manually with a build of hcldec from
this codebase, which should produce the same result.
2018-08-12 18:22:10 -07:00
Martin Atkins 12f0f2dbc5 specsuite: a few additional tests for structure
This is still not fully comprehensive, but tests some basic functionality.
2018-08-12 18:18:58 -07:00
Martin Atkins 74466f4d35 cmd/hclspecsuite: show source snippets for errors in .hcldec files 2018-08-12 10:29:13 -07:00
Martin Atkins a5c0f7fdcc cmd/hclspecsuite: Check for expected diagnostics
When a test file declares one or more expected diagnostics, we check those
instead of checking the result value. The severities and source ranges
must match.

We don't test the error messages themselves because they are not part of
the specification and may vary between implementations or, in future, be
translated into other languages.
2018-08-12 10:08:27 -07:00
Martin Atkins 767fb36174 cmd/hclspecsuite: Check for traversals when requested 2018-08-12 09:31:28 -07:00
Martin Atkins 95b1859585 cmd/hclspecsuite: Decode expected traversals and diagnostics
These are not used by the test harness yet, but they can now be decoded
from a test spec file.
2018-08-11 20:21:32 -07:00
Martin Atkins 65f9271b86 specsuite: Initial test for top-level attribute handling 2018-08-10 08:57:59 -07:00
Martin Atkins db04b3dffe specsuites: Tests for comment parsing 2018-08-10 08:51:51 -07:00
Martin Atkins 48039c0368 cmd/hclspecsuite: basic runner functionality for successful cases
The harness can now run tests that decode successfully and compare the
result with a given value. Further work is required in later commits to
deal with other cases, such as tests that intentionally produce errors.
2018-08-10 08:49:43 -07:00
Martin Atkins 0956c193b7 specsuite: Start of the harness for the specification test suite 2018-08-09 19:29:32 -07:00
Martin Atkins 6743a2254b cmd/hcldec: opt-in JSON-formatted diagnostics
By default we generate human-readable diagnostics on the assumption that
the caller is a simple program that is capturing stdin via a pipe and
letting stderr go to the terminal.

More sophisticated callers may wish to analyze the diagnostics themselves
and perhaps present them in a different way, such as via a GUI.
2018-08-09 18:10:14 -07:00
Martin Atkins 609cc35d49 cmd/hcldec: --var-refs option
This option skips the usual decoding step and instead prints out a JSON-
formatted list of the variables that are referenced by the configuration.

In simple cases this is not required, but for more complex use-cases it
can be useful to first analyze the input to see which variables need to
be in the scope, then construct a suitable set of variables before finally
decoding the input. For example, some of the variable values may be
expensive to produce.
2018-08-09 18:10:14 -07:00
Martin Atkins bb724af7fd hcldec: BlockAttrsSpec spec type
This is the hcldec interface to Body.JustAttributes, producing a map whose
keys are the child attribute names and whose values are the results of
evaluating those expressions.

We can't just expose a JustAttributes-style spec directly here because
it's not really compatible with how hcldec thinks about things, but we
can expose a spec that decodes a specific child block because that can
then compose properly with other specs at the same level without
interfering with their operation.

The primary use for this is to allow the use of the block syntax to define
a map:

    dynamic_stuff {
      foo = "bar"
    }

JustAttributes is normally used in static analysis situations such as
enumerating the contents of a block to decide what to include in the
final EvalContext. That's not really possible with the hcldec model
because both structural decoding and expression evaluation happen
together. Therefore the use of this is pretty limited: it's useful if you
want to be compatible with an existing format based on legacy HCL where a
map was conventionally defined using block syntax, relying on the fact
that HCL did not make a strong distinction between attribute and block
syntax.
2018-08-09 16:53:16 -07:00
Martin Atkins 59bb5c2670 hclwrite: Fix NewExpressionAbsTraversal signature
It is still not implemented, but at least now it is declared with the
correct return type.
2018-08-09 08:47:37 -07:00
Martin Atkins c8c208e083 hclwrite: Body.SetAttributeValue
For now, this is the only way to set an attribute, and so attributes can
only be set to literal values.

Later this will be generalized so that this is just a helper wrapper
around a "SetAttribute" method that just uses a given expression, which
then helps by constructing the expression from the value first.
2018-08-09 08:44:48 -07:00
Martin Atkins 77c0b55a59 hclwrite: Simplify internal data structures
The original prototype of hclwrite tried to track both the tokens and
the AST as two parallel data structures. This quickly exploded in
complexity, leading to lots of messy code to manage keeping those two
structures in sync.

This new approach melds the two structures together, creating first a
physical token tree (made of "node" objects, and hidden from the caller)
and then attaching the AST nodes to that token tree as additional sidecar
data.

The result is much easier to work with, leading to less code in the parser
and considerably less complex data structures in the parser's tests.

This commit is enough to reach feature parity with the previous prototype,
but it remains a prototype. With a more usable foundation, we'll evolve
this into a more complete implementation in subsequent commits.
2018-08-01 08:46:31 -07:00
Martin Atkins b21bf61698 hclsyntax: Annotate diags from IndexExpr with source expr information 2018-07-28 15:44:44 -07:00
Martin Atkins f6fe9b5c69 hcl: Deduplicate symbols when printing diagnostic messages 2018-07-28 15:44:15 -07:00
Martin Atkins 8dd89ebbb3 hclsyntax: Fix error message for inconsistent conditional expr values 2018-07-28 15:29:34 -07:00
Martin Atkins 7cc8ebfacf hcl: diagnosticTextWriter fix value reporting for 1-element collection 2018-07-28 15:26:11 -07:00
Martin Atkins 627c12b67c hclsyntax: report expr and ctx correctly in ForExpr diagnostics
We previously weren't returning appropriate Expression and EvalContext
references inside many of the diagnostics for ForExpr.

First, it was using the top-level expression instead of one of the nested
expressions in many cases. Secondly, it was using the given context
rather than the child context when talking about expressions that get
evaluated once per iteration.

As a result of this reporting we must now produce a new EvalContext for
each iteration, rather than sharing and mutating as we did before, but
in retrospect that's less likely to cause other confusing bugs anyway,
since we don't generally expect EvalContexts to be mutated.
2018-07-28 15:24:39 -07:00
Martin Atkins 5919f80710 hcl: When rendering diagnostics, elide complex index keys
In practice this should never arise because the index operator only works
for lists and maps and they use string keys, but we'll guard against this
anyway and return a placeholder for other values so that the output
doesn't grow unreadably long in that case.
2018-07-28 14:51:11 -07:00
Martin Atkins f45c1cdace hcl: Include variable values in rendered diagnostics messages
If a diagnostic has an associated Expression and EvalContext then we can
look up the values of any variables referenced in the expression and show
them in the diagnostics message as additional context.

This is particularly useful when dealing with situations where a given
expression is evaluated multiple times with different variables, such as
in a 'for' expression, since each evaluation may produce a different set
of diagnostics.
2018-07-28 14:42:53 -07:00
Martin Atkins 6356254632 hcl: Include Expression reference in diagnostics
If a diagnostic occurs while we're evaluating an expression, we'll now
include a reference to that expression in the diagnostic object. We
previously added the corresponding EvalContext here too, and so with these
together it is now possible for a diagnostic renderer to see not only
what was in scope when the problem occurred but also what parts of that
scope the expression was relying on (via method Expression.Variables).
2018-07-28 13:36:55 -07:00
Martin Atkins 956c336d40 hcl: Best-effort "what's at this position" helpers
When building tools around HCL configuration files it is useful to be
able to ask what is present at a given position in a file. This set of
new helper functions provide a best-effort implementation of this for
the native syntax only.

It cannot be supported for JSON syntax with these signatures because the
JSON syntax is ambiguous and thus can't be interpreted without a schema
for each structural level. In practice this is not a big loss because
JSON files will usually be generated rather than hand-written anyway, and
so doing automatic analysis and transformation of them would not be
useful: the program that generated the file must be updated instead.
2018-07-28 13:17:51 -07:00
Martin Atkins 93562f805f hcl: Annotate diagnostics with expression EvalContext
When we're evaluating expressions, we may end up evaluating the same
source-level expression a number of times in different contexts, such as
in a 'for' expression, where each one may produce a different set of
diagnostic messages.

Now we'll attach the EvalContext to each expression diagnostic so that
a diagnostic renderer can potentially show additional information to help
distinguish the different iterations in rendered diagnostics.
2018-07-28 13:14:36 -07:00