-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #19 from quoll/pabu
Pabu
- Loading branch information
Showing
15 changed files
with
379 additions
and
16 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
sibling(fred, barney). | ||
parent(fred, mary). | ||
sibling(mary, george). | ||
gender(george, male). | ||
|
||
parent(B, C) :- sibling(A, B), parent(A, C). | ||
brother(A, B) :- sibling(A, B), gender(B, male). | ||
uncle(A, C) :- parent(A, B), brother(B, C). | ||
/* sibling(A, B) :- parent(A, P), parent(B, P). */ | ||
gender(F, male) :- father(A, F). | ||
parent(A, F) :- father(A, F). | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
(ns ^{:doc "Command line interface for interacting with Naga." | ||
:author "Paula Gearon"} | ||
naga.cli | ||
(:require [clojure.tools.cli :refer [parse-opts]] | ||
[clojure.string :as string] | ||
[clojure.java.io :as io] | ||
[naga.lang.pabu :as pabu] | ||
[naga.rules :as r] | ||
[naga.engine :as e] | ||
[naga.store :as store] | ||
[naga.storage.memory.core])) | ||
|
||
(def stores (map name (keys @store/registered-stores))) | ||
|
||
(def cli-options | ||
[["-s" "--storage" "Select store type" | ||
:validate [(set stores) "Must be a registered storage type."]] | ||
["-h" "--halp" "Print help"]]) | ||
|
||
(defn exit | ||
[status message] | ||
(println message) | ||
(System/exit status)) | ||
|
||
(defn usage | ||
[{summary :summary}] | ||
(->> ["Executes Naga on a program." | ||
"" | ||
"Usage: naga [filename]" | ||
"" | ||
summary | ||
(str "Store types: " (into [] stores)) | ||
""] | ||
(string/join \newline))) | ||
|
||
(defn run-all | ||
"Runs a program, and returns the data processed, the results, and the stats. | ||
Takes an input stream. Returns a map of: | ||
:input, :output, :stats" | ||
[in] | ||
;; read the program | ||
(let [{:keys [rules axioms]} (pabu/read-stream in) | ||
|
||
;; instantiate a database. For the demo we're using "in-memory" | ||
fresh-store (store/get-storage-handle {:type :memory}) | ||
|
||
;; assert the initial axioms. The program can do that, but | ||
;; we want to do it here so we can see the original store | ||
;; (we may use it for comparisons some time in the future) | ||
original-store (store/assert-data fresh-store axioms) | ||
|
||
;; Configure the storage the program will use. Provide a store | ||
;; so the program won't try to create its own | ||
config {:type :memory :store original-store} | ||
|
||
;; compile the program | ||
program (r/create-program rules []) | ||
|
||
;; run the program | ||
[store results] (e/run config program) | ||
|
||
;; dump the database by resolving an unbound constraint | ||
data (store/resolve-pattern store '[?e ?p ?v])] | ||
{:input axioms | ||
:output (remove (set axioms) data) | ||
:stats results})) | ||
|
||
|
||
(defn- nm | ||
"Returns a string version of a keyword. These are not being represented | ||
as Clojure keywords, so namespaces (when they exist) are separated by | ||
a : character" | ||
[k] | ||
(if-let [n (namespace k)] | ||
(str n ":" (name k)) | ||
(name k))) | ||
|
||
|
||
(defn- predicate-string | ||
"Convert a predicate triplet into a string." | ||
[[e p v]] | ||
(if (= p :rdf/type) | ||
(str (nm e) "(" (nm v) ").") | ||
(str (nm p) "(" (nm e) ", " (nm v) ")."))) | ||
|
||
|
||
(defn -main [& args] | ||
(let [{:keys [options arguments] :as opts} (parse-opts args cli-options)] | ||
(when (:halp options) (exit 1 (usage opts))) | ||
(let [in-stream (if-let [filename (first arguments)] | ||
(io/input-stream filename) | ||
*in*) | ||
{:keys [input output stats]} (run-all in-stream)] | ||
(println "INPUT DATA") | ||
(doseq [a input] (println (predicate-string a))) | ||
(println "\nNEW DATA") | ||
(doseq [a output] (println (predicate-string a)))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
(ns ^{:doc "Implements Pabu, which is a Prolog-like language for Naga. | ||
Parses code and returns Naga rules." | ||
:author "Paula Gearon"} | ||
naga.lang.pabu | ||
(:require [naga.schema.structs :as structs :refer [Axiom Program]] | ||
[naga.lang.parser :as parser] | ||
[naga.rules :as r] | ||
[schema.core :as s]) | ||
(:import [java.io InputStream] | ||
[naga.schema.structs Rule])) | ||
|
||
;; TODO: Multi-arity not yet supported | ||
(def Args | ||
[(s/one s/Any "entity") | ||
(s/optional s/Any "value")]) | ||
|
||
(def AxiomAST | ||
{:type (s/eq :axiom) | ||
:axiom [(s/one s/Keyword "Property") | ||
(s/one Args "args")]}) | ||
|
||
(def Triple | ||
[(s/one s/Any "entity") | ||
(s/one s/Any "property") | ||
(s/one s/Any "value")]) | ||
|
||
(s/defn triplet :- Triple | ||
[[property [s o :as args]]] | ||
(if (= 1 (count args)) | ||
[s :rdf/type property] | ||
[s property o])) | ||
|
||
(s/defn ast->axiom :- Axiom | ||
"Converts the axiom structure returned from the parser" | ||
[{axiom :axiom :as axiom-ast} :- AxiomAST] | ||
(triplet axiom)) | ||
|
||
(def VK "Either a Variable or a Keyword" (s/cond-pre s/Keyword s/Symbol)) | ||
|
||
(def Predicate [(s/one VK "property") | ||
(s/one Args "arguments")]) | ||
|
||
(def RuleAST | ||
{:type (s/eq :rule) | ||
:head [(s/one VK "property") | ||
(s/one Args "arguments")] | ||
:body [Predicate]}) | ||
|
||
(s/defn ast->rule | ||
"Converts the rule structure returned from the parser" | ||
[{:keys [head body] :as rule-ast} :- RuleAST] | ||
(r/rule (triplet head) (map triplet body) (-> head first name gensym name))) | ||
|
||
(s/defn read-str :- {:rules [Rule] | ||
:axioms [Axiom]} | ||
"Reads a string" | ||
[s :- s/Str] | ||
(let [program-ast (parser/parse s) | ||
axioms (filter (comp (partial = :axiom) :type) program-ast) | ||
rules (filter (comp (partial = :rule) :type) program-ast)] | ||
{:rules (map ast->rule rules) | ||
:axioms (map ast->axiom axioms)})) | ||
|
||
(s/defn read-stream :- Program | ||
"Reads a input stream" | ||
[in :- InputStream] | ||
(let [text (slurp in)] | ||
(read-str text))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
(ns ^{:doc "Parser for Pabu, which is a Prolog-like syntax for Naga." | ||
:author "Paula Gearon"} | ||
naga.lang.parser | ||
(:refer-clojure :exclude [char]) | ||
(:require [the.parsatron :refer :all])) | ||
|
||
(defn choice* | ||
"choice with backtracking." | ||
[& args] | ||
(apply choice (map attempt args))) | ||
|
||
(defn either* | ||
"either with backtracking." | ||
[p q] | ||
(either (attempt p) (attempt q))) | ||
|
||
(defn upper-case-letter? | ||
"Prolog considers underscores to be equivalent to an uppercase letter" | ||
[c] | ||
(or (Character/isUpperCase ^Character c) (= \_ c))) | ||
|
||
(defn upper-case-letter | ||
[] | ||
(token upper-case-letter?)) | ||
|
||
(def non-star (token (complement #{\*}))) | ||
(def non-slash (token (complement #{\/}))) | ||
|
||
(defparser cmnt [] | ||
(let->> [_ (>> (string "/*") (many non-star) (many1 (char \*))) | ||
_ (many (>> non-slash (many non-star) (many1 (char \*)))) | ||
_ (char \/)] | ||
(always :cmnt))) | ||
|
||
(def whitespace-char (token #{\space \newline \tab})) | ||
(def opt-whitespace (many (either whitespace-char (cmnt)))) | ||
(def separator (>> opt-whitespace (char \,) opt-whitespace)) | ||
(def open-paren (>> (char \() opt-whitespace)) | ||
(def close-paren (>> opt-whitespace (char \)))) | ||
|
||
(def word (many1 (letter))) | ||
|
||
(def digits (many1 (digit))) | ||
|
||
(defparser signed-digits [] | ||
(let->> [s (token #{\+ \-}) | ||
ds digits] | ||
(always (cons s ds)))) | ||
|
||
(defparser integer [] | ||
(let->> [i (either digits (signed-digits))] | ||
(always (Long/parseLong (apply str i))))) | ||
|
||
(defparser floating-point [] | ||
(let->> [i (either digits (signed-digits)) | ||
f (>> (char \.) (many1 (digit)))] | ||
(always (Double/parseDouble (apply str (apply str i) \. f))))) | ||
|
||
(def number (either* (floating-point) (integer))) | ||
|
||
(defparser pstring1 [] | ||
(let->> [s (many1 (between (char \') (char \') (many (any-char)))) ] | ||
(always (flatten (interpose \' s))))) | ||
|
||
(defparser pstring2 [] | ||
(let->> [s (many1 (between (char \") (char \") (many (any-char))))] | ||
(always (flatten (interpose \" s))))) | ||
|
||
(def pstring (either (pstring1) (pstring2))) | ||
|
||
(defparser variable [] | ||
(let->> [f (upper-case-letter) | ||
r (many (letter))] | ||
(always (symbol (apply str "?" (Character/toLowerCase f) r) )))) | ||
|
||
(defparser kw [] | ||
(let->> [r word] | ||
(always (keyword (apply str r))))) | ||
|
||
(defparser atm [] | ||
(choice (kw) pstring number)) | ||
|
||
(defparser elt [] | ||
(choice (variable) (atm))) | ||
|
||
(defparser arg-list [] | ||
(let->> [f (elt) | ||
r (many (>> separator (elt)))] | ||
(always (cons f r)))) | ||
|
||
(defparser structure [] | ||
(let->> [p (elt) | ||
args (between open-paren close-paren (arg-list))] | ||
(always [p args]))) | ||
|
||
(defparser structures [] | ||
(let->> [s (structure) | ||
ss (many (attempt (>> separator (structure))))] | ||
(always (cons s ss)))) | ||
|
||
(defparser nonbase-clause [] | ||
(let->> [head (>> opt-whitespace (structure)) | ||
_ (>> opt-whitespace (string ":-") opt-whitespace) | ||
body (structures) | ||
_ (>> opt-whitespace (char \.) opt-whitespace)] | ||
(always {:type :rule | ||
:head head | ||
:body body}))) | ||
|
||
(defparser base-clause [] | ||
(let->> [structure (>> opt-whitespace (structure)) | ||
_ (>> opt-whitespace (char \.) opt-whitespace)] | ||
(always {:type :axiom | ||
:axiom structure}))) | ||
|
||
(def program (many (either* (nonbase-clause) (base-clause)))) | ||
|
||
(defn parse | ||
"Parse a string" | ||
[s] | ||
(run program s)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
src/naga/storage/memory_index.clj → src/naga/storage/memory/index.clj
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.