packages feed

language-java-0.1.0: Language/Java/Lexer.x

{
module Language.Java.Lexer (L(..), Token(..), lexer) where

import Numeric
import Data.Char

import Debug.Trace (trace)
}

%wrapper "posn"

$digit      = [0-9]
$nonzero    = [1-9]
$octdig     = [0-7]
$hexdig     = [0-9A-Fa-f]

@lineterm = [\n\r] | \r\n

@any = . | @lineterm
@tradcomm = "/*" @any* "*/"
@linecomm = "//" .* @lineterm
@comm = @tradcomm | @linecomm

$javaLetter = [a-zA-Z\_\$]
$javaDigit = $digit
$javaLetterOrDigit = [a-zA-Z0-9\_\$]

@octEscape = [0123]? $octdig{1,2}
@hexEscape = u $hexdig{4}
@charEscape = \\ (@octEscape | @hexEscape | [btnfr\"\'])

@expsuffix = [\+\-]? $digit+
@exponent = [eE] @expsuffix
@pexponent = [pP] @expsuffix

tokens  :-

    $white+         ;
    @comm           ;

    abstract        { \p _ -> L (pos p) $ KW_Abstract     }
    assert          { \p _ -> L (pos p) $ KW_Assert       }
    boolean         { \p _ -> L (pos p) $ KW_Boolean      }
    break           { \p _ -> L (pos p) $ KW_Break        }
    byte            { \p _ -> L (pos p) $ KW_Byte         }
    case            { \p _ -> L (pos p) $ KW_Case         }
    catch           { \p _ -> L (pos p) $ KW_Catch        }
    char            { \p _ -> L (pos p) $ KW_Char         }
    class           { \p _ -> L (pos p) $ KW_Class        }
    const           { \p _ -> L (pos p) $ KW_Const        }
    continue        { \p _ -> L (pos p) $ KW_Continue     }
    default         { \p _ -> L (pos p) $ KW_Default      }
    do              { \p _ -> L (pos p) $ KW_Do           }
    double          { \p _ -> L (pos p) $ KW_Double       }
    else            { \p _ -> L (pos p) $ KW_Else         }
    enum            { \p _ -> L (pos p) $ KW_Enum         }
    extends         { \p _ -> L (pos p) $ KW_Extends      }
    final           { \p _ -> L (pos p) $ KW_Final        }
    finally         { \p _ -> L (pos p) $ KW_Finally      }
    float           { \p _ -> L (pos p) $ KW_Float        }
    for             { \p _ -> L (pos p) $ KW_For          }
    goto            { \p _ -> L (pos p) $ KW_Goto         }
    if              { \p _ -> L (pos p) $ KW_If           }
    implements      { \p _ -> L (pos p) $ KW_Implements   }
    import          { \p _ -> L (pos p) $ KW_Import       }
    instanceof      { \p _ -> L (pos p) $ KW_Instanceof   }
    int             { \p _ -> L (pos p) $ KW_Int          }
    interface       { \p _ -> L (pos p) $ KW_Interface    }
    long            { \p _ -> L (pos p) $ KW_Long         }
    native          { \p _ -> L (pos p) $ KW_Native       }
    new             { \p _ -> L (pos p) $ KW_New          }
    package         { \p _ -> L (pos p) $ KW_Package      }
    private         { \p _ -> L (pos p) $ KW_Private      }
    protected       { \p _ -> L (pos p) $ KW_Protected    }
    public          { \p _ -> L (pos p) $ KW_Public       }
    return          { \p _ -> L (pos p) $ KW_Return       }
    short           { \p _ -> L (pos p) $ KW_Short        }
    static          { \p _ -> L (pos p) $ KW_Static       }
    strictfp        { \p _ -> L (pos p) $ KW_Strictfp     }
    super           { \p _ -> L (pos p) $ KW_Super        }
    switch          { \p _ -> L (pos p) $ KW_Switch       }
    synchronized    { \p _ -> L (pos p) $ KW_Synchronized }
    this            { \p _ -> L (pos p) $ KW_This         }
    throw           { \p _ -> L (pos p) $ KW_Throw        }
    throws          { \p _ -> L (pos p) $ KW_Throws       }
    transient       { \p _ -> L (pos p) $ KW_Transient    }
    try             { \p _ -> L (pos p) $ KW_Try          }
    void            { \p _ -> L (pos p) $ KW_Void         }
    volatile        { \p _ -> L (pos p) $ KW_Volatile     }
    while           { \p _ -> L (pos p) $ KW_While        }

    0               { \p _ -> L (pos p) $ IntTok 0        }
    0 [lL]          { \p _ -> L (pos p) $ LongTok 0       }
    0 $octdig+      { \p s -> L (pos p) $ IntTok (fst . head $ readOct s) }
    0 $octdig+ [lL] { \p s -> L (pos p) $ LongTok (fst . head $ readOct (init s)) }
    $nonzero $digit*        { \p s -> L (pos p) $ IntTok (read s) }
    $nonzero $digit* [lL]   { \p s -> L (pos p) $ LongTok (read (init s)) }
    0 [xX] $hexdig          { \p s -> L (pos p) $ IntTok (fst . head $ readHex (drop 2 s)) }
    0 [xX] $hexdig [lL]     { \p s -> L (pos p) $ IntTok (fst . head $ readHex (init (drop 2 s))) }

    $digit+ \. $digit* @exponent? [dD]?           { \p s -> L (pos p) $ DoubleTok (fst . head $ readFloat $ '0':s) }
            \. $digit+ @exponent? [dD]?           { \p s -> L (pos p) $ DoubleTok (fst . head $ readFloat $ '0':s) }
    $digit+ \. $digit* @exponent? [fF]            { \p s -> L (pos p) $ FloatTok  (fst . head $ readFloat $ '0':s) }
            \. $digit+ @exponent? [fF]            { \p s -> L (pos p) $ FloatTok  (fst . head $ readFloat $ '0':s) }
    $digit+ @exponent? [dD]?                      { \p s -> L (pos p) $ DoubleTok (fst . head $ readFloat s) }
    $digit+ @exponent? [fF]                       { \p s -> L (pos p) $ FloatTok  (fst . head $ readFloat s) }
    0 [xX] $hexdig* \.? $hexdig* @pexponent [dD]? { \p s -> L (pos p) $ DoubleTok (readHexExp (drop 2 s)) }
    0 [xX] $hexdig* \.? $hexdig* @pexponent [fF]  { \p s -> L (pos p) $ FloatTok  (readHexExp (drop 2 s)) }

    true            { \p _ -> L (pos p) $ BoolTok True    }
    false           { \p _ -> L (pos p) $ BoolTok False   }

    '(@charEscape)'                         { \p s -> L (pos p) $ CharTok (readCharTok s) }
    '(~[\'])'                               { \p s -> L (pos p) $ CharTok (readCharTok s) }

    \" (@charEscape | ~[\"])* \"            { \p s -> L (pos p) $ StringTok (readStringTok s) }

    null            {\p _ -> L (pos p) $ NullTok }

    $javaLetter $javaLetterOrDigit*     { \p s -> L (pos p) $ IdentTok s }

    \(              { \p _ -> L (pos p) $ OpenParen       }
    \)              { \p _ -> L (pos p) $ CloseParen      }
    \[              { \p _ -> L (pos p) $ OpenSquare      }
    \]              { \p _ -> L (pos p) $ CloseSquare     }
    \{              { \p _ -> L (pos p) $ OpenCurly       }
    \}              { \p _ -> L (pos p) $ CloseCurly      }
    \;              { \p _ -> L (pos p) $ SemiColon       }
    \,              { \p _ -> L (pos p) $ Comma           }
    \.              { \p _ -> L (pos p) $ Period          }

    "="             { \p _ -> L (pos p) $ Op_Equal        }
    ">"             { \p _ -> L (pos p) $ Op_GThan        }
    "<"             { \p _ -> L (pos p) $ Op_LThan        }
    "!"             { \p _ -> L (pos p) $ Op_Bang         }
    "~"             { \p _ -> L (pos p) $ Op_Tilde        }
    "?"             { \p _ -> L (pos p) $ Op_Query        }
    ":"             { \p _ -> L (pos p) $ Op_Colon        }
    "=="            { \p _ -> L (pos p) $ Op_Equals       }
    "<="            { \p _ -> L (pos p) $ Op_LThanE       }
    ">="            { \p _ -> L (pos p) $ Op_GThanE       }
    "!="            { \p _ -> L (pos p) $ Op_BangE        }
    "&&"            { \p _ -> L (pos p) $ Op_AAnd         }
    "||"            { \p _ -> L (pos p) $ Op_OOr          }
    "++"            { \p _ -> L (pos p) $ Op_PPlus        }
    "--"            { \p _ -> L (pos p) $ Op_MMinus       }
    "+"             { \p _ -> L (pos p) $ Op_Plus         }
    "-"             { \p _ -> L (pos p) $ Op_Minus        }
    "*"             { \p _ -> L (pos p) $ Op_Star         }
    "/"             { \p _ -> L (pos p) $ Op_Slash        }
    "&"             { \p _ -> L (pos p) $ Op_And          }
    "|"             { \p _ -> L (pos p) $ Op_Or           }
    "^"             { \p _ -> L (pos p) $ Op_Caret        }
    "%"             { \p _ -> L (pos p) $ Op_Percent      }
    "<<"            { \p _ -> L (pos p) $ Op_LShift       }
    ">>"            { \p _ -> L (pos p) $ Op_RShift       }
    ">>>"           { \p _ -> L (pos p) $ Op_RRShift      }
    "+="            { \p _ -> L (pos p) $ Op_PlusE        }
    "-="            { \p _ -> L (pos p) $ Op_MinusE       }
    "*="            { \p _ -> L (pos p) $ Op_StarE        }
    "/="            { \p _ -> L (pos p) $ Op_SlashE       }
    "&="            { \p _ -> L (pos p) $ Op_AndE         }
    "|="            { \p _ -> L (pos p) $ Op_OrE          }
    "^="            { \p _ -> L (pos p) $ Op_CaretE       }
    "%="            { \p _ -> L (pos p) $ Op_PercentE     }
    "<<="           { \p _ -> L (pos p) $ Op_LShiftE      }
    ">>="           { \p _ -> L (pos p) $ Op_RShiftE      }
    ">>>="          { \p _ -> L (pos p) $ Op_RRShiftE     }


{

readHexExp :: Floating a => String -> a
readHexExp s = let (m, suf) = head $ readHex s
                   (e, _) = case suf of
                             p:s | toLower p == 'p' -> head $ readHex s
                             _ -> (0, "")
                in m ** e

readCharTok :: String -> Char
readCharTok s = trace s $ read . convChar $ s
readStringTok :: String -> String
readStringTok = read . convChar

convChar :: String -> String
convChar ('\\':'u':s) = '\\':'x':convChar s
convChar (x:s) = x:convChar s
convChar "" = ""


data L a = L Pos a
  deriving (Show, Eq)

-- (line, column)
type Pos = (Int, Int)

pos :: AlexPosn -> Pos
pos (AlexPn _ l c) = (l,c)

data Token
    -- Keywords
    = KW_Abstract
    | KW_Assert
    | KW_Boolean
    | KW_Break
    | KW_Byte
    | KW_Case
    | KW_Catch
    | KW_Char
    | KW_Class
    | KW_Const
    | KW_Continue
    | KW_Default
    | KW_Do
    | KW_Double
    | KW_Else
    | KW_Enum
    | KW_Extends
    | KW_Final
    | KW_Finally
    | KW_Float
    | KW_For
    | KW_Goto
    | KW_If
    | KW_Implements
    | KW_Import
    | KW_Instanceof
    | KW_Int
    | KW_Interface
    | KW_Long
    | KW_Native
    | KW_New
    | KW_Package
    | KW_Private
    | KW_Protected
    | KW_Public
    | KW_Return
    | KW_Short
    | KW_Static
    | KW_Strictfp
    | KW_Super
    | KW_Switch
    | KW_Synchronized
    | KW_This
    | KW_Throw
    | KW_Throws
    | KW_Transient
    | KW_Try
    | KW_Void
    | KW_Volatile
    | KW_While

    -- Separators
    | OpenParen
    | CloseParen
    | OpenSquare
    | CloseSquare
    | OpenCurly
    | CloseCurly
    | SemiColon
    | Comma
    | Period

    -- Literals
    | IntTok  Integer
    | LongTok Integer
    | DoubleTok Double
    | FloatTok Double
    | CharTok Char
    | StringTok String
    | BoolTok Bool
    | NullTok

    -- Identifiers
    | IdentTok String

    -- Operators
    | Op_Equal
    | Op_GThan
    | Op_LThan
    | Op_Bang
    | Op_Tilde
    | Op_Query
    | Op_Colon
    | Op_Equals
    | Op_LThanE
    | Op_GThanE
    | Op_BangE
    | Op_AAnd
    | Op_OOr
    | Op_PPlus
    | Op_MMinus
    | Op_Plus
    | Op_Minus
    | Op_Star
    | Op_Slash
    | Op_And
    | Op_Or
    | Op_Caret
    | Op_Percent
    | Op_LShift
    | Op_RShift
    | Op_RRShift
    | Op_PlusE
    | Op_MinusE
    | Op_StarE
    | Op_SlashE
    | Op_AndE
    | Op_OrE
    | Op_CaretE
    | Op_PercentE
    | Op_LShiftE
    | Op_RShiftE
    | Op_RRShiftE
  deriving (Show, Eq)

lexer :: String -> [L Token]
lexer = alexScanTokens

}