From 18266866b6ca51919bfcf9433b3bdf97fdcbd78f Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Fri, 17 Jan 2020 01:06:11 -0300 Subject: [PATCH 1/2] warning the user at compile time about the unused bindings --- src/main/clojure/clara/rules/compiler.clj | 3 +++ src/main/clojure/clara/rules/logger.cljc | 25 +++++++++++++++++++++++ 2 files changed, 28 insertions(+) create mode 100644 src/main/clojure/clara/rules/logger.cljc diff --git a/src/main/clojure/clara/rules/compiler.clj b/src/main/clojure/clara/rules/compiler.clj index 8d9699cd..06b00705 100644 --- a/src/main/clojure/clara/rules/compiler.clj +++ b/src/main/clojure/clara/rules/compiler.clj @@ -5,6 +5,7 @@ (:require [clara.rules.engine :as eng] [clara.rules.listener :as listener] [clara.rules.platform :as platform] + [clara.rules.logger :as logger] [clara.rules.schema :as schema] [clojure.core.reducers :as r] [clojure.reflect :as reflect] @@ -2060,6 +2061,8 @@ (transient #{})) persistent!)] + (logger/warn-unused-bindings! productions) + (if-let [session (get @session-cache [productions options])] session (let [session (mk-session* productions options)] diff --git a/src/main/clojure/clara/rules/logger.cljc b/src/main/clojure/clara/rules/logger.cljc new file mode 100644 index 00000000..c74b93f5 --- /dev/null +++ b/src/main/clojure/clara/rules/logger.cljc @@ -0,0 +1,25 @@ +(ns clara.rules.logger) + +(defn- warn-unused-binding + [{:keys [lhs rhs] :as production}] + (let [re-binding #"\?[\w-]+" + constraints-bindings (->> lhs + (mapcat :constraints) + (map (comp (partial re-find re-binding) str)) + (filter some?)) + fact-bindings (->> lhs + (map :fact-binding) + (filter some?) + (map name)) + rhs-bindings (re-seq re-binding (str rhs))] + (run! (fn [[?bind freq]] + (when (= freq 1) + (println (format "WARNING: binding %s defined at %s is not being used" ?bind (:name production))))) + (->> constraints-bindings + (concat fact-bindings rhs-bindings) + (filter some?) + frequencies)))) + +(defn warn-unused-bindings! + [productions] + (run! warn-unused-binding productions)) From 29ca62853e0353667141a6fad58fc9319fe3aca3 Mon Sep 17 00:00:00 2001 From: Wanderson Ferreira Date: Thu, 20 Feb 2020 06:15:29 -0300 Subject: [PATCH 2/2] unused bindings --- src/main/clojure/clara/rules/analysis.cljc | 30 ++++++++++ .../clojure/clara/rules/analysis_utils.cljc | 7 +++ src/main/clojure/clara/rules/compiler.clj | 57 +++++++++++++++---- src/main/clojure/clara/rules/logger.cljc | 25 -------- 4 files changed, 83 insertions(+), 36 deletions(-) create mode 100644 src/main/clojure/clara/rules/analysis.cljc create mode 100644 src/main/clojure/clara/rules/analysis_utils.cljc delete mode 100644 src/main/clojure/clara/rules/logger.cljc diff --git a/src/main/clojure/clara/rules/analysis.cljc b/src/main/clojure/clara/rules/analysis.cljc new file mode 100644 index 00000000..c5f09647 --- /dev/null +++ b/src/main/clojure/clara/rules/analysis.cljc @@ -0,0 +1,30 @@ +(ns clara.rules.analysis + (:require [clara.rules.analysis-utils :as utils])) + +(defn- warn-unused-binding + [{:keys [lhs rhs] :as production}] + (let [constraints-bindings (->> (filter utils/is-variable? (flatten (mapcat :constraints lhs)))) + fact-bindings (filter some? (flatten (map :fact-binding lhs))) + rhs-bindings (filter utils/is-variable? (flatten rhs))]) + (println lhs) + #_(let [re-binding #"\?[\w-]+" + constraints-bindings (->> lhs + (mapcat :constraints) + (map (comp utils/is-variable? str)) + (filter some?)) + fact-bindings (->> lhs + (map :fact-binding) + (filter some?) + (map name)) + rhs-bindings (re-seq re-binding (str rhs))] + (run! (fn [[?bind freq]] + (when (= freq 1) + (println (format "WARNING: binding %s defined at %s is not being used" ?bind (:name production))))) + (->> constraints-bindings + (concat fact-bindings rhs-bindings) + (filter some?) + frequencies)))) + +(defn warn-unused-bindings! + [productions] + (run! warn-unused-binding productions)) diff --git a/src/main/clojure/clara/rules/analysis_utils.cljc b/src/main/clojure/clara/rules/analysis_utils.cljc new file mode 100644 index 00000000..ed5d197b --- /dev/null +++ b/src/main/clojure/clara/rules/analysis_utils.cljc @@ -0,0 +1,7 @@ +(ns clara.rules.analysis-utils) + +(defn is-variable? + "Returns true if the given expression is a variable (a symbol prefixed by ?)" + [expr] + (and (symbol? expr) + (.startsWith (name expr) "?"))) diff --git a/src/main/clojure/clara/rules/compiler.clj b/src/main/clojure/clara/rules/compiler.clj index 06b00705..c3b47b35 100644 --- a/src/main/clojure/clara/rules/compiler.clj +++ b/src/main/clojure/clara/rules/compiler.clj @@ -5,8 +5,9 @@ (:require [clara.rules.engine :as eng] [clara.rules.listener :as listener] [clara.rules.platform :as platform] - [clara.rules.logger :as logger] [clara.rules.schema :as schema] + [clara.rules.analysis :as analysis] + [clara.rules.analysis-utils :refer [is-variable?]] [clojure.core.reducers :as r] [clojure.reflect :as reflect] [clojure.set :as s] @@ -14,7 +15,8 @@ [clojure.string :as string] [clojure.walk :as walk] [schema.core :as sc] - [schema.macros :as sm]) + [schema.macros :as sm] + [clara.rules.testfacts :as tf]) (:import [clara.rules.engine ProductionNode QueryNode @@ -69,8 +71,8 @@ query-nodes :- {sc/Any QueryNode} ;; Map of id to one of the alpha or beta nodes (join, accumulate, etc). id-to-node :- {sc/Num (sc/conditional - :activation AlphaNode - :else BetaNode)} + :activation AlphaNode + :else BetaNode)} ;; Function for sorting activation groups of rules for firing. activation-group-sort-fn ;; Function that takes a rule and returns its activation group. @@ -80,12 +82,6 @@ ;; A map of [node-id field-name] to function. node-expr-fn-lookup :- schema/NodeFnLookup]) -(defn- is-variable? - "Returns true if the given expression is a variable (a symbol prefixed by ?)" - [expr] - (and (symbol? expr) - (.startsWith (name expr) "?"))) - (def ^:private reflector "For some reason (bug?) the default reflector doesn't use the Clojure dynamic class loader, which prevents reflecting on @@ -2061,7 +2057,7 @@ (transient #{})) persistent!)] - (logger/warn-unused-bindings! productions) + (analysis/warn-unused-bindings! productions) (if-let [session (get @session-cache [productions options])] session @@ -2073,3 +2069,42 @@ ;; Return the session. session))))) + +(comment + (require '[clara.rules :as rl]) + (require '[clara.rules.accumulators :as acc]) + (require '[clara.rules.testfacts :as tf]) + (import clara.rules.testfacts.ColdAndWindy) + (import clara.rules.testfacts.Temperature) + + (defrecord CurrentTemperature [temperature]) + + + (rl/defrule rule-testing + [?cold <- ColdAndWindy (= ?w windspeed) (< temperature 10) + (= ?w 20)] + => + (println ?cold) + (println "All bindings used")) + + (rl/defrule rule-testing-warning + [?cold <- ColdAndWindy (= ?w windspeed) (< temperature 10)] + => + (println "Warning, ?w not used")) + + (def newest-temp (acc/max :timestamp :returns-fact true)) + + (rl/defrule get-current-temperature + [?current-temp <- newest-temp :from [Temperature (= ?location location)]] + => + (rl/insert! (->CurrentTemperature ?current-temp)) + ) + + (rl/mk-session `rule-testing + `rule-testing-warning + `get-current-temperature + ) + + + + ) diff --git a/src/main/clojure/clara/rules/logger.cljc b/src/main/clojure/clara/rules/logger.cljc deleted file mode 100644 index c74b93f5..00000000 --- a/src/main/clojure/clara/rules/logger.cljc +++ /dev/null @@ -1,25 +0,0 @@ -(ns clara.rules.logger) - -(defn- warn-unused-binding - [{:keys [lhs rhs] :as production}] - (let [re-binding #"\?[\w-]+" - constraints-bindings (->> lhs - (mapcat :constraints) - (map (comp (partial re-find re-binding) str)) - (filter some?)) - fact-bindings (->> lhs - (map :fact-binding) - (filter some?) - (map name)) - rhs-bindings (re-seq re-binding (str rhs))] - (run! (fn [[?bind freq]] - (when (= freq 1) - (println (format "WARNING: binding %s defined at %s is not being used" ?bind (:name production))))) - (->> constraints-bindings - (concat fact-bindings rhs-bindings) - (filter some?) - frequencies)))) - -(defn warn-unused-bindings! - [productions] - (run! warn-unused-binding productions))