Skip to content

warning the user at compile time about the unused bindings #448

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions src/main/clojure/clara/rules/analysis.cljc
Original file line number Diff line number Diff line change
@@ -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))
7 changes: 7 additions & 0 deletions src/main/clojure/clara/rules/analysis_utils.cljc
Original file line number Diff line number Diff line change
@@ -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) "?")))
56 changes: 47 additions & 9 deletions src/main/clojure/clara/rules/compiler.clj
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,17 @@
[clara.rules.listener :as listener]
[clara.rules.platform :as platform]
[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]
[clojure.set :as set]
[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
Expand Down Expand Up @@ -68,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.
Expand All @@ -79,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
Expand Down Expand Up @@ -2060,6 +2057,8 @@
(transient #{}))
persistent!)]

(analysis/warn-unused-bindings! productions)

(if-let [session (get @session-cache [productions options])]
session
(let [session (mk-session* productions options)]
Expand All @@ -2070,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
)



)