packages feed

ideas-1.0: src/Documentation/ServicePage.hs

{-# LANGUAGE RankNTypes #-}
-----------------------------------------------------------------------------
-- Copyright 2011, Open Universiteit Nederland. This file is distributed
-- under the terms of the GNU General Public License. For more information,
-- see the file "LICENSE.txt", which is included in the distribution.
-----------------------------------------------------------------------------
-- |
-- Maintainer  :  bastiaan.heeren@ou.nl
-- Stability   :  provisional
-- Portability :  portable (depends on ghc)
--
-----------------------------------------------------------------------------
module Documentation.ServicePage (makeServicePage) where

import Common.Exercise
import Common.Id
import Common.Utils (Some(..))
import Control.Monad
import Documentation.DefaultPage
import Service.DomainReasoner
import Service.State
import Service.TypedExample
import Service.Types
import Text.HTML
import Text.XML (XML)

makeServicePage :: String -> Service -> DomainReasoner ()
makeServicePage dir s = do
   xs <- examplesFor (showId s)
   generatePageAt 1 dir (servicePageFile s)  (servicePage xs s)

servicePage :: [Example] -> Service -> HTMLBuilder
servicePage xs s = do
   h1 (showId s)

   para $ do
      bold $ text "Signature:"
      space
      case serviceFunction s of
         _ ::: t -> ttText (show t)
   para $ do
      bold $ text "Description: "
      br
      text $ description s

   when (serviceDeprecated s) $
      para $ bold $ text "Warning: this service is deprecated!"

   unless (null xs) $ do
      h2 $ "XML examples (" ++ show (length xs) ++ ")"
      forM_ (zip [1::Int ..] xs) $
         \(i, (msg, (xmlRequest, xmlReply, xmlTest))) -> do
            h2 $ show i ++ ". " ++ msg
            bold $ text "Request:"
            highlightXML True xmlRequest
            bold $ text "Reply:"
            highlightXML True xmlReply
            unless xmlTest $
               spanClass "error" $
                  bold $ text "Error: invalid request/reply pair"

-----------------------------------------------------------------------
-- Examples

type Example = (String, (XML, XML, Bool))

examplesFor :: String -> DomainReasoner [Example]
examplesFor s = tryAll [ f t | (t, f) <- list, s == t ]
 where
   list =
      [ ("derivation",   makeExample "logic.dnf"  (noCfg +++ logic1))
      , ("derivation",   makeExample "math.lineq" (noCfg +++ lineq1))
      , ("allfirsts",    makeExample "logic.dnf"  logic2)
      , ("allfirsts",    makeExample "math.lineq" lineq2)
      , ("onefirst",     makeExample "logic.dnf"  logic2)
      , ("onefirst",     makeExample "math.lineq" lineq2)
      , ("rulesinfo",    makeExample "math.lineq" noArgs)
      , ("rulelist",     makeExample "math.lineq" exArgs)
      , ("strategyinfo", makeExample "math.lineq" exArgs)
      , ("examples",     makeExample "math.lineq" exArgs)
      ]

   logic1, logic2 :: Args
   logic1 ex = newState ex "~(p /\\ ~q)"
   logic2 ex = newState ex "~~p /\\ T"

   lineq1, lineq2 :: Args
   lineq1 ex = newState ex "5*(x+1) == 11"
   lineq2 ex = newState ex "5*(x+1) == (x-1)/2"

   (f +++ g) ex = f ex ++ g ex

   noCfg _   = [Nothing ::: maybeType StrategyCfg]
   noArgs _  = []
   exArgs ex = [ex ::: Exercise]

tryAll :: [DomainReasoner a] -> DomainReasoner [a]
tryAll xs =
   let f m = liftM return m `catchError` const (return [])
   in liftM concat (mapM f xs)

newState :: Monad m => Exercise a -> String -> m (TypedValue a)
newState ex s =
   case parser ex s of
      Left msg -> fail ("newState: " ++ msg)
      Right a  -> return (emptyState ex a ::: stateType)

type Args = forall a . Exercise a -> [TypedValue a]

makeExample :: String -> Args -> String -> DomainReasoner Example
makeExample exName f srvName = do
   Some ex <- findExercise (newId exName)
   srv     <- findService srvName
   tr      <- typedExample ex srv (f ex)
   return (showId ex, tr)