Filter simplified expressions in reporter, not in `simplify` #20

Closed
wants to merge 1 commit into
from

Projects

None yet

4 participants

@lynaghk
Contributor
lynaghk commented Mar 21, 2012

I'm putting together a tool that uses kibit for rewriting Clojure code into ClojureScript (see cljsbuild issue here). Most expressions stay the same and just need to get passed through to the reporter, so I've moved the filtering (when-not (= alt expr) ...) clause to the default cli reporter.

@lynaghk lynaghk Don't filter expressions in `simplify`. This allows one to use the ki…
…bit library as a code rewriting tool by just adding their own rules and reporter.
b808a63
@ohpauleez
Collaborator

Hey Kevin!

Thanks for the patch. I'm not sure this is the right approach to achieve what you want.
I will create a new branch and do a refactor for you, and you can test it out. Sound good?

Also, take a look at TXL if you need something even crazier to do rewrites.

@lynaghk
Contributor
lynaghk commented Mar 21, 2012

Hey Paul!

What's the issue? Do you think it's still too high up because, e.g., the reporter is called on toplevel forms individually rather than being given the seq?

Or do you think Kibit won't be flexible enough to achieve some of the rewrites I'll need?

@swannodette

I actually think it would be pretty neat for kibit to do CLJ <-> CLJS transformation, especially if it seems like the machinery is already there. But I understand if you all don't think it's in scope.

@lynaghk
Contributor
lynaghk commented Mar 21, 2012

I've only been playing around with it for a day, but direct symbol replacement (clojure.lang.IFn -> IFn) is easy, as is excluding toplevel vars with appropriate metadata (e.g. remove (defn ^:clj sqrt [x] (Math/sqrt x)) when compiling to cljs).

One thing that I don't think is going to fit easily in kibit is automatically detecting macros and moving them to a custom namespace. I also don't have a ton of core.logic experience, so I don't know how easy it'll be to replace more complex forms (like protocol method name differences within a reify or extend).

@jonase
Owner
jonase commented Mar 21, 2012

This is definitely interesting.

One thing that the rule system cannot express currently is

(.member obj) -> (.-member obj)

Similarly, I'd like the following rule in kibit

(. obj method arg1 arg2 ...) -> (.method obj arg1 arg2 ...)

@lynaghk
Contributor
lynaghk commented Mar 21, 2012

@jonase Why can't the rule system express your first example right now using simple symbol substitution?

@jonase
Owner
jonase commented Mar 21, 2012

It can, if you enumerate all patterns as different rules, but not as one general rule.

i.e. The following is possible now:

[(.someMember ?obj) (.-someMember ?obj)]

but not

[(?some-member ?obj) (?.-some-member ?obj) :when [(symbol-starts-with .)]]

Kind of hard to explain, hopefully you know what I mean.

@lynaghk
Contributor
lynaghk commented Mar 21, 2012

Ah, I see. One way around that would be to execute special forms in the replacement process (i.e. at "kibit-time") to munge the symbols bound to ?x via something like (symbol (str ".-" (name ?x))). I don't know how doable that is though.

@swannodette

It's really simple to build parsers with core.logic. Changing kibit so that we grab all patterns until we hit :when or :alt would not be hard. That was why I included :when and :alt in my rule guards example on the other ticket.

@jonase
Owner
jonase commented Mar 21, 2012

@swannodette - I'm studying your code in #19 more thoroughly, maybe I missed some of its implications. I have a couple of questions.

The first form in the rule

[[(fn ?args (?fun . ?args)) :when [fn-call?] :alt ?fun]]

is (in a sense) redundant since you could do the exact same thing in fn-call?, right? I guess one problem is that we lose the captured logic vars which are later used in the substitution part of the rule.

Currently the :alt part of the rule simply substitutes the logic vars into the new form. If we want to write a rule which would transform

(. obj method arg) 

into

(.method obj arg)

(i.e., squash together . and method into a single symbol) we'd need to do something similar as what is done in the :when part. The open question (for me) is if this is possible and still keep basic rules like

[(+ ?x 1) (inc ?x)] 

as easy to write (and read) as they are now?

@swannodette

Seems possible to me, I'll try to come up with some code later today to deal with these concerns.

@swannodette
(defn not-keywordo [x]
  (all
   (!= x :when)
   (!= x :alt)))

(defne parse-rule [rule ps gs alt]
  ([[alt] () () _])
  ([[:alt alt] () () _])
  ([[:when gs . r] () _ _]
     (fresh [ngs]
       (parse-rule r ps ngs alt)))
  ([[p . r] [p . nps] _ _]
     (not-keywordo p)
     (parse-rule r nps gs alt)))

(run* [q]
  (fresh [ps gs alt]
    (parse-rule '[(+ ?x 1) (inc ?x)] ps gs alt)
    (== q [:patterns ps :guards gs :alt alt])))
;; ([:patterns ((+ ?x 1)) :guards () :alt (inc ?x)])

(run* [q]
  (fresh [ps gs alt]
    (parse-rule '[(fn ?args (?fun . ?args)) :when [fn-call?] :alt ?fun]
                ps gs alt)
    (== q [:patterns ps :guards gs :alt alt])))
;; ([:patterns ((fn ?args (?fun . ?args)))
;;   :guards [fn-call?]
;;   :alt ?fun])

(run* [q]
  (fresh [ps gs alt]
    (parse-rule '[(fn ?args (?fun . ?args))
                  (fn ?name ?args (?fun . ?args))
                  :when [fn-call?] :alt ?fun]
                ps gs alt)
    (== q [:patterns ps :guards gs :alt alt])))
;; ([:patterns ((fn ?args (?fun . ?args))
;;              (fn ?name ?args (?fun . ?args)))
;;   :guards [fn-call?]
;;   :alt ?fun])

(run* [q]
  (fresh [ps gs alt]
    (parse-rule '[(fn ?args (?fun . ?args))
                  (fn ?name ?args (?fun . ?args))
                  :when [fn-call?] ?fun]
                ps gs alt)
    (== q [:patterns ps :guards gs :alt alt])))
;; ([:patterns ((fn ?args (?fun . ?args))
;;              (fn ?name ?args (?fun . ?args)))
;;   :guards [fn-call?]
;;   :alt ?fun])
@ohpauleez
Collaborator

Totally badass @swannodette.
This is an awesome concept, and yes, I've been amazed at how easy/open core.logic is to generating anything you can think up.

@lynaghk I just wanted to decouple the decision to guard on simplify's output, rather than shove processing logic onto a reporter, who should only be reporting what it's tossed.

https://github.com/jonase/kibit/tree/guarded-simplify
diff at: master...guarded-simplify

@lynaghk
Contributor
lynaghk commented Mar 22, 2012

@ohpauleez That branch will work for me. I'll close this pull and let you guys know when I have some clj/cljs generation code public.

@lynaghk lynaghk closed this Mar 22, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment