var TokenType = require('../token-types'); module.exports = (function() { /** * Mark whitespaces and comments */ function markSC(tokens) { var tokensLength = tokens.length, ws = -1, // flag for whitespaces sc = -1, // flag for whitespaces and comments t; // current token // For every token in the token list, mark spaces and line breaks // as spaces (set both `ws` and `sc` flags). Mark multiline comments // with `sc` flag. // If there are several spaces or tabs or line breaks or multiline // comments in a row, group them: take the last one's index number // and save it to the first token in the group as a reference // (e.g., `ws_last = 7` for a group of whitespaces or `sc_last = 9` // for a group of whitespaces and comments): for (var i = 0; i < tokensLength; i++) { t = tokens[i]; switch (t.type) { case TokenType.Space: case TokenType.Tab: t.ws = true; t.sc = true; if (ws === -1) ws = i; if (sc === -1) sc = i; break; case TokenType.Newline: t.ws = true; t.sc = true; ws = ws === -1 ? i : ws; sc = sc === -1 ? i : ws; tokens[ws].ws_last = i - 1; tokens[sc].sc_last = i - 1; tokens[i].ws_last = i; tokens[i].sc_last = i; ws = -1; sc = -1; break; case TokenType.CommentML: case TokenType.CommentSL: if (ws !== -1) { tokens[ws].ws_last = i - 1; ws = -1; } t.sc = true; break; default: if (ws !== -1) { tokens[ws].ws_last = i - 1; ws = -1; } if (sc !== -1) { tokens[sc].sc_last = i - 1; sc = -1; } } } if (ws !== -1) tokens[ws].ws_last = i - 1; if (sc !== -1) tokens[sc].sc_last = i - 1; } /** * Pair brackets */ function markBrackets(tokens) { var tokensLength = tokens.length; var ps = [], // parenthesis sbs = [], // square brackets cbs = [], // curly brackets t; // current token // For every token in the token list, if we meet an opening (left) // bracket, push its index number to a corresponding array. // If we then meet a closing (right) bracket, look at the corresponding // array. If there are any elements (records about previously met // left brackets), take a token of the last left bracket (take // the last index number from the array and find a token with // this index number) and save right bracket's index as a reference: for (var i = 0; i < tokens.length; i++) { t = tokens[i]; switch(t.type) { case TokenType.LeftParenthesis: ps.push(i); break; case TokenType.RightParenthesis: if (ps.length) { t.left = ps.pop(); tokens[t.left].right = i; } break; case TokenType.LeftSquareBracket: sbs.push(i); break; case TokenType.RightSquareBracket: if (sbs.length) { t.left = sbs.pop(); tokens[t.left].right = i; } break; case TokenType.LeftCurlyBracket: cbs.push(i); break; case TokenType.RightCurlyBracket: if (cbs.length) { t.left = cbs.pop(); tokens[t.left].right = i; } break; } } } function markBlocks(tokens) { var tokensLength = tokens.length; var blocks = [], currentLN = 1, currentIL = 0, prevIL = 0, i = 0, l = tokens.length, iw; for (; i != l; i++) { if (!tokens[i - 1]) continue; // Skip all tokens on current line: if (tokens[i].ln == currentLN) continue; else currentLN = tokens[i].ln; // Get indent level: prevIL = currentIL; if (tokens[i].type === TokenType.Newline) continue; else if (tokens[i].type === TokenType.Space && tokens[i + 1] && tokens[i + 1].type === TokenType.Newline) continue; else if (tokens[i].type !== TokenType.Space) currentIL = 0; else { // If we don't know ident width yet, count number of spaces: if (!iw) iw = tokens[i].value.length; prevIL = currentIL; currentIL = tokens[i].value.length / iw; } // Decide whether it's block's start or end: if (prevIL === currentIL) continue; else if (currentIL > prevIL) { blocks.push(i); continue; } else { var il = prevIL; while (blocks.length > 0 && il !== currentIL) { tokens[blocks.pop()].block_end = i - 1; il--; } } } while (blocks.length > 0) { tokens[blocks.pop()].block_end = i - 1; } } return function(tokens) { markBrackets(tokens); markSC(tokens); markBlocks(tokens); } })();