packages feed

language-lua-0.11.0: src/Language/Lua/Annotated/Lexer.x

{

{-# OPTIONS_GHC -w #-}
{-# LANGUAGE TemplateHaskell, BangPatterns #-}

module Language.Lua.Annotated.Lexer
  ( llex
  , llexNamed
  , llexNamedWithWhiteSpace
  , llexFile
  , SourcePos(..)
  , SourceRange(..)
  , dropWhiteSpace
  , Lexeme(..)
  ) where

import           Data.Text (Text)
import qualified Data.Text as Text
import qualified Data.Text.IO as Text

import           Language.Lua.Token
import           Language.Lua.LexerUtils
import           AlexTools

}

$letter      = [a-zA-Z_]                -- first letter of variables
$identletter = [a-zA-Z_0-9]             -- letters for rest of variables

$digit    = 0-9                         -- decimal digits
$hexdigit = [0-9a-fA-F]                 -- hexadecimal digits

$dqstr    = . # [ \" \\ ]               -- valid character in a string literal with dquotes
$sqstr    = . # [ \' \\ ]               -- valid character in a string literal with quotes
$longstr  = [ . \n ]                    -- valid character in a long string

-- escape characters
@charesc   = \\ ([ntvbrfa\\"'] | $digit{1,3} | x$hexdigit{2} | u\{$hexdigit+\} | \n | z $white*)

@digits    = $digit+
@hexdigits = $hexdigit+

@mantpart = @digits | @digits \. @digits | @digits \. | \. @digits
@exppart  = [eE][\+\-]? @digits

@hexprefix   = 0x | 0X
@mantparthex = @hexdigits | @hexdigits \. @hexdigits | @hexdigits \. | \. @hexdigits
@expparthex  = [pP][\+\-]? @hexdigits

tokens :-

    <0> $white+    { lexeme TokWhiteSpace }

    -- keywords
    <0> "and"      { lexeme TokAnd }
    <0> "break"    { lexeme TokBreak }
    <0> "do"       { lexeme TokDo }
    <0> "else"     { lexeme TokElse }
    <0> "elseif"   { lexeme TokElseIf }
    <0> "end"      { lexeme TokEnd }
    <0> "false"    { lexeme TokFalse }
    <0> "for"      { lexeme TokFor }
    <0> "function" { lexeme TokFunction }
    <0> "goto"     { lexeme TokGoto }
    <0> "if"       { lexeme TokIf }
    <0> "in"       { lexeme TokIn }
    <0> "local"    { lexeme TokLocal }
    <0> "nil"      { lexeme TokNil }
    <0> "not"      { lexeme TokNot }
    <0> "or"       { lexeme TokOr }
    <0> "repeat"   { lexeme TokRepeat }
    <0> "return"   { lexeme TokReturn }
    <0> "then"     { lexeme TokThen }
    <0> "true"     { lexeme TokTrue }
    <0> "until"    { lexeme TokUntil }
    <0> "while"    { lexeme TokWhile }

    -- identifiers
    <0> $letter $identletter* { lexeme TokIdent }

    -- number literals
    <0> @digits                              { lexeme TokInt   }
    <0> @hexprefix @digits                   { lexeme TokInt   }
    <0> @mantpart @exppart?                  { lexeme TokFloat }
    <0> @hexprefix @mantparthex @expparthex? { lexeme TokFloat }

    <0> \'                   { enterString SingleQuote }
    <state_sstring> @charesc ;
    <state_sstring> $sqstr   ;
    <state_sstring> \'       { endMode }

    -- string literals
    <0> \"                   { enterString DoubleQuote }
    <state_dstring> @charesc ;
    <state_dstring> $dqstr   ;
    <state_dstring> \"       { endMode }

    -- long strings
    <0> \[ =* \[              { enterLongString }
    <state_lstring> \] =* \] / { endStringPredicate } { endMode }
    <state_lstring> $longstr  ;

    -- comments
    <0> "--" \[ =* \[       { enterLongComment }
    <0> "--"                { enterComment }
    <state_comment> .*      { endMode }

    -- operators
    <0> "+"   { lexeme TokPlus }
    <0> "-"   { lexeme TokMinus }
    <0> "*"   { lexeme TokStar }
    <0> "/"   { lexeme TokSlash }
    <0> "//"  { lexeme TokDSlash }
    <0> "%"   { lexeme TokPercent }
    <0> "^"   { lexeme TokExp }
    <0> "#"   { lexeme TokSh }
    <0> "=="  { lexeme TokEqual }
    <0> "~="  { lexeme TokNotequal }
    <0> "<="  { lexeme TokLEq }
    <0> ">="  { lexeme TokGEq }
    <0> "<"   { lexeme TokLT }
    <0> ">"   { lexeme TokGT }
    <0> "="   { lexeme TokAssign }
    <0> "("   { lexeme TokLParen }
    <0> ")"   { lexeme TokRParen }
    <0> "{"   { lexeme TokLBrace }
    <0> "}"   { lexeme TokRBrace }
    <0> "["   { lexeme TokLBracket }
    <0> "]"   { lexeme TokRBracket }
    <0> "::"  { lexeme TokDColon }
    <0> ";"   { lexeme TokSemic }
    <0> ":"   { lexeme TokColon }
    <0> ","   { lexeme TokComma }
    <0> "."   { lexeme TokDot }
    <0> ".."  { lexeme TokDDot }
    <0> "..." { lexeme TokEllipsis }
    <0> "&"   { lexeme TokAmpersand }
    <0> "|"   { lexeme TokPipe }
    <0> "~"   { lexeme TokTilde }
    <0> "<<"  { lexeme TokDLT }
    <0> ">>"  { lexeme TokDGT }

    <state_sstring,state_dstring> \\ .  { invalidEsc }
    <state_sstring,state_dstring> \n { unterminatedString }

    <0> .                              { invalidChar }

{

lexerTools :: Input -> [Lexeme Token]
lexerTools = $makeLexer LexerConfig
  { lexerInitialState = NormalMode
  , lexerEOF = \_ _ -> []
  , lexerStateMode = \mode ->
       case mode of
         NormalMode        -> 0
         CommentMode    {} -> state_comment
         QuoteMode      {} -> state_lstring
         StringMode SingleQuote _ _ -> state_sstring
         StringMode DoubleQuote _ _ -> state_dstring
  }

alexGetByte = makeAlexGetByte (fromIntegral . min 127 . fromEnum)

-- | Lua lexer with default @=<string>@ name.
llex :: Text {- ^ chunk -} -> [Lexeme Token]
llex = llexNamed "=<string>"


-- | Lua lexer with explicit name.
llexNamed ::
  String {- ^ name -} ->
  Text   {- ^ chunk -} ->
  [Lexeme Token]
llexNamed name chunk = dropWhiteSpace (llexNamedWithWhiteSpace name chunk)


-- | Lua lexer with explicit name, preseves white space and comments.
llexNamedWithWhiteSpace ::
  String {- ^ name -} ->
  Text   {- ^ chunk -} ->
  [Lexeme Token]
llexNamedWithWhiteSpace name chunk =
   lexerTools (initialInput (Text.pack name) (dropSpecialComment chunk))


-- | Run Lua lexer on a file.
llexFile :: FilePath -> IO [Lexeme Token]
llexFile fp = fmap (llexNamed fp) (Text.readFile fp)

}