module Parse where
import Text.ParserCombinators.Parsec hiding (parse)
import Graph

parse = runParser graphs () ""

parseFile filename = do contents <- readFile filename
                        return (runParser graphs () filename contents)

graphs = do ws
            result <- many graph
            eof
            return result

ws = many (oneOf " \r\n\t")

identifier = do n <- many1 (letter <|> digit)
                ws
                return n

readDouble "" ys = readDouble "0" ys
readDouble xs "" = readDouble xs "0"
readDouble xs ys = read (xs++"."++ys)::Double

double = do
  whole <- many1 digit
  frac <- option "" (do char '.'
                        many digit)
  return (readDouble whole frac)

keyword name = try (do n <- identifier
                       if n /= name then fail "" else return ())

keyop name = do string name
                ws
                return ()

parens f = between (keyop "(") (keyop ")") f
braces f = between (keyop "{") (keyop "}") f
brackets f = between (keyop "[") (keyop "]") f
commas f = sepBy f (keyop ",")
semis f = sepBy f (keyop ";")

graph = do keyword "def"
           inlets <- many identifier
           name <- brackets identifier
           outlets <- many identifier
           keyop "="
           nodes <- (semis) node
           keyop "."
           return (name
                  ,Graph { inlets=inlets
                         , outlets=outlets
                         , nodes=nodes
                         }
                  )

operator =
    choice [keyop "+">>return Add
           ,keyop "-">>return Sub
           ,keyop "*">>return Mul
           ,keyop "/">>return Div
           ,brackets (do id <- identifier
                         case id of
                           "put" -> do var <- identifier
                                       return (Put var)
                           "get" -> do var <- identifier
                                       return (Get var)
                           _ -> return (App id)
                     )
           ]

node = do inputs <- many identifier
          op <- operator
          outputs <- many identifier
          return (Node { inputs=inputs
                       , op = op
                       , outputs=outputs
                       })