Listening To Reason

random musings about technologies by Andy Norris

04 March 2007

A Simple JavaScript Command Line Interpreter for Windows in JScript.Net

I've been playing around with JavaScript quite a bit lately, and one thing I enjoyed having was a web-based JavaScript shell for trying out JavaScript commands quickly. I was also thinking about the fact that my command-line skills have gotten a little rusty lately, and that I should get those back into shape. I remembered JScript.Net, which I've been meaning to read more about anyway as a possible solution for embedded scripting in .net applications. So I decided to write a simple interactive command-line interpreter, and see how far I got.

Working with JScript

The JScript compiler, jsc ships with the .Net SDK. If you Have Visual Studio (I've tested this casually with both 2003 and 2005), you can launch the Visual Studio command prompt and just type jsc foo.js to get it to compile jscript. The resulting executable will run against the .Net runtime, and unlike C# or VB.Net, it doesn't require you to create a class with a main function. In fact, here is "Hello World:"


print("Hello, World!");

That's all there is to it.

If you save it as hello.js and enter jsc hello.js, it will compile to hello.exe, and you can then type hello at the command line to run it. Dead simple.

That's the good news. The bad news is that the JScript.Net compiler is configured to be much more .Net-like than any other JavaScript compiler you're likely used to dealing with. For example, suppose you create the following program, and save it as bar.js:


function bar() { 
  print(5);
}

bar = function() {
  print(9);
}

Straightforward, right? It declares a function bound to bar, then changes bar to point to a new function. Well, if you compile this with jsc bar.js, it will throw an error at you:

bar.js(5,1) : error JS5040: 'bar' is read-only

In fact, there's enough annoying limitations that the obvious conclusion to draw is that JScript.Net is flatly broken.

Fortunately, there's a way around all the limitations. The reason it's so broken is that JScript is trying to produce code that will run reasonably quickly on the .Net CLR. And as many people have noticed by now, there aren't a lot of affordances in the CLR for dynamic languages. This is called "fast mode," and it's enabled by default. But if you care more about compatibility with the ECMAScript spec than speed, you can turn it off.

If you type jsc /fast- bar.js, then it will compile just fine, and pretty much all the features you expect will be there.

A Simple Interpreter

Once I figured out how to make the full JavaScript language compile, it was pretty easy to make an interactive interpreter. The core of one is ridiculously simple:


import System;

for ( ;; ) {
  Console.Write("%");  // prompt

  var input = Console.ReadLine();

  if(input == "quit" || input == "exit") { break; }

  try {
    Console.WriteLine(eval(input, "unsafe"));
  } catch(ex) {
    Console.WriteLine(ex.ToString());
  }
}

This is really all there is to a read-eval-print loop.

I refined it a little from there, with support for multiline statements (by ending with a backslash, which is a little cheesy, but I don't think I can support something like shift-enter without using a more elaborate IO methodology).

I also added a load command, so you can bring in libraries from file. The load has to be handled specially, so that the resulting code will be in the global namespace and not inside a closure, where the bindings will be lost on function exit. I think I can do better than the current implementation, however. load("baz.js") will load a library "baz.js" from the working directory. load("c:\\scripts\\baz.js") will do the obvious thing -- you should be able to use any path you choose to declare.

Finally, I added a cmd() function, that will execute its argument in the windows command shell, and return stdout and stderr to you. As with load, the argument will be evaluated like any other javascript expression, so if you do something like:

var xyzzy = "directory";
cmd(xyzzy.substr(0,3))

then xyzzy.substr(0,3) will evaluate to "dir", and the command will list the working directory. Of course, you can also do things like

%var dir = function() { return cmd("dir"); }
function() { return cmd("dir"); }
%dir()

which will then list your directory. So if you have common tasks like listing directories, listing file contents, etc., you can just map them to javascript functions for easy use. Obviously, you could also map ls(), if you prefer Unix-style commands. Of course, with the parentheses, it's more verbose than using a real shell -- or even a language like perl -- but it still makes general command line functionality fairly accessible.

There are obviously plenty of ways in which the code could be enhanced beyond this, but this seemed like enough to pass along to anyone who might be interested. If you have ideas for additional functionality, let me know. Or, for that matter, implement it yourself -- it's a simple code base. If you do anything cool, I'd love to hear about it.

The source

I don't have anywhere to post this for file download, and it's short, so I'm just going to post it here, inline. If you save this as "ijs.js", you can compile it with

jsc /fast- ijs.js

Then you can just run it at the command line with ijs.

Here's the source in full. It clocks in at under 100 lines at the moment:


// ijs.js -- an interactive javascript interpreter for Windows in JScript.Net
// Copyright 2007 Andrew Norris
// Anyone is free to use, alter, or redistribute this code for any purpose.

import System;
import System.Diagnostics;
import System.IO;

function loadFile(input) {
  // pull out what's inside the parens
  var begin = input.indexOf("(");
  if (begin == -1) {
    Console.WriteLine("syntax error: bad argument to load");
    return null;
  }
  var end = input.lastIndexOf(")");
  if (end == -1 || end < begin) {
    Console.WriteLine("syntax error: bad argument to load");
    return null;
  }
  var fileExpr = input.substring(begin+1, end);

  var fileName = "";
  try {
    fileName = eval(fileExpr, "unsafe");
  } catch(ex) {
    Console.WriteLine(
        "Exception evaluating file expression '" + fileExpr + "':\n" + ex.ToString());
    return null;
  }

  try {
    var file = new StreamReader(fileName);
    var result = file.ReadToEnd();
    file.Close();
    return result;
  } catch(ex) {
    Console.WriteLine(
        "Exception loading file '" + fileName + "':\n" + ex.ToString());
    return null;
  }
}

function cmd(cmdName) {
  var process = new Process();
  process.StartInfo.UseShellExecute = false;
  process.StartInfo.RedirectStandardOutput = true;
  process.StartInfo.RedirectStandardError = true;
  process.StartInfo.CreateNoWindow = true;
  process.StartInfo.FileName = "cmd.exe";
  process.StartInfo.Arguments = "/c " + cmdName;

  try {
    process.Start();
  } catch (ex) { 
    Console.WriteLine(ex.ToString());
  }
  Console.WriteLine(process.StandardOutput.ReadToEnd());
  Console.WriteLine(process.StandardError.ReadToEnd());
}

Console.WriteLine("Welcome to Interactive JavaScript.");

var cont = false;
for ( ;; ) {
  Console.Write("%");  // prompt

  var input = (cont) ? input + Console.ReadLine() : Console.ReadLine();

  // trim leading and trailing whitespace
  input = input.replace(/^[ \t]+/, "");
  input = input.replace(/[ \t]+$/, "");

  // end execution on quit
  if(input == "quit" || input == "exit") { break; }

  if (input.charAt(input.length-1) == '\\') {
    // lines ending in backslash continue on the next line
    input = input.substring(0,input.length-2);
    cont = true;
    continue;
  } else if(input.match(/^load\W/)) {
    // load file to eval
    input = loadFile(input);
    if (!input) { continue; }
  }
  cont=false;

  // eval the input
  try {
    Console.WriteLine(eval(input, "unsafe"));
  } catch(ex) {
    Console.WriteLine(ex.ToString());
  }
}

Labels: , , , ,

22 Comments:

At 8:49 PM, Blogger Unknown said...

Pretty freaking cool :D

 
At 8:40 PM, Anonymous Anonymous said...

You know ,I have some Anarchy credits, and my friend also has some
Anarchy Online credits, do you kouw they have the same meaning,Both of them can be called
Anarchy gold,I just want to buy AO credits, because there are many cheap Anarchy online gold.

 
At 11:19 PM, Anonymous Anonymous said...

I can get ro zeny cheaply,
Yesterday i want to buy ragnarok zenyfor my brother.
i hope him like it. i will buy iro zeny for him
as birthday present. i like the cheap zeny very much.
I usually buy ragnarok online zeny and keep it in my store.

I can get LOTRO Gold cheaply,
Yesterday i bought Lord Of The Rings Goldfor my brother.
i hope him like it. i will give cheap Lord Of The Rings Gold to him as
birthday present. I usually buy LOTRO Gold and keep it in my store.

 
At 12:35 AM, Anonymous Anonymous said...

latale online gold in the game which movement is much like an arcade game. We know, the latale gold can exchange the real money of the reality. The world you are enjoying in latale money can entertainment and get to know new friends. This economic structure lead buy latale online gold has one kinds of real value in the real world. You can use cheap latale gold to purchase various items of course, there are need to change.

 
At 8:27 AM, Anonymous Anonymous said...

Czyść brudną tapicerke z karcher odkurzaczem, tanio i wygodnie. Czyszczenie dywanów odbywa się szybko i dokładnie.
Promocje związane z czyszczenie katowice ślask sosnowiec jest na prawdę tanie.
Czyszczenie odbywa się na mokro. Dywan, tapicerka samochodowa i meblowa. Czyść spontanicznie i nie nerwowo ale pewnie i tanio.

 
At 8:27 AM, Anonymous Anonymous said...

Poker on line sign up poker account for free huge and gift promotion.
free no deposit need id have similar free starting $50 capital for $50 bankroll.
Over fifty sponsors dollars euro with free bankroll no id veryfication all possible $50 bankrolls.
starting bankrolls and capital for poker bonuses need no risk information for poker, no deposit bonuses no id verify from bet poker blog.
money poker I came across another great free cheap bonus through them bankroll poker . Do you want to try Full tilt room texas hold em? instant poker bonus - Poker online no deposit $45 bonus promotions.
bonus for full tilt Poker we have. poker bonus darmowe promocje bez depozytu tylko dokonaj za darmo.
Ale także bez wpłaty no i titan,poker darmowe free vulcan i party poker w promocji bez deponowania funduszy to ma być poziomo mansion $50 plus 100 no id verification.
Graj bez beponowaia pieniędzy online poker i casino online czyszczenie free promo.

 
At 2:39 PM, Blogger pedro velasquez said...

I have a project that needs to create and use COM objects. I found sportsbook
some examples using Javascript on the command-line and it looks like the perfect option for me. They will likely be short scripts (<100 lines) that talk to a COM server and a Postgres database.
Does anyone have a better approach? Is there a good tool that can assist with creating this type of Javascript. bet nfl Most tools (like aptana) tend to focus on running javascript from a browser, not from the command line. I would really like just a simple IDE with breakpoints and watches or even a simple terminal application that would allow me to type a javascript command and see a result. http://www.enterbet.com Any suggestions?

 
At 4:18 PM, Blogger Unknown said...

Dofus Kamas|Prix Moins Cher Dofus Kamas|Kamas par allopass|Dofus kamas audiotel|Dofus kamas par telephone sur Virstock.com

Meilleur prix dofus kamas stock de dofus kamas

Prix moins cher dofus kamas
vente dofus kamas sur www.virstock.com

Kamas par allopass sur dofus kamas

Dofus kamas par telephone sur dofus kamas

Dofus kamas audiotel sur dofus kamas

http://www.virstock.com/jsp/comments.jsp dofus kamas vente

http://www.virstock.com

 
At 5:16 PM, Anonymous costa rica vacation said...

Hey this is very interesting post found here.... Really that above picture said all thing. Great blog. Keep posting. I'm looking forward to your new posts.

 
At 4:32 PM, Anonymous game reviews said...

Wonderful information, I will save this and show it to my friend, she is huge fan of this. It's been a pleasure to read your post.
Hannah from SheepArcade
If you like to play games, visit sheep arcade and play poker games and much more free games.

 
At 12:11 PM, Anonymous Buy Leather Jackets online said...

Pretty freaking cool :D

 
At 1:49 PM, Blogger Frank said...

Hey,
Loving your blog, awesome tips on blog you have here. I
would just like to ask you some questions privately, mindweb hosting in pakistan,samsung mobile prices in pakistan,nokia mobile prices in pakistan,VLC Player Free Download

 
At 5:19 AM, Blogger Knox Karter said...

Awesome article. Thanks for sharing lots of information. Its very helpful to me.
Law Logo

 
At 12:39 AM, Blogger Knox Karter said...

This is really awesome blog and the information is more awesome and great to see!


Internet Marketing

 
At 3:40 PM, Anonymous price per head said...

Its so interesting article..Thanks for sharing..

 
At 7:54 PM, Anonymous baixar facebook movel said...

Many thanks for the exciting blog posting!
----
descargar mobogenie and apply baixar facebook | mobogenie

 
At 2:05 AM, Anonymous juegos de kizi said...

This article is really fantastic and thanks for sharing the valuable post.
----
play game juegos de kizi online and play game jogos friv

 
At 8:19 PM, Blogger Unknown said...

This is also a very good post which I really enjoyed reading. It is not everyday that I have the possibility to see something like this.
Signature:
i like happy wheels 2 games online and play games happy wheels demo full and Download retrica online includes more than eighty different filters with many different styles and include retrica indir , and zombie tsunami is the ideal game for anyone who loves the running game genre

 
At 3:25 AM, Blogger Regina Hilary said...

This app is great it gives you those moments of relaxation and incredibly wonderful
age of war 2 | tank trouble | gold miner | tank trouble 3
Just wanted to tell you keep up the fantastic work!my weblog:
earn to die 5 | earn to die 6

 
At 12:57 AM, Blogger expertshelp said...

Your blog on listening to reasoning is one very interesting one, in a way its immensely informative and many people would agree that a Simple JavaScript Command Line Interpreter can be suitable for Windows in JScript.Net. This is what you call listening to reason, which leaves you much more informed. Duck Resin Statue Thank you for a great and nice blog.

 
At 1:12 AM, Blogger ngocanhng said...

Your blog posts are more interesting and impressive. I think there are many people like and visit it regularly, including me.I actually appreciate your own position and I will be sure to come back here.
brtaram

 
At 3:29 AM, Blogger Drift Financial Services said...

Good luck & keep writing such awesome content.

Virgin Linseed Oil BP
Pure Linseed Oil

 

Post a Comment

<< Home