augeas

Iterated lens leads to 'ambiguous tree iteration'


While writing a lens for Deckard tests I ran into a problem.

This lens

let eol = ws . ((del /[;#]/ ";" . [label "#comment" . store /[^\n]*/] 
          . del_str "\n") | (del_str "\n"))* . del_str "\n"

results in this error:

$ augparse /usr/share/augeas/lenses/dist/deckard.aug
Syntax error in lens definition
/usr/share/augeas/lenses/dist/deckard.aug:22.0-.119:Failed to compile eol
/usr/share/augeas/lenses/dist/deckard.aug:22.15-.104:exception: ambiguous tree iteration
  Iterated regexp: /     { /#comment/ = /[^\001-\004\n]*/ }
  | ()/
  ' { "#comment" }' can be split into
  '|=| { "#comment" }'

 and
  ' { "#comment" }|=|'

Iterated lens: /usr/share/augeas/lenses/dist/deckard.aug:22.15-.102:

I can't get my head around the notation of Augeas' tree -> plaintext exception notation so I have no idea what is augparse trying to say.

Can anyone help me with an explanation or fix for the lens?


Solution

  • What Augeas is trying to say here is the following: it was trying to match a tree to this pattern

    /{ /#comment/ = /[^\001-\004\n]*/ } | ()/
    

    For the tree -> text direction, Augeas talks about how it matches tree nodes. That notation uses { LABEL_RX = VALUE_RX } to indicate that it tries to match a tree node whose label matches LABEL_RX and whose value matches VALUE_RX — the children of a tree node are never used for matching. The first part of the above pattern (before the |) matches a tree node whose label is #comment and whose value matches [^\001-\004\n]*. (The \001-\004 is in there for internal reasons, and Augeas 1.9 will suppress them) The second part matches (), Augeas' way to say 'nothing'.

    The fact that it talks about iteration means that it found the above construct in an iteration, i.e. something that has a * after it.

    What it is having trouble with is that if it sees a tree node { "#comment" }: it can't decide whether it should first match the () nothing part and then the #comment part or vice versa. Since matching the nothing part can cause things to be put into the output (in this case, the \n from the del_str lens), Augeas throws its hands up and complains about it.

    One way out of this is to modify the lens like this:

    let eol = ws . 
            (del /[;#]/ ";" . [label "#comment" . store /[^\n]*/] . del_str "\n")* .
            del_str "\n"
    

    This gets rid of the 'ambiguous tree iteration', at the price that empty lines also create #comment nodes (without values) in the tree. But that's probably acceptable.