eo-phi-normalizer-3.0.0: src/Language/EO/Phi/Syntax/Lex.x
-- -*- haskell -*- File generated by the BNF Converter (bnfc 2.9.5).
-- Lexer definition for use with Alex 3
{
{-# OPTIONS -fno-warn-incomplete-patterns #-}
{-# OPTIONS_GHC -w #-}
{-# LANGUAGE PatternSynonyms #-}
module Language.EO.Phi.Syntax.Lex where
import Prelude
import qualified Data.Bits
import Data.Char (ord)
import Data.Function (on)
import Data.Word (Word8)
}
-- Predefined character classes
$c = [A-Z\192-\221] # [\215] -- capital isolatin1 letter (215 = \times) FIXME
$s = [a-z\222-\255] # [\247] -- small isolatin1 letter (247 = \div ) FIXME
$l = [$c $s] -- letter
$d = [0-9] -- digit
$i = [$l $d _ '] -- identifier character
$u = [. \n] -- universal: any character
-- Symbols and non-identifier-like reserved words
@rsyms = \Φ | \ξ | \Δ | \λ | \φ | \ρ | \{ | \⟦ | \⟧ | \} | \( | \) | \. | \Φ \̇ | \⊥ | \[ | \↦ | \] | \⌈ | \, | \⌉ | \* | \∅ | \⤍ | \~
:-
-- Line comment "//"
"//" [.]* ;
-- Block comment "/*" "*/"
\/ \* [$u # \*]* \* ([$u # [\* \/]] [$u # \*]* \* | \*)* \/ ;
-- Whitespace (skipped)
$white+ ;
-- Symbols
@rsyms
{ tok (eitherResIdent TV) }
-- token Bytes
\- \- | [0 1 2 3 4 5 6 7 8 9 A B C D E F][0 1 2 3 4 5 6 7 8 9 A B C D E F]\- | [0 1 2 3 4 5 6 7 8 9 A B C D E F][0 1 2 3 4 5 6 7 8 9 A B C D E F](\- [0 1 2 3 4 5 6 7 8 9 A B C D E F][0 1 2 3 4 5 6 7 8 9 A B C D E F]) +
{ tok (eitherResIdent T_Bytes) }
-- token Function
$c [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_Function) }
-- token LabelId
$s [$u # [\t \n \r \ \! \' \( \) \, \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_LabelId) }
-- token AlphaIndex
α 0 | α [$d # 0]$d *
{ tok (eitherResIdent T_AlphaIndex) }
-- token LabelMetaId
\! τ [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_LabelMetaId) }
-- token TailMetaId
\! t [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_TailMetaId) }
-- token BindingsMetaId
\! B [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_BindingsMetaId) }
-- token ObjectMetaId
\! b [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_ObjectMetaId) }
-- token BytesMetaId
\! y [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_BytesMetaId) }
-- token MetaFunctionName
\@ [$u # [\t \n \r \ \! \' \( \) \, \- \. \: \; \? \[ \] \{ \| \} \⟦ \⟧]] *
{ tok (eitherResIdent T_MetaFunctionName) }
-- token IntegerSigned
\- ? $d +
{ tok (eitherResIdent T_IntegerSigned) }
-- token DoubleSigned
\- ? $d + \. $d + (e \- ? $d +)?
{ tok (eitherResIdent T_DoubleSigned) }
-- token StringRaw
\" ([$u # [\" \\]] | \\ [\" \\ f n r t u]) * \"
{ tok (eitherResIdent T_StringRaw) }
-- Keywords and Ident
$l $i*
{ tok (eitherResIdent TV) }
-- String
\" ([$u # [\" \\ \n]] | (\\ (\" | \\ | \' | n | t | r | f)))* \"
{ tok (TL . unescapeInitTail) }
-- Integer
$d+
{ tok TI }
-- Double
$d+ \. $d+ (e (\-)? $d+)?
{ tok TD }
{
-- | Create a token with position.
tok :: (String -> Tok) -> (Posn -> String -> Token)
tok f p = PT p . f
-- | Token without position.
data Tok
= TK {-# UNPACK #-} !TokSymbol -- ^ Reserved word or symbol.
| TL !String -- ^ String literal.
| TI !String -- ^ Integer literal.
| TV !String -- ^ Identifier.
| TD !String -- ^ Float literal.
| TC !String -- ^ Character literal.
| T_Bytes !String
| T_Function !String
| T_LabelId !String
| T_AlphaIndex !String
| T_LabelMetaId !String
| T_TailMetaId !String
| T_BindingsMetaId !String
| T_ObjectMetaId !String
| T_BytesMetaId !String
| T_MetaFunctionName !String
| T_IntegerSigned !String
| T_DoubleSigned !String
| T_StringRaw !String
deriving (Eq, Show, Ord)
-- | Smart constructor for 'Tok' for the sake of backwards compatibility.
pattern TS :: String -> Int -> Tok
pattern TS t i = TK (TokSymbol t i)
-- | Keyword or symbol tokens have a unique ID.
data TokSymbol = TokSymbol
{ tsText :: String
-- ^ Keyword or symbol text.
, tsID :: !Int
-- ^ Unique ID.
} deriving (Show)
-- | Keyword/symbol equality is determined by the unique ID.
instance Eq TokSymbol where (==) = (==) `on` tsID
-- | Keyword/symbol ordering is determined by the unique ID.
instance Ord TokSymbol where compare = compare `on` tsID
-- | Token with position.
data Token
= PT Posn Tok
| Err Posn
deriving (Eq, Show, Ord)
-- | Pretty print a position.
printPosn :: Posn -> String
printPosn (Pn _ l c) = "line " ++ show l ++ ", column " ++ show c
-- | Pretty print the position of the first token in the list.
tokenPos :: [Token] -> String
tokenPos (t:_) = printPosn (tokenPosn t)
tokenPos [] = "end of file"
-- | Get the position of a token.
tokenPosn :: Token -> Posn
tokenPosn (PT p _) = p
tokenPosn (Err p) = p
-- | Get line and column of a token.
tokenLineCol :: Token -> (Int, Int)
tokenLineCol = posLineCol . tokenPosn
-- | Get line and column of a position.
posLineCol :: Posn -> (Int, Int)
posLineCol (Pn _ l c) = (l,c)
-- | Convert a token into "position token" form.
mkPosToken :: Token -> ((Int, Int), String)
mkPosToken t = (tokenLineCol t, tokenText t)
-- | Convert a token to its text.
tokenText :: Token -> String
tokenText t = case t of
PT _ (TS s _) -> s
PT _ (TL s) -> show s
PT _ (TI s) -> s
PT _ (TV s) -> s
PT _ (TD s) -> s
PT _ (TC s) -> s
Err _ -> "#error"
PT _ (T_Bytes s) -> s
PT _ (T_Function s) -> s
PT _ (T_LabelId s) -> s
PT _ (T_AlphaIndex s) -> s
PT _ (T_LabelMetaId s) -> s
PT _ (T_TailMetaId s) -> s
PT _ (T_BindingsMetaId s) -> s
PT _ (T_ObjectMetaId s) -> s
PT _ (T_BytesMetaId s) -> s
PT _ (T_MetaFunctionName s) -> s
PT _ (T_IntegerSigned s) -> s
PT _ (T_DoubleSigned s) -> s
PT _ (T_StringRaw s) -> s
-- | Convert a token to a string.
prToken :: Token -> String
prToken t = tokenText t
-- | Finite map from text to token organized as binary search tree.
data BTree
= N -- ^ Nil (leaf).
| B String Tok BTree BTree
-- ^ Binary node.
deriving (Show)
-- | Convert potential keyword into token or use fallback conversion.
eitherResIdent :: (String -> Tok) -> String -> Tok
eitherResIdent tv s = treeFind resWords
where
treeFind N = tv s
treeFind (B a t left right) =
case compare s a of
LT -> treeFind left
GT -> treeFind right
EQ -> t
-- | The keywords and symbols of the language organized as binary search tree.
resWords :: BTree
resWords =
b "\934\775" 13
(b "]" 7
(b "," 4
(b ")" 2 (b "(" 1 N N) (b "*" 3 N N)) (b "[" 6 (b "." 5 N N) N))
(b "~" 10
(b "}" 9 (b "{" 8 N N) N) (b "\934" 12 (b "\916" 11 N N) N)))
(b "\8869" 20
(b "\966" 17
(b "\958" 15 (b "\955" 14 N N) (b "\961" 16 N N))
(b "\8709" 19 (b "\8614" 18 N N) N))
(b "\10214" 23
(b "\8969" 22 (b "\8968" 21 N N) N)
(b "\10509" 25 (b "\10215" 24 N N) N)))
where
b s n = B bs (TS bs n)
where
bs = s
-- | Unquote string literal.
unescapeInitTail :: String -> String
unescapeInitTail = id . unesc . tail . id
where
unesc s = case s of
'\\':c:cs | elem c ['\"', '\\', '\''] -> c : unesc cs
'\\':'n':cs -> '\n' : unesc cs
'\\':'t':cs -> '\t' : unesc cs
'\\':'r':cs -> '\r' : unesc cs
'\\':'f':cs -> '\f' : unesc cs
'"':[] -> []
c:cs -> c : unesc cs
_ -> []
-------------------------------------------------------------------
-- Alex wrapper code.
-- A modified "posn" wrapper.
-------------------------------------------------------------------
data Posn = Pn !Int !Int !Int
deriving (Eq, Show, Ord)
alexStartPos :: Posn
alexStartPos = Pn 0 1 1
alexMove :: Posn -> Char -> Posn
alexMove (Pn a l c) '\t' = Pn (a+1) l (((c+7) `div` 8)*8+1)
alexMove (Pn a l c) '\n' = Pn (a+1) (l+1) 1
alexMove (Pn a l c) _ = Pn (a+1) l (c+1)
type Byte = Word8
type AlexInput = (Posn, -- current position,
Char, -- previous char
[Byte], -- pending bytes on the current char
String) -- current input string
tokens :: String -> [Token]
tokens str = go (alexStartPos, '\n', [], str)
where
go :: AlexInput -> [Token]
go inp@(pos, _, _, str) =
case alexScan inp 0 of
AlexEOF -> []
AlexError (pos, _, _, _) -> [Err pos]
AlexSkip inp' len -> go inp'
AlexToken inp' len act -> act pos (take len str) : (go inp')
alexGetByte :: AlexInput -> Maybe (Byte,AlexInput)
alexGetByte (p, c, (b:bs), s) = Just (b, (p, c, bs, s))
alexGetByte (p, _, [], s) =
case s of
[] -> Nothing
(c:s) ->
let p' = alexMove p c
(b:bs) = utf8Encode c
in p' `seq` Just (b, (p', c, bs, s))
alexInputPrevChar :: AlexInput -> Char
alexInputPrevChar (p, c, bs, s) = c
-- | Encode a Haskell String to a list of Word8 values, in UTF8 format.
utf8Encode :: Char -> [Word8]
utf8Encode = map fromIntegral . go . ord
where
go oc
| oc <= 0x7f = [oc]
| oc <= 0x7ff = [ 0xc0 + (oc `Data.Bits.shiftR` 6)
, 0x80 + oc Data.Bits..&. 0x3f
]
| oc <= 0xffff = [ 0xe0 + (oc `Data.Bits.shiftR` 12)
, 0x80 + ((oc `Data.Bits.shiftR` 6) Data.Bits..&. 0x3f)
, 0x80 + oc Data.Bits..&. 0x3f
]
| otherwise = [ 0xf0 + (oc `Data.Bits.shiftR` 18)
, 0x80 + ((oc `Data.Bits.shiftR` 12) Data.Bits..&. 0x3f)
, 0x80 + ((oc `Data.Bits.shiftR` 6) Data.Bits..&. 0x3f)
, 0x80 + oc Data.Bits..&. 0x3f
]
}