[augeas-devel] Fixing ambiguous iteration errors

David Lutterkort lutter at redhat.com
Fri Nov 18 00:35:39 UTC 2011


On Mon, 2011-10-31 at 18:29 -0400, Tom Limoncelli wrote:
> Thanks for the help so far.  I took your advice and looked at json.aug
> for inspiration.

Welcome back to the worlds slowest-moving mail thread. Sorry about the
huge delay.

> Currently I keep getting:
> Syntax error in lens definition
> ./xendconfsxp.aug:31.0-.50:Failed to compile lns
> ./xendconfsxp.aug:31.12-.30:exception: overlapping lenses in tree union.put
>     Example matched by both:
>     First lens: ./xendconfsxp.aug:29.12-.55:
>     Second lens: ./xendconfsxp.aug:16.17-.36:
> 
> The example is blank.  I'm not sure if that means "\n" or "" or if
> this is a bug.

It literally means 'no tree', in C, a NULL pointer. Might need a better
textual representation. Because:

>     31	let lns = ( sexpr | empty_line | no_ws_comment ) *

Both empty_line and no_ws_comment are essentially 'del something'. That
means they produce no tree (NULL pointer). When Augeas goes from tree ->
file (that's what the words 'tree' and 'put' try to indicate in the
error message, suggestions to improve htem most welcome), and it finds a
tree node produced by sexpr it doesn't know whether it should go
straight to doing sexpr, or if it should do, for example, 'empty_line .
no_ws_comment . sexpr . empty_line'; both produce a tree in the file ->
tree direction that's identical to just plain sexpr.

I've changed the lens so that it passes typechecking, and modified some
of the tests to pass (sorry, don't have more time to finish fixing up
the tests tonight) Let me know if you want me to do that.

> I can narrow the problem down to an even more simple case.  At least I
> think this is the same:
> 
> module Foo =
>   let ws = del /[ \t\n]+/ " "
>   let a = key /a+/
>   let b = [ label "b" . store /b+/ ]
>   let lns = ws | a | b
> 
>   test lns get "aaa bbb " = ?

Yes, that's the same (well, almost, if you write 'let a = del /a+/ "a"'
it is )

> I'm unclear what I'm doing wrong.  Suggestions?

I hope my explanation made that a little clearer. And I promise to
respond more quickly in the future ;)

David

-------------- next part --------------
module Test_xendconfsxp =


 (* Empty file and comments *)

let source_0 = "\n"
 test Xendconfsxp.lns get source_0 = { }

 test Xendconfsxp.lns get "# my comment\n" =
   { "#comment" = "my comment" }

 test Xendconfsxp.lns get " \n# my comment\n" =
   { }
   { "#comment" = "my comment" }

 test Xendconfsxp.lns get "# my comment\n\n" =
   { "#comment" = "my comment" }
   { }

 test Xendconfsxp.lns get "# my comment\n \n" =
   { "#comment" = "my comment" }
   { }

 test Xendconfsxp.lns get "# my comment\n#com2\n" =
   { "#comment" = "my comment" }
   { "#comment" = "com2" }

 test Xendconfsxp.lns get "# my comment\n\n" =
   { "#comment" = "my comment" }
   { }

 test Xendconfsxp.lns get "\n# my comment\n" =
   { }
   { "#comment" = "my comment" }

 test Xendconfsxp.lns get "(key value)" =
  { "key" { "item" = "value" } }

 test Xendconfsxp.lns get "(key value)\n# com\n" =
   { "key" { "item" = "value" } }
   { }
   { "#comment" = "com" }

 test Xendconfsxp.lns get "(k2ey value)" =
   { "k2ey" { "item" = "value" } }

(* These are invalid *)
 test Xendconfsxp.lns get "(- value)" = *
 test Xendconfsxp.lns get "(-bar value)" = *

 test Xendconfsxp.lns get "(k-ey v-alue)\n# com\n" =
   { "k-ey" { "item" = "v-alue" } }
   { }
   { "#comment" = "com" }

 test Xendconfsxp.lns get "(key value)" =
   { "key" { "item" = "value" } }

 test Xendconfsxp.lns get "(key value)(key2 value2)" =
   { "key" = "value" }
   { "key2" = "value2" }

 test Xendconfsxp.lns get "( key value )( key2 value2 )" =
   { "key" = "value" }
   { "key2" = "value2" }

 let source_7 = "(key value)(key2 value2)"
 test Xendconfsxp.lns get source_7 =
   { "key" = "value" }
   { "key2" = "value2" }

(* 2 items?  it is a key/value *)

 test Xendconfsxp.lns get "(key value)" =
   { "key" = "value" }

 test Xendconfsxp.lns get "( key value )" =
   { "key" = "value" }

(* 3 items?  Not allowed. 2nd item must be in ()'s *)
test Xendconfsxp.lns get "(key value value2)" = *

(* key/list pairs. *)

(* 1 item *)

 test Xendconfsxp.lns get "(key (value) )" =
   { "key"
     { "array"
       { "1" = "value" }
     }
   }

(* 2 item *)

test Xendconfsxp.lns get "(xen-api-server (foo bar))" =
  { "xen-api-server"
    { "array"
      { "1" = "foo" }
      { "2" = "bar" }
    }
  }

test Xendconfsxp.lns get "( key ( value value2 ))" =
  { "key"
    { "array"
      { "1" = "value" }
      { "2" = "value2" }
    }
  }

(* 3 item *)

 test Xendconfsxp.lns get "( key ( value value2 value3 ))" =
  { "key"
    { "array"
      { "1" = "value" }
      { "2" = "value2" }
      { "3" = "value3" }
    }
  }

(* quotes *)
 test Xendconfsxp.lns get "(key \"foo\")" = { "key" = "\"foo\"" }
 test Xendconfsxp.lns get "(key \"\")" = { "key" = "\"\"" }
 test Xendconfsxp.lns get "( key \"foo\" )" = { "key" = "\"foo\"" }
 test Xendconfsxp.lns get "( key \"f oo\" )" = { "key" = "\"f oo\"" }
 test Xendconfsxp.lns get "( key \"f  oo\" )" = { "key" = "\"f  oo\"" }
 test Xendconfsxp.lns get "(foo \"this is \\\"quoted\\\" in quotes\")" =
    { "foo" = "\"this is \\"quoted\\" in quotes\"" }
 test Xendconfsxp.lns get "( key \"fo\\'\" )" = { "key" = "\"fo\\'\"" }
 test Xendconfsxp.lns get "( key \"fo\\'\" )" = { "key" = "\"fo\\'\"" }
 test Xendconfsxp.lns get "( key \"\")" = { "key" = "\"\"" }

(* Newlines in strange places *)
 test Xendconfsxp.lns get "(\nkey\nbar\n)" = { "key" = "bar" }
 test Xendconfsxp.lns get "(\n\n\nkey\n\n\nbar\n\n\n)" = { "key" = "bar" }
 test Xendconfsxp.lns get "(\nkey\nbar\n)" = { "key" = "bar" }

(* Comments in strange places *)
 test Xendconfsxp.lns get "(\nkey #aa\nbar)" =
    { "key" = "bar"
      { "#comment" = "aa" }
    }
 test Xendconfsxp.lns get "(\nkey\n#aa\nbar)" =
    { "key" = "bar"
      { "#comment" = "aa" }
    }

 test Xendconfsxp.lns get "(\nkey\n #aa\nbar)" =
  { "key" = "bar"
    { "#comment" = "aa" }
  }

(* This is either a bug or a feature.  There "key#comment" is not allowed. *)
 test Xendconfsxp.lns get "(\nkey# com\nbar\n)" = *
 test Xendconfsxp.lns get "(\nkey#aa\nbar)" = *

(* Sub lists *)
 test Xendconfsxp.lns get "(aaa ((bbb ccc ddd) (eee fff)))" = ?


(* Does not work yet.
 test Xendconfsxp.lns get "(\nkey\nbar # bb\n)" = ?
 test Xendconfsxp.lns get "(\nkey\nbar \n#cc)" = ?
 test Xendconfsxp.lns get "(\nkey\nbar \n #cc)" = ?
 test Xendconfsxp.lns get "( key ())" = ?
 test Xendconfsxp.lns get "(xen-api-server ((9363 pam '^localhost$ example\\.com$') (unix none)))" = ?
 test Xendconfsxp.lns get "(key ( (foo bar bar bat ) ) )" = ?
 test Xendconfsxp.lns get "(key ((foo foo) (bar bar)))" = ?
 test Xendconfsxp.lns get "(key ((foo foo foo (bar bar bar))))" = ?
*)
-------------- next part --------------
module Xendconfsxp =
  autoload xfm

let spc1 = /[ \t\n]+/
let ws = del spc1 " "

let lbrack = del /\([ \t\n]*/ "("
let rbrack = del /[ \t\n]*\)/ ")"

(*
 First try which didn't work. Commenting this out and using more simple one for now. *)
let no_ws_comment =
    [ label "#comment" . del /#[ \t]*/ "# "
        . store /[^ \t]+[^\n]*/ . del /\n/ "\n" ]

let empty_line = [ del /[ \t]*\n/ "\n" ]

let var_name = key Rx.word
(* Either a word or a quoted string *)
let str_store = store /[A-Za-z0-9_.-]+|\"([^\"\\\\]|(\\\\.))*\"/
let str = [ label "string" . str_store ]

let rec thing =
    let array = [ label "array" . lbrack . Build.list thing ws . rbrack ] in
    let str = [ label "item" . str_store ] in
    str | array

let sexpr = [ lbrack . var_name . ws . thing . rbrack ]

let lns = ( sexpr | no_ws_comment | empty_line ) *

let filter = incl "xend-config.sxp" . Util.stdexcl
let xfm = transform lns filter


More information about the augeas-devel mailing list