Commit Graph

241 Commits

Author SHA1 Message Date
Martin Atkins 6c9e11162b Relicense under MPL, rather than MIT
zcl is (was?) my side-project and so licensed the way I usually license
such things, but HashiCorp prefers MPL license and so here we are.
2017-09-11 16:43:03 -07:00
Martin Atkins 708abb8c97 Move the zcl package and its two parsing subpackages to "hcl" names
This is a super-invasive update since the "zcl" package in particular
is referenced all over.

There are probably still a few zcl references hanging around in comments,
etc but this takes care of most of it.
2017-09-11 16:40:37 -07:00
Martin Atkins 0dc3a6015c Rename the ancillary packages from "zcl" to "hcl".
The main "zcl" package requires a bit more care because of how many
callers it has and because of its two subpackages, so we'll take care
of that one separately.
2017-09-11 16:00:31 -07:00
Martin Atkins 386f7134f1 zcl/hclhil: remove HCL/HIL support
This package was a prototype of wrapping the HCL/HIL API in the new zcl
API as a compatibility strategy. This avenue wasn't chosen in the end, so
we'll remove this to avoid confusion as we rename everything else in this
repository to be called "hcl" now.
2017-09-11 15:46:01 -07:00
Martin Atkins c3ca111fff Adjust import paths for hashicorp/hcl2 repo
This begins 'the great fork' of zcl to HCL.
2017-09-11 15:38:42 -07:00
Martin Atkins 523939034f ext/include: extension for including bodies into other bodies
This package implements a language extension that allows configuration
authors to include the content of another file into a body, using syntax
like this:

  include {
    path = "./foo.zcl"
  }

This is implemented as a transform.Transformer so that it can be used
as part of a transform chain when decoding nested block structures to
allow includes at any arbitrary point.

This capability is not built into the language because certain
applications will offer higher-level constructs for connecting multiple
separate config files, which may e.g. have a separate evaluation scope
for each file, etc.
2017-07-27 18:15:56 -07:00
Martin Atkins fffca3d205 ext/transform: helper package for applying transforms to bodies
This utility is intended to support the extension packages that are
siblings of this package, along with third-party extensions, by providing
a way to transform bodies in arbitrary ways.

The "Deep" function then provides a means to apply a particular transform
recursively to a nested block tree, allowing a particular extension to
be supported at arbitrary nesting levels.

This functionality is provided in terms of the standard zcl.Body
interface, so that transform results can be used with any code that
operates generically on bodies. This includes the zcldec and gozcl
packages, so files with extensions can still be decoded in the usual
way.
2017-07-27 16:23:20 -07:00
Martin Atkins a414468aac zcltest: package with mock helpers for testing zcl-based apps 2017-07-27 15:59:32 -07:00
Martin Atkins 26f1e48014 ext/userfunc: extension for user-defined functions
This package provides helper function that looks in a given body for
blocks that define functions, returning a function map suitable for use
in a zcl.EvalContext.
2017-07-25 18:34:56 -07:00
Martin Atkins f03b4a0acd ext: A directory for packages implementing zcl language extensions
These will provide additional language features that are implemented in
terms of the basic zcl functionality, so that applications can opt-in to
some more-dynamic behavior if desired.

The general pattern here will be to provide a function that
partially-decodes a given zcl.Body to look for certain block types and
then returns its result along with a zcl.Body representing the remaining,
as-yet-unprocessed content.
2017-07-25 18:30:59 -07:00
Martin Atkins 4c269b52e2 gozcl: fix redundant error message in DecodeExpression
The convert errors already contain the string "incorrect type", so it's
redundant to add that as a further prefix here.
2017-07-25 18:24:55 -07:00
Martin Atkins 0598a0b79b zcldec: initial implementation of BlockListSpec
This initial pass supports only blocks without labels. BlockLabelSpec will
be wired in here later to allow decoding blocks with labels too.
2017-07-17 17:29:06 -07:00
Martin Atkins 4df9fd1372 zcldec: test that all Spec types actually implement the interface 2017-07-17 16:54:24 -07:00
Martin Atkins ade2a149ef zcldec: implement sourceRange for remaining Spec types 2017-07-17 16:54:09 -07:00
Martin Atkins 59a1343216 zclsyntax: allow numeric "attributes" inside attr-only splats
Terraform interprets HIL variables in such a way that it allows numeric
attribute names which then get interpreted as numeric indices into a
list. This is used to work around the fact that the splat expressions
don't work for the index operator.

zcl has "full splats" that _do_ support the index operator, but to allow
old Terraform configs to be processed by zcl we'll accept this special
case within attribute-only-splats only.

For the moment this is a special exception made by this specific
implementation of zcl rather than part of the spec, since it's
specifically a pragmatic Terraform migration strategy, but it might get
upgraded to full spec status later if we end up needing to support it
in other host languages.

This requires the scanner to be a little more picky about the ending
of numeric literals, so that they won't absorb the trailing period after
the number in foo.*.baz.1.baz . This is okay because the spec doesn't
allow trailing periods anyway, and this is not actually a change in
final behavior because the parser was already catching this situation
and rejecting it at a later point.
2017-06-24 09:39:16 -07:00
Martin Atkins 2c9302b699 cmd/zclfmt: skip formatting a file only if it has errors
Previously we were erroneously skipping formatting it whenever check mode
was enabled, regardless of errors.
2017-06-24 09:13:48 -07:00
Martin Atkins f8561de857 zclsyntax: permit dashes in identifiers
While this does create some ambiguity with arithmetic on variables, like
a-b, this is permitted by HCL and so we'll permit it for zcl too, at the
expense of requiring spaces to be used around minus signs for correct
interpretation.
2017-06-24 09:12:24 -07:00
Martin Atkins cab61b36dc zclwrite: format shouldn't add spaces around attribute access dots 2017-06-24 09:08:49 -07:00
Martin Atkins d1fb42746b cmd/zclfmt: new options for checking validity of input files 2017-06-24 09:02:30 -07:00
Martin Atkins aba54359ba cmd/zclfmt: zcl native syntax pretty-printer
This applies the simple native syntax reformatting function to one or
more files. It does not support JSON or any other syntax.

Calling applications might provide their own versions of this that e.g.
can format an entire directory by matching on filename patterns, but
this serves as an example and a utility for single files.
2017-06-24 09:02:11 -07:00
Martin Atkins e24fecb79d zclsyntax: ParseTraversalAbs function
This uses a subset of the expression syntax to allow representations of
traversals. The use-case for this is in applications that need to support
references to objects using familiar syntax without actually evaluating
those objects or dealing with the complexity of arbitrary expression
syntax.
2017-06-22 08:00:24 -07:00
Martin Atkins ef39087c4b zcl: beginnings of the spec for the syntax-agnostic model 2017-06-21 22:00:23 -07:00
Martin Atkins a05726630e json: beginnings of a JSON syntax specification document 2017-06-20 08:07:10 -07:00
Martin Atkins 6fcbd510c5 zclsyntax: beginnings of a language specification document 2017-06-18 19:34:25 -07:00
Martin Atkins a226ea120d zclsyntax: catch and test for more errors in for expressions 2017-06-18 09:36:06 -07:00
Martin Atkins b625d4b90e zclsyntax: test some more cases of unknowns in "for" 2017-06-18 09:13:48 -07:00
Martin Atkins 1ef7d6f6de zclsyntax: disallow dupe keys in "for" when grouping not enabled 2017-06-18 08:49:52 -07:00
Martin Atkins 2506450b6e zclsyntax: correct evaluation of the for expression "group" mode
This further alters the object-construction mode so that rather than
producing a flat object it instead produces an object of tuples. All
items that produce the same key are grouped together under the same
key in the result, allowing projections that flip the orientation of
a key/value sequence where the new keys are not necessarily unique.
2017-06-18 08:45:45 -07:00
Martin Atkins b83b6b27be zclsyntax: catch and test more erroneous use of "for" 2017-06-18 08:28:20 -07:00
Martin Atkins 61ebd9b65b zclsyntax: template "for" construct 2017-06-18 08:14:55 -07:00
Martin Atkins 833ff9ecd7 zclsyntax: evaluation of ForExpr into a tuple 2017-06-18 08:14:36 -07:00
Martin Atkins fdd68833f3 zclsyntax: template single-interpolation case as separate AST node
Rather than setting an "Unwrap" field on the existing TemplateExpr, we'll
instead use a separate, simpler AST node.

There is very little in common between these two cases, so overloading the
TemplateExpr node doesn't buy much. A separate node is needed here,
rather than just returning the wrapped node directly, to give us somewhere
to capture the full source range extent of the wrapping template, whereas
the inner expression only captures the range of itself. This is important
both for good diagnostics and for transforming zclsyntax AST into
zclwrite AST.
2017-06-18 07:44:57 -07:00
Martin Atkins e594a232b3 zclsyntax: change template control sequence introducer to %{
Previously it was !{, but in real examples this looked confusing since
an exclamation point after a word looks (to humans) like literal
punctuation rather than syntax.

% is not ideal either since it's also the marker traditionally used for
printf, but has the advantage that programmers are already primed for it
to be syntax.
2017-06-17 18:33:56 -07:00
Martin Atkins e7d33665d0 json: allow "//" keys to be used as comments in bodies
Since the native syntax requires that attribute names and block types
be identifiers, there is no way for "//" to be a valid symbol in a body.
Therefore we can special-case it here as an ignored property name that
users can then use for comments.

This special handling intentionally does not apply to objects representing
zcl object expressions, since it _is_ valid to have non-identifier keys
there and so "//" may be a legitimate object key for some applications.
2017-06-17 10:17:05 -07:00
Martin Atkins 15e3d80e6c zclsyntax: parsing of template if construct
Since this ultimately just returns a ConditionalExpr, the evaluation is
already implemented too.
2017-06-17 10:07:59 -07:00
Martin Atkins 2f1bfd284c zclsyntax: reorganize template parsing
Previously we tried to do the whole template parse in one pass. This was
adequate for dealing with literals and interpolations because they
create a flat structure, but to parse the template control sequences we
need to be able to deal with nested template sequences.

As a building block towards this, we first do a pass of extracting the
template-level "tokens": literals, interpolations, control sequences.
We then pass over that sequence of tokens and parse it, which is then
simplified because the larger template atoms have already been produced.
2017-06-17 09:05:15 -07:00
Martin Atkins d90da0c4ba zclsyntax: specific error message for nested attr-only splat
Attribute-only splat expressions cannot have other splats nested inside,
since we're only interested in supporting how these behaved for HIL when
running inside Hashicorp Terraform. More complex cases should be dealt
with using either full splats (bracketed *) or "for" expressions.
2017-06-16 08:39:28 -07:00
Martin Atkins 22bc5ce5c6 zclsyntax: parsing of "attribute-only" splat expressions
Attribute-only splat expressions, indicated by using the star symbol as
if it were an attribute, are inherited from HIL and are a limited sort of
splat that only works for walking through attributes in each item of its
source.

Later zcl will also get full splat expressions, whose syntax is using
the star symbol as if it were an _index_, which will generalize to
supporting _all_ postfix traversal operations, including indexing and
nested splats.
2017-06-16 08:33:35 -07:00
Martin Atkins 78db663590 zclsyntax: evaluation of splat expressions 2017-06-16 08:31:01 -07:00
Martin Atkins b2e6e2d0d0 zclsyntax: look in parent EvalContexts for functions
If we can't find a function in the given EvalContext, we must traverse
the context chain until either we run out of contexts or we find a
matching function.

At present there is no reason for a non-root context to have any
functions, so this will always traverse to the root. This may change in
future if we introduce constructs that define local functions.
2017-06-16 07:28:29 -07:00
Martin Atkins 4e18e3a8a8 zcl: allow nil Variables in EvalContext
it's acceptable to have "Variables" set to nil in an EvalContext, if
a particular scope has no variables at all. If _no_ contexts in the
chain have non-nil variables, this is considered to mean that variables
are not allowed at all, which produces a different error message.
2017-06-16 07:15:14 -07:00
Martin Atkins 4ab33cdce0 zclsyntax: "expanding" function arguments
This syntax func(arg...) allows the final argument to be a sequence-typed
value that then expands to be one argument for each element of the
value.

This allows applications to define variadic functions where that's
user-friendly while still allowing users to pass tuples to those functions
in situations where the args are chosen dynamically.
2017-06-15 08:18:00 -07:00
Martin Atkins fa06f40141 zclsyntax: ForExpr.Value implementation for object construction
The tuple path is not yet implemented and will panic.
2017-06-14 08:56:28 -07:00
Martin Atkins 0cf39f0f62 zclsyntax: FIXME to support parent ctx in function call 2017-06-14 08:54:53 -07:00
Martin Atkins 9340e6da4e zcl: TraverseAbs through parent scopes
An EvalContext can have a parent, so it's necessary to walk up until
the root is reached in case a parent scope defines the name we're
looking for.
2017-06-14 08:54:12 -07:00
Martin Atkins 51945b4e0c zclsyntax: In Variables, don't return traversals in child scopes
The purpose of the Variables function is to tell a calling application
what symbols need to be present in the _root_ scope, so it would be
unhelpful to include child scope traversals. Child scopes are populated
by the nodes that create them, and are thus not interesting to the
calling application (for this purpose, at least).
2017-06-14 08:03:32 -07:00
Martin Atkins bdfe5c1b11 zclsyntax: visit both LHS and RHS of binary op in walk
Due to a typo, it was previously visiting LHS twice, and destroying the
RHS by overwriting it by LHS.
2017-06-14 07:29:37 -07:00
Martin Atkins 6c7802d404 zclsyntax: Parsing of ForExpr
The ForExpr is essentially a list/map comprehension, allowing projecting
one expression into another. From a syntactic standpoint it's the most
complex structure we've dealt with so far, with many separate parts.

The tests introduced here are not exhaustive but illustrate that the
basic mechanism is working.
2017-06-13 08:53:33 -07:00
Martin Atkins 5ad092067b zclsyntax: Ellipsis and "fat arrow" tokens
These will be used in the "for" expression, and later ellipsis will also
be used within calls to expand tuples as args.
2017-06-13 08:50:20 -07:00
Martin Atkins e0c5f51bd5 zclsyntax: "Keyword" type
This is a helper for recognizing identifiers that are actually keywords.
2017-06-13 08:43:03 -07:00