-- Module ParseTRL for parsing The Robot Language (TRL)
--   by: Anton Erholt <aerholt@kth.se>

module ParseTRL
(main) where

import System.IO
import Control.Monad
import Text.ParserCombinators.Parsec
import Text.ParserCombinators.Parsec.Expr
import Text.ParserCombinators.Parsec.Language
import qualified Text.ParserCombinators.Parsec.Token as Token


--- Represent the robot operations as data types


data Statement = Seq [Statement]
               | TURN Double
               | GOFORWARD Integer
               | GOBACKWARD Integer
               | DIG Integer
               deriving Show

--- Define The Robot Lang

languageDef =
  emptyDef { Token.commentStart = ""
           , Token.commentEnd = ""
           , Token.commentLine = "#"
           , Token.identStart = letter
           , Token.identLetter = alphaNum
           , Token.reservedNames = [ "TURN"
                                   , "GO"
                                   , "DIG"
                                   , "FORWARD"
                                   , "BACKWARD"
                                   ]
           , Token.reservedOpNames = []
           }

--- Build the lexer

lexer = Token.makeTokenParser languageDef

-- Simplify parsing
reserved = Token.reserved lexer
semi = Token.semi lexer
integer = Token.integer lexer
double = Token.float lexer
identifier = Token.identifier lexer
whiteSpace = Token.whiteSpace lexer

--- Build the parser

trlParser :: Parser Statement
trlParser = whiteSpace >> statement

statement :: Parser Statement
statement = seqOfStatements

seqOfStatements =
  do list <- (sepBy1 statement' semi)
     return $ if length list == 1 then head list else Seq list

statement' :: Parser Statement
statement' = turn
             <|> go
             <|> dig

turn :: Parser Statement
turn =
  do reserved "TURN"
     degrees <- double
     return $ TURN degrees


go :: Parser Statement
go =
  do reserved "GO"
     dir <- direction
     time <- integer
     return $ dir time

direction =     (reserved "FORWARD" >> return GOFORWARD)
            <|> (reserved "BACKWARD" >> return GOBACKWARD)




dig :: Parser Statement
dig =
  do reserved "DIG"
     time <- integer
     return $ DIG time



--- Build an AST

parseString :: String -> Statement
parseString str =
  case parse trlParser "" str of
   Left e -> error $ show e
   Right r -> r


-- Simple Tests

s1 = "TURN 3.14"
s2 = "TURN 15.0;TURN 45.0"
s3 = "GO FORWARD 120;GO BACKWARD 10"

t1 = parseString s1

te = parseString

main :: IO()
main = do
  putStrLn "Hello world!"
