packages feed

WashNGo-2.12: washparser/hs/WASHExpression.hs

module WASHExpression where

import List
import Monad

import WASHFlags
import qualified WASHUtil
import WASHData
import WASHOut

code :: FLAGS -> [CodeFrag] -> ShowS
code flags [] = id
code flags (x:xs) = code' flags x . code flags xs

code' :: FLAGS -> CodeFrag -> ShowS
code' flags (HFrag h) = 
  showString h
code' flags (EFrag e) =
  runOut $ element flags e
code' flags (CFrag cnts) =
  showChar '(' .
  runOut (contents flags [] cnts) .
  showChar ')'
code' flags (AFrag attrs) =
  showChar '(' .
  WASHUtil.itemList (attribute flags) "CGI.empty" " >> " attrs .
  showChar ')'
code' flags (VFrag var) = 
  id
code' flags _ = error "Unknown type: code"

outMode :: Mode -> Out ()
outMode = outShowS . showMode

showMode :: Mode -> ShowS
showMode V = id
showMode S = showString "_T"
showMode F = showString "_S"

element :: FLAGS -> Element -> Out [String]
element flags el@(Element mode nm ats cnt et) =
  case break (==':') nm of
    (ns, ':' : elnm) ->
      ns_element flags ns elnm el 
    ("input", "") ->
      input_element flags mode nm ats cnt et
    ("textarea", "") ->
      textarea_element flags mode nm ats cnt et
    _ ->
      do outChar '('
	 outString "CGI."
	 outString nm
	 when (generateBT flags) $ outMode mode
	 outChar '('
	 outShowS $ attributes flags ats
	 rvs <- contents flags [] cnt
	 outString "))"
	 return rvs

textarea_element flags mode nm ats cnt et =
  let at_name = getAttribute ats "name"
      preset = getTextualContentAsStringExpression cnt
      processedAttributes = ["name"]
      cleanedAttributes = removeAttributes (`elem` processedAttributes) ats
  in
      do outString "(CGI."
	 outString "makeTextarea"
	 -- attention: the preset text is raw so it may contain character references!
	 outString preset
	 outChar '('
	 outShowS $ attributes flags cleanedAttributes
	 outString "empty))"
	 return [at_name]

input_element flags mode nm ats cnt et =
  let at_type = getAttribute ats "type"
      at_name = getAttribute ats "name"
      parms    = getAttribute ats "WASH:parms"
      callback = getAttribute ats "WASH:callback"
      call     = getAttribute ats "WASH:call"
      preset = getTextualContent cnt
      processedAttributes = ["type", "name", "WASH:parms", "WASH:callback", "WASH:call"]
      cleanedAttributes = removeAttributes (`elem` processedAttributes) ats
      do_element elnm =
	do outChar '('
	   outString "CGI."
	   outString elnm
	   outChar '('
	   outShowS $ attributes flags cleanedAttributes
	   outString "empty))"
	   return [at_name]
  in
  case at_type of
    "text" ->
      do_element "inputField"
    "password" ->
      do_element "passwordInputField"
    "checkbox" ->
      do_element "checkboxInputField"
    -- "radio" -> -- use the RB abstraction
    "submit" ->
      let Just (funpart, args) = 
	       parse_WASH_call call `mplus`
	       parse_WASH_callback callback parms
	  largs = length args
      in
      do outString "(CGI."
	 outString at_type
	 foldr (\arg out -> do outString " (CGI.F2 ("
			       outString arg
			       outString ") "
			       out
			       outString ")")
	       (outString " CGI.F0") 
	       args
	 outString "(\\"
	 convertArgs largs
	 outString " -> "
	 outChar '('
	 outString funpart -- funpart :: (arg1, ..., argn) -> CGI ()
	 outChar ')'
	 unless (null args) $ convertRess '(' largs
	 outChar ')'
	 outChar '('
	 outShowS $ attributes flags cleanedAttributes
	 outString "empty))"
	 return []
    "reset" ->
      do_element "resetField"
    "file" ->
      do_element "fileInputField"
    -- "hidden" -> -- useless in WASH
    -- "image" ->  -- ???
    -- "button" -> -- ???

convertArgs 0 =
  outString " CGI.F0"
convertArgs n =
  do outString "(CGI.F2 xxxx____"
     outString (show n)
     convertArgs (n-1)
     outString ")"

convertRess c 0 =
  outChar ')'
convertRess c n =
  do outString (c:"CGI.value xxxx____")
     outString (show n)
     convertRess ',' (n-1)

parse_WASH_callback cb parms =
  Just (cb, parse_WASH_call_args [] parms)

parse_WASH_call str =
  case break (=='(') str of
    (funpart, '(':rest1 ) ->
      Just (funpart, parse_WASH_call_args [] rest1)
    ("", "") ->
      Nothing
    (funpart, "") ->
      Just (funpart, [])
    _ -> Nothing

parse_WASH_call_args acc str =
  case break (`elem` ",)") str of
    (arg, ',': rest) ->
      parse_WASH_call_args (arg:acc) rest
    (arg, ')': rest) ->
      reverse (arg:acc)
    ("", "") ->
      reverse (acc)
    (arg, "") ->
      reverse (arg:acc)

ns_element flags "WASH" elnm (Element mode _ ats cnt et) =
  let var = getAttribute ats "WASH:name"
      chk = getAttribute ats "WASH:check"
      parms    = getAttribute ats "WASH:parms"
      callback = getAttribute ats "WASH:callback"
      preset = getTextualContent cnt
  in
  if elnm `elem` [ "submit", "submitLink"] then
      let args     = words parms in
      do outString "(CGI."
	 outString elnm
	 if null args
	   then outChar '0'
	   else do outString ("(CGI.F" ++ show (length args))
		   mapM (\arg -> outString (' ' : arg)) args
		   outChar ')'
	 outChar '('
	 outString callback
	 outChar ')'
	 outChar '('
	 outShowS $ attributes flags (removeAttributes (isPrefixOf "WASH:") ats)
	 outString "empty))"
	 return []
  else if elnm `elem` [ "inputField", "textInputField"
		      , "passwordInputField", "checkboxInputField"
		      , "fileInputField"] then
      do outChar '('
	 outString "CGI."
	 outString elnm
	 outChar '('
	 outShowS $ attributes flags (removeAttributes (isPrefixOf "WASH:") ats)
	 outString "empty))"
	 return [var]
  else if elnm `elem` [ "checkedTextInputField", "checkedFileInputField"] then
      do outChar '('
	 outString "CGI."
	 outString elnm
	 outChar '('
	 outString chk
	 outChar ')'
	 outChar '('
	 outShowS $ attributes flags (removeAttributes (isPrefixOf "WASH:") ats)
	 outString "empty))"
	 return [var]
  else if elnm `elem` ["makeTextarea"] then
      do outString "(CGI."
	 outString elnm
	 -- attention: the preset text is raw so it may contain character references!
	 outString (show preset)
	 outChar '('
	 outShowS $ attributes flags (removeAttributes (isPrefixOf "WASH:") ats)
	 outString "empty))"
	 return [var]
  else if elnm `elem` ["makeButton"] then
      do outString "(CGI."
	 outString elnm
	 outChar '('
	 outShowS $ attributes flags (removeAttributes (isPrefixOf "WASH:") ats)
	 rvs <- contents flags [] cnt
	 outString "))"
	 return (var:rvs)
  else if elnm `elem` ["makeForm"] then
      do outString "(CGI."
	 outString elnm
	 outChar '('
	 outShowS $ attributes flags (removeAttributes (isPrefixOf "WASH:") ats)
	 rvs <- contents flags [] cnt
	 outString "))"
	 return rvs
  else
      error ("WASH element "++elnm++" not defined, yet")
ns_element flags ns elnm (Element mode nm ats cnt et) =
  do outChar '('
     outString "CGI.mkElement"
     when (generateBT flags) $ outMode mode
     outString (show nm)
     outChar '('
     outShowS $ attributes flags ats
     rvs <- contents flags [] cnt
     outString "))"
     return rvs

outRVS :: [String] -> Out ()
outRVS [] = outString "()"
outRVS (x:xs) =
  do outChar '('
     outString x
     mapM_ g xs
     outChar ')'
  where g x = do { outChar ','; outString x; }

outRVSpat :: [String] -> Out ()
outRVSpat [] = outString "(_)"
outRVSpat xs = outRVS xs

contents :: FLAGS -> [String] -> [Content] -> Out [String]
contents flags inRVS cts =
  case cts of
    [] ->
      do outString "return"
	 outRVS inRVS
	 return inRVS
    ct:cts ->
      do rvs <- content flags ct
	 case rvs of
	   [] ->
             case (cts, inRVS) of
	       ([],[]) ->
	         return []
	       _ ->
		 do outString " >> "
		    contents flags inRVS cts
	   _ ->
	     case (cts, inRVS) of
	       ([],[]) ->
	         return rvs
	       _ ->
		 do outString " >>= \\ "
		    outRVSpat rvs
		    outString " -> "
		    contents flags (rvs ++ inRVS) cts

content :: FLAGS -> Content -> Out [String]
content flags (CElement elem)  = 
  element flags elem
content flags (CText txt) =
  do text flags txt
     return []
content flags (CCode (VFrag var:c)) =
  do outShowS $ (showChar '(' . code flags c . showChar ')')
     return [var]
content flags (CCode c) =
  do outShowS $ (showChar '(' . code flags c . showChar ')')
     return []
content flags (CComment cc) =
  do outShowS $ (showString "return (const () " . shows cc . showChar ')')
     return []
content flags (CReference txt) =
  do text flags txt
     return []
content flags c = 
  error $ "Unknown type: content -- " ++ (show c)

text :: FLAGS -> Text -> Out [String]
text flags txt =
  do outString "CGI.rawtext"
     when (generateBT flags) $ outMode (textMode txt)
     outChar ' '
     outs (textString txt)
     return []

attributes :: FLAGS -> [Attribute] -> ShowS
attributes flags atts = 
  f atts
    where
      f [] = id
      f (att:atts) = 
	attribute flags att .
	showString " >> " .
	f atts

attribute :: FLAGS -> Attribute -> ShowS
attribute flags (Attribute m n v) = 
  showString "(CGI.attr" .
  (if generateBT flags then (attrvalueBT m v) else id) .
  showChar ' ' .
  shows n . 
  showString " " .
  attrvalue v .
  showString ")"
attribute flags (AttrPattern pat) =
  showString "( " .
  showString pat .
  showString " )"
attribute flags a = error $ "Unknown type: attribute -- " ++ (show a)

attrvalue :: AttrValue -> ShowS
attrvalue (AText t) = 
  shows t
attrvalue (ACode c) =
  showString "( " .
  showString c .
  showString " )"
attrvalue a = error $ "Unknown type: attrvalue -- " ++ (show a)

raw_attrvalue :: AttrValue -> String
raw_attrvalue (AText t) = t
raw_attrvalue (ACode c) = c
raw_attrvalue a = error $ "Unknown type: raw_attrvalue -- " ++ show a

attrvalueBT :: Mode -> AttrValue -> ShowS
attrvalueBT V _ = id
attrvalueBT m (AText _) = showMode m . showChar 'S'
attrvalueBT m (ACode _) = showMode m . showChar 'D'
attrvalueBT m a = error $ "Unknown type: attrvalueBT -- " ++ (show a)

getAttribute :: [Attribute] -> String -> String
getAttribute [] atname = ""
getAttribute (Attribute m n v : rest) atname 
  | n == atname = raw_attrvalue v
  | otherwise   = getAttribute rest atname
getAttribute (_ : rest) atname =
  getAttribute rest atname

removeAttributes :: (String -> Bool) -> [Attribute] -> [Attribute]
removeAttributes p = 
  filter g
  where
    g (Attribute m n v) = not (p n)
    g (AttrPattern _) = True

getTextualContent :: [Content] -> String
getTextualContent = concatMap g
  where
  g (CElement _)  = "" 
  g (CText txt) = textString txt
  g (CCode _) = ""
  g (CComment _) = ""
  g (CReference txt) = textString txt

getTextualContentAsStringExpression :: [Content] -> String
getTextualContentAsStringExpression = 
  wrap . foldrx h z . map g
  where
  foldrx a b [] = b
  foldrx a b xs = foldr1 a xs
  z = "\"\""
  h e1 e2 = e1 ++ " ++ " ++ e2
  g (CElement _)  = z
  g (CText txt) = show (textString txt)
  g (CCode ccode) = getCodeFragsAsStringExpression ccode
  g (CComment _) = z
  g (CReference txt) = show (textString txt)
  wrap s = '(' : s ++ ")"

getCodeFragsAsStringExpression =
  concatMap g
  where
  g (HFrag str) = str
  g (EFrag element) = ""
  g (HSFrag str) = str
  g (CFrag conts) = ""
  g (AFrag attrs) = ""
  g (VFrag str) = str