-
Notifications
You must be signed in to change notification settings - Fork 114
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
base: main
Are you sure you want to change the base?
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
(ns clara.rules.logger) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we go with this approach, I'd not call the ns "logger". Something like |
||
|
||
(defn- warn-unused-binding | ||
[{:keys [lhs rhs] :as production}] | ||
(let [re-binding #"\?[\w-]+" | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd suggest using the is-variable? function in the interest of consistency; we could factor it out into say an "analysis-utils" namespace to avoid a cyclic dependency. |
||
constraints-bindings (->> lhs | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. super nit/style: Could these be replaced by transducers? |
||
(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)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A binding in an accumulator constraint will cause accumulation to occur over each value of that binding, so even if it is a new binding that isn't used elsewhere it actually does impact rule semantics. So these two rules don't behave the same way:
http://www.clara-rules.org/docs/accumulators/ discusses this, specifically the paragraph after the first example. So I think we need logic that excludes from this check bindings that only appear once, but where that appearance is in an accumulator.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! I'm glad you pointed this out. I should have paid more attention. Can't this be the case for more than just an accumulator then? This may make the whole effort here need to shift to something within the compiler more than an external pass over the production structures as currently being done.
I thought this external "linting" approach was fine since we could just ignore nearly all structure and find variables. However, seeing this accumulator case reminds me there are more semantics to perhaps be aware of. The detection may be more "context dependent" than I thought...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting corner case, I will write some code to handle the accumulator approach. Maybe if something else appear that is more dependent of context, we can revisit this approach of external linting.