Files
Oliver Calder 8fc33dd912 i/prompting: render path patterns variants using recursive descent parser (#14059)
* i/prompting: implement path pattern expansion

Path patterns may include arbitrary nested groups, delimited by '{' and
'}', up to a limit on the total number of groups. In order to compare
the precedence of path patterns which match a given path, these path
patterns must be expanded until no groups remain, and thus the
particular group-free patterns which was resolved from the original
patterns when matching the path can be compared.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting: add PathPattern type for pattern validation and expansion

Rather than separately validate and expand path patterns, storing the
result as a list of expanded patterns, parse a pattern into a
PathPattern type, which can dynamically render expanded path patterns as
needed with minimal overhead.

When path patterns are received from prompting clients, path patterns
can be unmarshalled and automatically validated, and any future use of
the pattern in-memory can use the pre-parsed PathPattern to iterate
through expanded path patterns without needing to explicitly expand and
store all path patterns.

Additionally, the new PathPattern type should be used in Constraints in
place of the old path pattern string.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting: refactor path pattern parsing

Rather than keep separate stacks for the sequences and paths which the
parser is currently inside, instead keep a single stack, to which the
existing sequence and a new group is added whenever a '{' rune is
encountered.

Then there is no need to no need for a variable to hold the current
group, peeking the stack yields the most recent group, to which the
current sequence can be added whenever a ',' or '}' is encountered.

When a '}' is encountered, the most recent group is popped off the
stack, the current sequence is added to it (completing the group), and
then the previous sequence is popped off the stack and the completed
group is added to it. From there, that previous sequence is now
considered the current sequence until another '{' is encountered.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting: use stack instead of non-temp current sequence variable

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting: improve error message prefixes

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting: moved patterns to dedicated subpackage of prompting

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: add scanner, parser, and renderer for path patterns

Co-authored-by: Oliver Calder <oliver.calder@canonical.com>
Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: add minimal tests for scan and render

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: replace parser in path pattern struct

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: add recursion depth check for nested groups

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: adjusted error messages

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: preserve escape characters in expanded patterns

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: scanner detects invalid chars and returns error

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting: fix formatting

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: add helper for converting read runes into text token

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: consolidate render node types into render.go

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: only re-render differences from previous configuration

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: remove GoString functions from render config types

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting{,/patterns}: added dedicated Match method to PathPattern

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: unexport all internal types and interfaces

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: rename renderConfig to variantState

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: unexported internal renderAllVariants

Also improved naming and documentation.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: renamed local variables to match new variantState naming

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: variantState has Render method and renderNode

Add a reference to the `renderNode` used to generate a given
`variantState` to that state itself. This allows methods on
`variantState` to be called without needing to pass as a parameter the
same `renderNode` which was used to generate the `variantState`.

Also, move the `Render` function to be a method on `variantState`
instead of `renderNode`. This makes sense semantically, since we render
particular variants, rather than nodes themselves, and makes sense
ergonomically since we now have a reference to the `renderNode` within
each `variantState`, so there is no need to pass parameters around for
nodes and variants which are required to be associated anyway.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: consolidate optimize and fix nodeEqual

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: add tests for tokenType.String

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: use dedicated flag to tell when all seq variants are exhausted

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: use ..._internal_test.go for non-exported test files

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: fix growing of render buffer, unexport peek

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: merge literalVariant into literal

Add comment as such to the `literal` type definition, and have
`literal.NextVariant` return length 0 to make it consistent with other
`variantState` types.

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: preallocate render buffer for initial variant

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: improve error handling

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: moved simple bad pattern checks to scanner

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: return length along with initial variant

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

* i/prompting/patterns: simplify check if more variants remain when rendering

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>

---------

Signed-off-by: Oliver Calder <oliver.calder@canonical.com>
Co-authored-by: Zygmunt Krynicki <me@zygoon.pl>
2024-06-28 13:16:11 -05:00
..