Commit Graph

1139 Commits

Author SHA1 Message Date
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
Florian Forster
23ed7ba25b scanner: Don't call unread() after reading EOF.
This fixes the TestScanDigitsUnread() unit test.
2018-03-20 21:24:50 +01:00
Florian Forster
cade852d47 scanner: Add unit test triggering a panic in unread().
For example, the (Go quoted) input "\"\\00" creates the following stack
trace:

```
panic: bytes.Buffer: UnreadRune: previous operation was not a successful ReadRune

goroutine 1 [running]:
github.com/hashicorp/hcl/hcl/scanner.(*Scanner).unread(0xc420090270)
        gopath/src/github.com/hashicorp/hcl/hcl/scanner/scanner.go:112 +0x245
github.com/hashicorp/hcl/hcl/scanner.(*Scanner).scanDigits(0xc420090270, 0x0, 0x8, 0x3, 0x5c2005b740)
        gopath/src/github.com/hashicorp/hcl/hcl/scanner/scanner.go:557 +0x1ba
github.com/hashicorp/hcl/hcl/scanner.(*Scanner).scanEscape(0xc420090270, 0xc40000005c)
        gopath/src/github.com/hashicorp/hcl/hcl/scanner/scanner.go:520 +0x181
github.com/hashicorp/hcl/hcl/scanner.(*Scanner).scanString(0xc420090270)
        gopath/src/github.com/hashicorp/hcl/hcl/scanner/scanner.go:504 +0x2c3
github.com/hashicorp/hcl/hcl/scanner.(*Scanner).Scan(0xc420090270, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        gopath/src/github.com/hashicorp/hcl/hcl/scanner/scanner.go:172 +0x509
github.com/hashicorp/hcl/hcl/parser.(*Parser).scan(0xc42005bd18, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        gopath/src/github.com/hashicorp/hcl/hcl/parser/parser.go:448 +0xf4
github.com/hashicorp/hcl/hcl/parser.(*Parser).objectKey(0xc42005bd18, 0x530aa8, 0xc42005bd18, 0xc42005bd18, 0x18, 0x50f980)
        gopath/src/github.com/hashicorp/hcl/hcl/parser/parser.go:224 +0xca
github.com/hashicorp/hcl/hcl/parser.(*Parser).objectItem(0xc42005bd18, 0x0, 0x0, 0x0)
        gopath/src/github.com/hashicorp/hcl/hcl/parser/parser.go:150 +0xbf
github.com/hashicorp/hcl/hcl/parser.(*Parser).objectList(0xc42005bd18, 0xc42000e000, 0x0, 0x0, 0x0)
        gopath/src/github.com/hashicorp/hcl/hcl/parser/parser.go:88 +0x139
github.com/hashicorp/hcl/hcl/parser.(*Parser).Parse(0xc42005bd18, 0xc420090270, 0x200000, 0xc42005bce0)
        gopath/src/github.com/hashicorp/hcl/hcl/parser/parser.go:59 +0xf3
github.com/hashicorp/hcl/hcl/parser.Parse(0x7fca1fdd9000, 0x4, 0x200000, 0x8, 0x0, 0x0)
        gopath/src/github.com/hashicorp/hcl/hcl/parser/parser.go:46 +0x294
github.com/hashicorp/hcl/hcl/printer.Format(0x7fca1fdd9000, 0x4, 0x200000, 0x0, 0xc42005bef0, 0x464307, 0x4, 0xc42005bed0)
        gopath/src/github.com/hashicorp/hcl/hcl/printer/printer.go:53 +0x5b
```
2018-03-20 21:24:50 +01:00
Mitchell Hashimoto
f40e974e75
Merge pull request #240 from octo/scanner-next
scanner: Update prevPos even when returning utf8.RuneError.
2018-03-20 13:20:55 -07:00
Mitchell Hashimoto
adef769457
Merge pull request #241 from octo/scanner-null
printer, scanner: Don't produce unparsable output.
2018-03-20 13:19:40 -07:00
Florian Forster
ec2ba18997 scanner: Fail if U+E123 is found in input.
This (invalid) Unicode codepoint is used by the printer package to fix up
the indentation of generated files. If this codepoint is present in the
input, the package gets confused and removes more than it should,
producing unparsable output.
2018-03-20 20:46:51 +01:00
Florian Forster
a5efd34964 scanner: Report null bytes as errors, even at the end of file.
The formatter will append a newline at the end of file, causing the output
of printer.Format() to be invalid.
2018-03-20 20:46:51 +01:00
Florian Forster
a81aa7b5dd printer: Add unit test of Format() producing unparsable output. 2018-03-20 20:46:51 +01:00
Florian Forster
fdaaf22252 scanner: Update prevPos even when returning utf8.RuneError.
The calling code will still call unread(), causing panics.
This fixes the TestScanHeredocRegexpCompile() unit test.
2018-03-20 20:46:20 +01:00
Florian Forster
73fde59edb scanner: Add unit test triggering a panic in scanHeredoc().
```
panic: regexp: Compile("[[:space:]]*<\xc8\\z"): error parsing regexp: invalid UTF-8: `�\z`

goroutine 32 [running]:
testing.tRunner.func1(0xc4200cae10)
        /usr/lib/google-golang/src/testing/testing.go:742 +0x29d
panic(0x507a00, 0xc420290690)
        /usr/lib/google-golang/src/runtime/panic.go:505 +0x229
regexp.MustCompile(0xc420289e10, 0x10, 0xc420087680)
        /usr/lib/google-golang/src/regexp/regexp.go:240 +0x171
github.com/hashicorp/hcl/hcl/scanner.(*Scanner).scanHeredoc(0xc4200878c0)
        gopath/src/github.com/hashicorp/hcl/hcl/scanner/scanner.go:444 +0x3a9
github.com/hashicorp/hcl/hcl/scanner.(*Scanner).Scan(0xc4200878c0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
        gopath/src/github.com/hashicorp/hcl/hcl/scanner/scanner.go:186 +0x3e5
```
2018-03-20 20:46:20 +01:00
Seth Vargo
b1738d9053 Fix broken formatting directives (#242)
It looks like Go 1.10 fails these. This makes the build green again.
2018-03-20 14:36:33 -04:00
Martin Atkins
5f8ed954ab hclsyntax: count \r\n line endings properly in source ranges
Previously we were only counting a \n as starting a new line, so input
using \r\n endings would get treated as one long line for source-range
purposes.

Now we also consider \r\n to be a newline marker, resetting the column
count to zero and incrementing the line just as we would do for a single
\n. This is made easier because the unicode definition of "grapheme
cluster" considers \r\n to be a single character, so we don't need to
do anything special in order to match it.
2018-03-08 08:30:58 -08:00
Martin Atkins
7d6ed4d8f3 hclsyntax: emit Newline after a CHeredoc
Previously, due to how heredoc scanning was implemented, the closing
marker for a heredoc would consume the newline that terminated it. This
was problematic in any context that is newline-sensitive, because it
would cause us to skip the TokenNewline that might terminate e.g. an
attribute definition:

    foo = <<EOT
    hello
    EOT
    bar = "hello"

Previously the "foo" attribute would fail to parse properly due to trying
to consume the "bar" definition as part of its expression.

Now we synthetically split the marker token into two parts: the marker
itself and the newline that follows it. This means that using a heredoc
in any context where newlines are sensitive will involuntarily introduce
a newline, but that seems consistent with user expectation based on how
heredocs seem to be used "in the wild".
2018-03-08 08:22:32 -08:00