-----------------------------------------------------------
-- Daan Leijen (c) 2000, daan@cs.uu.nl
-----------------------------------------------------------
module Main where

import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import Text.ParserCombinators.Parsec.Token
import Text.ParserCombinators.Parsec.Language 

		
    
-----------------------------------------------------------
-- 
-----------------------------------------------------------
run :: Show a => Parser a -> String -> IO ()
run p input
        = case (parse p "" input) of
            Left err -> do{ putStr "parse error at "
                          ; print err
                          }
            Right x  -> print x


runLex :: Show a => Parser a -> String -> IO ()
runLex p 
        = run (do{ whiteSpace lang
                 ; x <- p
                 ; eof
                 ; return x
                 }
              ) 

-----------------------------------------------------------
-- Sequence and choice 
-----------------------------------------------------------
simple  :: Parser Char
simple  = letter

openClose :: Parser Char
openClose = do{ char '('
              ; char ')'
              }
            
matching:: Parser ()
matching= do{ char '('
            ; matching
            ; char ')'
            ; matching
            }
        <|> return ()
        

-- Predictive parsing
testOr  =   do{ char '('; char 'a'; char ')' }
        <|> do{ char '('; char 'b'; char ')' }
        
testOr1 = do{ char '('
            ; char 'a' <|> char 'b'
            ; char ')'
            }
            
testOr2 =   try (do{ char '('; char 'a'; char ')' })
        <|> do{ char '('; char 'b'; char ')' }                    
        
   
-- Semantics        
nesting :: Parser Int
nesting = do{ char '('
            ; n <- nesting
            ; char ')'
            ; m <- nesting
            ; return (max (n+1) m)
            }
        <|> return 0        

word1   :: Parser String
word1   = do{ c  <- letter
            ; do{ cs <- word1
                ; return (c:cs)
                }
              <|> return [c]
            }  

-----------------------------------------------------------
-- 
-----------------------------------------------------------

word    :: Parser String
word    = many1 (letter <?> "") <?> "word"

sentence    :: Parser [String]
sentence    = do{ words <- sepBy1 word separator
                ; oneOf ".?!" <?> "end of sentence"
                ; return words
                }
                
separator   :: Parser ()
separator   = skipMany1 (space <|> char ',' <?> "")


-----------------------------------------------------------
-- Tokens
-----------------------------------------------------------
lang    = makeTokenParser 
            (haskellStyle{ reservedNames = ["return","total"]})


-----------------------------------------------------------
-- 
-----------------------------------------------------------
expr    = buildExpressionParser table factor
        <?> "expression"
        
table   = [[op "*" (*) AssocLeft, op "/" div AssocLeft]
          ,[op "+" (+) AssocLeft, op "-" (-) AssocLeft]
          ]
        where
          op s f assoc
             = Infix (do{ symbol lang s; return f} <?> "operator") assoc

factor  =   parens lang expr
        <|> natural lang
        <?> "simple expression"


test1   = do{ n <- natural lang
            ; do{ symbol lang "+"
                ; m <- natural lang
                ; return (n+m) 
                } 
            <|> return n
            }

-----------------------------------------------------------
--
-----------------------------------------------------------
{-
receipt ::= product* total
product ::= "return" price ";"
		  | identifier price ";"		  
total   ::= price "total"
price   ::= natural "." digit digit
-}

receipt :: Parser Bool
receipt	= do{ ps <- many produkt
	    ; p  <- total
	    ; return (sum ps == p)
	    }
			
produkt = do{ reserved lang "return"
	    ; p <- price
	    ; semi lang
	    ; return (-p)
	    }
      <|> do{ identifier lang
       	    ; p  <- price
      	    ; semi lang
      	    ; return p
      	    }
      <?> "product"

total	= do{ p <- price
	    ; reserved lang "total"
	    ; return p
	    }
	
price   :: Parser Int			
price   = lexeme lang (
	  do{ ds1 <- many1 digit
	    ; char '.'
	    ; ds2 <- count 2 digit
	    ; return (convert 0 (ds1 ++ ds2))			
	    })
	  <?> "price"
	  where
	    convert n []     = n
	    convert n (d:ds) = convert (10*n + digitToInt d) ds
		
digitToInt :: Char -> Int
digitToInt d = fromEnum d - fromEnum '0'

main :: IO ()
main = putStrLn "I'm only a dummy..."
