Commit Graph

241 Commits

Author SHA1 Message Date
Martin Atkins
54fcc09ed4 zclsyntax: AST node for the "for" expression
This expression is used to project collections into other collections.
2017-06-13 08:42:36 -07:00
Martin Atkins
b878a4ef98 json: parse strings as zclsyntax templates
This is the same idea as our existing HIL template support, but uses the
zclsyntax template parser instead of HIL's parser.
2017-06-12 07:25:09 -07:00
Martin Atkins
a0be779c9c zclsyntax: operation failure diagnostics apply to whole expr 2017-06-12 07:14:09 -07:00
Martin Atkins
9be04673c3 zclsyntax: UnaryOpExpr.Value 2017-06-12 07:13:17 -07:00
Martin Atkins
e709d7bcc0 zclsyntax: operations are now pointers to a struct value
Previously operations were an enum, but we've ended up needing to store
a collection of values against each, so an operation being a pointer to
a struct feels more natural.

This in turn allows us to more easily fix the return types of the
operations, so that we don't need to do any unusual work to understand
that (for example) arithmetic always returns a number.
2017-06-12 07:09:24 -07:00
Martin Atkins
c332084224 zclsyntax: BinaryOpExpr.Value 2017-06-11 18:55:27 -07:00
Martin Atkins
e69036995d zclwrite: Body.FindAttribute implementation 2017-06-11 18:24:15 -07:00
Martin Atkins
09f9e6c8e8 zclsyntax: deal with template unwrapping at eval time
Previously we were detecting the exactly-one-part case at parse time and
skipping the TemplateExpr node in the AST, but this was problematic
because we then misaligned the source range for the expression to the
_content_ of the quotes, rather than including the quotes themselves.

As well as producing confusing diagnostics, this also caused problems for
zclwrite since it relies on source ranges to map our AST back onto the
source tokens it came from.
2017-06-11 08:39:40 -07:00
Martin Atkins
e571ec5810 zcl: Range.String should not be a pointer method
We don't usually use ranges as pointers, except in diagnostics.
2017-06-11 08:37:28 -07:00
Martin Atkins
cb768a591a zclwrite: parsing of blocks
There's something a little off here, as illustrated by the failing
round trip test. Will figure that out later.
2017-06-10 17:16:19 -07:00
Martin Atkins
948b2e0b7b zclwrite: populate EOLTokens when parsing attributes 2017-06-10 16:06:09 -07:00
Martin Atkins
1565d4f906 zclwrite: formatting round-trip test
The existing round trip test was testing that we can pass through a set
of tokens through the AST entirely unmodified.

This new round-trip test passes the source through the Format function
and then checks that it has the same semantics, by evaluating it both
before and after and expecting an identical set of values.
2017-06-10 14:14:01 -07:00
Martin Atkins
ac42b456f3 zclwrite: "format" implementation
This tweaks the number of spaces before each token to create a consistent
layout. It doesn't (yet?) attempt to add or remove line breaks or
otherwise mess with the non-space characters in the code.

The main goal here is to get things to line up. zcl syntax is simple
enough that there's not much latitude for super-weird usage, and so if
someone does manage to write something weird (asymmetric breaking of
brackets between lines, etc) we won't try to fix it here.
2017-06-10 14:11:47 -07:00
Martin Atkins
040160f3f9 zclwrite: line/cell splitting for "format"
Our approach here is to split the input into lines and then to split
each line into up to three cells which, when present, should have their
leftmost characters aligned (eventually) by the formatter.
2017-06-10 07:47:15 -07:00
Martin Atkins
a523846abd zclwrite: start to stub out the mutation API
These new stub methods will allow dealing with attributes within a body.
2017-06-09 08:31:14 -07:00
Martin Atkins
5477fecfad zclsyntax: require newlines after block items
Previously we tolerated EOF as an alias for newline, but a file without
a newline at the end is a edge case primarily limited to contrived
examples in unit tests, and requiring it simplifies tasks such as code
generation in zclwrite, since we can always assume that every block item
comes with a built-in line terminator.
2017-06-09 08:19:47 -07:00
Martin Atkins
1de72e146e zclwrite: consume trailing line comments and newlines in body items
We consume both of these things primarily so that when we manipulate
the AST they will all stay together. For example, removing an attribute
from a body should take its comments and newline too.
2017-06-09 08:00:38 -07:00
Martin Atkins
755fe38505 zclsyntax: peeker pretends single-line comments are newlines
When we're skipping comments but retaining newlines, we need to do some
slight-of-hand because single-line comment tokens contain the newline
that terminates them (for simpler handling of lead doc comments) but our
parsing can be newline-sensitive.

To allow for this, as a special case we transform single-line comment
tokens into newlines when in this situation, thus allowing parser code
to just worry about the newlines and skip over the comments.
2017-06-09 07:19:25 -07:00
Martin Atkins
c88641b147 zclwrite: absorb lead comments into attributes
The native parser's ranges don't include any surrounding comments, so we
need to do a little more work to pick them out of the surrounding token
sequences.

This just takes care of _lead_ comments, which are those that appear as
whole line comments above the item in question. Line comments, which
appear after the item on the same line, will follow in a later commit.
2017-06-08 09:04:27 -07:00
Martin Atkins
7609327736 zclwrite: Rename "Parse" to "ParseConfig"
This is mainly for symmetry with the API of zclsyntax, but also later
we'll probably have a ParseExpression function that can be used to make
edits to individual expressions.
2017-06-07 08:28:43 -07:00
Martin Atkins
13c93e974f zclwrite: initial attribute and basic expression parsing
This is not yet complete, since it fails to capture the newline, line
comments, and variable references in expressions. However, it does
capture the broad structure of an attribute, along with gathering up
all of its _interior_ tokens.
2017-06-07 08:24:33 -07:00
Martin Atkins
15b38d8a48 zclwrite: correct silly misplaced colon in round_trip_test 2017-06-07 08:01:30 -07:00
Martin Atkins
33c3d6e5ad zclwrite: standardize on TokenSeq for all node parts
We'll use TokenSeq for everything, including sequences we expect to
contain only one token, mainly for consistency but also so that our local
"parser" doesn't need to care about whether the main parser is returning
one token or many.
2017-06-07 07:41:39 -07:00
Martin Atkins
ed2a739cdb zclwrite: Don't crash if EachToken called on a nil TokenSeq. 2017-06-07 07:39:01 -07:00
Martin Atkins
69a87c73b4 zclwrite: start to partition body items
So far they are still just all unstructured, but each item is a separate
node.
2017-06-07 07:38:44 -07:00
Martin Atkins
363d08ed0d zclwrite: File-level AllTokens
This captures any leftover tokens that aren't considered part of the
file's main body, such as the trailing EOF token.
2017-06-07 07:37:56 -07:00
Martin Atkins
fa8a707c7f zclwrite: begin to flesh out public interface 2017-06-07 07:24:10 -07:00
Martin Atkins
598740b638 zclwrite: method for writing tokens to a writer
This now allows for round-tripping some input from bytes to tokens and
then back to bytes again. With no other changes, we expect this to produce
an identical result.
2017-06-07 07:06:23 -07:00
Martin Atkins
efbcfd19b2 zclwrite: TokenGen interface has EachToken, not AppendToTokens
Although building a flat array of tokens is _one_ use-case for TokenGen,
this new approach means we can also use the interface to write to an
io.Writer without needing to produce an intermediate buffer.
2017-06-07 06:45:01 -07:00
Martin Atkins
c233270a9b zclwrite: use a single, flat writer token buffer
Previously we were allocating a separate heap object for each token, which
creates a lot of small objects for the GC to manage. Since we know that
we're always converting from a flat array of native tokens, we can produce
a flat array of writer tokens first and _then_ take pointers into that
array to achieve our goal of making a slice of pointers.

For the use-case of formatting a sequence of tokens by tweaking the
"SpacesBefore" value, this means we can get all of our memory allocation
done in a single chunk and then just tweak the allocated, contiguous
tokens in-place, which should reduce memory pressure for a task which
will likely be done frequently by a text editor integration doing "format
on save".
2017-06-07 06:38:41 -07:00
Martin Atkins
3c0dde2ae5 zclwrite: foundations of the writer parser
The "writer parser" is a parser that produces a writer AST rather than
a zclsyntax AST. This can be used to produce a writer AST from existing
source in order to modify it before writing it out again.

It's implemented with the somewhat-unintuitive approach of running the
main zclsyntax parser and then mapping the source ranges it finds back
onto the token sequence to pull out the raw tokens for each object.
This allows us to avoid maintaining two parsers but also keeps all of
this raw-token-wrangling complexity out of the main parser.
2017-06-06 08:53:13 -07:00
Martin Atkins
34be20cc5d zclsyntax: ScopeTraversalExpr.Value implementation, and tests 2017-06-05 08:02:54 -07:00
Martin Atkins
68aa56c795 zcl: Implement Traversal.TraverseAbs 2017-06-05 07:55:33 -07:00
Martin Atkins
ace387f5f9 zclsyntax: evaluation of relative traversal and index nodes 2017-06-05 07:41:02 -07:00
Martin Atkins
b604827bb2 zcl: Automatically convert key types when indexing
For example, if a map is indexed with a number then we'll automatically
convert it to string before attempting to use it as an index.
2017-06-05 07:39:14 -07:00
Martin Atkins
36eacf5110 zcl: Factor the index operation out into its own function
Indexing is pretty fundamental and it's also non-trivial, so having this
exposed will make it easier for it to be implemented consistently across
many different callers, including within calling applications.
2017-06-05 07:31:59 -07:00
Martin Atkins
0266334560 zclsyntax: handle case where functions are not allowed
Previously this would panic.
2017-06-05 07:31:09 -07:00
Martin Atkins
bca573d3d0 zclsyntax: parsing of the index operator
This can either be a traversal or a first-class node depending on whether
the given expression is a literal. This exception is made to allow
applications to conditionally populate only part of a potentially-large
collection if the config is only requesting one or two distinct indices.

In particular, it allows the following to be considered a single traversal
from the scope:

    foo.bar[0].baz
2017-06-05 07:09:04 -07:00
Martin Atkins
8fc5bd5141 zclsyntax: run stringer after other generators
stringer is more sensitive to certain errors than other generators, so
by running it last we give the other generators a chance to get things
straight before we ask stringer to run.
2017-06-05 07:04:26 -07:00
Martin Atkins
b5471b9715 zclsyntax: beginnings of parsing traversal operators
Traversal operators are the operators that can appear after a value
to traverse into the data structure that value represents. So far only
the attribute access operator is implemented.
2017-06-04 18:41:16 -07:00
Martin Atkins
0d0404867c zclsyntax: RelativeTraversalExpr
This is similar to ScopeTraversalExpr, but it traverses relative to the
result of another expression rather than relative to a variable in the
scope.
2017-06-04 18:40:15 -07:00
Martin Atkins
6f2bd0009c zclsyntax: parsing and evaluation for object constructors 2017-06-04 16:14:02 -07:00
Martin Atkins
cac847b163 zclsyntax: separate tokens for assign = and equality test == 2017-06-04 16:00:40 -07:00
Martin Atkins
c3f4694e06 zclsyntax: parsing and evaluation of tuple constructors 2017-06-04 14:22:51 -07:00
Martin Atkins
4488df0cd8 zclsyntax: create comma tokens in the scanner 2017-06-04 14:22:27 -07:00
Martin Atkins
cd85a1f0a6 zcldec: convert AttrSpec results to the given type 2017-06-04 13:22:03 -07:00
Martin Atkins
446387109d zcldec: AttrSpec should return null for missing attributes
Previously it was returning DynamicVal, but that's incorrect since it
would mean that even an otherwise-complete result that has an unpopulated
optional attribute would include an unknown.
2017-06-04 13:05:35 -07:00
Martin Atkins
c9c2a2bd16 zclsyntax: Implement the ContextString interface on our Nav
This allows tooling to get a string describing the context of a particular
offset into the file. This is used, for example, to provide context
above the source code snippets in console-printed diagnostic messages.
2017-06-04 09:52:16 -07:00
Martin Atkins
6f1cf4465d zcl: Range.ContainsOffset should not have pointer receiver 2017-06-04 09:37:37 -07:00
Martin Atkins
44670ddd50 zclparse: keep ParseZCL results in the files registry
This is important to make the source code and context available for
printing diagnostics.
2017-06-04 09:02:41 -07:00