Download NetBeans!

20070316 Friday March 16, 2007

Hello Schliemann

Time to meet Heinrich Schliemann. "Schliemann wrote his diary in the language of whatever country he happened to be in," his entry in Wikipedia tells us. "Schliemann had a gift for languages and by the end of his life he was conversant in English, French, Dutch, Spanish, Portuguese, Swedish, Italian, Greek, Latin, Russian, Arabic and Turkish as well as his native German."

As a tribute to Schliemann, there's a NetBeans project for defining programming languages declaratively and integrating them in NetBeans IDE. Undoubtedly, the best resources on this project are:

If you keep up with the above three resources, you'll end up knowing everything there's worth knowing. But how about a brief introduction, just to get our feet wet? I asked Hanz for exactly that a few days ago and below follows everything he told me. It is based on the daily build of NetBeans 6.0 from the 13th of March. (I heard rumors that the functionality was removed after that, for lack of stability, so I suggest you take the daily build specifically from March 13th, which is what I used without any problems, other than those mentioned below.)

Below, we create a new language support for files with the imaginary "foo" extension. At the end of the story, our "foo" files will look as follows in NetBeans IDE:

In the above screenshot, notice the following:

  • syntax coloring

  • Navigator window support

  • code folding

  • indentation

What you don't see is brace completion, and a right-click pop-up menu with items for formatting and collapsing/expanding code folds.

And... not one single Java file was created (as you can see in the Projects window above) to make all of this happen.

Setting Up the Development Environment

  1. Install NetBeans IDE 6.0 dev build. (As pointed out above, I know the build from the 13th of March works. I don't know this to be true for any other build, although it possibly is true for builds after the 13th.)

  2. Check that the Generic Language Framework is installed by going to the Module Manager. In the Module Manager, you should see a category called "Languages Support". Within that category you should see "Generic Languages Framework".

  3. Go to the Update Center wizard, where you will find the Development Update Center. In the Development Update Center, find "Generic Languages Framework Studio". Importantly, this module must have 1.10 (or later) as its specification version, which you can see in the Update Center wizard. After you install this module, you should see "Generic Languages Framework Studio" under the "Languages Support" category in the Module Manager.

Creating Language Support for "Foo" Files

  1. Create a new module project and name it whatever you like.

  2. Add a dependency on the "Generic Languages Framework".

  3. In the New File template, choose the brand new template shown below and create a file called "foo", which will have the "nbs" (NetBeans Scripting) extension:

    This NBS template contains some example language definitions, as shown below, which will define our "foo" language:

    #
    # NBS Template
    #
    
    # definition of tokens
    TOKEN:keyword:( "while" | "if" | "else")
    TOKEN:operator:( "{" | "}" | "(" | ")" )
    TOKEN:identifier:( ["a"-"z"] ["a"-"z" "0"-"9"]* )
    TOKEN:whitespace:( [" " "\t" "\n" "\r"]+ )
    
    # parser should ignore whitespaces
    SKIP:whitespace
    
    # definition of grammar
    S = (Statement)*;
    Statement = WhileStatement | IfStatement | ExpressionStatement;
    WhileStatement = "while" "(" ConditionalExpression ")" Block;
    IfStatement = "if" "(" ConditionalExpression ")" Block;
    Block = "{" (Statement)* "}";
    ConditionalExpression = <identifier>;
    ExpressionStatement = <identifier>;
    
    # code folding
    FOLD:Block
    
    # navogator support
    NAVIGATOR:WhileStatement:"{$ConditionalExpression}"
    
    # brace completion
    COMPLETE "{:}"
    COMPLETE "(:)"
    
    # indentation support
    INDENT "{:}"
    INDENT "(:)"
    INDENT "\\s*(((if|while)\\s*\\(|else\\s*|else\\s+if\\s*\\(|for\\s*\\(.*\\))[^{;]*)"

    For info on the syntax of NBS files, see the three resources mentioned at the start of this blog entry, such as here in Hanz's blog. And here is the official Schliemann Language Definition.

  4. Create a new foo.xml file in your main package, with the following content:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE MIME-resolver PUBLIC "-//NetBeans//DTD MIME Resolver 1.0//EN" 
    "http://www.netbeans.org/dtds/mime-resolver-1_0.dtd">
    
    <MIME-resolver>
        <file>
            <ext name="foo"/>
            <resolver mime="text/foo"/>
        </file>
    </MIME-resolver>

    This file maps the "foo" file extension to the MIME type text/foo.

  5. Next we register foo.xml and foo.nbs in the XML layer:

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" 
    "http://www.netbeans.org/dtds/filesystem-1_1.dtd">
    
    <filesystem>
        
        <folder name="Services">
            <folder name="MIMEResolver">
                <file name="foo.xml" url="foo.xml"/>
            </folder>
        </folder>
    
        <folder name="Editors">
            <folder name="text">
                <folder name="foo">
                    <file name="language.nbs" url="foo.nbs"/>
                </folder>
            </folder>
        </folder>
        
    </filesystem>

  6. Our new module should be ready now, except that the Schliemann Project itself isn't ready. Therefore, even though you can compile and install the module, you'll probably need to restart the IDE for code folding (and possibly other features) to work. So, after installing the module and restarting the IDE, create a new file called "newfile.foo" and then type or paste in the following text:

    while (one) {
       two
       if (three) {
          four
       }
    }
    while (five) {
       six
    }

And that's it. You should now see the result shown in the screenshot at the start of this blog entry. If these instructions don't work for you, that's because this is really cutting edge stuff and Schliemann isn't completely complete yet. Why? Because he's still studying... give him some time and he'll speak your language too. (Check out the planned features here.)

In other news. The icon shown in the screenshots above for the new NBS file type reminds me a lot... of Superman... Hmmm... interesting. By the way, speaking of icons, note that by default the icon of your file type (here "newfile.foo") is the same icon as used by the NBS file type. However, you can change that declaratively in the XML layer, as an attribute of the element that registers the NBS file. For example, here I'm reusing the JavaScript icon from the NetBeans sources:

<file name="language.nbs" url="foo.nbs">
   <attr name="icon" stringvalue="org/netbeans/modules/languages/javascript/JavaScript.png"/>
</file>

Mar 16 2007, 04:43:56 AM PDT Permalink