falcor-path-syntax
Version:
Parser for Falcor Path Syntax
153 lines (131 loc) • 3.67 kB
JavaScript
var TokenTypes = require('./../TokenTypes');
var DOT_SEPARATOR = '.';
var COMMA_SEPARATOR = ',';
var OPENING_BRACKET = '[';
var CLOSING_BRACKET = ']';
var OPENING_BRACE = '{';
var CLOSING_BRACE = '}';
var COLON = ':';
var ESCAPE = '\\';
var DOUBLE_OUOTES = '"';
var SINGE_OUOTES = "'";
var SPACE = " ";
var SPECIAL_CHARACTERS = '\\\'"[]., ';
var EXT_SPECIAL_CHARACTERS = '\\{}\'"[]., :';
var Tokenizer = module.exports = function(string, ext) {
this._string = string;
this._idx = -1;
this._extended = ext;
this.parseString = '';
};
Tokenizer.prototype = {
/**
* grabs the next token either from the peek operation or generates the
* next token.
*/
next: function() {
var nextToken = this._nextToken ?
this._nextToken : getNext(this._string, this._idx, this._extended);
this._idx = nextToken.idx;
this._nextToken = false;
this.parseString += nextToken.token.token;
return nextToken.token;
},
/**
* will peak but not increment the tokenizer
*/
peek: function() {
var nextToken = this._nextToken ?
this._nextToken : getNext(this._string, this._idx, this._extended);
this._nextToken = nextToken;
return nextToken.token;
}
};
Tokenizer.toNumber = function toNumber(x) {
if (!isNaN(+x)) {
return +x;
}
return NaN;
};
function toOutput(token, type, done) {
return {
token: token,
done: done,
type: type
};
}
function getNext(string, idx, ext) {
var output = false;
var token = '';
var specialChars = ext ?
EXT_SPECIAL_CHARACTERS : SPECIAL_CHARACTERS;
var done;
do {
done = idx + 1 >= string.length;
if (done) {
break;
}
// we have to peek at the next token
var character = string[idx + 1];
if (character !== undefined &&
specialChars.indexOf(character) === -1) {
token += character;
++idx;
continue;
}
// The token to delimiting character transition.
else if (token.length) {
break;
}
++idx;
var type;
switch (character) {
case DOT_SEPARATOR:
type = TokenTypes.dotSeparator;
break;
case COMMA_SEPARATOR:
type = TokenTypes.commaSeparator;
break;
case OPENING_BRACKET:
type = TokenTypes.openingBracket;
break;
case CLOSING_BRACKET:
type = TokenTypes.closingBracket;
break;
case OPENING_BRACE:
type = TokenTypes.openingBrace;
break;
case CLOSING_BRACE:
type = TokenTypes.closingBrace;
break;
case SPACE:
type = TokenTypes.space;
break;
case DOUBLE_OUOTES:
case SINGE_OUOTES:
type = TokenTypes.quote;
break;
case ESCAPE:
type = TokenTypes.escape;
break;
case COLON:
type = TokenTypes.colon;
break;
default:
type = TokenTypes.unknown;
break;
}
output = toOutput(character, type, false);
break;
} while (!done);
if (!output && token.length) {
output = toOutput(token, TokenTypes.token, false);
}
if (!output) {
output = {done: true};
}
return {
token: output,
idx: idx
};
}