My diary of software development

Posts tagged ‘ANTLR’

Parsing JavaScript in C# Part I

I have a personal project I am working on in which I want to compile the method and class signatures (but not the implementation logic) of JavaScript files.

I found the solution I’m going to use but not before wandering through a buh-zillion pages on the web and trying a few approaches until I arrived at something which I think will work for what I need. This blog entry is about that wandering.

A JavaScript file for testing

I needed a script file with a class and method in it to use for my tests. There are different ways to create a ‘class’ in JavaScript, but for this test I decided to use the function prototype method generated from Script#.

The C# class:

public class Class1
{
    public void DoSomething(int parm1)
    {
    }
}

The resulting JavaScript:

//! SSGen.debug.js
//

(function() {

////////////////////////////////////////////////////////////////////////////////
// Class1

window.Class1 = function Class1() {
}
Class1.prototype = {

    doSomething: function Class1$doSomething(parm1) {
        ///
        ///
    }
}

Class1.registerClass('Class1');
})();

//! This script was generated using Script# v0.7.4.0

Attempt I – Use the Microsoft.JScript.Vsa.VsaEngine

I found an entry on Rick Strahl’s blog about evaluating JavaScript in C# and although it talks about evaluating JavaScript instead of parsing it, I figured it would be a good place to start.

I wrote this C# test code:

        static private void ParseJsWithVsa()
        {
            string jsPath = @"SSGen.debug.js";
            string javaScript = File.ReadAllText(jsPath);
            VsaEngine engine = VsaEngine.CreateEngine();
            object evalResult = Eval.JScriptEvaluate(javaScript, engine);
        }

And got these compilation warnings:

Warnings

But it it did compile! So I ran it and this was my result:

Err1

Okay, well that’ll be easy to fix I thought. I decided to just remove the Window. from line 10 of the JavaScript and try it again with this result:

Err1

Arrgh. I guess that the parsing worked without trouble but the actual evaluation failed, I couldn’t find any way to get the parsing results so I decided not to work on this approach any longer. Instead I decided I’d try the ICodeCompiler noted in the compilation warnings above.

Attempt II – Use the ICodeProvider

Here’s the c#:

        static private void ParseJsWithICodeCompiler()
        {
            string jsPath = @"SSGen.debug.js";
            JScriptCodeProvider jsProvider = CodeDomProvider.CreateProvider("JScript") as JScriptCodeProvider;
            using (TextReader text = File.OpenText(jsPath))
            {
                CodeCompileUnit ccu = jsProvider.Parse(text);
            }
        }

Here’s the result:

ICC Error

Oh well. So much for that idea.

Attempt III – Use JSLint

I know that JSLint is a code quality tool but I figured that somewhere down in the mess of JSLint code it’s got to parse the target script and maybe I could hook into it and get the results of the parsing action.

I created a test ASP.Net web site which would show me the results of running JSLint against my test script file.

Here is my ASP.Net site’s markup:


    JSLint Parse Tester
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js"></script><script type="text/javascript" src="Scripts/Test.js"></script>
<script type="text/javascript" src="Scripts/JSLint.js"></script></pre>
<form id="form1">
<div>
<h3>Result of calling JSLINT(script);</h3>

<hr />

<h3 id="resultsTitle"></h3>
<div id="results"></div>
</div>
</form>
<pre>

And here is the JavaScript I wrote to execute JSLint against my test script file:

///
///

function OnGetScriptToParseComplete(script)
{
    var result = JSLINT(script);
    $('#jsLintResult').text(result);

    if (result)
    {
        var tree = JSON.stringify(JSLINT.tree, [
         'string', 'arity', 'name', 'first',
         'second', 'third', 'block', 'else'
     ], 4);

        tree = tree.replace(/\n/g, "
");
        tree = tree.replace(/ /g, " ");
        $('#results').html(tree);

        $('#resultsTitle').text("JSLINT.tree:");
    }
    else
    {
        var errs = JSON.stringify(JSLINT.errors, undefined, 4);
        errs = errs.replace(/\n/g, "
");
        errs = errs.replace(/ /g, " ");
        $('#results').html(errs).css('color', 'red');

        $('#resultsTitle').text("JSLINT.errors:");
    }
}

$(document).ready(function ()
{
    $.ajax({
        url: "scripts/ToParse.js",
        dataType: 'text',
        success: OnGetScriptToParseComplete
    });
});

And here are the results:

JSLint results

Before I delved into this approach any further I continued looking online for solutions to parse JavaScript and found something named ANTLR which seemed to be exactly what I needed.

Attempt IV – Use ANTLR

ANTLR is a tool which, among many other things, allows me to generate lexers and parsers in a target language (i.e. C#) to use against a specific grammar.

I’ve been working with ANTLR for a couple of days now, it’s got several ‘pieces’ which must be downloaded, version matched, and fitted together to do what I need but it seems to be the best solution so far. I’ll write more about ANTLR and my project in the next part of this series.