Einar Egilsson

JScript REPL

Posted: Last updated:

Lately I have been doing some COM automation stuff on Windows. I've been using JScript (Microsoft's JavaScript implementation) since that's available on all Windows machines, and the other option, VBScript, is horrible. Normally I would use Python and the win32com package, but I needed to make some scripts that could work on any box without installing Python first. JScript is a pretty nice language, but it doesn't come with a REPL built in, which is very handy when you're doing experimental stuff (REPL = Read-Execute-Print-Loop). Now, writing your own REPL in a dynamic language with an eval statement is pretty easy, so I did just that. It took about 30 lines, of which about 10 are just about printing evaluated expressions nicely.

Here's how it works. If you enter a single line that ends with ; it is evaluated immediately. If it doesn't start with if,while,var,try,do,with,function,switch,for or print it is assumed to be an expression and its value is printed to the screen. If a new line doesn't end with ; is is assumed to be the beginning of a larger code block. In that case the script will keep reading in code without evaluating until either you end a line with ;; or you enter a line which consists of only one ;. The script also includes a convenience function called print() to print expressions. The script just uses a single variable, _$, so it won't conflict with variables you define when using it. Writing a single line with just the word ‘exit' will stop the script. Below you can see an example of the usage of the REPL. This sample is actually a online version that I did for fun, you can write in any command in it and try it out, it works exactly the same as the real script, although the online version took quite a bit more code. It even has command history, activated with the up and down arrow keys. (There are some issues in Internet Explorer, tab key doesn't work and strings with html entities my display incorrectly, because of weird behaviour with <pre> tags and the .innerHTML property).

Here's the code:

function print(s) { WScript.Echo(s);} var _$ = ''; while (_$ != 'exit') { WScript.StdOut.Write(_$ ? '... ' : '>>> '); _$ += (_$ ? '\n':'') + WScript.StdIn.ReadLine().replace(/^\s*|\s*$/g, ''); if (_$.match(/^[^\n]*;$|;;$|\n;$/)) { try { if (_$.match(/\n/) || _$.match(/^(if|while|var|try|do|with|function|switch|for|print)\b/)) { eval(_$); } else { _$ = eval(_$); if (typeof(_$) == 'undefined') { print('undefined'); } else if (typeof(_$) == 'boolean') { print(_$ ? 'true' : 'false'); } else if (typeof(_$) == 'string') { print("'" + _$ + "'"); } else { print(_$); } } } catch(_$) { print('ERROR: ' + _$.message); } _$ = ''; } }


If you read this far you should probably follow me on Twitter.