/**
* Constructs a token with the specified type and text
*
* @classdesc
*
* This class represents a token used in performing a text query. Tokens are
* produced by {@link LEMTokenizer}s from the raw query string and consumed by
* a {@link LEMParser}. Each token comprises a type and text. The type is a
* {@link TokenType} enum instance and specifies the type of the token. The text
* is a string and is the texual representation of the token.
*
* @constructor
* @param {TokenType} type The type of the token
* @param {String} text The texual representation of the token
*/
function Token(type, text) {
/** @private */
this.type = type;
/** @private */
this.text = text;
if (type.getText() != null && type.getText() != text) {
throw new Exception("Token constructor: the text argument must match the TokenType's text if the TokenType has a set text");
}
}
/**
* Gets the type of the token
*
* @returns {TokenType} The token type
*/
Token.prototype.getType = function() {
return this.type;
};
/**
* Gets the texual representation of the token
*
* @returns {String} The token text
*/
Token.prototype.getText = function() {
return this.text;
};
// ----------------------------------------------------------------------
/**
* The constructor for this enum should never be used outside of the TokenType
* class
*
* @classdesc
*
* <p>
* TokenType is an enum. A TokenType specifies the type of a token. The
* different token types are the differnt terminal tokens in the syntactic
* grammar defined in {@link LEMParser}
* </p>
*
* <p>
* Each TokenType has one or more texual representations. TokenTypes such as
* TokenType.PIPE (aka the | character) have only one texual representation.
* Other token types such as string literals have multiple or even an inifinite
* number of possible texual representations.
* </p>
*
* <p>
* Tokens can be either text-based or symbolic. For example, TokenType.AND
* ("and") is text-based whereas TokenType.EQUAL ("=") is symbolic
* </p>
*
* @constructor
* @param {String} text The texual representation of the token
* @param {?Boolean} [isText]
* @param {?String} [prettyName]
*/
function TokenType(text, isText, prettyName) {
/** @private */
this.text = text;
/** @private */
this.isText = !!isText;
/** @private */
this.prettyName = prettyName || text;
}
/**
* @const
* @static
*/
TokenType.DOLLAR = new TokenType("$");
/**
* @const
* @static
*/
TokenType.EXCLAMATION_EQUAL = new TokenType("!=");
/**
* @const
* @static
*/
TokenType.EQUAL = new TokenType("=");
/**
* @const
* @static
*/
TokenType.L_PAREN = new TokenType("(");
/**
* @const
* @static
*/
TokenType.R_PAREN = new TokenType(")");
/**
* @const
* @static
*/
TokenType.PIPE = new TokenType("|");
/**
* @const
* @static
*/
TokenType.AMP = new TokenType("&");
/**
* @const
* @static
*/
TokenType.CARET = new TokenType("^");
/**
* CHAR_SEQ = / [a-zA-Z0-9]* /
*
* @const
* @static
*/
TokenType.CHAR_SEQ = new TokenType(null, true, "a sequence of characters");
/**
* RegexLiteral = / \/[^\/]*\/ /
*
* @const
* @static
*/
TokenType.REGEX_LITERAL = new TokenType(null, true, "a regular expression");
/**
* StringLiteral = / "[^"]*" /
*
* @const
* @static
*/
TokenType.STRING_LITERAL = new TokenType(null, true, "a string literal");
/**
* Gets all valid token types
*
* @static
* @returns {Array<TokenType>} All valid token types as an array
*/
TokenType.getTokenTypes = function() {
return [ //
TokenType.DOLLAR, //
TokenType.EXCLAMATION_EQUAL, //
TokenType.EQUAL, //
TokenType.L_PAREN, //
TokenType.R_PAREN, //
TokenType.PIPE, //
TokenType.AMP, //
TokenType.CARET, //
TokenType.CHAR_SEQ, //
TokenType.REGEX_LITERAL, //
TokenType.STRING_LITERAL //
];
};
/**
* @private
* @static
*/
TokenType.hasStaticInit = false;
/**
* @private
* @static
*/
TokenType.symbolicTokenStringSet = {};
/**
* @private
* @static
*/
TokenType.textTokenStringSet = {};
/**
* @private
* @static
*/
TokenType.ensureStaticInit = function() {
if (TokenType.hasStaticInit) {
return;
}
TokenType.hasStaticInit = true;
var tokenTypes = TokenType.getTokenTypes();
for (var i = 0; i < tokenTypes.length; i++) {
var tokenType = tokenTypes[i];
if (!tokenType) {
throw new Exception("LEMToken: one of the tokens in TokenType.getTokenTypes is undefined.");
}
if (tokenType.getText() == null) {
return;
}
if (tokenType.getIsText()) {
TokenType.textTokenStringSet[tokenType.getText()] = tokenType;
}
else {
TokenType.symbolicTokenStringSet[tokenType.getText()] = tokenType;
}
}
};
/**
* Returns a mapping of the texual representation of symbolic tokens to the
* corresponding TokenType enum.
*
* @static
* @returns {Object<String, TokenType>}
*/
TokenType.getSymbolicTokenStringSet = function() {
TokenType.ensureStaticInit();
var ret = {};
for (var key in TokenType.symbolicTokenStringSet) {
ret[key] = TokenType.symbolicTokenStringSet[key];
}
return ret;
};
/**
* Returns a mapping of the texual representation of text-based tokens to the
* corresponding TokenType enum. TokenTypes that have multiple texual
* representations are not included.
*
* @static
* @returns {Object<String, TokenType>}
*/
TokenType.getTextTokenStringSet = function() {
TokenType.ensureStaticInit();
var ret = {};
for (var key in TokenType.textTokenStringSet) {
ret[key] = TokenType.textTokenStringSet[key];
}
return ret;
};
/**
* Gets the texual representation of this token type. If this token type has
* multiple permissible texual representations (such as a string literal token
* type), this method returns null
*
* @returns {String} The texual representation of this type of token, or null if
* multiple exist
*/
TokenType.prototype.getText = function() {
return this.text;
};
/**
* Returns true if this token type is text-based as opposed to symbolic
*
* @returns {Boolean} True if token type is text based
*/
TokenType.prototype.getIsText = function() {
return this.isText;
};
/**
* Returns the pretty name or display name of this token type. The pretty name
* is one that would make sense to the end-user
*
* @returns {String} The pretty name
*/
TokenType.prototype.getPrettyName = function() {
return this.prettyName;
};