packages feed

jukebox-0.2.14: src/Jukebox/TPTP/Lexer.x

-- -*- mode: haskell -*-

-- Roughly taken from the TPTP syntax reference
{
{-# OPTIONS_GHC -O2 -fno-warn-deprecated-flags #-}
{-# LANGUAGE BangPatterns #-}
module Jukebox.TPTP.Lexer(
  scan,
  Pos(..),
  Token(..),
  Punct(..),
  Defined(..),
  Keyword(..),
  TokenStream(..),
  Contents(..)) where

import Data.Word
import Data.Char
import Data.Ratio
}

$alpha = [a-zA-Z0-9_]
$anything = [. \n]
@quoted = ($printable # [\\']) | \\ $printable
@dquoted = ($printable # [\\\"]) | \\ $printable
@pnum = [1-9][0-9]*
@num  = 0 | @pnum

tokens :-
-- Comments and whitespace
"%" .* ;
"/*" (($anything # \*)* "*"+
      ($anything # [\/\*]))*
     ($anything # \*)* "*"* "*/" ; -- blech!
$white+ ;

-- Keywords.
"thf" { k Thf }
"tff" { k Tff }
"fof" { k Fof }
"cnf" { k Cnf }
"axiom" { k Axiom }
"hypothesis" { k Hypothesis }
"definition" { k Definition }
"assumption" { k Assumption }
"lemma" { k Lemma }
"theorem" { k Theorem }
"conjecture" { k Conjecture }
"negated_conjecture" { k NegatedConjecture }
"question" { k Question }
"plain" { k Plain }
"fi_domain" { k FiDomain }
"fi_hypothesis" { k FiHypothesis }
"fi_predicates" { k FiPredicates }
"type" { k Type }
"unknown" { k Unknown }
"include" { k Include }
-- Defined symbols.
"$true" { d DTrue }
"$false" { d DFalse }
"$distinct" { d DDistinct }
"$itef" { d DItef }
"$itett" | "$itetf" { d DItet }
"$o" | "$oType" { d DO }
"$i" | "$iType" { d DI }
"$tType" { d DTType }
-- Atoms.
"$"{0,2} [a-z] $alpha* { Atom Normal . copy }
-- Atoms with funny quoted names (here we diverge from the official
-- syntax, which only allows the escape sequences \\ and \' in quoted
-- atoms: we allow \ to be followed by any printable character)
"'"  @quoted+ "'" { Atom Normal . unquote }
-- Vars are easy :)
[A-Z][$alpha]* { Var . copy }
-- Distinct objects, which are double-quoted
\" @dquoted+  \" { DistinctObject . unquote }
-- Numbers
[\+\-]? @num/($anything # $alpha) { Number . read }
[\+\-]? @num\/@pnum { Rational . readRational }
[\+\-]? @num\.@num { Real . readReal }
[\+\-]? @num(\.@num)?[eE]@num { Real . readReal }

-- Operators (FOF)
"("  { p LParen }  ")"   { p RParen }  "["  { p LBrack }   "]"  { p RBrack }
","  { p Comma }   "."   { p Dot }     "|"  { p Or }       "&"  { p And }
"~"  { p Not }     "<=>" { p Iff }     "=>" { p Implies }  "<=" { p Follows }
"<~>"{ p Xor }     "~|"  { p Nor }     "~&" { p Nand }     "="  { p Eq }
"!=" { p Neq }     "!"   { p ForAll }  "?"  { p Exists }   ":=" { p Let }
":-" { p LetTerm }
-- Operators (TFF)
":" { p Colon }    "*"   { p Times }   "+"  { p Plus }     ">"  { p FunArrow }
-- Operators (THF)
"^"  { p Lambda } "@" { p Apply }  "!!" { p ForAllLam }  "??"  { p ExistsLam }
"@+" { p Some }   "@-" { p The }   "<<" { p Subtype }    "-->" { p SequentArrow }
"!>" { p DependentProduct }        "?*" { p DependentSum }

{
data Pos = Pos {-# UNPACK #-} !Word {-# UNPACK #-} !Word deriving Show
data Token = Atom { keyword :: !Keyword, tokenName :: !String }
           | Defined { defined :: !Defined  }
           | Var { tokenName :: !String }
           | DistinctObject { tokenName :: !String }
           | Number { value :: !Integer }
           | Rational { ratValue :: !Rational }
           | Real { ratValue :: !Rational }
           | Punct { kind :: !Punct }
           | Eof
           | Error

data Keyword = Normal
             | Thf | Tff | Fof | Cnf
             | Axiom | Hypothesis | Definition | Assumption
             | Lemma | Theorem | Conjecture | NegatedConjecture | Question
             | Plain | FiDomain | FiHypothesis | FiPredicates | Type | Unknown
             | Include deriving (Eq, Ord)

instance Show Keyword where
  show x =
    case x of {
      Normal -> "normal";
      Thf -> "thf"; Tff -> "tff"; Fof -> "fof"; Cnf -> "cnf";
      Axiom -> "axiom"; Hypothesis -> "hypothesis"; Definition -> "definition";
      Assumption -> "assumption"; Lemma -> "lemma"; Theorem -> "theorem";
      Conjecture -> "conjecture"; NegatedConjecture -> "negated_conjecture";
      Question -> "question"; Plain -> "plain"; FiDomain -> "fi_domain";
      FiHypothesis -> "fi_hypothesis"; FiPredicates -> "fi_predicates";
      Type -> "type"; Unknown -> "unknown"; Include -> "include" }

-- We only include defined names that need special treatment from the
-- parser here: you can freely make up any other names starting with a
-- '$' and they get turned into Atoms.
data Defined =
    DTrue | DFalse | DDistinct | DItef | DItet
  | DO | DI | DTType
  deriving (Eq, Ord)

instance Show Defined where
  show x =
    case x of {
      DTrue -> "$true"; DFalse -> "$false";
      DDistinct -> "$distinct"; DItef -> "$itef"; DItet -> "$itet";
      DO -> "$o"; DI -> "$i"; DTType -> "$tType" }

data Punct = LParen | RParen | LBrack | RBrack | Comma | Dot
           | Or | And | Not | Iff | Implies | Follows | Xor | Nor | Nand
           | Eq | Neq | ForAll | Exists | Let | LetTerm -- FOF
           | Colon | Times | Plus | FunArrow -- TFF
           | Lambda | Apply | ForAllLam | ExistsLam
           | DependentProduct | DependentSum | Some | The
           | Subtype | SequentArrow -- THF
             deriving (Eq, Ord)

instance Show Punct where
  show x =
    case x of {
      LParen -> "("; RParen -> ")"; LBrack -> "["; RBrack -> "]";
      Comma -> ","; Dot -> "."; Or -> "|"; And -> "&"; Not -> "~";
      Iff -> "<=>"; Implies -> "=>"; Follows -> "<="; Xor -> "<~>";
      Nor -> "~|"; Nand -> "~&"; Eq -> "="; Neq -> "!="; ForAll -> "!";
      Exists -> "?"; Let -> ":="; Colon -> ":"; Times -> "*"; Plus -> "+";
      FunArrow -> ">"; Lambda -> "^"; Apply -> "@"; ForAllLam -> "!!";
      ExistsLam -> "??"; Some -> "@+"; The -> "@-"; Subtype -> "<<";
      SequentArrow -> "-->"; DependentProduct -> "!>"; DependentSum -> "?*";
      LetTerm -> ":-" }

p x = const (Punct x)
k x = Atom x . copy
d x = const (Defined x)

copy :: String -> String
copy = id

unquote :: String -> String
unquote (_:x)
  | null z = init y
  | otherwise = y ++ [z !! 1] ++ unquote (drop 1 z)
  where (y, z) = break (== '\\') x

readRational :: String -> Rational
readRational = readSigned (readNum (\m ('/':xs) -> readNum (\n [] -> m % n) xs))

readReal :: String -> Rational
readReal = readSigned $ readNum $ \m xs ->
  case xs of
    '.':ys -> readDigits (readExp m) ys
    _ -> readExp m [] xs
  where
    readExp n ds ('e':xs) =
      readSign (\f -> readNum (result n ds . f)) xs
    readExp n ds ('E':xs) =
      readSign (\f -> readNum (result n ds . f)) xs
    readExp n ds xs = result n ds 0 xs
    result n ds e [] =
      (fromInteger n +
       fromInteger (read ds) / (10^length ds)) * (10^^e)

readSigned :: (String -> Rational) -> String -> Rational
readSigned f xs = readSign (\g -> g . f) xs

readSign :: Num a => ((a -> a) -> String -> Rational) -> String -> Rational
readSign f ('+':xs) = f id xs
readSign f ('-':xs) = f negate xs
readSign f xs = f id xs

readNum :: (Integer -> String -> Rational) -> String -> Rational
readNum f xs = readDigits (f . read) xs

readDigits :: (String -> String -> Rational) -> String -> Rational
readDigits f xs = f ys zs
  where
    (ys, zs) = span isDigit xs

-- The main scanner function, heavily modified from Alex's posn-bytestring wrapper.

data TokenStream = At {-# UNPACK #-} !Pos !Contents
data Contents = Cons !Token TokenStream

scan xs = go (Input (Pos 1 1) '\n' xs)
  where go inp@(Input pos _ xs) =
          case alexScan inp 0 of
                AlexEOF -> let t = At pos (Cons Eof t) in t
                AlexError _ -> let t = At pos (Cons Error t) in t
                AlexSkip  inp' _ -> go inp'
                AlexToken inp' len act ->
                  At pos (act (take len xs) `Cons` go inp')

data AlexInput = Input {-# UNPACK #-} !Pos {-# UNPACK #-} !Char String

alexInputPrevChar :: AlexInput -> Char
alexInputPrevChar (Input _ c _) = c

{-# INLINE alexGetByte #-}
alexGetByte :: AlexInput -> Maybe (Word8,AlexInput)
alexGetByte i = fmap f (alexGetChar i)
  where f (c, i') = (fromIntegral (ord c), i')
{-# INLINE alexGetChar #-}
alexGetChar :: AlexInput -> Maybe (Char,AlexInput)
alexGetChar (Input p _ (x:xs)) =
  Just (x, Input (advance p x) x xs)
alexGetChar _ = Nothing

{-# INLINE advance #-}
advance :: Pos -> Char -> Pos
advance (Pos l c) '\t' = Pos  l    (c+8 - (c-1) `mod` 8)
advance (Pos l _) '\n' = Pos (l+1) 1
advance (Pos l c) _    = Pos  l    (c+1)
}