Arc Forumnew | comments | leaders | submitlogin
Improved ppr (bodops* fix)
2 points by fallintothis 5423 days ago | 4 comments
The fix:

  (= bodops*
     (with (exclude '(aif)
            include '(after 1 annotate 1 atlet 2 atwith 1 atwiths 1 case 1
                       caselet 2 def 2 defhook 2 deftem 1 fn 1 mac 2))
       (fill-table (table
                     [each (op parms) sig
                       (unless (mem op exclude)
                         (when (is (reclist atom&idfn parms) 'body)
                           (= (_ op) (count (fn (x) t)
                                            (check parms acons)))))])
                   include)))
(See below for another approach, too.)

Explanation:

In pprint.arc, ppr decides how to indent certain expressions based on whether they're operators that have some body of code. For example, def should be indented like

  (def f (x)
    body)
instead of

  (def f
       (x)
       body)
But the body-operators are determined by the hard-coded table

  (= bodops* (fill-table (table)
     '(let 2 with 1 while 1 def 2 fn 1 rfn 2 afn 1
       when 1 unless 1 after 1 whilet 2 for 3 each 2 whenlet 2 awhen 1
       whitepage 0 tag 1 form 1 aform 1 aformh 1 w/link 1 textarea 3
     )))
This only has 22 operators and clearly misses a lot of them -- it doesn't even have mac!

But the definitions of body-operators are fairly reliable in Arc's source: they usually name their rest parameter "body". So, my fix:

- looks through sig for operators that take a rest parameter named "body"

- excludes false positives (I only noticed aif, but it's easily extensible)

- includes false negatives (e.g., def isn't in sig and atlet's rest parameter is named "args")

Thus, it makes the table less hard-coded, more future-proof, etc.

Caveat: this definition means that we'll only find as many body-operators as are in sig at the time pprint.arc is loaded. Note that libs.arc loads pprint.arc second:

  (map load '("strings.arc"
              "pprint.arc"
              "code.arc"
              "html.arc"
              "srv.arc"
              "app.arc"
              "prompt.arc"))
So, if we put this definition at the top of pprint.arc, we'll miss the body-operators of code.arc, html.arc, srv.arc, app.arc, and prompt.arc.

Possible solution: make a bodop function instead.

  (with (exclude '(aif)
         include (fill-table (table)
                   '(after 1 annotate 1 atlet 2 atwith 1 atwiths 1 case 1
                      caselet 2 def 2 defhook 2 deftem 1 fn 1 mac 2)))

    (defmemo bodop (op)
      (unless (mem op exclude)
        (or (include op)
            (let parms (sig op)
              (and (is (reclist atom&idfn parms) 'body)
                   (count (fn (x) t)
                          (check parms acons)))))))

    (each op (+ (keys sig) (keys include) exclude)
      (bodop op)))
On the plus side, the result is determined at runtime, so we don't need to worry about when bodop is defined in relation to body-operators. And though memoization makes it resistant to redefinitions (I'm not sure if that's good or bad), ppr could treat some user-defined operators as body-operators (this might actually be desirable).

My compromise for the time being is to put the original fix at the end of libs.arc instead of at the top of pprint.arc -- i.e., after all the libraries have been loaded. When this is done, we have

BEFORE:

  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (len bodops*)
  22
  arc> (sort < (keys bodops*))
  (afn aform aformh after awhen def each fn for form let rfn tag textarea
  unless w/link when whenlet while whilet whitepage with)
  arc> (ppr '(mac rfn (name parms . body)
               `(let ,name nil
                  (assign ,name (fn ,parms ,@body)))))
  (mac rfn
       (name parms . body)
       (quasiquote (let (unquote name) nil
                     (assign (unquote name)
                             (fn (unquote parms)
                               (unquote-splicing body))))))t
AFTER:

  Use (quit) to quit, (tl) to return here after an interrupt.
  arc> (len bodops*)
  100
  arc> (sort < (keys bodops*))
  (accum afn aform aformh after annotate arform arformh atlet atomic atwith
  atwiths awhen case caselet catch cdata center def defbg defcache defhook
  defmemo defop defop-raw defopl defopr defopr-raw defset deftem down each fn
  fontcolor for forlen form fromstring let linkf loop mac noisy-each on onlink
  onrlink point prbold repeat rfn rlinkf spanclass spanrow sptab summing tab
  taform tag tag-if tarform td tdcolor tdr textarea thread tostring tr trtd
  uform ulink underline unless until urform w/appendfile w/bars w/infile
  w/instring w/link w/link-if w/outfile w/outstring w/rlink w/socket w/stdin
  w/stdout w/table w/uniq when when-umatch when-umatch/r whenlet while whiler
  whilet whitepage widtable with withs zerotable)
  arc> (ppr '(mac rfn (name parms . body)
               `(let ,name nil
                  (assign ,name (fn ,parms ,@body)))))
  (mac rfn (name parms . body)
    (quasiquote (let (unquote name) nil
                  (assign (unquote name)
                          (fn (unquote parms)
                            (unquote-splicing body))))))t


1 point by shader 5422 days ago | link

If you're interested, I wrote a new version of ppr that's currently available on anarki, that properly displays most functions, macros, if statements, and quasiquotes. The goal was to get it to look as much like the original source code as possible, to work with my src function. It also makes it easy to define an indentation function for a particular form, if you don't like the default indentation.

-----

1 point by fallintothis 5422 days ago | link

Thanks, I did remember that. I suppose the outstanding bugs from http://arclanguage.org/item?id=9801 were fixed? e.g., My other post (http://arclanguage.org/item?id=11296) fixed the issue where long expressions (afn calls and such) would print on one line.

I'll still be combing over pg's pprint.arc, though. By keeping the changes small, modular, and as close to the original as possible, I figure that (a) there's a smaller chance of bugs, as each change is more understandable; (b) the code will be compatible with vanilla Arc; and thus (c) even if just a few fixes are cherry-picked, we might actually get a decent ppr in the next release. If nothing else, it's kind of fun. :)

-----

1 point by shader 5422 days ago | link

Indeed, that's the main reason I wrote my version of ppr ;) That's how I originally started my version - I was annoyed by the fact that pg's wouldn't properly print quasiquotes in my source code (and it's hard to debug macros that way) and just couldn't stop because it was so much fun.

And to be honest, I don't really know what the outstanding bugs are, or whether or not I ended up fixing them. It's been a while since I last looked at ppr.

-----

1 point by rntz 5419 days ago | link

All the bugs that I can recall finding are fixed.

-----