packages feed

smirk-0.1.0.0: src/Smirk/Core/AST.hs

{-# LANGUAGE DeriveGeneric #-}

{- |
Module      : Smirk.Core.AST
Description : Abstract Syntax Tree representation of PCRE regular expressions
Copyright   : (c) Nadia Yvette Chambers, 2026
License     : Apache-2.0

Defines the typed Abstract Syntax Tree (AST) for PCRE regular expressions,
supporting literals, character classes, anchors, sequences, alternations,
bounded repetitions with greediness controls, named/numbered capture groups,
and lookaround assertions.
-}
module Smirk.Core.AST
  ( AST (..)
  , CharClass (..)
  , CharRange (..)
  , Anchor (..)
  , RepKind (..)
  , LookDir (..)
  , Flags (..)
  , defaultFlags
  ) where

import Data.Text (Text)
import GHC.Generics (Generic)

-- | Regex compilation and matching flags controlling parser and VM semantics.
data Flags = Flags
  { caseInsensitive :: !Bool -- ^ (?i) Case-insensitive character matching
  , dotAll          :: !Bool -- ^ (?s) Dot matches newline characters as well
  , multiline       :: !Bool -- ^ (?m) ^ and $ match at beginning and end of each line
  } deriving (Eq, Show, Generic)

-- | Default flags (standard PCRE mode: case-sensitive, no dotAll, no multiline).
defaultFlags :: Flags
defaultFlags = Flags
  { caseInsensitive = False
  , dotAll          = False
  , multiline       = False
  }

-- | Character range within a character set ([a-z], [0-9]).
data CharRange
  = RangeSingle !Char          -- ^ Single character: @a@
  | RangeBetween !Char !Char   -- ^ Inclusive character range: @a@ to @z@
  deriving (Eq, Show, Generic)

-- | Character classes and custom character sets.
data CharClass
  = ClassAny                      -- ^ @.@ (any character, subject to dotAll)
  | ClassDigit                    -- ^ @\\d@ (ASCII or Unicode decimal digit)
  | ClassNotDigit                 -- ^ @\\D@ (any character that is not a digit)
  | ClassWord                     -- ^ @\\w@ (word character: alphanumeric plus underscore)
  | ClassNotWord                  -- ^ @\\W@ (non-word character)
  | ClassSpace                    -- ^ @\\s@ (whitespace character)
  | ClassNotSpace                 -- ^ @\\S@ (non-whitespace character)
  | ClassSet ![CharRange] !Bool   -- ^ @[a-z0-9]@ or negated @[^a-z]@ (negated when True)
  deriving (Eq, Show, Generic)

-- | Position and boundary assertions that do not consume characters.
data Anchor
  = AnchorStart                   -- ^ @^@ (start of input or start of line in multiline mode)
  | AnchorEnd                     -- ^ @$@ (end of input or end of line in multiline mode)
  | AnchorWordBoundary            -- ^ @\\b@ (word boundary transition)
  | AnchorNotWordBoundary         -- ^ @\\B@ (non-word boundary transition)
  deriving (Eq, Show, Generic)

-- | Repetition greediness and backtracking strategy.
data RepKind
  = RepGreedy                     -- ^ Standard greedy repetition (match as much as possible)
  | RepLazy                       -- ^ Non-greedy / reluctant repetition (match as little as possible)
  | RepPossessive                 -- ^ Possessive repetition (do not backtrack over matched elements)
  deriving (Eq, Show, Generic)

-- | Lookaround assertion direction.
data LookDir
  = Lookahead                     -- ^ Lookahead assertion: inspecting suffix after current position
  | Lookbehind                    -- ^ Lookbehind assertion: inspecting prefix before current position
  deriving (Eq, Show, Generic)

-- | Typed PCRE Abstract Syntax Tree nodes.
data AST
  = Lit !Char                                    -- ^ Exact literal character match
  | Class !CharClass                             -- ^ Character class or set match
  | AnchorAssert !Anchor                         -- ^ Zero-width boundary anchor assertion
  | Seq ![AST]                                   -- ^ Sequential concatenation of sub-expressions
  | Alt ![AST]                                   -- ^ Ordered alternation between sub-expressions
  | Repeat !Int !(Maybe Int) !RepKind !AST       -- ^ Repetition with min count, optional max count, greediness kind, and child AST
  | Group !(Maybe Text) !(Maybe Int) !AST        -- ^ Capturing group with optional name, 1-based index, and inner AST
  | NonCapturing !AST                            -- ^ Non-capturing group: @(?:...)@
  | Lookaround !LookDir !Bool !AST               -- ^ Zero-width lookaround assertion: direction, positive/negative, and inner AST
  | BackRef !Int                                 -- ^ Numbered backreference: @\\1@
  | NamedBackRef !Text                           -- ^ Named backreference: @\\k<name>@
  | Empty                                        -- ^ Empty / epsilon AST node
  deriving (Eq, Show, Generic)