{
module Lexer where
import Control.Monad.Fix
}

%wrapper "monad"

$alpha_or_number = [a-zA-Z0-9_]
$big_alpha       = [A-Z]
$small_alpha     = [a-z]


@decimal = [1-9] [0-9]*
@ident   = _? $small_alpha $alpha_or_number*
@cident  = _? $big_alpha   $alpha_or_number*

tokens :-
<0> $white+ ; -- We skip whitespaces
<0> "="      { mkTok $ \s -> TkEq }
<0> "("      { mkTok $ \s -> TkLPar }
<0> ")"      { mkTok $ \s -> TkRPar }
<0> ","      { mkTok $ \s -> TkComma }
<0> "@"      { mkTok $ \s -> TkAt }
<0> @ident   { mkTok $ \s -> TkIdent s }
<0> @cident  { mkTok $ \s -> TkCIdent s }
<0> @decimal { mkTok $ \s -> TkInt (read s) }
<0> .        { mkTok $ \s -> TkError s }
{
type PToken = (AlexPosn, Token)

pos :: PToken -> AlexPosn
pos (p,t) = p

body :: PToken -> Token
body (p,t) = t

data Token 
    = TkEq            -- = 
    | TkLPar          -- (
    | TkRPar          -- )
    | TkComma         -- ,
    | TkAt            -- @
    | TkIdent  String -- variables, functions 
    | TkCIdent String -- Constructors 
    | TkInt    Int
    | TkEOF
    | TkError String 
      deriving Eq

intValue (TkInt i) = i
strValue (TkIdent s)  = s
strValue (TkCIdent s) = s
strValue _            = ""

instance Show Token where 
    show TkEq    = "="
    show TkLPar  = "("
    show TkRPar  = ")"
    show TkComma = ","
    show TkAt    = "@"
    show (TkIdent s)  = s
    show (TkCIdent s) = s
    show (TkInt i)    = show i

mkTok f (p,_,str) len = return $ (p, f (take len str))
alexEOF = return $ (undefined, TkEOF)

scanTokens str 
    = runAlex str $ 
      fix (\loop ls -> do 
             { token@(p, tk) <- alexMonadScan;
               case tk of 
                 TkEOF -> return $ reverse ls 
                 _     -> loop $! (token:ls) }) []
}
