Commit Graph

1232 Commits

Author SHA1 Message Date
Martin Atkins 4c4fdbdcc0 hclwrite: Suspend indentation adjustment inside heredocs
Leading whitespace is significant in heredocs, so we'll avoid making any
indentation adjustments for lines between OHeredoc and CHeredoc.

This fixes #31.
2018-12-14 14:46:44 -08:00
Martin Atkins 002296d7bb hclwrite: add space between "in" keyword and expr in for expression
Our normal ruleset thinks that the "in" keyword here is a variable
reference and so writes it as "in[y]". Since there's never any reason for
a variable to appear immediately after another variable, we can check
for a preceding identifier as a heuristic to recognize whether in is
probably being used as a keyword rather than as a variable.

This is not exact, but the only time this should be a false positive is
if there were a syntax error in the input, and we don't make any
guarantees about the result in that case anyway.

This fixes #52.
2018-12-14 14:19:04 -08:00
Martin Atkins bafa0c5ace hcl/hclsyntax: Accept single-line block definitions
This relaxes our previous spec to include a special form from HCL 1:

    foo { bar = baz }

Although we normally require each argument to be on a line of its own, as
a special case we allow a block to be defined with a single nested
argument all on one line.

Only one nested argument definition is allowed, and a nested block
definition like "foo { bar {} }" is also disallowed in order to force the
more-readable split of bar {} onto a line of its own.

This is a pragmatic addition for broader compatibility with HCL 1-oriented
input. This single-line usage is not considered idiomatic HCL 2 and may
in future be undone by the formatter, though for now it is left as-is
aside from the spacing around the braces.

This also changes the behavior of the source code formatter to include
spaces on both sides of braces. This mimicks the formatting behavior of
HCL 1 for this situation, and (subjectively) reads better even for other
one-line braced expressions like object constructors and object for
expressions.
2018-12-14 13:45:03 -08:00
Martin Atkins 2934d2f033 cmd/hclspecsuite: Generate correct ranges in diagnostic-diagnostics
We were taking a pointer to a for loop iterator variable and thus
capturing the final iteration value rather than each one separately. By
using the .Ptr() method instead, we force a copy of the range which we
then take a pointer to.
2018-12-14 11:33:28 -08:00
Martin Atkins e8dbb16dbc hcl/hclsyntax: Fix up parsing of flush heredocs
This was implemented a long time ago in the original template parser, but
it was missed in the rewrite of the template parser to make it use a
two-stage parsing strategy.

It's implemented as a post-processing step on the result of the first
stage of parsing, which produces a flat sequence of literal strings,
interpolation markers, and control markers, and prior to the second stage
which matches opening and closing control markers to produce an expression
AST.

It's important to do this at parse time rather than eval time since it is
the static layout of the source code that decides the indentation level,
and so an interpolation marker at the start of a line that itself produces
spaces does not affect the result.
2018-12-13 17:22:41 -08:00
Martin Atkins c33bbe4c25 hcl/hclsyntax: Tests for normal (non-flush) heredoc expressions 2018-12-13 11:59:00 -08:00
Martin Atkins b056768a1c hcl/hclsyntax: Parsing of the "full splat" operator
The evaluation of this was there but the parsing was still a TODO comment
from early development. Whoops!

Fortunately the existing parser functionality makes this straightforward
since we can just have the traversal parser recursively call itself.

This fixes #63.
2018-12-12 17:41:28 -08:00
Martin Atkins ebe27107e1 hcl/json: Detect variable references in property names
When a JSON object is representing an expression, template sequences are
permitted in the property names as well as the values. We must detect
the references here so that applications that do dynamic scope
construction or dependency analysis will get the right result.
2018-12-12 16:49:01 -08:00
Martin Atkins 47d7fce5a6 hcl/hclsyntax: Properly support scanning from a non-zero start offset
Although our API had a place to provide a start position for scanning, it
didn't actually work in practice because the scanner wasn't aware of it
and so it would immediately undo the effect of that start offset when
making the first position adjustment.

Now we'll remember the byte offset we started at and offset the indices
the generate scanner produces so that they are are treated as relative
to that start byte instead of byte zero.

Since we rarely start with a non-zero pos this doesn't affect much, but
one specific thing it affects is the positions of native syntax templates
inside JSON syntax strings.
2018-12-12 16:38:20 -08:00
Martin Atkins a085fdcd82 hcl/hclsyntax: Don't eat errors in IndexExpr collection or key
Due to incorrect diagnostics discipline here, the result of the index
operation was overwriting any diagnostics from either the collection or
the key expressions.
2018-12-12 15:51:40 -08:00
Martin Atkins 854da97291 hcl/hclsyntax: Allow newline between { and "for" keyword
We were previously enabling newline-sensitivity too soon, before checking
for the "for" keyword, and thus seeing the newline token instead of the
for token when peeking ahead.

Now we peek for the for token first and turn on newline-sensitivity only
if it isn't present. This fixes another bug in turn where we would
previously have parsed the for expression itself in newline-sensitive
mode, which we no longer do because we delegate to the for expression
parser sooner.
2018-12-11 17:16:06 -08:00
Martin Atkins 447c39ed03 go fmt updates 2018-12-11 16:49:03 -08:00
Martin Atkins 7ace05a3be hcl/hclsyntax: Better handling of naked attribute keys with dots
To make things read better in the normal case, we treat naked identifiers
in the place of object keys as literal strings containing the identifier
text rather than as references. However, this had a couple sub-optimal
implications:

- If a user would try to create a key containing a period, the evaluator
  would see that it wasn't a valid keyword and try to resolve it as a
  normal scope traversal, causing a confusing error that didn't align
  with the user's intent.

- In the rarer case where the attempted key contains a period followed by
  a digit, the parser would trip over what seems to be an unexpected
  identifier following the colon and produce, again, a confusing error
  that doesn't align with what the user intended.

To address the first of these problems, it is now invalid to use a naked
traversal with more than one step as an object key, which allows us to
produce a targeted error message that directs the user to either put the
expression in parentheses to force interpretation as a scope traversal
or in quotes to force interpretation as a literal.

The second problem can't be addressed exactly due to it being a parser
problem, but we improve the situation slightly here by adding an extra
hint to the parse error message in this case so that a user making this
mistake might understand better how the error relates to what they were
trying to express.
2018-12-11 16:48:31 -08:00
Martin Atkins 17ab3729e7 hclsyntax: Highlight key expression on invalid key type in object cons
Previously we were incorrectly indicating the value expression as the
problem.

This fixes #54.
2018-12-11 15:33:14 -08:00
Derek McNeil 1681396757 hcl: Fix PartialContent used on MergeBody result 2018-12-11 15:23:12 -08:00
Martin Atkins 6709268582 hcl/hclsyntax: Return DynamicVal when splatting a DynamicVal
Since the result type from a splat is derived from the source value type,
we can't predict our result type when the source type isn't known.

Previously we were incorrectly returning cty.Tuple(cty.DynamicPseudoType)
in this case because of the automatic tuple promotion logic, but now we'll
correctly just give up even before we do _that_ when given a DynamicVal.
2018-12-07 16:37:05 -08:00
Martin Atkins df9794be1f hcl/hclsyntax: More accurate type information for splat expressions
Previously we were returning tuple-typed values in all cases, which meant
we had to return no type information at all if the source was an unknown
list since the length of that list is not predictable.

Instead we'll now return a list if the source is a list or set and a tuple
if the source is a tuple, allowing us to return exact type information
when the source value is unknown. This is important for catching type
errors early when accessing attributes across many objects using splat
syntax, since before the presence of a splat operator effectively caused
a total loss of downstream type checking for unknown values in expressions.
2018-12-05 16:59:33 -08:00
Martin Atkins cd67ba1b25 hcl/hclsyntax: Fix scanning of multi-line comments
The pattern here was being too greedy because by default the longest match
is taken, and "*/" followed by more content is always longer than just
the "*/" to terminate the match.

The :>> symbol is a "finish guard" which tells Ragel to prefer to exit
from any* as soon as "*/" matches, making the match ungreedy.

The result of this is that input files containing more than one multi-line
comment will now tokenize each one separately, whereas before we would
create one long comment including everything from the first /* to the
final */ in the file, effectively causing parts of the file to be
ignored entirely.
2018-12-03 16:26:30 -08:00
James Bardin 4d82d52bfa
update go.mod (#60)
Fix import for howett.net/plist, and update go.mod.
2018-11-29 15:21:51 -05:00
James Bardin acdba6be6b
convert to correct types in expressions (#59)
* Add tests to cover new behavior introduced in cty

Convert should now not convert null to DynamicPseudoType, and Equals
will always compare Nulls as equal.

* update go.mod
2018-11-29 14:43:45 -05:00
Radek Simko 67424e43b1
hcled: Introduce ContextDefRange (#58)
This can be used for looking up range of block definition
so that we can render it alongside attribute-agnostic errors
2018-11-26 23:35:46 +00:00
Martin Atkins 0467c0c38c hclpack: Update ExprSourceType.String to include ExprLiteralJSON 2018-11-11 09:29:36 -08:00
Martin Atkins 12378af8b3 new 'hclpack' package 2018-11-11 09:23:11 -08:00
Martin Atkins dcefc5ca24 hclpack: Body can now unmarshal from JSON
This allows us to round-trip Body to JSON and back without any loss as
long as the expression source codes are always valid UTF-8, and we require
that during expression parsing anyway so that is a fine restriction.

The JSON encoding is a little noisy to read due to the extra annotations
required to be lossless (including source ranges) but still relatively
compact due to the base64-VLQ encoding of the source location information.
2018-11-11 09:22:08 -08:00
Martin Atkins 30da06ec3f hclpack: Implement UnwrapExpression for our expressions
This allows the static analysis functions in the main HCL package to dig
through our wrapper to get the native expression object needed for most
analyses.

For example, this allows an expression with a native expression source
type whose source contains valid tuple constructor syntax to be used with
hcl.ExprList.
2018-11-11 08:34:44 -08:00
Martin Atkins 06d5709118 hclpack: Support literal JSON as an additional expression syntax
hclpack can potentially be used as an intermediary to more easily bring
non-HCL input into the HCL API, and so allowing a literal value in JSON
format as an expression type means that such a transcoder doesn't need to
worry about formatting values it encounters using HCL syntax and can
instead just encode directly to JSON, but at the expense of then not being
able to use the full expression/template syntax.
2018-11-11 08:26:37 -08:00
Martin Atkins 309e278914 hclpack: Implement JSON marshaling (but not unmarshaling, yet) 2018-11-11 03:25:19 +00:00
Martin Atkins ed7453e277 hclpack: PackNativeFile to get a packed version of a native syntax file
This is a straightforward way to get a hclpack.Body in the common case
where the input is already native syntax source code. Since the native
syntax is unambiguous about structure, the whole structure can be packed
in a single pass with no further information.
2018-11-11 00:40:31 +00:00
Martin Atkins 227ba9e86b hclpack: Start of definitions for JSON marshaling/unmarshaling
This is not yet complete.
2018-11-10 10:29:32 -08:00
Martin Atkins 5e07d8e1f9 hclpack: New package for wire representations of hcl bodies
In most applications it's possible to fully evaluate configuration at the
beginning and work only with resolved values after that, but in some
unusual cases it's necessary to split parsing and decoding between two
separate processes connected by a pipe or network connection.

hclpack is intended to provide compact wire formats for sending bodies
over the network such that they can be decoded and evaluated and get the
same results. This is not something that can happen fully automatically
because a hcl.Body is an abstract node rather than a physical construct,
and so access to the original source code is required to construct such
a representation, and to interpret any source ranges that emerged from
the final evaluation.
2018-11-10 09:36:26 -08:00
Martin Atkins 0a1bd51123 hclsyntax: "Arguments" instead of "attributes" in diagnostics
To reduce confusion with object attributes, we switched a while back to
using the term "argument" to refer to the key/value pairs in a body, but
these diagnostic messages were not updated.
2018-11-10 08:40:13 -08:00
Paul Tyng 9aa28a1a0b
Merge pull request #53 from hashicorp/pt/edges_from_hcl1
Add additional comment test cases
2018-11-06 18:06:04 -05:00
Martin Atkins 917fbe66e7 hclwrite: Expression.RenameVariablePrefix
This function serves the use-case of surgically renaming references to
variables in an existing file without disturbing other tokens.
2018-11-04 04:17:03 +00:00
Martin Atkins 0c14f1e3f6 hclwrite: Implement Body.SetAttributeTraversal 2018-11-04 02:09:35 +00:00
Martin Atkins 1b9738a196 gohcl: EncodeIntoBody and EncodeAsBlock functions
These are wrappers around the lower-level hclwrite package that are able
to reverse a subset of the behavior of the Decode functions to populate
an hclwrite DOM.

They are not fully symmetrical with DecodeBody because that function can
leave certain parts of the configuration in its opaque form for later
decoding, and these encode functions don't have enough information to
repack that abstract/opaque form into new source code.

In practice we expect that callers using complex techniques like partial
decoding will also use more complex techniques with the hclwrite API
directly, since they will need to coordinate partial _encoding_ of data
that has been portioned off into separate structures, which gohcl is not
equipped to do itself.
2018-11-04 01:16:51 +00:00
Martin Atkins 8cca983bca hclwrite: Support for creating new blocks and clearing bodies 2018-11-04 01:13:13 +00:00
Martin Atkins 361186aad0 hclwrite: Recast TestRoundupCreate as an example
Since the goal of this is to be somewhat realistic of what a caller might
do, we might as well also include it in the godoc examples.
2018-11-03 21:20:10 +00:00
Martin Atkins 17ff23300f hclwrite: NewEmptyFile function
This completes the minimal functionality for creating a new file from
scratch, rather than modifying an existing one. This is illustrated by
a new test TestRoundupCreate that uses the API to create a new file in a
similar way to how a calling application might.
2018-11-03 20:45:25 +00:00
Martin Atkins a44a287724 hclwrite: Make File and Tokens implement io.WriterTo
There isn't any strong reason for this -- they don't implement io.Reader
and so can't be used in places where a Reader+WriterTo is expected, like
io.Copy -- but go lint thinks that anything called WriteTo with an
io.Writer argument is an attempt to implement WriterTo and so this just
shuts up the linter.
2018-11-03 20:19:56 +00:00
Martin Atkins fd915f557d hclwrite: Rename Body.AppendBlock to AppendNewBlock
Since this function implicitly creates a new body, this name is more
appropriate and leaves the name "AppendBlock" open for a later method to
append an _existing_ block, such as when moving a block from one file
to another.
2018-11-03 19:54:56 +00:00
Martin Atkins 379d277e2b hcl/hclsyntax: Fix invalid block parsing test
Invalid blocks now have empty bodies rather than nil bodies, to avoid the
need to callers to specially handle nils here when they are doing analysis
of a partially-invalid file.
2018-11-03 19:49:14 +00:00
Martin Atkins 57c6d75eb8 hclwrite: Body.AppendBlock
This method allows a caller to generate a nested block within a body.
Since a nested block has its own content body, this now allows for deep
structures to be generated.
2018-11-03 09:21:43 -07:00
Martin Atkins 98352801f3 go mod tidy 2018-11-03 09:21:43 -07:00
Martin Atkins 04d1413613 hclwrite: Split Attribute and Block into their own source files
These will grow to have significant logic of their own, so hiding them at
the end of the Body file makes things harder to read.
2018-11-03 09:21:43 -07:00
Paul Tyng 9928b942bb
Add missing module 2018-10-31 12:26:27 -04:00
Paul Tyng e8e85f5edd
Add additional comment test cases
Some of these fail in HCL1 fmt
2018-10-31 12:25:12 -04:00
Martin Atkins 3e4b7e0eb2 hclsyntax: If nested block doesn't parse, produce empty body
Our usual rule for parse errors is to return a valid-but-incomplete object
along with error diagnostics. This was violating that rule by returning
a nil child body, which callers do not expect to deal with.

Instead, we'll return an *empty* body, so that callers who use the partial
result for careful analyses can still process the block header, without
needing to guard against the body being nil.
2018-10-01 14:06:26 -07:00
Martin Atkins cce5ae6cc5 hclsyntax: Remove hclsyntax.Transform
This was always a bit of an outlier here because the rest of the API is
intentionally designed to encourage treating AST nodes as immutable.

Although the transforming walkers were functionally correct, they were
causing false positives in the race detector if two walks run concurrently.

We may later introduce something similar to this in the hclwrite package,
where the AST nodes are explicitly mutable.
2018-09-26 07:38:54 -07:00
Radek Simko 3f1c5474d4 hclsyntax: Add test for idx'd func outputs 2018-09-25 10:55:40 -07:00
Martin Atkins 983c83c156 hclsyntax: Some tests for Walk
These tests are not yet comprehensive, but at least cover some normal
cases and some cases that have some trickier behavior.
2018-09-25 08:25:42 -07:00