packages feed

cgrep-9.0.0: src/CGrep/Parser/Char.hs

--
-- Copyright (c) 2013-2025 Nicola Bonelli <nicola@larthia.com>
--
-- This program is free software; you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation; either version 2 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program; if not, write to the Free Software
-- Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
--
{-# LANGUAGE OverloadedStrings #-}

module CGrep.Parser.Char (
    chr,
    ord,
    isDigit,
    isSpace,
    isHexDigit,
    isCharNumber,
    isAlphaNum,
    isAlpha,
    isAlphaNum_,
    isAlpha_,
    isAlpha_',
    isAlphaNum_',
    isAlphaDollar_,
    isAlphaNumDollar_,
    isUnicode_,
    isUnicodeNum_,
    isUnicodeDollar_,
    isUnicodeNumDollar_,
    isUnicodeNum_',
    isUnicodeXIDStart_,
    isUnicodeNumXIDCont_,
    isBracket',
    isPunctuation,
    isClojureIdentStart,
    isClojureIdentCont,
    isAlphaDash_,
    isAlphaNumDash_,
    isCSharpIdentStart,
    isCSharpIdentCont,
    isHtmlIdentStart,
    isHtmlIdentCont,
    isJavaIdentStart,
    isJavaIdentCont,
    isJuliaIdentStart,
    isJuliaIdentCont,
    isLispIdent,
    isAgdaIdent,
) where

import Data.Char (GeneralCategory (..), generalCategory, isLetter)
import GHC.Base (chr#, int2Word#, isTrue#, leWord#)
import GHC.Exts (Char (C#), Int (I#), ord#)
import GHC.Unicode (isAsciiLower)

ord :: Char -> Int
ord (C# c#) = I# (ord# c#)
{-# INLINE ord #-}

chr :: Int -> Char
chr i@(I# i#)
    | isTrue# (int2Word# i# `leWord#` 0x10FFFF##) = C# (chr# i#)
    | otherwise =
        errorWithoutStackTrace ("CGrep: chr bad argument: " <> show i)
{-# INLINE chr #-}

isBracket' :: Char -> Bool
isBracket' c = c `elem` ("[]{}()" :: String)
{-# INLINE isBracket' #-}

isPunctuation :: Char -> Bool
isPunctuation c = c `elem` (";,." :: String)
{-# INLINE isPunctuation #-}

isDigit :: Char -> Bool
isDigit c = (fromIntegral (ord c - ord '0') :: Word) <= 9
{-# INLINE isDigit #-}

isSpace :: Char -> Bool
isSpace c = uc == 32 || uc == 0xa0 || (uc - 0x9 <= 4) && not ctrl
  where
    uc = ord c
    ctrl = uc == 2 || uc == 3
{-# INLINE isSpace #-}

isHexDigit :: Char -> Bool
isHexDigit c =
    isDigit c
        || (fromIntegral (ord c - ord 'A') :: Word) <= 5
        || (fromIntegral (ord c - ord 'a') :: Word) <= 5
{-# INLINE isHexDigit #-}

isCharNumber :: Char -> Bool
isCharNumber c = isHexDigit c || c `elem` (".xX" :: String)
{-# INLINE isCharNumber #-}

isAlphaNum :: Char -> Bool
isAlphaNum c =
    o >= 97 && o <= 122
        || o >= 65 && o <= 90
        || o >= 48 && o <= 57
  where
    o = ord c
{-# INLINE isAlphaNum #-}

isAlpha :: Char -> Bool
isAlpha c =
    o >= 97 && o <= 122
        || o >= 65 && o <= 90
  where
    o = ord c
{-# INLINE isAlpha #-}

isAlphaNum_ :: Char -> Bool
isAlphaNum_ c =
    o >= 97 && o <= 122
        || o >= 65 && o <= 90
        || o >= 48 && o <= 57
        || c == '_'
  where
    o = ord c
{-# INLINE isAlphaNum_ #-}

isAlphaNumDash_ :: Char -> Bool
isAlphaNumDash_ c =
    o >= 97 && o <= 122
        || o >= 65 && o <= 90
        || o >= 48 && o <= 57
        || c == '_'
        || c == '-'
  where
    o = ord c
{-# INLINE isAlphaNumDash_ #-}

isAlpha_ :: Char -> Bool
isAlpha_ c =
    o >= 97 && o <= 122
        || o >= 65 && o <= 90
        || c == '_'
  where
    o = ord c
{-# INLINE isAlpha_ #-}

isAlphaDash_ :: Char -> Bool
isAlphaDash_ c =
    o >= 97 && o <= 122
        || o >= 65 && o <= 90
        || c == '_'
        || c == '-'
  where
    o = ord c
{-# INLINE isAlphaDash_ #-}

isAlpha_' :: Char -> Bool
isAlpha_' c = isAlpha_ c || c == '_' || c == '\''
{-# INLINE isAlpha_' #-}

isAlphaNum_' :: Char -> Bool
isAlphaNum_' c = isAlphaNum_ c || c == '_' || c == '\''
{-# INLINE isAlphaNum_' #-}

isAlphaDollar_ :: Char -> Bool
isAlphaDollar_ c = isAlphaNum_ c || c == '$'
{-# INLINE isAlphaDollar_ #-}

isAlphaNumDollar_ :: Char -> Bool
isAlphaNumDollar_ c = isAlphaNum_ c || c == '_' || c == '$'
{-# INLINE isAlphaNumDollar_ #-}

isClojureIdentStart :: Char -> Bool
isClojureIdentStart c
    | isSpace c = False
    | isClojureDelimiter c = False
    | isDigit c = False
    | c `elem` ("#:" :: String) = False
    | otherwise = True
  where
    isClojureDelimiter x = x `elem` ("()[]{}@;~`'\"\\" :: String)
{-# INLINE isClojureIdentStart #-}

isClojureIdentCont :: Char -> Bool
isClojureIdentCont c = isClojureIdentStart c || isDigit c
{-# INLINE isClojureIdentCont #-}

isCSharpIdentStart :: Char -> Bool
isCSharpIdentStart c =
    case generalCategory c of
        UppercaseLetter -> True -- Lu
        LowercaseLetter -> True -- Ll
        TitlecaseLetter -> True -- Lt
        ModifierLetter -> True -- Lm
        OtherLetter -> True -- Lo
        LetterNumber -> True -- Nl
        _ -> c == '_' -- underscore permesso
{-# INLINE isCSharpIdentStart #-}

isCSharpIdentCont :: Char -> Bool
isCSharpIdentCont c =
    case generalCategory c of
        UppercaseLetter -> True -- Lu
        LowercaseLetter -> True -- Ll
        TitlecaseLetter -> True -- Lt
        ModifierLetter -> True -- Lm
        OtherLetter -> True -- Lo
        LetterNumber -> True -- Nl
        DecimalNumber -> True -- Nd
        ConnectorPunctuation -> True -- Pc (include _)
        NonSpacingMark -> True -- Mn
        SpacingCombiningMark -> True -- Mc
        Format -> True -- Cf
        _ -> False
{-# INLINE isCSharpIdentCont #-}

isHtmlIdentStart :: Char -> Bool
isHtmlIdentStart = isAlpha
{-# INLINE isHtmlIdentStart #-}

isHtmlIdentCont :: Char -> Bool
isHtmlIdentCont c = isAlphaNum c || c == '_' || c == '-' || c == '.' || c == ':'
{-# INLINE isHtmlIdentCont #-}

isJavaIdentStart :: Char -> Bool
isJavaIdentStart c = c == '_' || c == '$' || isLetter c
{-# INLINE isJavaIdentStart #-}

isJavaIdentCont :: Char -> Bool
isJavaIdentCont c = c == '_' || c == '$' || isLetter c || isDigit c
{-# INLINE isJavaIdentCont #-}

isJuliaIdentStart :: Char -> Bool
isJuliaIdentStart c = c == '_' || isLetter c
{-# INLINE isJuliaIdentStart #-}

isJuliaIdentCont :: Char -> Bool
isJuliaIdentCont c = c == '_' || c == '!' || c == '?' || isLetter c || isDigit c
{-# INLINE isJuliaIdentCont #-}

isUnicode_ :: Char -> Bool
isUnicode_ c = c == '_' || isLetter c
{-# INLINE isUnicode_ #-}

isUnicodeNum_ :: Char -> Bool
isUnicodeNum_ c = c == '_' || isLetter c || isDigit c
{-# INLINE isUnicodeNum_ #-}

isUnicodeDollar_ :: Char -> Bool
isUnicodeDollar_ c = c == '_' || c == '\'' || isLetter c || isDigit c
{-# INLINE isUnicodeDollar_ #-}

isUnicodeNumDollar_ :: Char -> Bool
isUnicodeNumDollar_ c = c == '_' || c == '$' || isLetter c || isDigit c
{-# INLINE isUnicodeNumDollar_ #-}

isUnicodeNum_' :: Char -> Bool
isUnicodeNum_' c = c == '_' || c == '\'' || isLetter c || isDigit c
{-# INLINE isUnicodeNum_' #-}

isLispIdent :: Char -> Bool
isLispIdent c =
    isAsciiLower c
        || isDigit c
        || c `elem` ("-+*/@$%^&_=<>~!?[]{}" :: String)

isUnicodeXIDStart_ :: Char -> Bool
isUnicodeXIDStart_ x = x == '_' || isXIDStart x
  where
    isXIDStart c = case generalCategory c of
        UppercaseLetter -> True
        LowercaseLetter -> True
        TitlecaseLetter -> True
        ModifierLetter -> True
        OtherLetter -> True
        LetterNumber -> True
        _ -> False
{-# INLINE isUnicodeXIDStart_ #-}

isUnicodeNumXIDCont_ :: Char -> Bool
isUnicodeNumXIDCont_ c = c == '_' || isXIDContinue c
  where
    isXIDContinue x = case generalCategory x of
        UppercaseLetter -> True
        LowercaseLetter -> True
        TitlecaseLetter -> True
        ModifierLetter -> True
        OtherLetter -> True
        LetterNumber -> True
        DecimalNumber -> True
        NonSpacingMark -> True
        SpacingCombiningMark -> True
        ConnectorPunctuation -> True
        _ -> False
{-# INLINE isUnicodeNumXIDCont_ #-}

isAgdaIdent :: Char -> Bool
isAgdaIdent c = not (c `elem` ("@.(){};_" :: String))
{-# INLINE isAgdaIdent #-}