hsp/compiler/treebuilder/syntaxTree.js
function (blockType, index, blocks, out) {
        var node = new Node(blockType), block = blocks[index], blockValue, expAst;
        node.name = block.name;
        node.closed = block.closed;
        if (block.ref) {
            // only for components
            node.ref = block.ref;
        }

        // Handle attributes
        var attributes = block.attributes, attribute, outAttribute;
        node.attributes = [];

        for (var i = 0; i < attributes.length; i++) {
            attribute = attributes[i];
           
            //invalid attribute
            if (attribute.type === "invalidattribute") {
                for (var j = 0; j < attribute.errors.length; j++) {
                    var error = attribute.errors[j];
                    var msg = "Invalid attribute";
                    if (error.errorType === "name") {
                        msg = "Invalid attribute name: \\\"" + error.value + "\\\"";
                    }
                    else if (error.errorType === "value" || error.errorType === "tail") {
                        var valueAsString = "";
                        for (var k = 0; k < error.value.length; k++) {
                            var errorBlock = error.value[k];
                            if (k === 0) {
                                error.line = errorBlock.line;
                                error.column = errorBlock.column;
                            }
                            if (errorBlock.type === "expression") {
                                valueAsString += "{" + errorBlock.value + "}";
                                var expAst = this._validateExpressionBlock(errorBlock);
                                this._validateEventHandlerAttr(expAst, attribute);
                            }
                            else {
                                valueAsString += errorBlock.value;
                            }
                        }
                        if (typeof error.tail === "undefined") {
                            msg = "Invalid attribute value: \\\"" + valueAsString + "\\\"";
                        }
                        else {
                            msg = "Attribute value \\\"" + valueAsString + "\\\" has trailing chars: " + error.tail;
                        }
                    }
                    else if (error.errorType === "invalidquotes") {
                        msg = "Missing quote(s) around attribute value: " + error.value.replace("\"", "\\\"");
                    }
                    this._logError(msg, error);
                }
                continue;
            }

            //valid attribute
            var length = attribute.value.length;
            if (length === 0) {
                // this case arises when the attribute is empty - so let's create an empty text node
                if (attribute.value === "") {
                    // attribute has no value - e.g. autocomplete in an input element
                    outAttribute = {
                        name : attribute.name,
                        type : "name",
                        line : attribute.line,
                        column : attribute.column
                    };
                    node.attributes.push(outAttribute);
                    continue;
                } else {
                    attribute.value.push({
                        type : "text",
                        value : ""
                    });
                }
                length = 1;
            }

            if (length === 1) {
                // literal or expression
                var type = attribute.value[0].type;
                if (type === "text" || type === "expression") {
                    outAttribute = attribute.value[0];
                    outAttribute.name = attribute.name;
                    if (type === "expression") {
                        expAst = this._validateExpressionBlock(outAttribute);
                        this._validateEventHandlerAttr(expAst, attribute);
                    }
                } else {
                    this._logError("Invalid attribute type: " + type, attribute);
                    continue;
                }
            } else {
                // length > 1 so attribute is a text block
                // if attribute is an event handler, raise an error
                if (isEventHandlerAttr(attribute.name)) {
                    this._logError("Event handler attributes don't support text and expression mix", attribute);
                }

                //check expression attributes for syntax errors
                for (var j=0; j<length; j++) {
                    blockValue = attribute.value[j];
                    if (blockValue.type === "expression") {
                        expAst = this._validateExpressionBlock(blockValue);
                        this._validateEventHandlerAttr(expAst, attribute);
                    }
                }

                outAttribute = {
                    name : attribute.name,
                    type : "textblock",
                    content : attribute.value
                };
            }

            node.attributes.push(outAttribute);
        }

        //fills node.content with the next blocks, until an matching end element is found, if any
        node.content = [];
        out.push(node);

        if (!block.closed) {
            var endFound = false, blockName = block.name;

            while (!endFound) {
                index = this._advance(blocks, index + 1, node.content, function (type, name) {
                    return (type === "end" + blockType); // && name===blockName
                });
                if (index < 0 || !blocks[index]) {
                    if (blockType==="component") {
                        blockName="#"+this._getComponentPathAsString(block.ref);
                    }
                    // we didn't find any endelement or endcomponent
                    this._logError("Missing end " + blockType + " </" + blockName + ">", block);
                    endFound = true;
                } else {
                    // check if the end name is correct
                    var endBlock = blocks[index];
                    if (endBlock.type === "endelement" || endBlock.type === "endcptattribute") {
                        if (endBlock.name !== blockName) {
                            this._logError("Missing end " + blockType + " </" + blockName + ">", block);
                            index -= 1; // the current end element/component may be caught by a container element
                        }
                    } else {
                        // endcomponent
                        var beginPath = this._getComponentPathAsString(block.ref), endPath = this._getComponentPathAsString(endBlock.ref);
                        if (beginPath !== endPath) {
                            this._logError("Missing end component </#" + beginPath + ">", block);
                            index -= 1; // the current end element/component may be caught by a container element
                        }
                    }
                    endFound = true;
                }
            }
        }

        return index;
    }
function (blockType, index, blocks, out) {
        var node = new Node(blockType), block = blocks[index], blockValue, expAst;
        node.name = block.name;
        node.closed = block.closed;
        if (block.ref) {
            // only for components
            node.ref = block.ref;
        }

        // Handle attributes
        var attributes = block.attributes, attribute, outAttribute;
        node.attributes = [];

        for (var i = 0; i < attributes.length; i++) {
            attribute = attributes[i];
           
            //invalid attribute
            if (attribute.type === "invalidattribute") {
                for (var j = 0; j < attribute.errors.length; j++) {
                    var error = attribute.errors[j];
                    var msg = "Invalid attribute";
                    if (error.errorType === "name") {
                        msg = "Invalid attribute name: \\\"" + error.value + "\\\"";
                    }
                    else if (error.errorType === "value" || error.errorType === "tail") {
                        var valueAsString = "";
                        for (var k = 0; k < error.value.length; k++) {
                            var errorBlock = error.value[k];
                            if (k === 0) {
                                error.line = errorBlock.line;
                                error.column = errorBlock.column;
                            }
                            if (errorBlock.type === "expression") {
                                valueAsString += "{" + errorBlock.value + "}";
                                var expAst = this._validateExpressionBlock(errorBlock);
                                this._validateEventHandlerAttr(expAst, attribute);
                            }
                            else {
                                valueAsString += errorBlock.value;
                            }
                        }
                        if (typeof error.tail === "undefined") {
                            msg = "Invalid attribute value: \\\"" + valueAsString + "\\\"";
                        }
                        else {
                            msg = "Attribute value \\\"" + valueAsString + "\\\" has trailing chars: " + error.tail;
                        }
                    }
                    else if (error.errorType === "invalidquotes") {
                        msg = "Missing quote(s) around attribute value: " + error.value.replace("\"", "\\\"");
                    }
                    this._logError(msg, error);
                }
                continue;
            }

            //valid attribute
            var length = attribute.value.length;
            if (length === 0) {
                // this case arises when the attribute is empty - so let's create an empty text node
                if (attribute.value === "") {
                    // attribute has no value - e.g. autocomplete in an input element
                    outAttribute = {
                        name : attribute.name,
                        type : "name",
                        line : attribute.line,
                        column : attribute.column
                    };
                    node.attributes.push(outAttribute);
                    continue;
                } else {
                    attribute.value.push({
                        type : "text",
                        value : ""
                    });
                }
                length = 1;
            }

            if (length === 1) {
                // literal or expression
                var type = attribute.value[0].type;
                if (type === "text" || type === "expression") {
                    outAttribute = attribute.value[0];
                    outAttribute.name = attribute.name;
                    if (type === "expression") {
                        expAst = this._validateExpressionBlock(outAttribute);
                        this._validateEventHandlerAttr(expAst, attribute);
                    }
                } else {
                    this._logError("Invalid attribute type: " + type, attribute);
                    continue;
                }
            } else {
                // length > 1 so attribute is a text block
                // if attribute is an event handler, raise an error
                if (isEventHandlerAttr(attribute.name)) {
                    this._logError("Event handler attributes don't support text and expression mix", attribute);
                }

                //check expression attributes for syntax errors
                for (var j=0; j<length; j++) {
                    blockValue = attribute.value[j];
                    if (blockValue.type === "expression") {
                        expAst = this._validateExpressionBlock(blockValue);
                        this._validateEventHandlerAttr(expAst, attribute);
                    }
                }

                outAttribute = {
                    name : attribute.name,
                    type : "textblock",
                    content : attribute.value
                };
            }

            node.attributes.push(outAttribute);
        }

        //fills node.content with the next blocks, until an matching end element is found, if any
        node.content = [];
        out.push(node);

        if (!block.closed) {
            var endFound = false, blockName = block.name;

            while (!endFound) {
                index = this._advance(blocks, index + 1, node.content, function (type, name) {
                    return (type === "end" + blockType); // && name===blockName
                });
                if (index < 0 || !blocks[index]) {
                    if (blockType==="component") {
                        blockName="#"+this._getComponentPathAsString(block.ref);
                    }
                    // we didn't find any endelement or endcomponent
                    this._logError("Missing end " + blockType + " </" + blockName + ">", block);
                    endFound = true;
                } else {
                    // check if the end name is correct
                    var endBlock = blocks[index];
                    if (endBlock.type === "endelement" || endBlock.type === "endcptattribute") {
                        if (endBlock.name !== blockName) {
                            this._logError("Missing end " + blockType + " </" + blockName + ">", block);
                            index -= 1; // the current end element/component may be caught by a container element
                        }
                    } else {
                        // endcomponent
                        var beginPath = this._getComponentPathAsString(block.ref), endPath = this._getComponentPathAsString(endBlock.ref);
                        if (beginPath !== endPath) {
                            this._logError("Missing end component </#" + beginPath + ">", block);
                            index -= 1; // the current end element/component may be caught by a container element
                        }
                    }
                    endFound = true;
                }
            }
        }

        return index;
    }
function ( blockType , index , blocks , out ) { var node = new Node ( blockType ) , block = blocks [ index ] , blockValue , expAst ; node . name = block . name ; node . closed = block . closed ; if ( block . ref ) { // only for components node . ref = block . ref ; } // Handle attributes var attributes = block . attributes , attribute , outAttribute ; node . attributes = [ ] ; for ( var i = 0 ; i < attributes . length ; i ++ ) { attribute = attributes [ i ] ; //invalid attribute if ( attribute . type === "invalidattribute" ) { for ( var j = 0 ; j < attribute . errors . length ; j ++ ) { var error = attribute . errors [ j ] ; var msg = "Invalid attribute" ; if ( error . errorType === "name" ) { msg = "Invalid attribute name: \\\"" + error . value + "\\\"" ; } else if ( error . errorType === "value" || error . errorType === "tail" ) { var valueAsString = "" ; for ( var k = 0 ; k < error . value . length ; k ++ ) { var errorBlock = error . value [ k ] ; if ( k === 0 ) { error . line = errorBlock . line ; error . column = errorBlock . column ; } if ( errorBlock . type === "expression" ) { valueAsString += "{" + errorBlock . value + "}" ; var expAst = this . _validateExpressionBlock ( errorBlock ) ; this . _validateEventHandlerAttr ( expAst , attribute ) ; } else { valueAsString += errorBlock . value ; } } if ( typeof error . tail === "undefined" ) { msg = "Invalid attribute value: \\\"" + valueAsString + "\\\"" ; } else { msg = "Attribute value \\\"" + valueAsString + "\\\" has trailing chars: " + error . tail ; } } else if ( error . errorType === "invalidquotes" ) { msg = "Missing quote(s) around attribute value: " + error . value . replace ( "\"" , "\\\"" ) ; } this . _logError ( msg , error ) ; } continue ; } //valid attribute var length = attribute . value . length ; if ( length === 0 ) { // this case arises when the attribute is empty - so let's create an empty text node if ( attribute . value === "" ) { // attribute has no value - e.g. autocomplete in an input element outAttribute = { name : attribute . name , type : "name" , line : attribute . line , column : attribute . column } ; node . attributes . push ( outAttribute ) ; continue ; } else { attribute . value . push ( { type : "text" , value : "" } ) ; } length = 1 ; } if ( length === 1 ) { // literal or expression var type = attribute . value [ 0 ] . type ; if ( type === "text" || type === "expression" ) { outAttribute = attribute . value [ 0 ] ; outAttribute . name = attribute . name ; if ( type === "expression" ) { expAst = this . _validateExpressionBlock ( outAttribute ) ; this . _validateEventHandlerAttr ( expAst , attribute ) ; } } else { this . _logError ( "Invalid attribute type: " + type , attribute ) ; continue ; } } else { // length > 1 so attribute is a text block // if attribute is an event handler, raise an error if ( isEventHandlerAttr ( attribute . name ) ) { this . _logError ( "Event handler attributes don't support text and expression mix" , attribute ) ; } //check expression attributes for syntax errors for ( var j = 0 ; j < length ; j ++ ) { blockValue = attribute . value [ j ] ; if ( blockValue . type === "expression" ) { expAst = this . _validateExpressionBlock ( blockValue ) ; this . _validateEventHandlerAttr ( expAst , attribute ) ; } } outAttribute = { name : attribute . name , type : "textblock" , content : attribute . value } ; } node . attributes . push ( outAttribute ) ; } //fills node.content with the next blocks, until an matching end element is found, if any node . content = [ ] ; out . push ( node ) ; if ( ! block . closed ) { var endFound = false , blockName = block . name ; while ( ! endFound ) { index = this . _advance ( blocks , index + 1 , node . content , function ( type , name ) { return ( type === "end" + blockType ) ; // && name===blockName } ) ; if ( index < 0 || ! blocks [ index ] ) { if ( blockType === "component" ) { blockName = "#" + this . _getComponentPathAsString ( block . ref ) ; } // we didn't find any endelement or endcomponent this . _logError ( "Missing end " + blockType + " </" + blockName + ">" , block ) ; endFound = true ; } else { // check if the end name is correct var endBlock = blocks [ index ] ; if ( endBlock . type === "endelement" || endBlock . type === "endcptattribute" ) { if ( endBlock . name !== blockName ) { this . _logError ( "Missing end " + blockType + " </" + blockName + ">" , block ) ; index -= 1 ; // the current end element/component may be caught by a container element } } else { // endcomponent var beginPath = this . _getComponentPathAsString ( block . ref ) , endPath = this . _getComponentPathAsString ( endBlock . ref ) ; if ( beginPath !== endPath ) { this . _logError ( "Missing end component </#" + beginPath + ">" , block ) ; index -= 1 ; // the current end element/component may be caught by a container element } } endFound = true ; } } } return index ; }
Processing function for elements, components and component attributes
@arg blockType {String} "element", "component" or "cptattribute".
@param {Array} blocks the full list of blocks.
@param {Integer} index the index of the block to manage.
@param {Array} out the output as an array of Node.
@return {Integer} the index of the block where the function stopped or -1 if all blocks have been handled.
Processing function for elements components and component attributes