#!/usr/bin/env tclsh
#
# <20200717.1526.10>
#
# This file is part of frputs the filerunner debug code.
# It should be called from 'snit' code as the last thing after
# in its load file (is this needed?). It does depent on 'info script'
# to find the source file it analizes.
# It reads tcl 'snit' code and produces an index for it.
# The index contains each 'constructor' 'destructor' 'method' 'proc'
# 'type' 'widget' and 'widgetadaptor'
# Its output is an update to the frputs::indxAry to include the line
# numbers of methods, procs, constructors and destructors in that script.
#

# We assume that the info script will give us the required file name
# If not, for debug, we accept a parameter...

proc frputsSnit {args} {
  set file [info script]
  if {$file == {}} {set file [lindex $args 0]}
  if {$file == {}} {return}
  frputs::setUpSnitIndex $file
  return
}

# a little routine to get the second item in a line without triping on braces
#
proc ::frputs::getSecond {str} {
  regexp {^ *[^ ]+ +([^ ]+)($| +.*$)} $str -> val
  return $val
}

proc ::frputs::setUpSnitIndex {file} {
  variable indxAry
  set lines [read [set fid [open $file r]]]
  close $fid
  set lines [split $lines \n]
  # puts "$file"
  if {[set nsStartLn [lsearch -regexp -all\
			  $lines {^ *(::|)snit::(type|widget).*$}]] == {}} {return}
  # Ok, each one of these should start a namespace

  foreach ln $nsStartLn {
    lappend nsList [getSecond [lindex $lines $ln]] $ln
  }
  
  
  # first where does each namespace start.
  # puts "snit lines $nsStartLn"
  foreach line $nsStartLn {
    foreach ns [array names nsAry] {
      if {[string match "*$ns*" [lindex $lines $line]]} {
	set nsLineAry($ns) $line
	break
      }
    }
  }
  # sort these
  set sortList [lsort -index 1 -stride 2 -integer $nsList ]
  # puts "sortList $sortList"
  # set begin and end indexes
  foreach {ns st} [lrange $sortList 2 end] {
    lappend endL $st
  }
  lappend endL "end"
  # build the location table
  
  # The negative numbers in the line number expression are fudges to
  # account for code that snit inserts which differs depending on
  # method / proc / constructor /destructor
  #(I am guessing about destructor at this time)
  foreach {ns st} $sortList endv $endL {
    # puts "build $ns $st $endv"
    set lns [lsearch -regexp -all [lrange $lines $st $endv] {^ *method .*$}]
    foreach ln $lns {
      set indxAry(::${ns}::Snit_method[getSecond [lindex $lines $ln+$st]])\
	  [expr {$ln - 3 + $st}]
    }
    set lns [lsearch -regexp -all [lrange $lines $st $endv] {^ *proc .*$}]
    foreach ln $lns {
      set indxAry(::${ns}::[getSecond [lindex $lines $ln+$st]])\
	  [expr {$ln - 1 + $st}]
    }
    set lns [lsearch -regexp -all [lrange $lines $st $endv] {^ *constructor .*$}] 
    foreach ln $lns {
      set indxAry(::${ns}::Snit_constructor) [expr {$ln -3 + $st}]
    }
    set lns [lsearch -regexp -all [lrange $lines $st $endv] {^ *destructor .*$}]
    foreach ln $lns {
      set indxAry(::${ns}::Snit_destructor) [expr {$ln -3 + $st}]
    }
  }
  frputs "Snit indxAry updated "
  # foreach {id ln} [array get indxAry] {
  #   puts "line $ln is $id"
  # }
}
