Brace-level pretty printer

Script bracelevel.tcl: Purpose: to output to the screen a tcl script with indicators of the nesting level of the code.

(AM Added the description below to help newcomers understand how it does what it does and why it can be useful)

Braces, { and }, are the main characters in Tcl code to structure the code. They are used for constructions such as if, for, foreach and switch. They also mark the beginning and end of the code implementing a procedure. In general, braces should be properly paired.

What may surprise people new to Tcl is that braces in comments should also be paired, as a comment is best regarded as a no-op command.

The script below is a simple but adequate means to visualise where nesting due to braces begins and ends. The idea is simple:

  • Read the complete file from standard input as a string
  • Split the string into lines (the command [split $str \n] will do this, \n being the newline character)
  • Then split each line into individual characters - this is done with [split $str ""]
  • Examine each character: an open brace will increment the count, a close brace will decrement it
  • Print the original line with the count of the open braces

Small exercise: Tcl reports runtime errors via the line count within the procedure's body, not by the line in the original source file (as procedures can be created "on the fly" there may not even be a source file with exactly that line ...). You can modify the script below to print the line count within a procedure's body:

  • If the open brace count becomes 1, set the line count to 0
  • Increase with every line read
  • Print the line count rather than the brace count

Note:

The script below does not take into account that braces can be escaped by a backslash (\) in which case they lose their special meaning, or that they can be embedded in a string, also to lose their special meaning.

Extending the script to care of these possibilities will make it slightly more complicated. We leave that as a larger exercise.


# prefix the current brace level on each line -jcw

# I guess the reason for this script is to help in finding missing braces AK.

 proc bracelevel {str} {
   set lev 0
   set out ""
   foreach l [split $str \n] {
     append out $lev \t
     set skip 0
     foreach c [split $l ""] {
       append out $c
       if {$skip} { set skip 0; continue }
       switch -- $c \{ { incr lev } \} { incr lev -1 } \\ { set skip 1 }
     }
     append out \n
   }
   return $out
 }

 puts [bracelevel [read stdin]]

Output of running bracelevel.tcl with itself as input:

 0
 0        proc bracelevel {str} {
 1          set lev 0
 1          set out ""
 1          foreach l [split $str \n] {
 2            append out $lev \t
 2            set skip 0
 2            foreach c [split $l ""] {
 3              append out $c
 3              if {$skip} { set skip 0; continue }
 3              switch -- $c \{ { incr lev } \} { incr lev -1 } \\ { set skip 1 }
 3            }
 2            append out \n
 2          }
 1          return $out
 1        }
 0
 0       puts [bracelevel [read stdin]]
 0

LV To interpret this output - the numbers indicate how many { characters (without matching } characters) have been encountered before the line that follows was read.

So, for instance, on the foreach line, before that line was examined, there was one open brace pair. That was the one on the proc statement. Notice that the next line (the first of the append lines), the number has increased to two.


AM Change the first append to:

   append out [string repeat "=" $lev] \t

for a more graphical layout.

NEM 2008-11-12: Changed proc to deal with backslash-escaped braces too.


frink auto-indents or beautifies Tcl source when invoked as, for example,

    frink -egINnz ...

[Explain dump in tkcon.]