{
{-# LANGUAGE OverloadedStrings #-}

module Language.Virgil.Parser where

import Language.Virgil.AST
import Language.Virgil.Lexer

}

%name parse
%tokentype { Token }
%monad { Alex }
%lexer { lexwrap } { Token _ TkEOF }
%error { happyError }

%token
  '{' { Token _ TkLCurl }
  '}' { Token _ TkRCurl }
  '[' { Token _ TkLBrac }
  ']' { Token _ TkRBrac }
  ':' { Token _ TkColon }
  ';' { Token _ TkSemi  }
  ',' { Token _ TkComma  }

  with  { Token _ (TkKw KwWith) }
  true  { Token _ (TkKw KwTrue) }
  false { Token _ (TkKw KwFalse) }
  null  { Token _ (TkKw KwNull) }

  int   { Token _ (TkInt $$) }
  float { Token _ (TkFloat $$) }
  str   { Token _ (TkStr $$) }

%%

tlexpr
  : '[' list { mkArray $2 }
  | '{' dict { mkObject $2 }

scalar
  : int   { ChNumber (fromIntegral $1) }
  | float { ChNumber $1 }
  | str   { ChString $1 }
  | true  { ChBool True }
  | false { ChBool False}
  | null  { ChNull }

expr
  : tlexpr { $1 }
  | scalar { $1 }

list
  : ']'           { [] }
  | expr ']'      { [ $1 ] }
  | expr ',' list { $1 : $3 }

dict
  : '}'               { [] }
  | str ':' expr '}'  { [ ($1, $3) ] }
  | str ':' expr ',' dict { ($1, $3) : $5 }

{

-- info :: a -> Alex (Info a)
-- info x = do
--   (AlexPn _ ln cl,_,_,_) <- alexGetInput
--   fp <- getFilePath
--   return $ Info { node    = x
--                 , srcLine = ln
--                 , srcCol  = cl
--                 , srcFile = fp
--                 }

lexwrap :: (Token -> Alex a) -> Alex a
lexwrap = (alexMonadScan' >>=)

happyError :: Token -> Alex a
happyError (Token p t) =
  alexError' p ("parse error at token " ++ show t)

parseFile :: FilePath -> String -> Either String ChValue
parseFile = runAlex' parse
}
