govendor fetch github.com/hashicorp/hcl2/...
This includes updates to various diagnostic messages to improve precision and consistency of terminology. It also includes some other changes to portions of HCL API that Terraform isn't yet using.
This commit is contained in:
parent
aa6b55bb17
commit
3855b79736
|
@ -96,6 +96,17 @@ func (d Diagnostics) HasErrors() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
func (d Diagnostics) Errs() []error {
|
||||
var errs []error
|
||||
for _, diag := range d {
|
||||
if diag.Severity == DiagError {
|
||||
errs = append(errs, diag)
|
||||
}
|
||||
}
|
||||
|
||||
return errs
|
||||
}
|
||||
|
||||
// A DiagnosticWriter emits diagnostics somehow.
|
||||
type DiagnosticWriter interface {
|
||||
WriteDiagnostic(*Diagnostic) error
|
||||
|
|
|
@ -55,7 +55,7 @@ Token:
|
|||
Severity: hcl.DiagError,
|
||||
Summary: "Attribute redefined",
|
||||
Detail: fmt.Sprintf(
|
||||
"The attribute %q was already defined at %s. Each attribute may be defined only once.",
|
||||
"The argument %q was already set at %s. Each argument may be set only once.",
|
||||
titem.Name, existing.NameRange.String(),
|
||||
),
|
||||
Subject: &titem.NameRange,
|
||||
|
@ -80,15 +80,15 @@ Token:
|
|||
if bad.Type == TokenOQuote {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid attribute name",
|
||||
Detail: "Attribute names must not be quoted.",
|
||||
Summary: "Invalid argument name",
|
||||
Detail: "Argument names must not be quoted.",
|
||||
Subject: &bad.Range,
|
||||
})
|
||||
} else {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Attribute or block definition required",
|
||||
Detail: "An attribute or block definition is required here.",
|
||||
Summary: "Argument or block definition required",
|
||||
Detail: "An argument or block definition is required here.",
|
||||
Subject: &bad.Range,
|
||||
})
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ func (p *parser) ParseBodyItem() (Node, hcl.Diagnostics) {
|
|||
return nil, hcl.Diagnostics{
|
||||
{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Attribute or block definition required",
|
||||
Detail: "An attribute or block definition is required here.",
|
||||
Summary: "Argument or block definition required",
|
||||
Detail: "An argument or block definition is required here.",
|
||||
Subject: &ident.Range,
|
||||
},
|
||||
}
|
||||
|
@ -139,8 +139,8 @@ func (p *parser) ParseBodyItem() (Node, hcl.Diagnostics) {
|
|||
return nil, hcl.Diagnostics{
|
||||
{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Attribute or block definition required",
|
||||
Detail: "An attribute or block definition is required here. To define an attribute, use the equals sign \"=\" to introduce the attribute value.",
|
||||
Summary: "Argument or block definition required",
|
||||
Detail: "An argument or block definition is required here. To set an argument, use the equals sign \"=\" to introduce the argument value.",
|
||||
Subject: &ident.Range,
|
||||
},
|
||||
}
|
||||
|
@ -171,8 +171,8 @@ func (p *parser) finishParsingBodyAttribute(ident Token) (Node, hcl.Diagnostics)
|
|||
if !p.recovery {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing newline after attribute definition",
|
||||
Detail: "An attribute definition must end with a newline.",
|
||||
Summary: "Missing newline after argument",
|
||||
Detail: "An argument definition must end with a newline.",
|
||||
Subject: &end.Range,
|
||||
Context: hcl.RangeBetween(ident.Range, end.Range).Ptr(),
|
||||
})
|
||||
|
@ -244,7 +244,7 @@ Token:
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid block definition",
|
||||
Detail: "The equals sign \"=\" indicates an attribute definition, and must not be used when defining a block.",
|
||||
Detail: "The equals sign \"=\" indicates an argument definition, and must not be used when defining a block.",
|
||||
Subject: &tok.Range,
|
||||
Context: hcl.RangeBetween(ident.Range, tok.Range).Ptr(),
|
||||
})
|
||||
|
@ -1135,8 +1135,8 @@ func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) {
|
|||
if next.Type == TokenNewline || next.Type == TokenComma {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing item value",
|
||||
Detail: "Expected an item value, introduced by an equals sign (\"=\").",
|
||||
Summary: "Missing attribute value",
|
||||
Detail: "Expected an attribute value, introduced by an equals sign (\"=\").",
|
||||
Subject: &next.Range,
|
||||
Context: hcl.RangeBetween(open.Range, next.Range).Ptr(),
|
||||
})
|
||||
|
@ -1144,7 +1144,7 @@ func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) {
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing key/value separator",
|
||||
Detail: "Expected an equals sign (\"=\") to mark the beginning of the item value.",
|
||||
Detail: "Expected an equals sign (\"=\") to mark the beginning of the attribute value.",
|
||||
Subject: &next.Range,
|
||||
Context: hcl.RangeBetween(open.Range, next.Range).Ptr(),
|
||||
})
|
||||
|
@ -1182,8 +1182,8 @@ func (p *parser) parseObjectCons() (Expression, hcl.Diagnostics) {
|
|||
if !p.recovery {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing item separator",
|
||||
Detail: "Expected a newline or comma to mark the beginning of the next item.",
|
||||
Summary: "Missing attribute separator",
|
||||
Detail: "Expected a newline or comma to mark the beginning of the next attribute.",
|
||||
Subject: &next.Range,
|
||||
Context: hcl.RangeBetween(open.Range, next.Range).Ptr(),
|
||||
})
|
||||
|
@ -1277,7 +1277,7 @@ func (p *parser) finishParsingForExpr(open Token) (Expression, hcl.Diagnostics)
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid 'for' expression",
|
||||
Detail: "For expression requires 'in' keyword after names.",
|
||||
Detail: "For expression requires the 'in' keyword after its name declarations.",
|
||||
Subject: p.Peek().Range.Ptr(),
|
||||
Context: hcl.RangeBetween(open.Range, p.Peek().Range).Ptr(),
|
||||
})
|
||||
|
@ -1305,7 +1305,7 @@ func (p *parser) finishParsingForExpr(open Token) (Expression, hcl.Diagnostics)
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid 'for' expression",
|
||||
Detail: "For expression requires colon after collection expression.",
|
||||
Detail: "For expression requires a colon after the collection expression.",
|
||||
Subject: p.Peek().Range.Ptr(),
|
||||
Context: hcl.RangeBetween(open.Range, p.Peek().Range).Ptr(),
|
||||
})
|
||||
|
@ -1459,7 +1459,7 @@ Token:
|
|||
case TokenTemplateControl, TokenTemplateInterp:
|
||||
which := "$"
|
||||
if tok.Type == TokenTemplateControl {
|
||||
which = "!"
|
||||
which = "%"
|
||||
}
|
||||
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
|
|
|
@ -4,12 +4,12 @@ This is the specification of the syntax and semantics of the native syntax
|
|||
for HCL. HCL is a system for defining configuration languages for applications.
|
||||
The HCL information model is designed to support multiple concrete syntaxes
|
||||
for configuration, but this native syntax is considered the primary format
|
||||
and is optimized for human authoring and maintenence, as opposed to machine
|
||||
and is optimized for human authoring and maintenance, as opposed to machine
|
||||
generation of configuration.
|
||||
|
||||
The language consists of three integrated sub-languages:
|
||||
|
||||
* The _structural_ language defines the overall heirarchical configuration
|
||||
* The _structural_ language defines the overall hierarchical configuration
|
||||
structure, and is a serialization of HCL bodies, blocks and attributes.
|
||||
|
||||
* The _expression_ language is used to express attribute values, either as
|
||||
|
@ -186,7 +186,7 @@ for later evaluation by the calling application.
|
|||
### Blocks
|
||||
|
||||
A _block_ creates a child body that is annotated with a block _type_ and
|
||||
zero or more block _labels_. Blocks create a structural heirachy which can be
|
||||
zero or more block _labels_. Blocks create a structural hierachy which can be
|
||||
interpreted by the calling application.
|
||||
|
||||
Block labels can either be quoted literal strings or naked identifiers.
|
||||
|
@ -296,7 +296,7 @@ There is a syntax ambiguity between _for expressions_ and collection values
|
|||
whose first element is a reference to a variable named `for`. The
|
||||
_for expression_ interpretation has priority, so to produce a tuple whose
|
||||
first element is the value of a variable named `for`, or an object with a
|
||||
key named `for`, use paretheses to disambiguate:
|
||||
key named `for`, use parentheses to disambiguate:
|
||||
|
||||
* `[for, foo, baz]` is a syntax error.
|
||||
* `[(for), foo, baz]` is a tuple whose first element is the value of variable
|
||||
|
@ -482,7 +482,7 @@ object.
|
|||
In the case of object `for`, it is an error if two input elements produce
|
||||
the same result from the attribute name expression, since duplicate
|
||||
attributes are not possible. If the ellipsis symbol (`...`) appears
|
||||
immediately after the value experssion, this activates the grouping mode in
|
||||
immediately after the value expression, this activates the grouping mode in
|
||||
which each value in the resulting object is a _tuple_ of all of the values
|
||||
that were produced against each distinct key.
|
||||
|
||||
|
@ -769,7 +769,7 @@ sequence is escaped as `%%{`.
|
|||
|
||||
When the template sub-language is embedded in the expression language via
|
||||
_template expressions_, additional constraints and transforms are applied to
|
||||
template literalsas described in the definition of template expressions.
|
||||
template literals as described in the definition of template expressions.
|
||||
|
||||
The value of a template literal can be modified by _strip markers_ in any
|
||||
interpolations or directives that are adjacent to it. A strip marker is
|
||||
|
@ -903,7 +903,7 @@ key/value pairs given are returned as the static pairs, with no further
|
|||
interpretation.
|
||||
|
||||
The usual requirement that an attribute name be interpretable as a string
|
||||
does not apply to this static analyis, allowing callers to provide map-like
|
||||
does not apply to this static analysis, allowing callers to provide map-like
|
||||
constructs with different key types by building on the map syntax.
|
||||
|
||||
### Static Call
|
||||
|
|
|
@ -229,7 +229,7 @@ func checkInvalidTokens(tokens Tokens) hcl.Diagnostics {
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid character",
|
||||
Detail: "The \";\" character is not valid. Use newlines to separate attributes and blocks, and commas to separate items in collection values.",
|
||||
Detail: "The \";\" character is not valid. Use newlines to separate arguments and blocks, and commas to separate items in collection values.",
|
||||
Subject: &tok.Range,
|
||||
})
|
||||
|
||||
|
|
|
@ -55,7 +55,7 @@ func parseValue(p *peeker) (node, hcl.Diagnostics) {
|
|||
return wrapInvalid(nil, hcl.Diagnostics{
|
||||
{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing attribute value",
|
||||
Summary: "Missing JSON value",
|
||||
Detail: "A JSON value must start with a brace, a bracket, a number, a string, or a keyword.",
|
||||
Subject: &tok.Range,
|
||||
},
|
||||
|
@ -144,8 +144,8 @@ Token:
|
|||
if !ok {
|
||||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Invalid object attribute name",
|
||||
Detail: "A JSON object attribute name must be a string",
|
||||
Summary: "Invalid object property name",
|
||||
Detail: "A JSON object property name must be a string",
|
||||
Subject: keyNode.StartRange().Ptr(),
|
||||
})
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ Token:
|
|||
// Possible confusion with native HCL syntax.
|
||||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing attribute value colon",
|
||||
Summary: "Missing property value colon",
|
||||
Detail: "JSON uses a colon as its name/value delimiter, not an equals sign.",
|
||||
Subject: &colon.Range,
|
||||
})
|
||||
|
@ -179,8 +179,8 @@ Token:
|
|||
|
||||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing attribute value colon",
|
||||
Detail: "A colon must appear between an object attribute's name and its value.",
|
||||
Summary: "Missing property value colon",
|
||||
Detail: "A colon must appear between an object property's name and its value.",
|
||||
Subject: &colon.Range,
|
||||
})
|
||||
}
|
||||
|
@ -205,7 +205,7 @@ Token:
|
|||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Trailing comma in object",
|
||||
Detail: "JSON does not permit a trailing comma after the final attribute in an object.",
|
||||
Detail: "JSON does not permit a trailing comma after the final property in an object.",
|
||||
Subject: &comma.Range,
|
||||
})
|
||||
}
|
||||
|
@ -234,7 +234,7 @@ Token:
|
|||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing attribute seperator comma",
|
||||
Detail: "A comma must appear between each attribute declaration in an object.",
|
||||
Detail: "A comma must appear between each property definition in an object.",
|
||||
Subject: p.Peek().Range.Ptr(),
|
||||
})
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ Token:
|
|||
return nil, diags.Append(&hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Trailing comma in array",
|
||||
Detail: "JSON does not permit a trailing comma after the final attribute in an array.",
|
||||
Detail: "JSON does not permit a trailing comma after the final value in an array.",
|
||||
Subject: &comma.Range,
|
||||
})
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ for defining configuration languages for applications. The HCL information
|
|||
model is designed to support multiple concrete syntaxes for configuration,
|
||||
and this JSON-based format complements [the native syntax](../hclsyntax/spec.md)
|
||||
by being easy to machine-generate, whereas the native syntax is oriented
|
||||
towards human authoring and maintenence.
|
||||
towards human authoring and maintenance
|
||||
|
||||
This syntax is defined in terms of JSON as defined in
|
||||
[RFC7159](https://tools.ietf.org/html/rfc7159). As such it inherits the JSON
|
||||
|
@ -280,9 +280,9 @@ When interpreted as an expression, a JSON array represents a value of a HCL
|
|||
tuple type.
|
||||
|
||||
Each element of the JSON array represents an element of the HCL tuple type.
|
||||
The tuple type is constructed by enumerationg the JSON array elements, creating
|
||||
The tuple type is constructed by enumerating the JSON array elements, creating
|
||||
for each an element whose type is the result of recursively applying the
|
||||
expression mapping rules. Correspondance is preserved between the array element
|
||||
expression mapping rules. Correspondence is preserved between the array element
|
||||
indices and the tuple element indices.
|
||||
|
||||
An instance of the constructed tuple type is then created, whose values are
|
||||
|
@ -325,7 +325,7 @@ HCL null value of the dynamic pseudo-type.
|
|||
|
||||
### Strings
|
||||
|
||||
When intepreted as an expression, a JSON string may be interpreted in one of
|
||||
When interpreted as an expression, a JSON string may be interpreted in one of
|
||||
two ways depending on the evaluation mode.
|
||||
|
||||
If evaluating in literal-only mode (as defined by the syntax-agnostic
|
||||
|
|
|
@ -64,7 +64,7 @@ func (b *body) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnostic
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Extraneous JSON object property",
|
||||
Detail: fmt.Sprintf("No attribute or block type is named %q.%s", k, suggestion),
|
||||
Detail: fmt.Sprintf("No argument or block type is named %q.%s", k, suggestion),
|
||||
Subject: &attr.NameRange,
|
||||
Context: attr.Range().Ptr(),
|
||||
})
|
||||
|
@ -114,8 +114,8 @@ func (b *body) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Bod
|
|||
if existing, exists := content.Attributes[attrName]; exists {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate attribute definition",
|
||||
Detail: fmt.Sprintf("The attribute %q was already defined at %s.", attrName, existing.Range),
|
||||
Summary: "Duplicate argument",
|
||||
Detail: fmt.Sprintf("The argument %q was already set at %s.", attrName, existing.Range),
|
||||
Subject: &jsonAttr.NameRange,
|
||||
Context: jsonAttr.Range().Ptr(),
|
||||
})
|
||||
|
@ -149,8 +149,8 @@ func (b *body) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Bod
|
|||
if _, defined := content.Attributes[attrS.Name]; !defined {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing required attribute",
|
||||
Detail: fmt.Sprintf("The attribute %q is required, but no definition was found.", attrS.Name),
|
||||
Summary: "Missing required argument",
|
||||
Detail: fmt.Sprintf("The argument %q is required, but no definition was found.", attrS.Name),
|
||||
Subject: b.MissingItemRange().Ptr(),
|
||||
})
|
||||
}
|
||||
|
@ -175,7 +175,7 @@ func (b *body) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Incorrect JSON value type",
|
||||
Detail: "A JSON object is required here, defining the attributes for this block.",
|
||||
Detail: "A JSON object is required here, setting the arguments for this block.",
|
||||
Subject: b.val.StartRange().Ptr(),
|
||||
})
|
||||
return attrs, diags
|
||||
|
@ -197,7 +197,7 @@ func (b *body) JustAttributes() (hcl.Attributes, hcl.Diagnostics) {
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Duplicate attribute definition",
|
||||
Detail: fmt.Sprintf("The attribute %q was already defined at %s.", name, existing.Range),
|
||||
Detail: fmt.Sprintf("The argument %q was already set at %s.", name, existing.Range),
|
||||
Subject: &jsonAttr.NameRange,
|
||||
})
|
||||
continue
|
||||
|
@ -345,7 +345,7 @@ func (b *body) collectDeepAttrs(v node, labelName *string) ([]*objectAttr, hcl.D
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Incorrect JSON value type",
|
||||
Detail: "A JSON object is required here, to define attributes and child blocks.",
|
||||
Detail: "A JSON object is required here, to define arguments and child blocks.",
|
||||
Subject: ev.StartRange().Ptr(),
|
||||
})
|
||||
}
|
||||
|
@ -364,7 +364,7 @@ func (b *body) collectDeepAttrs(v node, labelName *string) ([]*objectAttr, hcl.D
|
|||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Incorrect JSON value type",
|
||||
Detail: "Either a JSON object or JSON array of objects is required here, to define attributes and child blocks.",
|
||||
Detail: "Either a JSON object or JSON array of objects is required here, to define arguments and child blocks.",
|
||||
Subject: v.StartRange().Ptr(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -109,9 +109,9 @@ func (mb mergedBodies) JustAttributes() (Attributes, Diagnostics) {
|
|||
if existing := attrs[name]; existing != nil {
|
||||
diags = diags.Append(&Diagnostic{
|
||||
Severity: DiagError,
|
||||
Summary: "Duplicate attribute",
|
||||
Summary: "Duplicate argument",
|
||||
Detail: fmt.Sprintf(
|
||||
"Attribute %q was already assigned at %s",
|
||||
"Argument %q was already set at %s",
|
||||
name, existing.NameRange.String(),
|
||||
),
|
||||
Subject: &attr.NameRange,
|
||||
|
@ -182,9 +182,9 @@ func (mb mergedBodies) mergedContent(schema *BodySchema, partial bool) (*BodyCon
|
|||
if existing := content.Attributes[name]; existing != nil {
|
||||
diags = diags.Append(&Diagnostic{
|
||||
Severity: DiagError,
|
||||
Summary: "Duplicate attribute",
|
||||
Summary: "Duplicate argument",
|
||||
Detail: fmt.Sprintf(
|
||||
"Attribute %q was already assigned at %s",
|
||||
"Argument %q was already set at %s",
|
||||
name, existing.NameRange.String(),
|
||||
),
|
||||
Subject: &attr.NameRange,
|
||||
|
@ -212,9 +212,9 @@ func (mb mergedBodies) mergedContent(schema *BodySchema, partial bool) (*BodyCon
|
|||
// use of required attributes on merged bodies.
|
||||
diags = diags.Append(&Diagnostic{
|
||||
Severity: DiagError,
|
||||
Summary: "Missing required attribute",
|
||||
Summary: "Missing required argument",
|
||||
Detail: fmt.Sprintf(
|
||||
"The attribute %q is required, but was not assigned.",
|
||||
"The argument %q is required, but was not set.",
|
||||
attrS.Name,
|
||||
),
|
||||
})
|
||||
|
|
|
@ -29,7 +29,7 @@ which are discussed in detail in a later section.
|
|||
A _block_ is a nested structure that has a _type name_, zero or more string
|
||||
_labels_ (e.g. identifiers), and a nested body.
|
||||
|
||||
Together the structural elements create a heirarchical data structure, with
|
||||
Together the structural elements create a hierarchical data structure, with
|
||||
attributes intended to represent the direct properties of a particular object
|
||||
in the calling application, and blocks intended to represent child objects
|
||||
of a particular object.
|
||||
|
@ -269,7 +269,7 @@ are two structural type _kinds_:
|
|||
has a type. Attribute names are always strings. (_Object_ attributes are a
|
||||
distinct idea from _body_ attributes, though calling applications
|
||||
may choose to blur the distinction by use of common naming schemes.)
|
||||
* _Tuple tupes_ are constructed of a sequence of elements, each of which
|
||||
* _Tuple types_ are constructed of a sequence of elements, each of which
|
||||
has a type.
|
||||
|
||||
Values of structural types are compared for equality in terms of their
|
||||
|
@ -301,10 +301,10 @@ the same element type.
|
|||
|
||||
### Null values
|
||||
|
||||
Each type has a null value. The null value of a type represents the absense
|
||||
Each type has a null value. The null value of a type represents the absence
|
||||
of a value, but with type information retained to allow for type checking.
|
||||
|
||||
Null values are used primarily to represent the conditional absense of a
|
||||
Null values are used primarily to represent the conditional absence of a
|
||||
body attribute. In a syntax with a conditional operator, one of the result
|
||||
values of that conditional may be null to indicate that the attribute should be
|
||||
considered not present in that case.
|
||||
|
@ -458,7 +458,7 @@ If semantic checking succeeds without error, the call is _executed_:
|
|||
definition is used to determine the call's _result value_.
|
||||
|
||||
The result of a function call expression is either an error, if one of the
|
||||
erroenous conditions above applies, or the _result value_.
|
||||
erroneous conditions above applies, or the _result value_.
|
||||
|
||||
## Type Conversions and Unification
|
||||
|
||||
|
@ -505,7 +505,7 @@ Bidirectional conversions are available between the string and number types,
|
|||
and between the string and boolean types.
|
||||
|
||||
The bool value true corresponds to the string containing the characters "true",
|
||||
while the bool value false corresponds to teh string containing the characters
|
||||
while the bool value false corresponds to the string containing the characters
|
||||
"false". Conversion from bool to string is safe, while the converse is
|
||||
unsafe. The strings "1" and "0" are alternative string representations
|
||||
of true and false respectively. It is an error to convert a string other than
|
||||
|
@ -671,7 +671,7 @@ The language-agnosticism of this specification assumes that certain behaviors
|
|||
are implemented separately for each syntax:
|
||||
|
||||
* Matching of a body schema with the physical elements of a body in the
|
||||
source language, to determine correspondance between physical constructs
|
||||
source language, to determine correspondence between physical constructs
|
||||
and schema elements.
|
||||
|
||||
* Implementing the _dynamic attributes_ body processing mode by either
|
||||
|
|
|
@ -26,8 +26,8 @@ func (b mockBody) Content(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.Diagnos
|
|||
for _, attr := range remain.C.Attributes {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Extraneous attribute in mock body",
|
||||
Detail: fmt.Sprintf("Mock body has extraneous attribute %q.", attr.Name),
|
||||
Summary: "Extraneous argument in mock body",
|
||||
Detail: fmt.Sprintf("Mock body has extraneous argument %q.", attr.Name),
|
||||
Subject: &attr.NameRange,
|
||||
})
|
||||
}
|
||||
|
@ -63,8 +63,8 @@ func (b mockBody) PartialContent(schema *hcl.BodySchema) (*hcl.BodyContent, hcl.
|
|||
if attrS.Required {
|
||||
diags = append(diags, &hcl.Diagnostic{
|
||||
Severity: hcl.DiagError,
|
||||
Summary: "Missing required attribute",
|
||||
Detail: fmt.Sprintf("Mock body doesn't have attribute %q", name),
|
||||
Summary: "Missing required argument",
|
||||
Detail: fmt.Sprintf("Mock body doesn't have argument %q", name),
|
||||
Subject: b.C.MissingItemRange.Ptr(),
|
||||
})
|
||||
}
|
||||
|
|
|
@ -162,12 +162,12 @@ func (n *Block) Tokens() *TokenSeq {
|
|||
}
|
||||
|
||||
type Expression struct {
|
||||
AllTokens *TokenSeq
|
||||
VarRefs []*VarRef
|
||||
AllTokens *TokenSeq
|
||||
AbsTraversals []*Traversal
|
||||
}
|
||||
|
||||
func (n *Expression) walkChildNodes(w internalWalkFunc) {
|
||||
for _, name := range n.VarRefs {
|
||||
for _, name := range n.AbsTraversals {
|
||||
w(name)
|
||||
}
|
||||
}
|
||||
|
@ -176,16 +176,30 @@ func (n *Expression) Tokens() *TokenSeq {
|
|||
return n.AllTokens
|
||||
}
|
||||
|
||||
type VarRef struct {
|
||||
// Tokens alternate between TokenIdent and TokenDot, with the first
|
||||
// and last elements always being TokenIdent.
|
||||
type Traversal struct {
|
||||
AllTokens *TokenSeq
|
||||
Steps []*Traverser
|
||||
}
|
||||
|
||||
func (n *VarRef) walkChildNodes(w internalWalkFunc) {
|
||||
// no child nodes of a variable name
|
||||
func (n *Traversal) walkChildNodes(w internalWalkFunc) {
|
||||
for _, step := range n.Steps {
|
||||
w(step)
|
||||
}
|
||||
}
|
||||
|
||||
func (n *VarRef) Tokens() *TokenSeq {
|
||||
func (n *Traversal) Tokens() *TokenSeq {
|
||||
return n.AllTokens
|
||||
}
|
||||
|
||||
type Traverser struct {
|
||||
AllTokens *TokenSeq
|
||||
Logical hcl.Traverser
|
||||
}
|
||||
|
||||
func (n *Traverser) Tokens() *TokenSeq {
|
||||
return n.AllTokens
|
||||
}
|
||||
|
||||
func (n *Traverser) walkChildNodes(w internalWalkFunc) {
|
||||
// No child nodes for a traversal step
|
||||
}
|
||||
|
|
|
@ -239,6 +239,10 @@ func spaceAfterToken(subject, before, after *Token) bool {
|
|||
// No space right before a comma in an argument list
|
||||
return false
|
||||
|
||||
case subject.Type == hclsyntax.TokenComma:
|
||||
// Always a space after a comma
|
||||
return true
|
||||
|
||||
case subject.Type == hclsyntax.TokenQuotedLit || subject.Type == hclsyntax.TokenStringLit || subject.Type == hclsyntax.TokenOQuote || subject.Type == hclsyntax.TokenOHeredoc || after.Type == hclsyntax.TokenQuotedLit || after.Type == hclsyntax.TokenStringLit || after.Type == hclsyntax.TokenCQuote || after.Type == hclsyntax.TokenCHeredoc:
|
||||
// No extra spaces within templates
|
||||
return false
|
||||
|
@ -296,8 +300,6 @@ func spaceAfterToken(subject, before, after *Token) bool {
|
|||
|
||||
func linesForFormat(tokens Tokens) []formatLine {
|
||||
if len(tokens) == 0 {
|
||||
// should never happen, since we should always have EOF, but let's
|
||||
// not crash anyway.
|
||||
return make([]formatLine, 0)
|
||||
}
|
||||
|
||||
|
@ -331,6 +333,16 @@ func linesForFormat(tokens Tokens) []formatLine {
|
|||
}
|
||||
}
|
||||
|
||||
// If a set of tokens doesn't end in TokenEOF (e.g. because it's a
|
||||
// fragment of tokens from the middle of a file) then we might fall
|
||||
// out here with a line still pending.
|
||||
if lineStart < len(tokens) {
|
||||
lines[li].lead = tokens[lineStart:]
|
||||
if lines[li].lead[len(lines[li].lead)-1].Type == hclsyntax.TokenEOF {
|
||||
lines[li].lead = lines[li].lead[:len(lines[li].lead)-1]
|
||||
}
|
||||
}
|
||||
|
||||
// Now we'll pick off any trailing comments and attribute assignments
|
||||
// to shuffle off into the "comment" and "assign" cells.
|
||||
for i := range lines {
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
package hclwrite
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"unicode"
|
||||
"unicode/utf8"
|
||||
|
||||
"github.com/hashicorp/hcl2/hcl/hclsyntax"
|
||||
"github.com/zclconf/go-cty/cty"
|
||||
)
|
||||
|
||||
// TokensForValue returns a sequence of tokens that represents the given
|
||||
// constant value.
|
||||
//
|
||||
// This function only supports types that are used by HCL. In particular, it
|
||||
// does not support capsule types and will panic if given one.
|
||||
//
|
||||
// It is not possible to express an unknown value in source code, so this
|
||||
// function will panic if the given value is unknown or contains any unknown
|
||||
// values. A caller can call the value's IsWhollyKnown method to verify that
|
||||
// no unknown values are present before calling TokensForValue.
|
||||
func TokensForValue(val cty.Value) Tokens {
|
||||
toks := appendTokensForValue(val, nil)
|
||||
format(toks) // fiddle with the SpacesBefore field to get canonical spacing
|
||||
return toks
|
||||
}
|
||||
|
||||
func appendTokensForValue(val cty.Value, toks Tokens) Tokens {
|
||||
switch {
|
||||
|
||||
case !val.IsKnown():
|
||||
panic("cannot produce tokens for unknown value")
|
||||
|
||||
case val.IsNull():
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenIdent,
|
||||
Bytes: []byte(`null`),
|
||||
})
|
||||
|
||||
case val.Type() == cty.Bool:
|
||||
var src []byte
|
||||
if val.True() {
|
||||
src = []byte(`true`)
|
||||
} else {
|
||||
src = []byte(`false`)
|
||||
}
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenIdent,
|
||||
Bytes: src,
|
||||
})
|
||||
|
||||
case val.Type() == cty.Number:
|
||||
bf := val.AsBigFloat()
|
||||
srcStr := bf.Text('f', -1)
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenNumberLit,
|
||||
Bytes: []byte(srcStr),
|
||||
})
|
||||
|
||||
case val.Type() == cty.String:
|
||||
// TODO: If it's a multi-line string ending in a newline, format
|
||||
// it as a HEREDOC instead.
|
||||
src := escapeQuotedStringLit(val.AsString())
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenOQuote,
|
||||
Bytes: []byte{'"'},
|
||||
})
|
||||
if len(src) > 0 {
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenQuotedLit,
|
||||
Bytes: src,
|
||||
})
|
||||
}
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenCQuote,
|
||||
Bytes: []byte{'"'},
|
||||
})
|
||||
|
||||
case val.Type().IsListType() || val.Type().IsSetType() || val.Type().IsTupleType():
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenOBrack,
|
||||
Bytes: []byte{'['},
|
||||
})
|
||||
|
||||
i := 0
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
if i > 0 {
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenComma,
|
||||
Bytes: []byte{','},
|
||||
})
|
||||
}
|
||||
_, eVal := it.Element()
|
||||
toks = appendTokensForValue(eVal, toks)
|
||||
i++
|
||||
}
|
||||
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenCBrack,
|
||||
Bytes: []byte{']'},
|
||||
})
|
||||
|
||||
case val.Type().IsMapType() || val.Type().IsObjectType():
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenOBrace,
|
||||
Bytes: []byte{'{'},
|
||||
})
|
||||
|
||||
i := 0
|
||||
for it := val.ElementIterator(); it.Next(); {
|
||||
if i > 0 {
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenComma,
|
||||
Bytes: []byte{','},
|
||||
})
|
||||
}
|
||||
eKey, eVal := it.Element()
|
||||
if hclsyntax.ValidIdentifier(eKey.AsString()) {
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenIdent,
|
||||
Bytes: []byte(eKey.AsString()),
|
||||
})
|
||||
} else {
|
||||
toks = appendTokensForValue(eKey, toks)
|
||||
}
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenEqual,
|
||||
Bytes: []byte{'='},
|
||||
})
|
||||
toks = appendTokensForValue(eVal, toks)
|
||||
i++
|
||||
}
|
||||
|
||||
toks = append(toks, &Token{
|
||||
Type: hclsyntax.TokenCBrace,
|
||||
Bytes: []byte{'}'},
|
||||
})
|
||||
|
||||
default:
|
||||
panic(fmt.Sprintf("cannot produce tokens for %#v", val))
|
||||
}
|
||||
|
||||
return toks
|
||||
}
|
||||
|
||||
func escapeQuotedStringLit(s string) []byte {
|
||||
if len(s) == 0 {
|
||||
return nil
|
||||
}
|
||||
buf := make([]byte, 0, len(s))
|
||||
for i, r := range s {
|
||||
switch r {
|
||||
case '\n':
|
||||
buf = append(buf, '\\', 'n')
|
||||
case '\r':
|
||||
buf = append(buf, '\\', 'r')
|
||||
case '\t':
|
||||
buf = append(buf, '\\', 't')
|
||||
case '"':
|
||||
buf = append(buf, '\\', '"')
|
||||
case '\\':
|
||||
buf = append(buf, '\\', '\\')
|
||||
case '$', '%':
|
||||
buf = appendRune(buf, r)
|
||||
remain := s[i+1:]
|
||||
if len(remain) > 0 && remain[0] == '{' {
|
||||
// Double up our template introducer symbol to escape it.
|
||||
buf = appendRune(buf, r)
|
||||
}
|
||||
default:
|
||||
if !unicode.IsPrint(r) {
|
||||
var fmted string
|
||||
if r < 65536 {
|
||||
fmted = fmt.Sprintf("\\u%04x", r)
|
||||
} else {
|
||||
fmted = fmt.Sprintf("\\U%08x", r)
|
||||
}
|
||||
buf = append(buf, fmted...)
|
||||
} else {
|
||||
buf = appendRune(buf, r)
|
||||
}
|
||||
}
|
||||
}
|
||||
return buf
|
||||
}
|
||||
|
||||
func appendRune(b []byte, r rune) []byte {
|
||||
l := utf8.RuneLen(r)
|
||||
for i := 0; i < l; i++ {
|
||||
b = append(b, 0) // make room at the end of our buffer
|
||||
}
|
||||
ch := b[len(b)-l:]
|
||||
utf8.EncodeRune(ch, r)
|
||||
return b
|
||||
}
|
|
@ -327,9 +327,54 @@ func parseBlock(nativeBlock *hclsyntax.Block, from, leadComments, lineComments,
|
|||
}
|
||||
|
||||
func parseExpression(nativeExpr hclsyntax.Expression, from inputTokens) *Expression {
|
||||
// TODO: Populate VarRefs by analyzing the result of nativeExpr.Variables()
|
||||
var allTokens TokenSeq
|
||||
nativeVars := nativeExpr.Variables()
|
||||
var absTraversals []*Traversal
|
||||
for _, nativeTraversal := range nativeVars {
|
||||
var traversalTokens TokenSeq
|
||||
var before, traversalFrom inputTokens
|
||||
before, traversalFrom, from = from.Partition(nativeTraversal.SourceRange())
|
||||
if before.Len() > 0 {
|
||||
allTokens = append(allTokens, before.Seq())
|
||||
}
|
||||
|
||||
var steps []*Traverser
|
||||
|
||||
for _, nativeStep := range nativeTraversal {
|
||||
var stepFrom inputTokens
|
||||
before, stepFrom, traversalFrom = traversalFrom.Partition(nativeStep.SourceRange())
|
||||
stepTokens := stepFrom.Seq()
|
||||
if before.Len() > 0 {
|
||||
traversalTokens = append(traversalTokens, before.Seq())
|
||||
}
|
||||
traversalTokens = append(traversalTokens, stepTokens)
|
||||
step := &Traverser{
|
||||
AllTokens: stepTokens,
|
||||
Logical: nativeStep,
|
||||
}
|
||||
steps = append(steps, step)
|
||||
}
|
||||
// Attach any straggler that don't belong to a step to the traversal itself.
|
||||
if traversalFrom.Len() > 0 {
|
||||
traversalTokens = append(traversalTokens, traversalFrom.Seq())
|
||||
}
|
||||
allTokens = append(allTokens, &traversalTokens)
|
||||
|
||||
absTraversals = append(absTraversals, &Traversal{
|
||||
AllTokens: &traversalTokens,
|
||||
Steps: steps,
|
||||
})
|
||||
}
|
||||
// Attach any stragglers that don't belong to a traversal to the expression
|
||||
// itself. In an expression with no traversals at all, this is just the
|
||||
// entirety of "from".
|
||||
if from.Len() > 0 {
|
||||
allTokens = append(allTokens, from.Seq())
|
||||
}
|
||||
|
||||
return &Expression{
|
||||
AllTokens: from.Seq(),
|
||||
AllTokens: &allTokens,
|
||||
AbsTraversals: absTraversals,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1915,68 +1915,68 @@
|
|||
{
|
||||
"checksumSHA1": "dJPromzLdd492RQjE/09klKRXGs=",
|
||||
"path": "github.com/hashicorp/hcl2/ext/dynblock",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "IAfC0Xri1iCRgbbiDBgs6ue8/Ic=",
|
||||
"path": "github.com/hashicorp/hcl2/ext/typeexpr",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "BRJaQcKriVKEirVC7YxBxPufQF0=",
|
||||
"path": "github.com/hashicorp/hcl2/gohcl",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "v1JCFNvhLqF3ErYcxkJJPboKO8c=",
|
||||
"checksumSHA1": "3ypdUCoJwZt+XRMV/6FoRhywz8A=",
|
||||
"path": "github.com/hashicorp/hcl2/hcl",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "6H/LBmIYL/dNjKvlbB2hAsxm2rw=",
|
||||
"checksumSHA1": "o6XGTmFfazaLQiSVs5cnaNvJhYQ=",
|
||||
"path": "github.com/hashicorp/hcl2/hcl/hclsyntax",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "G40fCmu1bSWXv4Hw5JXwEUTVThk=",
|
||||
"checksumSHA1": "Cuhv6UBgimVhWWwYm8v7Moisrhg=",
|
||||
"path": "github.com/hashicorp/hcl2/hcl/json",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "iIVMnRuvfOy/tJ1zE9rVcjD/01A=",
|
||||
"path": "github.com/hashicorp/hcl2/hcldec",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "sySYF9Ew71VS/LfrG+s/0jK+1VQ=",
|
||||
"path": "github.com/hashicorp/hcl2/hcled",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "IzmftuG99BqNhbFGhxZaGwtiMtM=",
|
||||
"path": "github.com/hashicorp/hcl2/hclparse",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "v5qx2XghQ+EtvFLa4a0Efjiwt9I=",
|
||||
"checksumSHA1": "UQzPVMlOo/3CJQnShbnNVcTF4EA=",
|
||||
"path": "github.com/hashicorp/hcl2/hcltest",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "C82otWNczU2S3azjxsjdGH9zW+Y=",
|
||||
"checksumSHA1": "v2ADtHrkDgQdqsroh9SJRsfANTk=",
|
||||
"path": "github.com/hashicorp/hcl2/hclwrite",
|
||||
"revision": "36446359d27574bf110611001414da561731b62d",
|
||||
"revisionTime": "2018-05-24T19:11:53Z"
|
||||
"revision": "41cff854d8157be197e6b4698a8d9570ced9476b",
|
||||
"revisionTime": "2018-07-18T22:41:35Z"
|
||||
},
|
||||
{
|
||||
"checksumSHA1": "M09yxoBoCEtG7EcHR8aEWLzMMJc=",
|
||||
|
|
Loading…
Reference in New Issue