packages feed

tpdb-2.9.0: src/TPDB/ARI.hs

{-# language OverloadedStrings #-}
{-   # options_ghc -fdefer-typed-holes #-}

module TPDB.ARI where

import Data.AttoLisp
import qualified Data.Attoparsec.ByteString as DAB
import Data.Attoparsec.Number
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Text as T
import qualified Data.HashMap.Strict as M
import Control.Applicative (many)
import Control.Monad (guard)
import TPDB.Data
import TPDB.Plain.Write
import TPDB.Pretty

-- writer
put :: TRS Identifier Identifier -> BSL.ByteString
put = BSL.concat . map encodeLn . w

encodeLn x = encode x `BSL.snoc` lf
  where lf = fromIntegral $ fromEnum '\n' -- HACK

w :: TRS Identifier Identifier -> [Lisp]
w sys =
  let sym s = Symbol $ name s
      sig = do
        s <- signature sys
        return $ List [ Symbol "fun", sym s
                 , Number $ I $ fromIntegral $ arity s
                      ]
      trm t = case t of
        Var v -> sym v
        Node f args -> List $ sym f : map trm args
      rul = do
         u <- rules sys
         return $ List
               $ [ Symbol "rule", trm (lhs u), trm (rhs u) ]
               <> case relation u of
                   Strict -> []
                   Weak -> [ Symbol ":cost", Number (I 0) ]
  in  [ List [Symbol "format", Symbol "TRS" ] ]
      <> sig
      <> rul


-- parser

get :: BS.ByteString -> Either String (TRS Identifier Identifier)
get s = DAB.parseOnly ( p <* DAB.atEnd ) s

p :: DAB.Parser (TRS Identifier Identifier)
p = do
  cl : auses <- many lisp
  guard $ cl == List [Symbol "format", Symbol "TRS"]
  let symbolize s0 = maybe s0 id $ do
        ('|', s1) <- T.uncons s0; (s2, '|') <- T.unsnoc s1; return s2
      funs = do
        List [Symbol "fun", Symbol s, Number (I a)] <- auses
        return (s, mk (fromIntegral a) $ symbolize s)
      sig = M.fromListWith (error "conflict") funs
  let rs :: [ Rule (Term Identifier Identifier) ]
      rs = do
        List (Symbol "rule" : l : r : trailer) <- auses
        return $ Rule { lhs = termof sig l
                      , rhs = termof sig r
                      , relation = case trailer of
                          [ ] -> Strict
                          [ Symbol ":cost", Number (I 0) ]
                             -> Weak
                      , top = False
                      , original_variable = Nothing
                      }
  return $ RS
    { signature = map snd funs
    , rules = rs
    , separate = False
    }

termof :: M.HashMap T.Text Identifier -> Lisp
  -> Term Identifier Identifier
termof sig (List (Symbol s : args)) =
  case M.lookup s sig of
    Just f | arity f == length args ->
             Node f $ map (termof sig) args
termof sig (Symbol s) = case M.lookup s sig of
  Nothing -> Var $ mk 0 s
  Just f -> Node f [] -- ?