-- Bonus lecture, Part 1: Another example of "instructions"
-- Instructions for parsing

import Parsing
-- A small library for Parsing strings into things
-- parse :: Parser a -> String -> Maybe (a, String)

import Data.Char
import Data.Maybe

-- Example: parsing phone numbers in one of two formats:

data PhoneNr = Global Int Int | Local Int
  deriving Show

showNr (Global cc n) = "+" ++ show cc ++ " " ++ show n
showNr (Local n)     = '0':show n

work = Local 7372076
home = Global 46 73720766


-- Library: char, digit
countryCode :: Parser Int
countryCode = do
           char '+'
           d1 <- digit
           d2 <- digit
           return (read [d1,d2])
      

-- Library functions: oneOrMore 
nat :: Parser Int
nat = do
  ds <- oneOrMore digit
  return (read ds)

-- Library: (+++)
phoneP:: Parser PhoneNr
phoneP = localP +++ globalP
  where localP = do
             n <- nat
             return $ Local n
        globalP = do
                cc <- countryCode
                char ' '
                n <- nat
                return (Global cc n)
                

-- Library: sat and chain
phoneList :: Parser [PhoneNr]

-- list of comma- or semicolon- separated phone numbers
phoneList = chain phoneP (sat sep) -- (char ';' +++ char ',') -- sat
      where sep c = c `elem` ";,"

---------------------------------------------------
data Expr
  = Num Int
  | Add Expr Expr
  | Mul Expr Expr
 deriving (Eq
          ,Show
          )

-- Parsing arithmetic expressions: 

expr,term,factor :: Parser Expr
-- expressions are a sum of one or more terms
expr = do
   es <- chain term (char '+')
   return $ foldr1 Add es
   
-- terms are products of one or more factors
term = do
   fs <- chain factor (char '*')
   return $ foldr1 Mul fs
   
-- factors are an expression in brackets or a number
factor = bracketed +++ num
  where bracketed =
           do char '('
              e <- expr
              char ')'
              return e
        num =
           do n <- nat -- negative numbers as an exercise
              return $ Num n