суббота, 24 ноября 2012 г.

Tcl 'regsub' with replacing by procedure call

This is the procedure like regsub but replacement is happens with procedure - not text:
proc regsub2 {re inStr by {varName ""}} {
# Simple version of regsub but support substitution by proc:
# regsub2 $re $str $by, where $by can be {proc \1 \2...}
    set result $inStr
    set byCallStr [regsub -all {\\(\d+)} $by {$m\1}]
    set matchedVarsCount [lindex [regexp -about $re] 0]
    set matchedVarNames {all}
    for {set i 1} {$i <= $matchedVarsCount} {incr i} {
        lappend matchedVarNames "m$i"
    }
    set nsubs 0
    foreach $matchedVarNames [regexp -all -inline $re $result] {
        set byRes [eval $byCallStr]
        set result [regsub $re $result $byRes]
        incr nsubs
    }
    if {$varName eq ""} {
        return $result
    } else {
        upvar 1 $varName varName_
        set varName_ $result
        return $nsubs
    }
}
If you call it with IncrTcl then use ::itcl::code proc.

суббота, 3 ноября 2012 г.

New Literate Programming Tool - TCLP 1.0!

I done new LP tool: very small (about 700-800Kb!) and flexible!
Main features are:
  1. Document has 'document header' with fields: TITLE, PROJECT, VERSION, DESCRIPTION, AUTHOR, ADDRESS, TAGS, it shown on the top of document.
  2. User can define values of this fields (and any other field) and can use defined fields in the document body (even in code chunks). There are special fields: APPNAME, APPVERSION, TIMESTAMP, DATE, TIME.
  3. Document has auto-generated TOC (table-of-contents), IT (index-table), ERT (external-references-table). TOC is placed in the start of the document. IT is placed at the end of document. ERT is placed last.
  4. TOC is generated automatically for all headers, defined with 'head' command.
  5. IT is generated automatically for all code chunks and includes file names of output chunks and lines numbers where to find them.
  6. ERT is generated automatically for all external references in the document, defined with 'ref' command and includes back-references to it's usage in the document body.
  7. Markup commands includes commands for bold, underlined, italic and monotyped text. Top/bottom indexes are supported also. Markups can be nested.
  8. There is special file with abbreviations to be used in section names and acronyms also.
  9. User can use acronym in the text from abbreviations file or explicitly with embedded expansion.
  10. User can create "vocabularies" - tables of definitions - from abbreviations file or embedded, defined explicitly.
  11. There are named counters (auto-incremented) to use in captions and so on.
  12. Code chunks are special formatted fragments of source code with lines numbering, optional syntax highlighting (only keywords). Lines can be numbered in continuously manner (with the same counter names) or in independent. User can reference to code lines by chunk name (section) and line number or with defining NAME of code line and usage of this name for referencing.
  13. Tables are supported: with attributes (table/row/cell), spanning, nesting.
  14. Lists (ordered/unordered) are also supported: with attributes; they can be nested also.
  15. User can insert image with 'embed' command. Any fragment of document can be "framed" with 'frame' command. It creates frame with caption (on top/on bottom), name and links (for referencing).
  16. There are 2 kinds of citations: inlined and blocked. Citation can have linked URL (shown as "More...")
  17. User can insert in document text any previous defined field values, but also variables from environment. Special environment variables is the USER - this is the name of user running tool.
  18. There is a special command 'wrap' for wrapping text with any word or quotation symbols, braces, etc.
  19. There is a command 'ent' to translate special symbols to HTML entities.
  20. There are references:
    • to external URL
    • to header
    • to line of code chunk/named line of code chunk
    • to code chunk
    • to frames
    • to any place of document where user defines own link
  21. There are 2 special commands: 'atstart', 'atend'. Mainly used is 'atend' for code generation from code chunks. User can define there what code chunks to be written to output source files (by sections, by glob-pattern of sections). Also is possible to write any free text to output file.
  22. Most of created HTML tags has CSS-classes. For all available CSS classes, see 'tclp.css' file. Used CSS file can be defined with command line option.
  23. User can add syntax keywords for any other language (for highlighting).
You can try it from Google Projects: http://code.google.com/p/tclp/

Automatic generation of proc/methods help in Tcl

Often you write not only internal code but procs for user's usage (in console and so on). It's difficult to write documentation of procedures in different file, so let's use doc-strings like Lisp, Python and so on.
It's not Java, so you don't need special tool :)
Considering that out procedures/IncrTcl methods has comments like this:
proc f {args} {
## Doc-string for this method.
# Syntax: f ...
##
... CODE ...
}
OR even:
proc f {args} {
## Doc-string for this method.
# Syntax: f ...
# Other help ##
... CODE ...
}
Well, doc-string is at proc body start, and begins with '##' and ends with '##' (at the same line or next), other comments are treated as usual comments and are ignored for doc-string mechanism. Here is example how to parse suck doc-strings:
package provide mydoc 1.1

package require Itcl

namespace eval mydoc {
    namespace export doc
}

set _NOHELPMSG "No help."

proc ::mydoc::_docstring {body} {
    set body [string trim $body]
    set docstring ""
    # without 1st '^' will match any FIRST docstring block even after
    # commands!
    if {[regexp {^##\s*([^\n]+\n?)+(##)} $body docstring]} {
        set docstring [regsub -all {\s*#\s?} $docstring \n]
        set docstring [string trim $docstring]
        return $docstring
    }
}

proc ::mydoc::doc args {
    ## Help on command: procedure or class method. Call:
    #   doc some_object some_method
    #   doc some_class some_method
    #   doc some_proc ##
    global _NOHELPMSG
    set found ""
    switch -- [llength $args] {
        1 {
            # args: proc
            set name [lindex $args 0]
            set arguments [info args $name]
            set body [info body $name]
            set found [_docstring $body]
        }
        2 {
            # FIXME not optimal!
            # args: object|class method
            lassign $args cls_obj meth
            set objs [itcl::find objects]
            # cls_obj may be object OR class. What is it?
            if {-1 != [lsearch -regexp $objs :*$cls_obj]} {
                # this is the object
                set arguments [$cls_obj info args $meth]
                set body [$cls_obj info body $meth]
                set found [_docstring $body]
            } else {
                # this is the class
                set arguments [namespace eval ::$cls_obj info args $meth]
                set body [namespace eval ::$cls_obj info body $meth]
                set found [_docstring $body]
            }
        }
        default { error "wrong args: proc | object method | class method" }
    }
    if {$found eq ""} {
        return $_NOHELPMSG
    } else {
        return $found
    }
}
Usage is simple, you can call:
doc object method
doc class method
doc usual-procedure
Class - is the IncrTcl class