packages feed

cpsa-4.4.4: src/CPSA/Prolog/Main.hs

-- Prints the output of a CPSA run as a Prolog database.

-- This programs loads CPSA output.  It assembles the skeletons in the
-- output into a forest of derivation trees.  It then prints the
-- forest in Prolog syntax.  To be loadable by Prolog, the output must
-- be sorted so that clauses of one predicate are colocated.

-- The output should be used by SWI Prolog as strings must not be atoms.
-- Load the generated file using consult/1.

-- Copyright (c) 2024 The MITRE Corporation
--
-- This program is free software: you can redistribute it and/or
-- modify it under the terms of the BSD License as published by the
-- University of California.

module Main (main) where

import System.IO
import Data.Char (toLower)
import Text.Printf (printf)
import CPSA.Lib.SExpr
import CPSA.Lib.Entry
import CPSA.Prolog.Loader
import CPSA.Prolog.Tree

main :: IO ()
main =
    do
      (p, (output, _)) <- start filterOptions filterInterp
      ks <- loadPreskels p
      h <- outputHandle output
      prolog h (forest ks)
      hClose h

-- Load preskeletons
loadPreskels :: PosHandle -> IO ([Preskel])
loadPreskels h =
    do
      (_, k, s) <- loadFirst h
      ks <- loop [k] s
      return ks
    where
      loop ks s =
          do
            n <- loadNext s
            case n of
              Nothing ->        -- EOF
                  return $ reverse ks
              Just (k, s) ->
                  loop (k:ks) s

-- Print forest
prolog :: Handle -> Forest -> IO ()
prolog h f = mapM_ (root h) f

root :: Handle -> Tree -> IO ()
root h t =
    do
      hPutStrLn h (printf "root(%d)." (label $ vertex t))
      tree h t

tree :: Handle -> Tree -> IO ()
tree h t =
    do
      let l = label $ vertex t
      body h l (alist $ vertex t)
      strands h l 0 (alist $ vertex t)
      mapM_ (child h l) (children t)
      mapM_ (dup h l) (seen $ vertex t)

body :: Handle -> Int -> [SExpr Pos] -> IO ()
body h l xs =
    do
      hPutStr h (printf "skel(%d, " l)
      sexprs h xs
      hPutStrLn h ")."

strands :: Handle -> Int -> Int -> [SExpr Pos] -> IO ()
strands _ _ _ [] =
    return ()
strands h l s (x@(L _ (S _ "defstrand" : _)) : xs) =
    do
      hPutStr h (printf "strand(%d, %d, " l s)
      sexpr h x
      hPutStrLn h ")."
      strands h l (s + 1) xs
strands h l s (x@(L _ (S _ "deflistener" : _)) : xs) =
    do
      hPutStr h (printf "strand(%d, %d, " l s)
      sexpr h x
      hPutStrLn h ")."
      strands h l (s + 1) xs
strands h l s (_ : xs) =
    do
      strands h l s xs

sexprs :: Handle -> [SExpr a] -> IO ()
sexprs h [] =
    hPutStr h "[]"
sexprs h (x : xs) =
    do
      hPutStr h "["
      sexpr h x
      rest h xs
      hPutStr h "]"

sexpr :: Handle -> SExpr a -> IO ()
sexpr h (S _ []) = -- This should never happen
    hPutStr h []
sexpr h (S _ (c : s)) = -- Ensure symbol is a Prolog constant
    hPutStr h (map toUnderScore (toLower c : s))
sexpr h (Q _ q) =
    do
      hPutStr h "\""
      hPutStr h q
      hPutStr h "\""
sexpr h (N _ n) =
    hPutStr h (printf "%d" n)
sexpr h (L _ xs) =
    sexprs h xs

toUnderScore :: Char -> Char
toUnderScore '-' = '_'
toUnderScore c = c

rest :: Handle -> [SExpr a] -> IO ()
rest _ [] =
    return ()
rest h (x : xs) =
    do
      hPutStr h ", "
      sexpr h x
      rest h xs

child :: Handle -> Int -> Tree -> IO ()
child h l t =
    do
      let lab = label $ vertex t
      hPutStrLn h (printf "child(%d, %d)." l lab)
      case assoc "operation" (alist $ vertex t) of
        Just op ->
            do
              hPutStr h (printf "step(%d, " l) --
              sexpr h (L () (S () "operation" : map strip op))
              hPutStrLn h (printf ", %d)." lab)
              tree h t
        _ ->
            do
              hPutStrLn h (printf "step(%d, [], %d)." l lab)
              tree h t

dup :: Handle -> Int -> (Int, SExpr a) -> IO ()
dup _ l (lab, _) | l == lab = return () -- Ignore self loops
dup h l (lab, op) =
    do
      hPutStr h (printf "step(%d, " l)
      sexpr h op
      hPutStrLn h (printf ", %d)." lab)