function parse(lexed, line) {

        var parsed = {
            symbols: [],
            weight: 0
        };

        var 
            currentVarientEnding = null,
            tupletBuffer = [],
            tupletCount = 0,
            tupletValue = 0;

        while (lexed.length > 0) {

            if (lexed[0].type === "data") {
                var lexedToken = lexed.shift();
                parsed.symbols.push({
                    type_class: "data",
                    type: lexedToken.subtype,
                    data: lexedToken.data
                });

                continue;
            }

            if (lexed[0].type === "beam") {
                lexed.shift();
                continue;
            }

            // if (lexed[0].type === "chord_annotation") {
            //     parsed.symbols.push({
            //         type_class: "drawable",
            //         type: "chord_annotation",
            //         text: lexed[0].data
            //     });
            //     lexed.shift();
            //     continue;
            // }
            if (lexed[0].type === "tuplet_start") {
                tupletCount = lexed[0].data;
                tupletValue = lexed[0].data;
                lexed.shift();
                continue;
            }

            if (lexed[0].type === "note") {
                parseNote(lexed, parsed);

                if(currentVarientEnding !== null && currentVarientEnding.start === null) {
                    currentVarientEnding.start = _.last(parsed.symbols);
                }

                if(tupletCount > 0) {
                    tupletBuffer.push(_.last(parsed.symbols));
                    tupletCount--;

                    if(tupletCount === 0) {

                        tupletBuffer.forEach(function(note) {
                            note.noteLength = (note.noteLength / tupletValue) * 2;
                            //note.weight = data_tables.symbol_width.note(note);
                        });

                        line.tuplets.push({
                            notes: tupletBuffer,
                            value: tupletValue
                        });
                        tupletBuffer = [];
                    }
                }

                continue;
            }

            if (lexed[0].type === "rest") {
                parsed.symbols.push(parseRest(lexed));
                parsed.weight += 1;
                continue;
            }

            if (lexed[0].type === "space") {
                parsed.symbols.push(new AbcSymbol("space", 0));
                lexed.shift();
                continue;
            }

            if(lexed[0].type === "varient_section") {
                var symbol = lexed.shift();

                currentVarientEnding = {
                    start: null,
                    name: symbol.data,
                    end: null
                };

                continue;
            }

            if (noteGroup(parsed, lexed, "chord", "chord_start", "chord_stop")) continue;
            if (parseSlur(parsed, lexed)) continue;
            if (noteGroup(parsed, lexed, "grace", "grace_start", "grace_stop")) continue;

            if (lexed[0].type === "barline") {

                if(parseBarline(lexed, parsed) === 1) {

                    if(line.firstEndingEnder === null) line.firstEndingEnder = _.last(parsed.symbols);

                    if(currentVarientEnding !== null) {
                        currentVarientEnding.end = _.last(parsed.symbols);
                        line.endings.push(currentVarientEnding);
                        currentVarientEnding = null;
                    }
                }

                
                continue;
            }

            if(lexed[0].type === "tie") {

                lexed.shift();

                //the last parsed symbol must be a note
                if(_.last(parsed.symbols).type === "note") {
                    
                    var tie = {
                        type: "tie",
                        start: _.last(parsed.symbols)
                    };

                    //eat the barline if required
                    if (lexed[0].type === "barline")parseBarline(lexed, parsed);

                    if (lexed[0].type === "note") {
                        parseNote(lexed, parsed);
                    } else {
                        //THROW ERROR
                        continue;
                    }

                    tie.end = _.last(parsed.symbols);

                    parsed.symbols.push(tie);
                } else {
                    //THROW ERROR
                    continue;
                }

                continue;
            }

            console.log(`PARSER ERROR: UNKNOWN ${lexed[0]}`);
            lexed.shift();
        }

        if(currentVarientEnding !== null) {
            line.endings.push(currentVarientEnding);
            line.endWithEndingBar = true;
        }

        return parsed;
    }
/**
     * A recursive decent parser that combines lexed tokens into a meaningful data structure
     * @param  {Array} An array of lexed tokens
     * @return {Array} An array of parsed symbols
     */
A recursive decent parser that combines lexed tokens into a meaningful data structure
@param  {Array} An array of lexed tokens
@return {Array} An array of parsed symbols
A recursive decent parser that combines lexed tokens into a meaningful data structure @param { Array } An array of lexed tokens @return { Array } An array of parsed symbols
function parse(lexed, line) {
        var parsed = {
            symbols: [],
            weight: 0
        };
        var 
            currentVarientEnding = null,
            tupletBuffer = [],
            tupletCount = 0,
            tupletValue = 0;
        while (lexed.length > 0) {
            if (lexed[0].type === "data") {
                var lexedToken = lexed.shift();
                parsed.symbols.push({
                    type_class: "data",
                    type: lexedToken.subtype,
                    data: lexedToken.data
                });
                continue;
            }
            if (lexed[0].type === "beam") {
                lexed.shift();
                continue;
            }
            if (lexed[0].type === "tuplet_start") {
                tupletCount = lexed[0].data;
                tupletValue = lexed[0].data;
                lexed.shift();
                continue;
            }
            if (lexed[0].type === "note") {
                parseNote(lexed, parsed);
                if(currentVarientEnding !== null && currentVarientEnding.start === null) {
                    currentVarientEnding.start = _.last(parsed.symbols);
                }
                if(tupletCount > 0) {
                    tupletBuffer.push(_.last(parsed.symbols));
                    tupletCount--;
                    if(tupletCount === 0) {
                        tupletBuffer.forEach(function(note) {
                            note.noteLength = (note.noteLength / tupletValue) * 2;
                        });
                        line.tuplets.push({
                            notes: tupletBuffer,
                            value: tupletValue
                        });
                        tupletBuffer = [];
                    }
                }
                continue;
            }
            if (lexed[0].type === "rest") {
                parsed.symbols.push(parseRest(lexed));
                parsed.weight += 1;
                continue;
            }
            if (lexed[0].type === "space") {
                parsed.symbols.push(new AbcSymbol("space", 0));
                lexed.shift();
                continue;
            }
            if(lexed[0].type === "varient_section") {
                var symbol = lexed.shift();
                currentVarientEnding = {
                    start: null,
                    name: symbol.data,
                    end: null
                };
                continue;
            }
            if (noteGroup(parsed, lexed, "chord", "chord_start", "chord_stop")) continue;
            if (parseSlur(parsed, lexed)) continue;
            if (noteGroup(parsed, lexed, "grace", "grace_start", "grace_stop")) continue;
            if (lexed[0].type === "barline") {
                if(parseBarline(lexed, parsed) === 1) {
                    if(line.firstEndingEnder === null) line.firstEndingEnder = _.last(parsed.symbols);
                    if(currentVarientEnding !== null) {
                        currentVarientEnding.end = _.last(parsed.symbols);
                        line.endings.push(currentVarientEnding);
                        currentVarientEnding = null;
                    }
                }
                continue;
            }
            if(lexed[0].type === "tie") {
                lexed.shift();
                if(_.last(parsed.symbols).type === "note") {
                    var tie = {
                        type: "tie",
                        start: _.last(parsed.symbols)
                    };
                    if (lexed[0].type === "barline")parseBarline(lexed, parsed);
                    if (lexed[0].type === "note") {
                        parseNote(lexed, parsed);
                    } else {
                        continue;
                    }
                    tie.end = _.last(parsed.symbols);
                    parsed.symbols.push(tie);
                } else {
                    continue;
                }
                continue;
            }
            console.log(`PARSER ERROR: UNKNOWN ${lexed[0]}`);
            lexed.shift();
        }
        if(currentVarientEnding !== null) {
            line.endings.push(currentVarientEnding);
            line.endWithEndingBar = true;
        }
        return parsed;
    }
function parse ( lexed , line ) { var parsed = { symbols : [ ] , weight : 0 } ; var currentVarientEnding = null , tupletBuffer = [ ] , tupletCount = 0 , tupletValue = 0 ; while ( lexed . length > 0 ) { if ( lexed [ 0 ] . type === "data" ) { var lexedToken = lexed . shift ( ) ; parsed . symbols . push ( { type_class : "data" , type : lexedToken . subtype , data : lexedToken . data } ) ; continue ; } if ( lexed [ 0 ] . type === "beam" ) { lexed . shift ( ) ; continue ; } if ( lexed [ 0 ] . type === "tuplet_start" ) { tupletCount = lexed [ 0 ] . data ; tupletValue = lexed [ 0 ] . data ; lexed . shift ( ) ; continue ; } if ( lexed [ 0 ] . type === "note" ) { parseNote ( lexed , parsed ) ; if ( currentVarientEnding !== null && currentVarientEnding . start === null ) { currentVarientEnding . start = _ . last ( parsed . symbols ) ; } if ( tupletCount > 0 ) { tupletBuffer . push ( _ . last ( parsed . symbols ) ) ; tupletCount -- ; if ( tupletCount === 0 ) { tupletBuffer . forEach ( function ( note ) { note . noteLength = ( note . noteLength / tupletValue ) * 2 ; } ) ; line . tuplets . push ( { notes : tupletBuffer , value : tupletValue } ) ; tupletBuffer = [ ] ; } } continue ; } if ( lexed [ 0 ] . type === "rest" ) { parsed . symbols . push ( parseRest ( lexed ) ) ; parsed . weight += 1 ; continue ; } if ( lexed [ 0 ] . type === "space" ) { parsed . symbols . push ( new AbcSymbol ( "space" , 0 ) ) ; lexed . shift ( ) ; continue ; } if ( lexed [ 0 ] . type === "varient_section" ) { var symbol = lexed . shift ( ) ; currentVarientEnding = { start : null , name : symbol . data , end : null } ; continue ; } if ( noteGroup ( parsed , lexed , "chord" , "chord_start" , "chord_stop" ) ) continue ; if ( parseSlur ( parsed , lexed ) ) continue ; if ( noteGroup ( parsed , lexed , "grace" , "grace_start" , "grace_stop" ) ) continue ; if ( lexed [ 0 ] . type === "barline" ) { if ( parseBarline ( lexed , parsed ) === 1 ) { if ( line . firstEndingEnder === null ) line . firstEndingEnder = _ . last ( parsed . symbols ) ; if ( currentVarientEnding !== null ) { currentVarientEnding . end = _ . last ( parsed . symbols ) ; line . endings . push ( currentVarientEnding ) ; currentVarientEnding = null ; } } continue ; } if ( lexed [ 0 ] . type === "tie" ) { lexed . shift ( ) ; if ( _ . last ( parsed . symbols ) . type === "note" ) { var tie = { type : "tie" , start : _ . last ( parsed . symbols ) } ; if ( lexed [ 0 ] . type === "barline" ) parseBarline ( lexed , parsed ) ; if ( lexed [ 0 ] . type === "note" ) { parseNote ( lexed , parsed ) ; } else { continue ; } tie . end = _ . last ( parsed . symbols ) ; parsed . symbols . push ( tie ) ; } else { continue ; } continue ; } console . log ( ` ${ lexed [ 0 ] } ` ) ; lexed . shift ( ) ; } if ( currentVarientEnding !== null ) { line . endings . push ( currentVarientEnding ) ; line . endWithEndingBar = true ; } return parsed ; }
A recursive decent parser that combines lexed tokens into a meaningful data structure
 @param  {Array} An array of lexed tokens
 @return {Array} An array of parsed symbols
A recursive decent parser that combines lexed tokens into a meaningful data structure @param { Array } An array of lexed tokens @return { Array } An array of parsed symbols
// if (lexed[0].type === "chord_annotation") { //     parsed.symbols.push({ //         type_class: "drawable", //         type: "chord_annotation", //         text: lexed[0].data //     }); //     lexed.shift(); //     continue; // } //note.weight = data_tables.symbol_width.note(note); //the last parsed symbol must be a note //eat the barline if required //THROW ERROR //THROW ERROR