Commit Graph

184 Commits

Author SHA1 Message Date
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
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
e100bf4723 zclsyntax: generate lexer diagnostics
There are certain tokens that are _never_ valid, so we might as well
catch them early in the Lex... functions rather than having to handle
them in many different contexts within the parser.

Unfortunately for now when such errors occur they tend to be echoed by
more confusing errors coming from the parser, but we'll accept that for
now.
2017-06-04 07:34:26 -07:00
Martin Atkins
c9ac91aa84 Add MissingItemRange to zcl.BodyContent
This allows code that only deals with BodyContent (post-decoding) to
still be able to report on missing items within the associated body while
providing a suitable source location.
2017-06-03 16:46:49 -07:00
Martin Atkins
cad3e7957f zclsyntax: Body.Content and Body.PartialContent 2017-06-03 09:04:16 -07:00
Martin Atkins
f9da844479 hclhil: use "Subject" rather than "Context" in structure diagnostics 2017-06-03 08:14:09 -07:00
Martin Atkins
da1f9950a6 zclsyntax: Body.JustAttributes implementation 2017-06-03 07:29:48 -07:00
Martin Atkins
aacf36abfd zclsyntax: permit arbitrary newlines inside template interpolations 2017-06-03 06:57:28 -07:00
Martin Atkins
c15eb86349 zclsyntax: require block definitions to end with a newline
Previously we ostensibly allowed block {}block {}, but now we'll reject
that.
2017-06-02 08:19:11 -07:00
Martin Atkins
4d6dbdbb37 zclsyntax: parsing of attributes within bodies 2017-06-02 08:12:33 -07:00
Martin Atkins
a1368a4d4d zclsyntax: parsing of function call expressions 2017-06-02 07:55:03 -07:00
Martin Atkins
e66e6a5f51 zclsyntax: add TokenComma TokenType 2017-06-02 07:40:42 -07:00
Martin Atkins
6052cb9938 zclsyntax: parse expressions in newline-ignoring mode
This applies both two the whole of bare expressions and to any nested
expressions within parentheses. The latter means that an attribute value
can span over multiple lines if it's wrapped in parens:

    foo = (
        1 + 2 + 3 + 4 + 5
    )
2017-06-02 07:26:45 -07:00
Martin Atkins
302487ce0f zclsyntax: template interpolation trimming
The ~ character can be used at the start and end of interpolation
sequences to trim off whitespace in neighboring literals, with the goal
of allowing extra whitespace to be included for readability without
including it in the resulting string.
2017-06-01 08:43:59 -07:00
Martin Atkins
fdfdfc4f3d zclsyntax: scan correctly closing ~} markers
Previously we were failing to return back to template-scanning mode due
to decrementing "braces" too early, causing the remainder of the template
to be scanned as if it were an expression.
2017-06-01 08:36:48 -07:00
Martin Atkins
8004488042 zclsyntax: public-facing ParseTemplate function
This allows calling applications to deal with bare templates, e.g. loaded
from separate files referenced in a main configuration.
2017-06-01 08:10:04 -07:00
Martin Atkins
8532fe32e6 zclsyntax: basic parsing and evaluation of string templates
Control sequences are not yet supported, but interpolation sequences work.
2017-06-01 08:01:12 -07:00
Martin Atkins
ab9bab3578 zclsyntax: parsing of the two unary operators 2017-06-01 07:05:22 -07:00
Martin Atkins
7f27d7b324 zclsyntax: parsing of boolean/null literals and root variable references 2017-06-01 06:56:45 -07:00
Martin Atkins
76d29e4031 zclsyntax: correct spelling of "parenthesis". 2017-06-01 06:42:04 -07:00
Martin Atkins
8f26a22933 zclsyntax: convert condition expr to bool in ConditionalExpr 2017-05-31 19:30:17 -07:00
Martin Atkins
085dff2472 zclsyntax: start of testing expression evaluation 2017-05-31 19:27:16 -07:00
Martin Atkins
3765519c52 zclsyntax: start of parsing expression terms
Just parenthesized expressions and errors so far.
2017-05-31 19:09:11 -07:00
Martin Atkins
9a380c6260 zclsyntax: first pass of parsing binary operations
Not actually tested yet, since it can't be used until parseExpressionTerm
works.
2017-05-31 18:54:54 -07:00
Martin Atkins
2fc14b729a zclsyntax: start of expression parsing
Conditional expression parsing is ostensibly implemented, but since it
depends on the rest of the expression parsers -- not yet implemented --
it cannot be tested in isolation.

Also includes an initial implementation of the conditional expression
node, but this is also not yet tested and so may need further revisions
once we're in a better position to test it.
2017-05-31 08:37:17 -07:00
Martin Atkins
3a0dec45a6 zclsyntax: enum for expression operations
Also includes the binary operator precedence table.
2017-05-31 07:39:23 -07:00
Martin Atkins
effa9a97b5 zclsyntax: add TokenPercent
This was missed on the first pass, and is needed for the modulo operator.
2017-05-31 07:31:49 -07:00
Martin Atkins
d003da232e zclsyntax: decode both quoted and unquoted string literals
This rewrite of decodeQuotedLit, now called decodeStringLit, is able to
handle both cases with a single function, and also now correctly handles
situations where double-$ and double-! are not followed immediately by
a { symbol, and must thus be treated literally.
2017-05-31 07:16:32 -07:00
Martin Atkins
f8bdda5ab9 zclsyntax: decoding of quoted string literal escape sequences 2017-05-30 19:38:31 -07:00
Martin Atkins
f94c89a6a5 zclsyntax: differentiate quoted and unquoted string literals
The context where a string literal was found affects what sort of escaping
it can have, so we need to distinguish these cases so that we will only
look for and handle backslash escapes in quoted strings.
2017-05-30 19:03:25 -07:00
Martin Atkins
57d8ff0c1b json: update tokentype_string for recent new token types 2017-05-30 19:01:40 -07:00
Martin Atkins
284eb635b9 zclsyntax: fix parser infinite loops on certain EOF cases
The recovery functions in particular were not all properly handling EOF,
so they would spin forever looking for the right place to stop.
2017-05-30 18:54:38 -07:00
Martin Atkins
db5167e3d8 zclsyntax: recoverAfterBodyItem implementation
This recovery method attempts to place the peeker directly after the
newline indicating the end of the current body item. It does this by
counting open and close bracketing constructs and then returning when
a newline is encountered with no bracketing constructs open.

It's designed for use in the "header" part of a body item, with no
bracketing constructs open yet. It _might_ work in other situations, but
is likely to end up choosing the wrong end point if used in the middle
of a bracketed expression that itself contains newlines.
2017-05-30 18:42:45 -07:00
Martin Atkins
9348014b2d zclparse: ParseZCL and ParseZCLFile methods
These are the top-level interface to parsing configuration files in the
native zcl syntax, similarly to the existing methods for parsing other
syntaxes.
2017-05-30 08:03:38 -07:00
Martin Atkins
e953e1c18a zclsyntax: parsing of nested blocks within bodies 2017-05-30 07:52:22 -07:00
Martin Atkins
2c90adb9e1 zclsyntax: track whether parser is in recovery mode
The parser has some recovery heuristics but they will not always achieve
the best result. To prevent unsuccessful recovery from causing a cascade
of confusing follow-on errors, we'll track in the parser whether recovery
has been attempted and then the specific sub-parsers can use this to
skip certain "unexpected token type" errors in recovery situations,
assuming instead that an earlier error will cover the problem and that
we just want to bail out quickly.
2017-05-30 07:51:55 -07:00
Martin Atkins
49aa35133f zclsyntax: helper for parsing literal quoted strings
The scanner produces complicated sequences for quoted strings due to the
template language, but sometimes we just want a simple string with no
interpolations.
2017-05-29 19:59:28 -07:00
Martin Atkins
cf3cd7f86d zclsyntax: don't allow quoted strings as attribute names
This will be allowed for object literals, but attributes are treated
differently to reinforce the fact that they have a predefined structure.
2017-05-29 19:58:45 -07:00
Martin Atkins
954939b49f zclsyntax: initial pass at body parsing
Only able to parse empty bodies so far.
2017-05-29 19:28:10 -07:00
Martin Atkins
14d256467a zclsyntax: peeker methods to get next and previous token ranges 2017-05-29 19:01:37 -07:00
Martin Atkins
23cb83ef3e zclsyntax: "peeker" helper
This will make it easier for the parser to walk through the token sequence
with one token of lookahead, maintaining state of where we've got to and
also allowing us to switch into and out of the newline-sensitive mode
as we transition to and from newline-sensitive constructs.
2017-05-29 18:09:58 -07:00
Martin Atkins
1a6dfffc4a zclsyntax: Stub public interface for parsing
Mirroring the Lex... triplet of functions, callers here can choose to
parse in one of three modes:

- ParseConfig is the main entry point and parses what we might consider
  a whole config file.

- ParseExpression parses a sequence as an isolated expression, which
  may be useful in implementing a REPL to inspect configuration or
  application state.

- ParseTemplate parses a sequence as an isolated template, which may be
  useful in parsing external files as templates, for situations where the
  input is too large to be conveniently embedded within configuration.
2017-05-29 17:19:23 -07:00
Martin Atkins
476e2c127e zclwrite: convert zclsyntax tokens into zclwrite tokens
In zclwrite we throw away the absolute source position information and
instead just retain the number of spaces before each token. This different
model allows us to rewrite parts of the token sequence without needing
to re-adjust all of the positions, and it also allows us to do simple
indentation and spacing adjustments just by walking through the token
list and adjusting these numbers.
2017-05-29 16:59:20 -07:00
Martin Atkins
865a5d8831 zclsyntax: public interface to the scanner
This LexConfig, LexExpression and LexTemplate set of functions allow
outside callers to use the scanner in isolation, skipping the parser.
This may be useful for use-cases such as syntax highlighting, separate
parsers (such as the one in zclwrite), and so forth. Most callers should
use the parser (once implemented) though, to get a semantic AST.
2017-05-29 16:17:07 -07:00
Martin Atkins
7ac858e3f5 zclsyntax: scanning of bare (top-level) templates
This alternative scanning mode makes the scanner start in template
context rather than normal context. This will be later used by the parser
to allow parsing of standalone templates that aren't embedded inside a
zcl configuration file.
2017-05-29 09:42:20 -07:00
Martin Atkins
f1c91b8eea zclsyntax: detect newlines during scanning
This is important because our syntax for objects uses newlines as the
separator between items, so this is the only signal we'll get that a
given item has ended and another is beginning.
2017-05-29 09:25:21 -07:00
Martin Atkins
861d0a1b4e zclsyntax: scanning of comments 2017-05-29 09:13:35 -07:00
Martin Atkins
2551856d22 zclsyntax: heredoc support in the scanner 2017-05-29 08:55:53 -07:00
Martin Atkins
4a939a2b46 zclsyntax: allow scanner to support multiple modes
A scanner "mode" decides which state it starts in, allowing us to start
in template mode for parsing top-level templates. However, currently the
only mode implemented is "normal" mode, which is the behavior we had
before.
2017-05-28 15:44:22 -07:00
Martin Atkins
da874ba0ff zclsyntax: disallow newlines in string templates
Heredocs will deal with the multiline string case once implemented.
2017-05-28 15:35:55 -07:00
Martin Atkins
18e45ec05c zclsyntax: scanner support of string templates
This requires some extra state-keeping because we allow templates to be
nested inside templates. This takes us outside of the world of regular
languages, but we accept that here because it makes things easier to
deal with down the line in the parser.

The methodology is to keep track of how many braces are open at a given
time and then, when a nested template interpolation begins, record the
current brace level. Then, when a closing brace is encountered, if its
nesting level is at the top of the stack then we pop off the stack and
return to "main" parsing mode.

Ragel's existing idea of calling and returning from machines is important
here too. As this currently stands this is not actually needed, but once
heredocs are in play we will have two possible places to return to at
the end of an interpolation sequence, so the state return stack maintained
by Ragel will determine whether to return to string mode or heredoc mode.
2017-05-28 15:33:01 -07:00
Martin Atkins
c50317a2e0 zclsyntax: scan multi-character punctuation tokens 2017-05-28 09:40:58 -07:00
Martin Atkins
bb87c7a0f9 zclsyntax: heredoc to be separate start/end tokens
Just as we have OQuote and CQuote, we need the same for heredocs so that
we can parse their contents as templates that may span multiple tokens.
2017-05-28 09:36:32 -07:00
Martin Atkins
5898b36695 zclsyntax: scan single-character tokens that represent themselves
For convenience we use the rune values of these tokens as their token
enum values, so we can handle them all via a single rule.
2017-05-28 09:34:20 -07:00
Martin Atkins
53944335f1 zclsyntax: identifiers in the scanner 2017-05-28 09:16:53 -07:00
Martin Atkins
6362354c87 zclsyntax: scanning of numeric literals 2017-05-28 08:56:43 -07:00
Martin Atkins
187d7b8045 zclsyntax: re-organize and simplify the scanner 2017-05-28 08:38:13 -07:00
Martin Atkins
b8db08bf04 zclsyntax: use stringer for TokenType stringification 2017-05-28 07:38:17 -07:00
Martin Atkins
63fcfd6b7d zclsyntax: include a token for the end of a template sequence
Although this end symbol appears as just a close-brace in source, it's
worth differentiating it because the scanner must differentiate it anyway
(to recognize moving back into template-scanning mode) and it avoids the
parser from having to similarly re-recognize the difference.
2017-05-28 07:20:39 -07:00
Martin Atkins
76c0ca70f0 zclsyntax: scanner to return whole token slice at once
On reflection, it seems easier to maintain the necessary state we need
by doing all of the scanning in a single pass, since we can then just
use local variables within the scanner function.
2017-05-28 07:11:24 -07:00
Martin Atkins
d57901de5f zclsyntax: start of a ragel-based scanner
Using Ragel here because the scanner is going to be somewhat complex due
to the need to switch back and forth between normal and template states,
etc. This should be easier to maintain than a hand-written scanner, while
ragel gives us the extra features we need to implement things that would
normally be too complex for a "regular" scanner generator.
2017-05-27 19:01:43 -07:00
Martin Atkins
e65eafbe83 zclsyntax: define the initial set of language tokens for the scanner 2017-05-27 19:00:00 -07:00
Martin Atkins
6bf26fc9cc Update cty references to its new home in the zclconf github account 2017-05-27 17:35:44 -07:00
Martin Atkins
308eb3a291 Relocate into the "zclconf" github account 2017-05-27 17:33:09 -07:00
Martin Atkins
42b18cc7c6 json: count whole grapheme clusters as columns for position purposes
This means we can actually point at a column in the console without it
getting misaligned by multi-byte UTF-8 sequences and Unicode combining
characters.
2017-05-27 17:10:51 -07:00
Martin Atkins
2b442985cd zclsyntax: FunctionCallExpr.Value
This is the first non-trivial expression Value implementation. Lots of
code here, so hopefully while implementing other expressions some
opportunities emerge to factor out some of these details.
2017-05-25 08:14:43 -07:00
Martin Atkins
8437058b60 zclsyntax: "Did you mean ...?" helper function 2017-05-25 07:14:29 -07:00
Martin Atkins
31caa36b9a zclsyntax: stub of FunctionCallExpr
This was added mainly just to spin the wheels of the Variables method
generator. Its implementation is not yet complete.
2017-05-24 08:51:34 -07:00
Martin Atkins
bae8f83298 zclsyntax: Generate "Variables" implementations for all Expressions
The implementation of Variables will be identical for every Expression
implementation since we just wrap our AST-walk-based "Variables" function
to do the work.

Rather than manually copy-pasting the declaration for each expression
type, instead we'll generate this programmatically using "go generate".
This will need to be re-run each time a new expression node type is
added, in order to make it actually implement the Expression interface.
2017-05-24 08:50:44 -07:00
Martin Atkins
007b38797b zclsyntax: Expression.Variables implementation using AST walk
This function is effectively the implementation of Variables for all
expressions, but unfortunately we still need to declare a wrapper around
it as a method on every single expression type.
2017-05-24 08:05:52 -07:00
Martin Atkins
dabdb3d059 zclsyntax: Structural AST nodes (blocks, bodies, etc) 2017-05-24 08:04:54 -07:00
Martin Atkins
e957bff8de zclsyntax: Start to stub out the zclsyntax package
This package will grow to contain all of the gory details of the native
zcl syntax, including it AST, parser, etc. Most callers should access
this via the simpler API in the top-level package, which then gives
automatic support for other syntaxes too.
2017-05-23 08:05:44 -07:00
Martin Atkins
1535d4b708 Ability to look up the variables in an expression 2017-05-22 18:54:23 -07:00
Martin Atkins
73b5ba8089 TraverseSplat Traverser placeholder
This will eventually deal with splats in traversals, but isn't yet
properly implemented.
2017-05-22 18:48:06 -07:00
Martin Atkins
a2d829cafc TraverseIndex traverser implementation 2017-05-22 17:54:58 -07:00
Martin Atkins
c1815fd6e4 Start of work on Traversals
Traversals are a generalized way to talk about paths taken from the scope
and from arbitrary values. These will be used for various analysis tasks,
such as determining what needs to be placed into a scope.
2017-05-22 08:05:19 -07:00
Martin Atkins
2c0a126fe6 hclhil: documentation typo 2017-05-21 22:37:15 -07:00
Martin Atkins
2cfc08c632 json: Allow strings to be treated as HIL templates
Eventually zcl will have its own native template format that we'll use
by default, but for applications migrating from HCL/HIL we can instead
parse strings as HIL templates, for compatibility with how JSON configs
would've been processed in a HCL/HIL app.

When this mode is not enabled, we still just treat strings as literals,
pending the implementation of the zcl template parser.
2017-05-21 22:34:23 -07:00
Martin Atkins
e4fdbb6b15 hclhil: interface to treat HIL templates as expressions 2017-05-21 22:09:17 -07:00
Martin Atkins
fde586e193 hclhil: Expression.Value implementation
Currently only deals with the literal HCL structure. Later we will also
support HIL parsing and evaluation within strings, to achieve parity with
existing uses of HCL/HIL together. For now, this has parity with uses of
HCL alone, with the exception that float and int values are not
distinguished, because cty does not make this distinction.
2017-05-21 18:42:39 -07:00
Martin Atkins
0b8f6498ff hclhil: Body.Content and Body.PartialContent implementations 2017-05-21 17:45:31 -07:00
Martin Atkins
764e4c465b hclhil: Parsing and JustAttributes for HCL 2017-05-21 16:13:04 -07:00
Martin Atkins
c5df265cd0 Define Body.JustAttributes as returning Attributes
This was missed when updating the previous direct references to
map[string]*Attribute.
2017-05-21 15:43:41 -07:00
Martin Atkins
e765ff422a zclparse: Stub API for HCL/HIL file parsing
This is intended as a backward-compatibility interface, allowing
applications that previously used HCL/HIL to adopt zcl while still being
able to parse their old HCL/HIL-based configuration file formats.
2017-05-21 13:04:33 -07:00
Martin Atkins
cd019809a4 json: detect and report insufficient object levels for block labels
When decoding a block with labels, the right number of object levels must
be present to populate the labels.
2017-05-21 12:42:42 -07:00
Martin Atkins
8654cf0361 Body.MissingItemRange method
When producing diagnostics about missing attributes or bodies it's
necessary to have a range representing the place where the missing thing
might be inserted.

There's not always a single reasonable value for this, so some liberty
can be taken about what exactly is returned as long as it's somewhere
the user can relate back to the construct producing the error.
2017-05-21 11:46:58 -07:00
Martin Atkins
5fa767a43a json: mark properties as used after blocks are decoded from them 2017-05-21 11:03:47 -07:00
Martin Atkins
64c1036f80 Remove "ExprRange" from zcl.Attribute
Now that expressions themselves have Range and StartRange methods, this
is redundant.
2017-05-21 09:50:29 -07:00
Martin Atkins
4fcad1f493 json: Respect hiddenAttrs in JustAttributes
Previously it was leaking out hidden attributes.
2017-05-21 09:46:50 -07:00
Martin Atkins
a291478c78 "Attributes" type for map[string]*Attribute
This is primarily for symmetry with "Blocks", but perhaps it will also
get some useful methods later.
2017-05-21 09:05:06 -07:00
Martin Atkins
bb5044d015 Range and StartRange methods on Expression
This gives us some contextual information to use for error handling when
working generically with expressions.
2017-05-20 17:40:03 -07:00