Commit Graph

1051 Commits

Author SHA1 Message Date
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
Martin Atkins
41cff854d8 Fix "attribute" vs "argument" terminology in diagnostics
During implementation of HCL in other applications, it became clear that
the overloading of the word "attribute" to mean both a key/value pair in
a body and an element within an object value creates confusion.

It's too late to change that in the HCL Go API now, but here we at least
update the diagnostic messages. The new convention is that a key/value
pair within a block is now called an "argument", while an element of an
object is still called an "attribute".

It is unfortunate that the Go-facing API still uses the word "attribute"
for both, but the user experience is the most important thing and in
practice many applications will treat block arguments as one way to set
the attributes of some object anyway, and in that case arguments can be
thought of as the subset of attributes of an object whose values come
from that object's associated block.

This also includes a few other minor terminology tweaks in the diagnostic
messages the reflect how our lexicon has evolved during development and
authoring of user-facing documentation.
2018-07-18 15:41:35 -07:00
Martin Atkins
966851f309 hclwrite: TokensForValue
This function produces a token stream of a reasonable source
representation of the given constant value.
2018-07-14 15:05:37 -07:00
Martin Atkins
3c0fafde46 hclwrite: Formatter should put a space after a comma 2018-07-14 15:05:37 -07:00
Martin Atkins
314ea6f332 hclwrite: Allow format to be called on fragment of tokens 2018-07-14 15:05:37 -07:00
Martin Atkins
d6367b5f96 hclwrite: Parsing of absolute traversals in expressions
This will allow for use-cases such as renaming a variable (changing the
content of the first token) and replacing variable references with
constant values that they evaluate to for debug purposes.
2018-07-14 13:07:39 -07:00
Martin Atkins
1718a963e6 extras: initial TextMate-style grammar for HCL
This is for the core HCL syntax, so it doesn't include any
application-specific keyword highlighting, etc.

The structural, expression, and template languages are separated into
different grammar definitions so that they can be used independently, but
they embed each other as needed to complete the language.

This is just a first pass, really. There are probably some bugs here, and
also some missing features.
2018-07-07 12:36:52 -07:00
Radek Simko
6558d83419
Merge pull request #37 from ceh/spec-typos
Fix spec typos
2018-07-03 18:59:26 +01:00
Radek Simko
2c946fb6e2
Merge pull request #39 from hashicorp/f-hcl-diag-as-errors
hcl: Add Diagnostics.Errs()
2018-07-03 18:58:32 +01:00
Radek Simko
1b7f2717a3
hcl: Add Diagnostics.Errs() 2018-07-03 08:41:19 +01:00
Emil Hessman
1308b594e2 Fix spec typos 2018-07-01 19:35:20 +02:00
Martin Atkins
36446359d2 hcldec: Variables must visit deeply-nested specifications
Previously this implementation was doing only one level of recursion in
its walk, which gave the appearance of working until the
transform/container-type specs (DefaultSpec, TransformSpec, ...) were
introduced, creating the possibility of "same body children" being more
than one level away from the initial spec.

It's still correct to only process the schema and content once, because
ImpliedSchema is already collecting all of the requirements from the
"same body children", and so our content object will include everything
that the nested specs should need to analyze needed variables.
2018-05-24 12:11:53 -07:00
Martin Atkins
81d2277300 hclwrite: Format shouldn't introduce spaces before index brackets
This is another heuristic because the "[" syntax is also the tuple
constructor start marker, but this takes care of the common cases of
indexing keywords and bracketed expressions.

This fixes #29.
2018-05-23 16:56:29 -07:00
Martin Atkins
524cf10f48 hclsyntax: Allow the splat operators to be applied to sets
We automatically convert from set to list in many other situations, so for
consistency we should accept sets here too and just treat them as
unordered sequences.

This closes #30.
2018-05-23 16:40:24 -07:00
Martin Atkins
3006ab4459 hclsyntax: Safe concurrent evaluation of splat expressions
Due to the special handling of the anonymous symbol employed to evaluate
a splat expression, we need to employ a lock on that symbol so that it's
safe for concurrent evaluation.

As before, it's not safe to concurrently evaluate the same expression in
the same context, but it is now safe to do so as long as all concurrent
evaluations have a _distinct_ EvalContext.

This fixes #28.
2018-05-23 16:38:39 -07:00
Martin Atkins
bbbd0ef30d hcldec: Fix DefaultSpec to allow attribute and block specs
Previously it was not implementing the two optional interfaces required
for this, and so decoding would fail for any AttrSpec or block spec nested
inside.

Now it passes through attribute requirements from both the primary and
default, and passes block requirements only from the primary, thus
allowing either fallback between two attributes, fallback from an
attribute to a constant, or fallback from a block to a constant. Other
permutations are also possible, but not very important.
2018-05-22 15:06:42 -07:00
Martin Atkins
9db880accf
ext/typeexpr: correct examples in the README 2018-04-05 19:34:53 -07:00
Mitchell Hashimoto
ef8a98b0bb
Merge pull request #243 from octo/single-line-lists
printer: Simplify the formatting of single-line lists.
2018-04-04 10:41:02 -07:00
Florian Forster
b07f6fa7a2 printer: Simplify the formatting of single-line lists.
This change splits out the formatting of simple single-line lists. A list
is considered "simple" if all of its elements are on one line, all
elements are literals (except heredoc) and there are no line comments.
As an exception, a heredoc string is allowed when it is the only element
in the list.

This fixes an issue with a single-line list with one element and a line
comment. The formatter used to pull the closing bracket on the same line
(after the comment), causing parse errors.
2018-04-04 19:34:59 +02:00
Florian Forster
26f11450d7 printer: Add another input breaking TestFormatValidOutput(). 2018-04-04 19:34:59 +02:00
Mitchell Hashimoto
e9ccac6b7f
Merge pull request #244 from octo/multiline-assign-comment
printer: Fix handling of line comments in multi-line statements.
2018-04-04 08:51:07 -07:00
Mitchell Hashimoto
653ccfb956
Merge pull request #246 from octo/zero-length-heredoc-anchor
scanner: Fix detection of zero-length heredoc anchor.
2018-04-04 08:50:57 -07:00
Florian Forster
a68b5db4c3 scanner: Fix detection of zero-length heredoc anchor. 2018-04-04 17:09:20 +02:00
Florian Forster
8bad6ac32e scanner: Add tests demonstrating issue with empty heredoc anchors. 2018-04-04 17:07:08 +02:00
Florian Forster
c2326d41d7 Fix handling of line comments in multi-line statements. 2018-04-03 19:39:12 +02:00
Florian Forster
ddff2bcdd7 printer: Add another failing input to TestFormatParsable. 2018-04-03 19:39:12 +02:00
Mitchell Hashimoto
061bf373e4
Merge pull request #239 from octo/scanner
scanner: Don't call unread() after reading EOF.
2018-04-03 10:01:18 -07:00
Mitchell Hashimoto
c247bd0851
Merge pull request #245 from octo/cartridge-return
scanner: Improve regular expression in "scanner".scanHeredoc().
2018-04-03 10:00:26 -07:00
Florian Forster
25340db58d scanner: scanHeredoc(): Accept any number of CRs (\r) at end of line.
When there are multiple cartridge returns at the end of the line, the regular expression will consider n-1 of them to be part of the string. Later, the last `\r` is removed. That may mean that a line that did previously *not* terminate a heredoc string may now terminate it, changing the meaning of the HCL file.
2018-04-03 16:23:33 +02:00
Florian Forster
6a21c5aa50 printer: Add another failing input to TestFormatParsable. 2018-04-03 16:18:04 +02:00
Florian Forster
13daa63726 scanner: Anchor heredoc-regexes at beginning of line. 2018-04-03 16:17:39 +02:00
Florian Forster
89240c3707 printer: Add another failing input to TestFormatParsable. 2018-04-03 16:16:34 +02:00