"use strict";
var __extends = (this && this.__extends) || function (d, b) {
    for (var p in b) /* istanbul ignore next */  if (b.hasOwnProperty(p)) d[p] = b[p];
    function __() { this.constructor = d; }
    /* istanbul ignore next */  d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
var utils_1 = require("../utils/utils");
var lang_extensions_1 = require("../lang/lang_extensions");
var lexer_public_1 = require("./lexer_public");
/**
 *  This can be used to improve the quality/readability of error messages or syntax diagrams.
 *
 * @param {Function} clazz - A constructor for a Token subclass
 * @returns {string} the Human readable label a Token if it exists.
 */
function tokenLabel(clazz) {
    if (hasTokenLabel(clazz)) {
        return clazz.LABEL;
    }
    else {
        return tokenName(clazz);
    }
}
exports.tokenLabel = tokenLabel;
function hasTokenLabel(clazz) {
    return utils_1.isString(clazz.LABEL) && clazz.LABEL !== "";
}
exports.hasTokenLabel = hasTokenLabel;
function tokenName(clazz) {
    // used to support js inheritance patterns that do not use named functions
    // in that situation setting a property tokenName on a token constructor will
    // enable producing readable error messages.
    if (utils_1.isString(clazz.tokenName)) {
        return clazz.tokenName;
    }
    else {
        return lang_extensions_1.functionName(clazz);
    }
}
exports.tokenName = tokenName;
/**
 * utility to help the poor souls who are still stuck writing pure javascript 5.1
 * extend and create Token subclasses in a less verbose manner
 *
 * @param {string} tokenName - the name of the new TokenClass
 * @param {RegExp|Function} patternOrParent - RegExp Pattern or Parent Token Constructor
 * @param {Function} parentConstructor - the Token class to be extended
 * @returns {Function} - a constructor for the new extended Token subclass
 */
function extendToken(tokenName, patternOrParent, parentConstructor) {
    if (patternOrParent === void 0) { patternOrParent = undefined; }
    if (parentConstructor === void 0) { parentConstructor = Token; }
    var pattern;
    if (utils_1.isRegExp(patternOrParent) ||
        patternOrParent === lexer_public_1.Lexer.SKIPPED ||
        patternOrParent === lexer_public_1.Lexer.NA) {
        pattern = patternOrParent;
    }
    else if (utils_1.isFunction(patternOrParent)) {
        parentConstructor = patternOrParent;
        pattern = undefined;
    }
    var derivedCostructor = function () {
        parentConstructor.apply(this, arguments);
    };
    // static properties mixing
    derivedCostructor = utils_1.assign(derivedCostructor, parentConstructor);
    // the tokenName property will be used by the Parser for Error Messages if the Token's constructor is anonymous
    derivedCostructor.tokenName = tokenName;
    derivedCostructor.prototype = Object.create(parentConstructor.prototype);
    derivedCostructor.prototype.constructor = derivedCostructor;
    if (!utils_1.isUndefined(pattern)) {
        derivedCostructor.PATTERN = pattern;
    }
    return derivedCostructor;
}
exports.extendToken = extendToken;
var Token = (function () {
    /**
     * @param {string} image the textual representation of the Token as it appeared in the text
     * @param {number} offset offset of the first character of the Token
     * @param {number} startLine line of the first character of the Token
     * @param {number} startColumn column of the first character of the Token
     * @param {number} endLine line of the last character of the Token
     * @param {number} endColumn column of the last character of the Token
     *
     * Things to note:
     * * "do"  {startColumn : 1, endColumn: 2} --> the range is inclusive to exclusive 1...2 (2 chars long).
     * * "\n"  {startLine : 1, endLine: 1} --> a lineTerminator as the last character does not effect the Token's line numbering.
     * * "'hello\tworld\uBBBB'"  {image: "'hello\tworld\uBBBB'"} --> a Token's image is the "literal" text
     *                                                              (unicode escaping is untouched).
     */
    function Token(image, offset, startLine, startColumn, endLine, endColumn) {
        if (endLine === void 0) { endLine = startLine; }
        if (endColumn === void 0) { endColumn = startColumn + image.length - 1; }
        this.image = image;
        this.offset = offset;
        this.startLine = startLine;
        this.startColumn = startColumn;
        this.endLine = endLine;
        this.endColumn = endColumn;
        // this marks if a Token does not really exist and has been inserted "artificially" during parsing in rule error recovery
        this.isInsertedInRecovery = false;
    }
    /**
     * A "human readable" Label for a Token.
     * Subclasses of Token may define their own static LABEL property.
     * This label will be used in error messages and drawing syntax diagrams.
     *
     * For example a Token constructor may be called LCurly, which is short for LeftCurlyBrackets, These names are either too short
     * or too unwieldy to be used in error messages.
     *
     * Imagine : "expecting LCurly but found ')'" or "expecting LeftCurlyBrackets but found ')'"
     *
     * However if a static property LABEL with the value '{' exists on LCurly class, that error message will be:
     * "expecting '{' but found ')'"
     */
    Token.LABEL = undefined;
    return Token;
}());
exports.Token = Token;
/**
 * a special kind of Token which does not really exist in the input
 * (hence the 'Virtual' prefix). These type of Tokens can be used as special markers:
 * for example, EOF (end-of-file).
 */
var VirtualToken = (function (_super) {
    __extends(VirtualToken, _super);
    function VirtualToken() {
        _super.call(this, "", -1, -1, -1, -1, -1);
    }
    return VirtualToken;
}(Token));
exports.VirtualToken = VirtualToken;
var EOF = (function (_super) {
    __extends(EOF, _super);
    function EOF() {
        _super.apply(this, arguments);
    }
    return EOF;
}(VirtualToken));
exports.EOF = EOF;
