Skip to content

Setting up a New Language in Waterbear

Dethe Elza edited this page Jan 16, 2015 · 9 revisions

OUTDATED: This page needs to be updated and does not reflect the current state of Waterbear.


Explanation

This page is intended to help you to understand everything required for getting a new language with no Waterbear support running in Waterbear.

File Hierarchy

To begin you should start by creating a new directory which will house all of your language specific config files. This file structure should look like this:

waterbear  
└── languages  
    └── myNewLanguage  
        ├──blocks  
        ├──examples  
        ├──templates  
        |  ├──examples.html
        |  └──stage.html
        ├──config.json  
        ├──ide.js  
        ├──myNewLang.css
        ├──~index.html  
        ├──~runtime.html  
        └──runtime.js  

"~" marks files that are automatically generated by build and shouldn't be created by hand or edited.

##Getting Started To get started you need at minimum to create

  • blocks
  • templates
  • examples.html
  • stage.html
  • config.json
  • myNewLang.css
  • ide.js

blocks

The folder blocks holds your block definitions. Information on how to create block definitions can be found here.

examples.html

The examples file holds menu definitions for the examples that you include in the examples folder. They are of the form:
<li><button class="load-example" data-example="EXAMPLE_FILE_NAME">Examples Name</button></li>
This file can be left empty.

stage.html

Stage.html allows you to define the Stage which is where your languages code will be output if it runs in the browser. A skeleton file for this looks like:

<div class="results">
    <div class="scripts_text_view"></div>
</div>

config.json

config.json holds information for the build script about your language. The file takes the form of:

 {
    "runsInBrowser": true, ;;can be true or false dictates whether the language will run in the browser or just display code
    "plugins": ["blocktype1", "blocktype2], ;;a list of all the block categories you have defined
    "runtimeLibs": [], ;;list of runtime libraries you use during runtime of code
                       ;;a good example of this would be if you are using a language to JS interpreter
                       ;;you would put the lib here
    "styles": ["highlight-github"], ;;styles for the code. can use highlight-github or nothing
    "ideLibs": ["ajax", "beautify", "highlight", "events.min"] ;;libraries used by the IDE
                                                               ;;include at least ajax and events.min
}  

myNewLang.css

This file should have an entry for how to color each block group in the language and value group. The file should look like this:

/* block and border colours for different groups of blocks */

//generic block group called "control"
.control, .control.holder{
    border-color: hsl(296, 65%, 57%);
    background-color: hsl(296, 65%, 77%);
}

/* Border colours for type values and sockets */

//set what the "any" type looks like
.any, .any .holder{
    border-color: gray;
}

ide.js

ide.js is the main file you will be working with and will look as follows:

(function(wb,Event){
    // Add some utilities
    'use strict';
    wb.wrap = function(script){}; //This function is used to wrap necessary additions around the script
                                
                                  
    //This function is used to setup running the script
    //it is called automatically on change of script
    //should always end with calling runScript
    function runCurrentScripts(force){ 
        if (!(wb.autorun || force)){
            // false alarm, we were notified of a script change, but user hasn't asked us to restart script
            return;
        }
        document.body.classList.add('running');
        if (!wb.scriptLoaded){
            console.log('not ready to run script yet, waiting');
            return;
        }else{
            console.log('ready to run script, let us proceed to the running of said script');
        }
        var blocks = wb.findAll(document.body, '.scripts_workspace'); //gets all the blocks
        //UPDATE THINGS NECESSARY FOR RUNNING 
        wb.runScript( wb.prettyScript(blocks) ); //actually run the script

    } 
    wb.runCurrentScripts = runCurrentScripts;


    if (!wb.iframeReady){
        document.querySelector('.stageframe').addEventListener('load', function(event){
            console.log('iframe ready, waiting: %s', !!wb.iframewaiting);
            if (wb.iframewaiting){
                wb.iframewaiting();
            }
            wb.iframewaiting = null;
        }, false);
    }

    //this function takes in the script and should actually run it and produce
    //output to the iframe Stage
    wb.runScript = function(script){}; 

    function clearStage(event){} //this function should include all functionality required to clear the Stage
    wb.clearStage = clearStage;
    Event.on('.clear-stage', 'click', null, clearStage);
    Event.on('.edit-script', 'click', null, clearStage);


    //this function produces the script from the blocks
    wb.prettyScript = function(elements){
        return elements.map(function(elem){
            return wb.codeFromBlock(elem);
        }).join('');
    }; 

    //this function writes the script to view so that the code can be seen
    wb.writeScript = function(elements, view){
        view.innerHTML = '<pre class="language-javascript">' + wb.prettyScript(elements) + '</pre>';
    };

    // End UI section

    //This is a list of some of the choices you can have for choiceLists you can create for
    //your blocks. This example is taken from the JS ide file
    wb.choiceLists = {
        boolean: ['true', 'false'],
        keys: 'abcdefghijklmnopqrstuvwxyz0123456789*+-./'
            .split('').concat(['up', 'down', 'left', 'right',
            'backspace', 'tab', 'return', 'shift', 'ctrl', 'alt',
            'pause', 'capslock', 'esc', 'space', 'pageup', 'pagedown',
            'end', 'home', 'insert', 'del', 'numlock', 'scroll', 'meta']),
        blocktypes: ['step', 'expression', 'context', 'eventhandler', 'asset'],
        types: ['string', 'number', 'boolean', 'array', 'object', 'function', 'any'],
        rettypes: ['none', 'string', 'number', 'boolean', 'array', 'object', 'function', 'any']
    };

    Event.on('.socket input', 'click', null, function(event){
        event.wbTarget.focus();
        event.wbTarget.select();
    });

})(wb, Event);  

All of the functions in this skeleton should be included to make sure a language runs properly.

Testing

Now that you have a (hopefully) working setup of files you should be able to start up your language. First start by building your language by running ./bin/build. After you have built your language you can run it by going to routetohost/myNewLanguage.html. If using a local python server you should be able to connect using localhost:8000/myNewLanguage.html.

If you haven't made any changes to the skeleton files this will not look very exciting you should have no blocks and no running environment for your code even if you had block definitions. However you have taken the first steps to creating a new language! From here if you plan to have the language run in browser you should work on getting runScript() working. After your code can run in browser (or if it isn't going to) block definitions should be created to test your implementation of runScript(). a good test block file is:

(function(wb){
    'use strict';
    wb.menu(
    {
        "sectionkey": "control",
        "name": "Control",
        "help": "Basic Control blocks for testing",
        "blocks": [
            {
                "blocktype": "step",
                "id": "eec0910c-be04-407f-9536-f246a65222b7",
                "script": "{{1}}",
                "help": "Overall control block",
                "sockets": [
                    {
                        "name": "",
                        "type": "any"
                    }
                ]
            }
        ]
    });
})(wb);

This should be saved as "controls_blockmenu.js". You should also make sure you have a copy of the example myNewLang.css file shown on this page for this to work. The block defined in this file will take any input so if you want to test your implementation before doing any more work you can just type language code into this block to make sure your runScript() is working properly.

More Advanced

Now that you have a basic implementation some more files can be covered.

Examples

Now that your language is working you can place saved .json files into the examples folder and add an entry in examples.html in the templates folder to have them show up in the menu for running.

runtime.js

runtime.js allows you to establish all of the functions your code will need at runtime. An excellent example of this can be found in the JavaScript implementation.