Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

[REBOL] Re: Rugby source code cleaner? :-)

From: joel:neely:fedex at: 30-Jan-2002 9:04

Hello, all, Joel Neely wrote:
> One of the factors which drove me to think about alternative styles > was the difficulty (i.e. impossibility) of algorithmically laying > out REBOL code in the general case. (Not that The Style That Must > Not Be Mentioned solved that problem by any stretch of the > imagination!) >
Motivated to see how far I could get with purely lexical/syntactic concepts (and hoping someone else could benefit/contribute), I hacked up a "pretty-printer" for REBOL structures. At this point it only handles blocks, objects, functions, and files (assumed to contain REBOL source), or words that are set to one of those types. PPR assumes that all whitespace (non-string, of course!) in an input file or block is ignorable -- after all, PPR is supposed to be doing the layout, and should assume that any pre-existing style in the source is obsolete! ;-) If PPR has any value (other than as a stimulus for further ideas), it would be as a "pre-pass" over code to perform basic structural layout. Real-world use would still require a human to go back and insert optional whitespace (horizontal and vertical) as desired to supply semantically-oriented grouping/separation, and to fix the mangled comments (see below). PPR attempts to implement the following rules, which I believe to be consistent with the RCUG style rules: - Use indentation (4 columns per level) to show nested structure. - Limit line length to 72 characters. - If the representation of a value will fit entirely on the on the current line, put it there. - If it will not fit on the current line, and it's not a block, start a new line (appropriately indented). - If it won't fit, and it's a block, indent the contents of the block; the opening bracket goes at the end of the previous line, and the closing bracket begins a new line resuming the previous indentation level. - Multiply-nested blocks can begin on the same line (as in the previous point) but their closing brackets will be on distinct lines at the appropriate "outdent". Additional heuristics are: - The result of PPR is a string (allowing it to be saved to a file for source cleanup). To simply see the output for testing purposes, PRINT PPR ... is the simplest thing to do. - If the argument to PPR is a word , the output resembles the setting of that word to a pretty-printed presentation of its value (see type limitations above!) - If the argument is a file, the content of the file is presented as if LOADed instead of DOne. Since REBOL doesn't recognize the distinction between data and code, no attempt was made to guess the meaning/usage of the content of a block, with one exception: - A new line is begun (at the appropriate level of indentation) whenever a set-word value (or sequence of consecutive set-word values) is encountered in a block which will not fit on a single line. This has the advantage of making objects appear in an intuitively obvious form (and function bodies, as well) but has the disadvantage that set-words embedded within larger running expressions don't appear as subordinate. In general, no attempt is made to fathom/guess the meaning/intent of a block, so the semantic concepts of "expression" and "belonging together" are essentially absent. One additional limitation: comments in source files are hopelessly mangled. The use of comment { ... } will allow the output of PPR to be valid for re-loading, but all layout is lost. OTOH, the use of ;-style comments will likely produce text that will choke REBOL upon reloading unless manual intervention occurs. This email is already too long, but as a quick demo (for those who may not want to bother trying it out themselves), here's a source file which contains three copies of the same function with various layouts (RCUG, Style R, and Obfuscated): 8<------------------------------------------------------------ REBOL [] bignum: func [/local a aa b c d] [ a: aa: 1.0 until [ aa: a b: 1.0 c: 1.0 until [ any [ error? try [ d: a + b if d > a [print [d b c]] a: d ] error? try [ c: c + c b: c ] ] ] print a a = aa ] print a ] bignum2: func [ /local a aa b c d ][ a: aa: 1.0 until [ aa: a b: 1.0 c: 1.0 until [ any [ error? try [ d: a + b if d > a [print [d b c]] a: d] error? try [ c: c + c b: c] ] ] print a a = aa ] print a ] bignum3: func[/local a aa b c d][a: aa: 1.0 until[aa: a b: 1.0 c: 1.0 until[any[error? try[d: a + b if d > a[print[d b c]]a: d]error? try[c: c + c b: c]]]print a a = aa]print a] 8<------------------------------------------------------------ And here's how PPR renders that file: 8<------------------------------------------------------------
>> print ppr %/a/bignum.r
[ bignum: func [/local a aa b c d] [ a: aa: 1 until [ aa: a b: 1 c: 1 until [ any [ error? try [d: a + b if d > a [print [d b c]] a: d] error? try [c: c + c b: c] ] ] print a a = aa ] print a ] bignum2: func [/local a aa b c d] [ a: aa: 1 until [ aa: a b: 1 c: 1 until [ any [ error? try [d: a + b if d > a [print [d b c]] a: d] error? try [c: c + c b: c] ] ] print a a = aa ] print a ] bignum3: func [/local a aa b c d] [ a: aa: 1 until [ aa: a b: 1 c: 1 until [ any [ error? try [d: a + b if d > a [print [d b c]] a: d] error? try [c: c + c b: c] ] ] print a a = aa ] print a ] ] 8<------------------------------------------------------------ and an individual function after the file is DOne: 8<------------------------------------------------------------
>> print ppr 'bignum3
bignum3: func [/local a aa b c d] [ a: aa: 1 until [ aa: a b: 1 c: 1 until [ any [ error? try [d: a + b if d > a [print [d b c]] a: d] error? try [c: c + c b: c] ] ] print a a = aa ] print a ] 8<------------------------------------------------------------ Without further ado, here's PPR: 8<------------------------------------------------------------ _ppr: make object! [ linelimit: 72 textbuffer: copy "" delimiter: "" linebuffer: copy "" linelength?: func [] [length? linebuffer] pad: func [] [ either all [ 0 < linelength? #" " <> last linebuffer ][" "][""] ] reset: func [] [textbuffer: copy linebuffer: copy delimiter: ""] roomfor?: func [s [string!]] [ (length? s) + linelength? + (length? pad) <= linelimit ] endline: func [] [ if 0 < linelength? [ append textbuffer join delimiter linebuffer delimiter: newline linebuffer: copy "" ] ] output: func [s [string!] inset [integer!] /left] [ inset: inset * 4 either left [ if inset < linelength? [endline] ][ append linebuffer pad ] while [inset > linelength?] [append linebuffer " "] append linebuffer s ] ppcontent: func [ arg [block!] indent [integer!] /local moldeditem firstitem wasblock wassetword ][ firstitem: true wasblock: false wassetword: false foreach item arg [ either roomfor? moldeditem: mold :item [ either any [ firstitem all [wasblock not block? :item] all [set-word? :item not wassetword] ][ output/left moldeditem indent ][ output moldeditem indent ] ][ either block? :item [ ppblock item indent ][ output/left moldeditem indent ] ] firstitem: false wasblock: block? :item wassetword: set-word? :item ] ] ppblock: func [arg [block!] indent [integer!] /local moldedarg] [ either roomfor? moldedarg: mold arg [ output moldedarg indent ][ output "[" indent ppcontent arg indent + 1 output/left "]" indent ] ] cleanblock: func [arg [block! string!]] [load trim/lines arg] run: func [arg [block! word! file! object!]] [ reset if word? arg [ output join to-string arg ":" 0 arg: get arg ] switch/default to-string type? :arg [ "file" [ppblock cleanblock read arg 0] "block" [ppblock cleanblock mold arg 0] "object" [ppcontent cleanblock mold :arg 0] "function" [ppcontent cleanblock mold :arg 0] ][ output mold :arg 0 ] endline textbuffer ] ] ppr: func [arg [block! word! file! object!]] [_ppr/run arg] 8<------------------------------------------------------------ Enjoy! -jn- -- ; sub REBOL {}; sub head ($) {@_[0]} REBOL [] # despam: func [e] [replace replace/all e ":" "." "#" "@"] ; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"} print head reverse despam "moc:xedef#yleen:leoj" ;