//! Utility parsing functions
//!
//! This module contains common parsing utilities and helpers.

use nom::{
    branch::alt,
    bytes::complete::tag,
    character::complete::alphanumeric1,
    combinator::{map, not},
    multi::many0,
    sequence::terminated,
    IResult, Parser,
};

/// Parse a keyword, ensuring it's not followed by alphanumeric characters
pub(crate) fn keyword<'a>(word: &'static str) -> impl FnMut(&'a str) -> IResult<&'a str, &'a str> {
    move |input| terminated(tag(word), not(alphanumeric1)).parse(input)
}

/// Parse optional whitespace including newlines
pub(crate) fn ws(input: &str) -> IResult<&str, ()> {
    map(
        many0(alt((tag(" "), tag("\t"), tag("\n"), tag("\r")))),
        |_| (),
    )
    .parse(input)
}

/// Known builtin function names that can be used without parentheses
pub(crate) const BUILTIN_FUNCTIONS: &[&str] = &[
    "length",
    "map",
    "sort",
    "keys",
    "values",
    "add",
    "sum",
    "min",
    "max",
    "count",
    "count_if",
    "avg_if",
    "avg_ifs",
    "least_frequent",
    "mean",
    "avg",
    "median",
    "std",
    "var",
    "first",
    "last",
    "reverse",
    "unique",
    "flatten",
    "transpose",
    "pivot",
    "unpivot",
    "join",
    "inner_join",
    "left_join",
    "right_join",
    "outer_join",
    "concat",
    "contains",
    "startswith",
    "endswith",
    "lstrip",
    "rstrip",
    "tolower",
    "toupper",
    "trim",
    "replace",
    "dos2unix",
    "type",
    "isnan",
    "isinf",
    "isnormal",
    "isfinite",
    "transform_values",
    "map_values",
    "url_set_query_string",
    "month",
    "array_shift",
    "array_unshift",
    "array_push",
    "transliterate",
    "fromjson",
    "tojson",
    "base32_encode",
    "base58_encode",
    "base58_decode",
    "base64_encode",
    "base64_decode",
    "sha512",
    "sha256",
    "url_strip_fragment",
    "abs",
    "to_ascii",
    "is_valid_utf8",
    "to_valid_utf8",
    "snake_case",
    "camel_case",
    "tostring",
    "tonumber",
    "split",
    "join",
    "concat",
    "coalesce",
    "columns",
    "shape",
    "dtypes",
    "group_by",
    "pi",
    "rand",
    "randarray",
    "randbetween",
    "floor",
    "roundup",
    "rounddown",
    "ceil",
    "mround",
    "pow",
    "atan",
    "acos",
    "asin",
    "sin",
    "tan",
    "exp",
    "minute",
    "has",
    "empty",
    "error",
    "sort_by",
    "repeat",
    "zip",
    "md5",
    "sha1",
    "SHA1",
];

/// Keywords that cannot be used as identifiers
pub(crate) const KEYWORDS: &[&str] = &[
    "if", "then", "else", "end", "try", "catch", "and", "or", "not", "del", "true", "false", "null",
];
