Version 4 of Empty interpreter

Updated 2008-07-15 10:18:40 by lars_h

An empty interpreter is a Tcl interpreter where there are neither commands nor variables.

The following creates an empty slave interp empty for you to experiment with:

 interp create -safe empty
 empty eval {namespace delete ::}

(The namespace delete trick here is by DGP, first published on the Braintwisters page.) empty now exhibits the following behaviour:

 % empty eval {info patchlevel}
 invalid command name "info"
 % empty eval {namespace exists ::}
 invalid command name "namespace"

and so on.

What good is such an interpreter? Well, it is still possible to create aliases in it:

 % empty alias list list {[list] in empty interp}    
 list
 % empty eval {list a b c}
 {[list] in empty interp} a b c

Hence empty interpreters can be used as config file parsers, for config files that follow Tcl syntax: For every allowed "config file command" you create that command as an alias to something in the main interpreter which actually does what that command is supposed to do. Then source or interp eval the config file in the empty interpreter, to have it safely processed.

How can I source the file when the source command is gone? you may ask? Well, as it turns out, the source command (and a few others) aren't really gone, since they were interp hidden from the namespace delete that emptied the interpreter:

 % empty hidden
 file socket open unload pwd glob exec encoding fconfigure load source exit cd
 % empty invokehidden source my-config-file
 couldn't read file "my-config-file": no such file or directory

Maybe some day someone will code up a full example of how to use these nice features of Tcl to allow the reading and creating of a config file, taking care of various safety issues. That would make a great example for people.

Lars H: OK, here's a chatlog reaper rewritten to use an empty interpreter for parsing, rather than just blindly evaluating whatever code http://tclers.tk/ is sending. It's supposed to only use the m command, but in an empty interpreter you can make sure that this is all there is to use.

#!/usr/bin/env tclsh
set usage {
   usage: today.tcl > today.html
   Retrieve today's chat log, format into HTML on stdout
}
set base http://tclers.tk/conferences/tcl/

if {$argv eq "-h"} {puts $usage; exit 1}

# Make empty interp [chatlog] for parsing
interp create -safe chatlog
chatlog eval {namespace delete ::}

#-- All chat entries invoke [m]
chatlog alias m html_m

proc html_m {time who what} {
   set tm [string range $time 9 13]
   if {$who eq "ijchain"} {
       set who [lindex [split $what] 0]
       if {$who eq "***"} {set who ""}
       set what [join [lrange [split $what] 1 end]]
   }
   set what [string map {\n <br/>} [html'escape $what]]
   if {$who eq ""} {                      #-- join/leave message
       puts "<br/>* <i>$what</i>"
   } elseif {[string match /me* $what]} { #-- "action"
       puts "<br/><i><b>[html'escape $who]</b> [string range $what 4 end]</i>"
   } else {                               #-- regular message
       if {$tm ne $::lasttime} {
           set who "$tm $who"
           set ::lasttime $tm
       }
       puts "<br/><b>[html'escape $who]:</b> $what"
   }
}

set map {}
foreach {char entity} {< lt > gt & amp} {
    lappend map $char &${entity}\;
}
interp alias {} html'escape {} string map $map


proc main argv {
   package require http
   set date [clock format [clock sec] -format %Y-%m-%d]
   #http::config -proxyhost proxy -proxyport 80
   set token [http::geturl $::base/$date.tcl -headers {Pragma no-cache}]

   puts "<html><head>Tclers' Chat of $date</head><body>"
   variable lasttime 00:00
   chatlog eval [http::data $token]
   puts <hr/>[clock format [clock sec]]</body></html>
}

main $argv

(Also, this has been slightly rewritten to collect more of the HTML handling in the m proc, to simplify supporting other output formats later.)


How do empty interps differ from safe interps? A safe interp cannot access the file system or do any networking, but it still provides a Turing-complete programming environment, which is overkill if the interpreter is meant to just parse data. If no commands