content: module OneLineAttrs(parseOneLineAttrs) where
  import Monad
  import Maybe
  import Char
  --import Attrs
  
  {-+
  A parser for attribute descriptions like these two:
  
    name=hyp, type=string, label="Depends on", optional
  
    name=conc, type=string/assertion, label="Conclusion", required
  -}
  
  --type Attr  = (String, String) -- tag, value
  --type Attrs = [Attr]
  
  --parseOneLineAttrs :: String -> Maybe Attrs
  parseOneLineAttrs = complete parseOneLineAttrs'
  
  parseOneLineAttrs' = manySep comma parseOneLineAttr
  comma s = [((),r)|(",",r)<-lex s]
  
  parseOneLineAttr s =
    [((name,value),r)|(name,r1)<-lex s,
  		    (value,r)<-parseValue r1]
  
  parseValue s =
    [(value,r)|("=" ,r1)<-lex s,
  	     (value,r)<-lexval r1]
    `orelse`
    [("",s)]
  
  lexval s =
    case s' of
      [] -> []
      '"':_ -> reads s' -- string literal
      _ -> [span isAttr s']
    where
      s'=dropWhile isSpace s
      isAttr c = c/=',' && isPrint c
  
  -- Parsing combinators for the ReadS type:
  
  xs `orelse` ys = take 1 (xs++ys)
  
  many p s = some p s `orelse` empty s
  some p s = [(x:xs,r)|(x,r1)<-p s,(xs,r)<-many p r1]
  empty s = [([],s)]
  
  prefix p1 p2 s = [xr|(_,r1)<-p1 s,xr<-p2 r1]
  
  someSep sep p s = [(x:xs,r)|(x,r1)<-p s,
                              (xs,r)<-many (prefix sep p) r1]
  
  manySep sep p s = someSep sep p s `orelse` [([],s)]
  
  complete p s = listToMaybe [x|(x,r)<-p s,("","")<-lex r]
  