// ------------------------------------------------------------------
// Chars
// ------------------------------------------------------------------
// prettier-ignore
var Chars;
(function (Chars) {
    /** Returns true if the char code is a whitespace */
    function IsWhitespace(value) {
        return value === 32;
    }
    Chars.IsWhitespace = IsWhitespace;
    /** Returns true if the char code is a newline */
    function IsNewline(value) {
        return value === 10;
    }
    Chars.IsNewline = IsNewline;
    /** Returns true if the char code is a alpha  */
    function IsAlpha(value) {
        return ((value >= 65 && value <= 90) || // A-Z 
            (value >= 97 && value <= 122) // a-z
        );
    }
    Chars.IsAlpha = IsAlpha;
    /** Returns true if the char code is zero */
    function IsZero(value) {
        return value === 48;
    }
    Chars.IsZero = IsZero;
    /** Returns true if the char code is non-zero */
    function IsNonZero(value) {
        return value >= 49 && value <= 57;
    }
    Chars.IsNonZero = IsNonZero;
    /** Returns true if the char code is a digit */
    function IsDigit(value) {
        return (IsNonZero(value) ||
            IsZero(value));
    }
    Chars.IsDigit = IsDigit;
    /** Returns true if the char code is a dot */
    function IsDot(value) {
        return value === 46;
    }
    Chars.IsDot = IsDot;
    /** Returns true if this char code is a underscore */
    function IsUnderscore(value) {
        return value === 95;
    }
    Chars.IsUnderscore = IsUnderscore;
    /** Returns true if this char code is a dollar sign */
    function IsDollarSign(value) {
        return value === 36;
    }
    Chars.IsDollarSign = IsDollarSign;
})(Chars || (Chars = {}));
// ------------------------------------------------------------------
// Trim
// ------------------------------------------------------------------
// prettier-ignore
var Trim;
(function (Trim) {
    /** Trims Whitespace and retains Newline, Tabspaces, etc. */
    function TrimWhitespaceOnly(code) {
        for (let i = 0; i < code.length; i++) {
            if (Chars.IsWhitespace(code.charCodeAt(i)))
                continue;
            return code.slice(i);
        }
        return code;
    }
    Trim.TrimWhitespaceOnly = TrimWhitespaceOnly;
    /** Trims Whitespace including Newline, Tabspaces, etc. */
    function TrimAll(code) {
        return code.trimStart();
    }
    Trim.TrimAll = TrimAll;
})(Trim || (Trim = {}));
// ------------------------------------------------------------------
// Const
// ------------------------------------------------------------------
/** Checks the value matches the next string  */
// prettier-ignore
function NextTokenCheck(value, code) {
    if (value.length > code.length)
        return false;
    for (let i = 0; i < value.length; i++) {
        if (value.charCodeAt(i) !== code.charCodeAt(i))
            return false;
    }
    return true;
}
/** Gets the next constant string value or empty if no match */
// prettier-ignore
function NextConst(value, code) {
    return NextTokenCheck(value, code)
        ? [code.slice(0, value.length), code.slice(value.length)]
        : [];
}
/** Takes the next constant string value skipping any whitespace */
// prettier-ignore
export function Const(value, code) {
    if (value.length === 0)
        return ['', code];
    const char_0 = value.charCodeAt(0);
    return (Chars.IsNewline(char_0) ? NextConst(value, Trim.TrimWhitespaceOnly(code)) :
        Chars.IsWhitespace(char_0) ? NextConst(value, code) :
            NextConst(value, Trim.TrimAll(code)));
}
// ------------------------------------------------------------------
// Ident
// ------------------------------------------------------------------
// prettier-ignore
function IdentIsFirst(char) {
    return (Chars.IsAlpha(char) ||
        Chars.IsDollarSign(char) ||
        Chars.IsUnderscore(char));
}
// prettier-ignore
function IdentIsRest(char) {
    return (Chars.IsAlpha(char) ||
        Chars.IsDigit(char) ||
        Chars.IsDollarSign(char) ||
        Chars.IsUnderscore(char));
}
// prettier-ignore
function NextIdent(code) {
    if (!IdentIsFirst(code.charCodeAt(0)))
        return [];
    for (let i = 1; i < code.length; i++) {
        const char = code.charCodeAt(i);
        if (IdentIsRest(char))
            continue;
        const slice = code.slice(0, i);
        const rest = code.slice(i);
        return [slice, rest];
    }
    return [code, ''];
}
/** Scans for the next Ident token */
// prettier-ignore
export function Ident(code) {
    return NextIdent(Trim.TrimAll(code));
}
// ------------------------------------------------------------------
// Number
// ------------------------------------------------------------------
/** Checks that the next number is not a leading zero */
// prettier-ignore
function NumberLeadingZeroCheck(code, index) {
    const char_0 = code.charCodeAt(index + 0);
    const char_1 = code.charCodeAt(index + 1);
    return ((
    // 1-9
    Chars.IsNonZero(char_0)) || (
    // 0
    Chars.IsZero(char_0) &&
        !Chars.IsDigit(char_1)) || (
    // 0.
    Chars.IsZero(char_0) &&
        Chars.IsDot(char_1)) || (
    // .0
    Chars.IsDot(char_0) &&
        Chars.IsDigit(char_1)));
}
/** Gets the next number token */
// prettier-ignore
function NextNumber(code) {
    const negated = code.charAt(0) === '-';
    const index = negated ? 1 : 0;
    if (!NumberLeadingZeroCheck(code, index)) {
        return [];
    }
    const dash = negated ? '-' : '';
    let hasDot = false;
    for (let i = index; i < code.length; i++) {
        const char_i = code.charCodeAt(i);
        if (Chars.IsDigit(char_i)) {
            continue;
        }
        if (Chars.IsDot(char_i)) {
            if (hasDot) {
                const slice = code.slice(index, i);
                const rest = code.slice(i);
                return [`${dash}${slice}`, rest];
            }
            hasDot = true;
            continue;
        }
        const slice = code.slice(index, i);
        const rest = code.slice(i);
        return [`${dash}${slice}`, rest];
    }
    return [code, ''];
}
/** Scans for the next number token */
// prettier-ignore
export function Number(code) {
    return NextNumber(Trim.TrimAll(code));
}
// ------------------------------------------------------------------
// String
// ------------------------------------------------------------------
// prettier-ignore
function NextString(options, code) {
    const first = code.charAt(0);
    if (!options.includes(first))
        return [];
    const quote = first;
    for (let i = 1; i < code.length; i++) {
        const char = code.charAt(i);
        if (char === quote) {
            const slice = code.slice(1, i);
            const rest = code.slice(i + 1);
            return [slice, rest];
        }
    }
    return [];
}
/** Scans the next Literal String value */
// prettier-ignore
export function String(options, code) {
    return NextString(options, Trim.TrimAll(code));
}
