132 lines
3.0 KiB
Haskell
Raw Normal View History

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).
"""