Check-in [b0688623ce]
Overview
SHA1:b0688623ce37f7ae2de31779c707f209916fd588
Date: 2013-11-24 10:21:03
User: suchenwi
Comment:factored out infovars, added README.txt
Timelines: family | ancestors | trunk
Downloads: Tarball | ZIP archive
Other Links: files | file ages | folders | manifest
Tags And Properties
Context
2013-11-24
10:21
[b0688623ce] Leaf: factored out infovars, added README.txt (user: suchenwi, tags: trunk)
08:24
[07c2ea91bc] added [file join], [file split] (user: suchenwi, tags: trunk)
Changes

Added README.txt version [a3de5c087d].

            1  +tcl.js "A Tcl implementation in Javascript"
            2  +
            3  + * Released under the same terms as Tcl itself.
            4  + * (BSD license found at <http://www.tcl.tk/software/tcltk/license.html>)
            5  + *
            6  + * Based on Picol by Salvatore Sanfilippo (<http://antirez.com/page/picol>)
            7  + * (c) St├ęphane Arnold 2007
            8  + * Richard Suchenwirth 2007, 2013: cleanup, additions
            9  +
           10  +This emulates (in part) an interpreter for the Tcl scripting language. Early versions were tested in browsers, but since the advent of node.js, I only use that, like a tclsh (interactive or with script file(s) to evaluate).
           11  +
           12  +The test suite is also frequently tested against a real tclsh, currently 8.5.13. Only a few tests dealing with special numbers (Infinity, NaN) are skipped when real Tcl runs.
           13  +
           14  +The tcljs project has a home at http://code.google.com/p/tcl-js/. 
           15  +Version control via mercurial (hg). 
           16  +Also via Fossil at https://chiselapp.com/user/suchenwi/repository/tcl-js/dir?ci=tip
           17  +
           18  +I used to develop this with node.js v0.6.19 (which was standard via apt-get). Now that backslash escapes are finally working, the test suite (which is in UTF-8) needs to be parsed as such, so I upgraded to node.js v0.10.22.
           19  +
           20  +On the command line you can pass code snippets that are executed before the Read-Eval-Print loop is entered For instance, this runs the test suite:
           21  +
           22  +$ DEBUG=0 node tcl053.js "source /home/suchenwi/tcl-js/test_tcljs.tcl"
           23  +
           24  +With DEBUG=1, all commands are reported before execution, and all exceptions.
           25  +
           26  +Still missing:
           27  +- blocking [exec]
           28  +- blocking [gets]
           29  +- [expr] to also accept command calls in braced expressions, e.g.
           30  +        if {[llength $x] > 2} ...
           31  +- [open], [puts] to file, [close]
           32  +-
           33  +- and many more...

Modified tcl053.js from [dc45822eaf] to [d5a4940aef].

   317    317   	if(found) {
   318    318   	  if(i == list.length) i -= 2;
   319    319   	    list.splice(i, 2);
   320    320   	    interp.setVar(name, dict);
   321    321   	}
   322    322   	return dict;
   323    323         });
   324         -    /*
   325         -      if(typeof(jQuery) != 'undefined') {
   326         -      this.registerCommand("dom", function (interp, args) {
   327         -      var selector = args[1].toString();
   328         -      var fn = args[2].toString();
   329         -      args = args.slice(3);
   330         -      for (var i in args) args[i] = args[i].toString();
   331         -      var q = $(selector);
   332         -      q[fn].apply(q,args);
   333         -      return "dom    " + selector;
   334         -      });
   335         -      }*/
   336    324       this.registerCommand("eval",function (interp, args) {
   337    325           this.arity(args, 2,Infinity);
   338    326           for (var i = 1; i < args.length; i++) args[i] = args[i].toString();
   339    327           if (args.length == 2) var code = args[1];
   340    328           else                  var code = args.slice(1).join(" ");
   341    329           return interp.eval(code);
   342    330         });
................................................................................
   360    348       */
   361    349       this.registerCommand("exit",function (interp, args) {
   362    350   	this.arity(args, 1,2);
   363    351   	var rc = 0;
   364    352   	if (args.length == 2) rc = args[1];
   365    353   	process.exit(rc);
   366    354         });
   367         -    var acos = Math.acos;
   368         -    var exp  = Math.exp;
   369         -    var sqrt = Math.sqrt; // "publish" other Math.* functions as needed
   370         -
   371    355       this.registerCommand("expr", function (interp, args) {
   372    356   	var expression = args.slice(1).join(" ");
   373    357   	return interp.expr(interp, expression);
   374    358         });
   375    359       this.expr = function (interp, expression) { // also used in for, if, while
   376    360         var mx;
          361  +      var acos = Math.acos;
          362  +      var exp  = Math.exp;
          363  +      var sqrt = Math.sqrt; // "publish" other Math.* functions as needed
   377    364         try {
   378    365   	mx = expression.match(/(\[.*\])/g);
   379    366   	for (var i in mx)
   380    367   	  puts("have to deal with "+mx[i].toString());
   381    368         } catch(e) {puts(i+". exception: "+e);}
   382    369         mx = expression.match(/(\$[A-Za-z0-9_:]+)/g);
   383    370         for (var i in mx) {
................................................................................
   457    444           var body = args[4].toString();
   458    445           interp.inLoop = true;
   459    446           interp.code = interp.OK;
   460    447           while (true) {
   461    448               test = interp.objectify(interp.expr(interp, cond));
   462    449               if (!test.toBoolean()) break;
   463    450               interp.eval(body);
   464         -            var ic = interp.code; // tested after step command
          451  +            var ic = interp.code; // will be tested after step command
   465    452               interp.eval(step);
   466    453               if(ic == interp.BRK) break;
   467    454               if(ic == interp.CNT) continue;
   468    455           }
   469    456           interp.inLoop = false;
   470    457           if(interp.code == interp.BRK || interp.code == interp.CNT)
   471         -            interp.code = interp.OK;
          458  +	  interp.code = interp.OK;
   472    459           return "";
   473    460       });
   474    461       this.registerCommand("foreach", function (interp, args) {
   475    462           this.arity(args, 4);
   476    463           var list = args[2].toList();
   477    464           var body = args[3].toString();
   478    465           var res    = "";
................................................................................
   597    584       });
   598    585       this.registerSubCommand("info", "exists", function (interp, args) {
   599    586           this.arity(args, 2);
   600    587   	var name = args[1];
   601    588   	try {interp.getVar(name); return 1;} catch(e) {return 0;}
   602    589       });
   603    590       this.registerSubCommand("info", "globals", function (interp, args) {
   604         -        return interp.mkList(interp.callframe[0]);
          591  +        return interp.infovars(0);
   605    592       });
   606         -    /* not in "real" Tcl
   607         -    this.registerSubCommand("info", "isensemble", function (interp, args) {
   608         -        this.arity(args, 2);
   609         -        var name = args[1].toString();
   610         -	var cmd  = interp.getCommand(name);
   611         -        return (cmd != null && cmd.ensemble != null)? "1" : "0";
   612         -	}); */
   613    593       this.registerSubCommand("info", "level", function (interp, args) {
   614    594   	if(args.length == 1)
   615    595   	  return interp.level;
   616    596   	var delta = args[1];
   617    597   	return interp.levelcall[interp.level - delta];
   618    598       });
   619    599       this.registerSubCommand("info", "nameofexecutable", function (interp, args) {
................................................................................
   625    605       this.registerSubCommand("info", "procs", function (interp, args) {
   626    606           return interp.mkList(interp.procs);
   627    607       });
   628    608       this.registerSubCommand("info", "script", function (interp, args) {
   629    609           return interp.script;
   630    610       });
   631    611       this.registerSubCommand("info", "vars", function (interp, args) {
   632         -	var res = [];
   633         -	for(var i in interp.callframe[interp.level]) {
   634         -	  try {
   635         -	    if(interp.getVar(i) != null) {res.push(i);}
   636         -	  } catch(e) {};
   637         -	}
   638         -	return res;
   639         -    });
          612  +	return interp.infovars(interp.level);
          613  +      });
          614  +    this.infovars = function(level) { // also used in [info globals]
          615  +      var res = [];
          616  +      for(var i in this.callframe[level]) {
          617  +	try {
          618  +	  if(this.getVar(i) != null) {res.push(i);}
          619  +	} catch(e) {};
          620  +      }
          621  +      return res;
          622  +    }
   640    623       this.registerCommand("join", function (interp, args) {
   641    624   	this.arity(args, 2, 3);
   642    625   	var lst = args[1].toList();
   643    626   	var sep = " ";
   644    627   	if(args.length == 3) sep = args[2].toString();
   645    628   	var res = [];
   646    629   	var re  = /^{.*}$/;