parsing facts/rules/queries

This commit is contained in:
Felix Dilke 2026-01-20 17:52:55 +00:00
parent 8744d97716
commit b41c3926df
3 changed files with 66 additions and 27 deletions

View File

@ -166,23 +166,3 @@ parseDatalog = parse (statement <* sc <* eof) "<datalog>"
parseDatalogFile :: Text -> Either (ParseErrorBundle Text Void) [Statement] parseDatalogFile :: Text -> Either (ParseErrorBundle Text Void) [Statement]
parseDatalogFile src = parse (many (statement <* sc)) "<datalog-file>" src parseDatalogFile src = parse (many (statement <* sc)) "<datalog-file>" src
-- Typical examples it can now parse
-- text-- Fact
-- parent("alice", "bob").
-- -- Fact with variables (uncommon but allowed)
-- edge(X, Y).
-- -- Rule
-- ancestor(X,Y) :- parent(X,Y).
-- ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y).
-- -- Query styles
-- ?- parent(alice,X).
-- ?- ancestor(X,Y), not blocked(X,Y).
-- ?- knows(a,X), friend(X,Y) → X,Y.
-- ?- edge(A,B), edge(B,C) → A,C .
-- -- With disjunction (rare but supported)
-- reached(X) :- start(X); via(Y), edge(Y,X).

View File

@ -22,8 +22,7 @@ import Control.Monad.Combinators.Expr
import Data.Functor (($>)) import Data.Functor (($>))
import Data.Void (Void) import Data.Void (Void)
import Text.Megaparsec import Text.Megaparsec
import Text.Megaparsec.Byte.Lexer (lexeme) import Text.Megaparsec.Char (char)
import Text.Megaparsec.Char (char, space)
import Text.Megaparsec.Char.Lexer (decimal) import Text.Megaparsec.Char.Lexer (decimal)
type Parser = Parsec Void String type Parser = Parsec Void String

View File

@ -32,9 +32,69 @@ spec = do
predName = "parent", predName = "parent",
arguments = [Sym "alice", Sym "bob"] arguments = [Sym "alice", Sym "bob"]
}) })
it "parsing a fact with variables" $ do
parseDatalog "edge(X, Y)." `shouldBe` Right (Fact Literal {
positive = True,
predName = "edge",
arguments = [Var "X", Var "Y"]
})
it "parsing a rule" $ do
parseDatalog "ancestor(X,Y) :- parent(X,Y)." `shouldBe` Right (Rule (HeadSingle Literal {
positive = True,
predName = "ancestor",
arguments = [Var "X", Var "Y"]
}) [Literal {
positive = True,
predName = "parent",
arguments = [Var "X", Var "Y"]
}])
it "parsing a more complex rule" $ do
parseDatalog "ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y)." `shouldBe` Right (Rule (HeadSingle (Literal {
positive = True,
predName = "ancestor",
arguments = [Var "X",Var "Y"]
})) [
Literal {
positive = True,
predName = "parent",
arguments = [Var "X",Var "Z"]
},
Literal {
positive = True,
predName = "ancestor",
arguments = [Var "Z",Var "Y"]}
])
it "parsing assorted queries" $ do
parseDatalog "?- parent(alice,X)." `shouldBe` Right (Query [] [Literal {
positive = True,
predName = "parent",
arguments = [Sym "alice", Var "X"]
}])
parseDatalog "?- ancestor(X,Y), not blocked(X,Y)." `shouldBe` Right (Query [] [Literal {
positive = True,
predName = "ancestor",
arguments = [Var "X", Var "Y"]
}, Literal {
positive = False,
predName = "blocked",
arguments = [Var "X", Var "Y"]
}])
parseDatalog "?- knows(a,X), friend(X,Y) → X,Y." `shouldBe` Right (Query ["X", "Y"] [Literal {
positive = True,
predName = "knows",
arguments = [Sym "a", Var "X"]
}, Literal {
positive = True,
predName = "friend",
arguments = [Var "X", Var "Y"]
}])
parseDatalog "?- edge(A,B), edge(B,C) → A,C ." `shouldBe` Right (Query ["A", "C"] [Literal {
positive = True,
predName = "edge",
arguments = [Var "A", Var "B"]
}, Literal {
positive = True,
predName = "edge",
arguments = [Var "B", Var "C"]
}])
-- eval (BinaryExpr Add (Literal 2) (Literal 3) ) `shouldBe` 5
-- eval (BinaryExpr Subtract (Literal 2) (Literal 3) ) `shouldBe` -1
-- eval (BinaryExpr Multiply (Literal 2) (Literal 3) ) `shouldBe` 6
-- eval (BinaryExpr Divide (Literal 7) (Literal 3) ) `shouldBe` 2
-- eval (UnaryExpr Negate (Literal 7) ) `shouldBe` -7