2026-03-03 10:29:22 +00:00
|
|
|
{-# LANGUAGE MultilineStrings #-}
|
2026-03-03 11:26:13 +00:00
|
|
|
{-# LANGUAGE BlockArguments #-}
|
2026-03-03 10:29:22 +00:00
|
|
|
|
2026-03-03 11:14:25 +00:00
|
|
|
module Datalog.Parser (
|
|
|
|
|
parseTerm,
|
|
|
|
|
parseAtom,
|
|
|
|
|
parseRule,
|
|
|
|
|
parseQuery,
|
|
|
|
|
parseProgram,
|
|
|
|
|
)
|
|
|
|
|
where
|
2026-03-02 16:19:40 +00:00
|
|
|
|
|
|
|
|
import Data.Text (Text)
|
|
|
|
|
import Data.Text qualified as T
|
|
|
|
|
import Data.Void (Void)
|
2026-03-03 11:14:25 +00:00
|
|
|
import Datalog.Syntax
|
2026-03-02 16:19:40 +00:00
|
|
|
import Text.Megaparsec
|
|
|
|
|
import Text.Megaparsec.Char
|
|
|
|
|
import Text.Megaparsec.Char.Lexer qualified as L
|
2026-03-03 10:29:22 +00:00
|
|
|
import Text.Pretty.Simple
|
2026-03-02 16:19:40 +00:00
|
|
|
|
|
|
|
|
type Parser = Parsec Void Text
|
|
|
|
|
|
|
|
|
|
lexeme :: (MonadParsec e Text m) => m a -> m a
|
|
|
|
|
lexeme = L.lexeme whitespace
|
|
|
|
|
|
|
|
|
|
symbol :: (MonadParsec e Text m) => Text -> m Text
|
|
|
|
|
symbol = L.symbol whitespace
|
|
|
|
|
|
|
|
|
|
whitespace :: (MonadParsec e Text m) => m ()
|
2026-03-03 11:14:25 +00:00
|
|
|
whitespace =
|
|
|
|
|
L.space
|
|
|
|
|
space1
|
|
|
|
|
(L.skipLineComment "--")
|
|
|
|
|
(L.skipBlockComment "{-" "-}")
|
2026-03-02 16:19:40 +00:00
|
|
|
|
|
|
|
|
parens :: (MonadParsec e Text m) => m a -> m a
|
|
|
|
|
parens = between (symbol "(") (symbol ")")
|
|
|
|
|
|
|
|
|
|
comma, period :: (MonadParsec e Text m) => m ()
|
|
|
|
|
comma = () <$ symbol ","
|
|
|
|
|
period = () <$ symbol "."
|
|
|
|
|
|
|
|
|
|
parseCon :: (MonadParsec e Text m) => m Term
|
2026-03-02 17:05:32 +00:00
|
|
|
parseCon = Con () . ConId . T.pack <$> lexeme (liftA2 (:) (numberChar <|> lowerChar) (many alphaNumChar))
|
2026-03-02 16:19:40 +00:00
|
|
|
|
|
|
|
|
parseVar :: (MonadParsec e Text m) => m Term
|
2026-03-02 17:05:32 +00:00
|
|
|
parseVar = Var () . VarId . T.pack <$> lexeme (liftA2 (:) upperChar (many alphaNumChar))
|
2026-03-02 16:19:40 +00:00
|
|
|
|
|
|
|
|
parseTerm :: Parser Term
|
|
|
|
|
parseTerm = parseVar <|> parseCon
|
|
|
|
|
|
|
|
|
|
parseAtom :: Parser Atom
|
|
|
|
|
parseAtom = do
|
2026-03-03 11:14:25 +00:00
|
|
|
rel <- RelId . T.pack <$> lexeme (liftA2 (:) lowerChar (many alphaNumChar))
|
|
|
|
|
args <- parens (parseTerm `sepBy` comma)
|
|
|
|
|
return (Atom () rel args)
|
2026-03-02 16:19:40 +00:00
|
|
|
|
|
|
|
|
parseQuery :: Parser [Atom]
|
|
|
|
|
parseQuery = parseAtom `sepBy` comma
|
|
|
|
|
|
|
|
|
|
parseFact :: Parser Rule
|
|
|
|
|
parseFact = do
|
2026-03-03 11:14:25 +00:00
|
|
|
headAtom <- parseAtom
|
|
|
|
|
period
|
|
|
|
|
return (Rule () headAtom [])
|
2026-03-02 16:19:40 +00:00
|
|
|
|
|
|
|
|
parseRule :: Parser Rule
|
2026-03-03 11:14:25 +00:00
|
|
|
parseRule =
|
|
|
|
|
try parseFact <|> do
|
|
|
|
|
headAtom <- parseAtom <* symbol ":-"
|
|
|
|
|
bodyAtoms <- parseQuery
|
|
|
|
|
period
|
|
|
|
|
return (Rule () headAtom bodyAtoms)
|
2026-03-03 11:26:13 +00:00
|
|
|
parseRule' :: Parser (Rule' SrcLoc)
|
|
|
|
|
parseRule' = _
|
2026-03-02 16:19:40 +00:00
|
|
|
|
2026-03-03 11:26:13 +00:00
|
|
|
-- parseProgram :: Parser Program
|
|
|
|
|
parseProgram :: Parser (Program' SrcLoc)
|
|
|
|
|
parseProgram = do
|
|
|
|
|
-- annotateSrcLoc $
|
|
|
|
|
s <- getSourcePos
|
|
|
|
|
c <- many parseRule'
|
|
|
|
|
e <- getSourcePos
|
|
|
|
|
-- Program _ <$> many parseRule
|
|
|
|
|
pure $ Program (SrcLoc s e) c
|
|
|
|
|
|
|
|
|
|
parseProgram' :: Parser (Program' SrcLoc)
|
|
|
|
|
parseProgram' = parseThingWithSub (many parseRule') Program
|
|
|
|
|
|
|
|
|
|
parseThingWithSub :: (Parser c) -> (SrcLoc -> c -> f SrcLoc) -> Parser (f SrcLoc)
|
|
|
|
|
parseThingWithSub parseSub f = do
|
|
|
|
|
-- annotateSrcLoc $
|
|
|
|
|
s <- getSourcePos
|
|
|
|
|
-- c <- many parseRule'
|
|
|
|
|
c <- parseSub
|
|
|
|
|
e <- getSourcePos
|
|
|
|
|
-- Program _ <$> many parseRule
|
|
|
|
|
pure $ f (SrcLoc s e) c
|
2026-03-03 10:29:22 +00:00
|
|
|
|
2026-03-03 11:14:25 +00:00
|
|
|
annotateSrcLoc :: (Functor f) => Parser (f a) -> Parser (f SrcLoc)
|
2026-03-03 10:29:22 +00:00
|
|
|
annotateSrcLoc p = do
|
|
|
|
|
s <- getSourcePos
|
|
|
|
|
res <- p
|
|
|
|
|
f <- getSourcePos
|
|
|
|
|
pure (SrcLoc s f <$ res)
|
|
|
|
|
|
|
|
|
|
data SrcLoc = SrcLoc
|
2026-03-03 11:14:25 +00:00
|
|
|
{ start :: SourcePos
|
|
|
|
|
, end :: SourcePos
|
|
|
|
|
}
|
|
|
|
|
deriving (Show)
|
2026-03-03 10:29:22 +00:00
|
|
|
|
|
|
|
|
test = do
|
2026-03-03 11:14:25 +00:00
|
|
|
let r = runParser parseProgram "???" prog
|
|
|
|
|
pPrint @IO r
|
|
|
|
|
|
|
|
|
|
prog =
|
|
|
|
|
"""
|
|
|
|
|
odd(X,Y) :- r(X,Y).
|
|
|
|
|
odd(X,Y) :- even(X,Z), r(Z,Y).
|
|
|
|
|
even(X,Y) :- odd(X,Z), r(Z,Y).
|
|
|
|
|
|
|
|
|
|
r(0,1).
|
|
|
|
|
r(1,2).
|
|
|
|
|
r(2,3).
|
|
|
|
|
r(3,4).
|
|
|
|
|
r(4,5).
|
|
|
|
|
|
|
|
|
|
r(X,Y) :- r(Y,X).
|
|
|
|
|
"""
|