packages feed

wireform-proto-0.1.0.0: src/Proto/IDL/AST/Span.hs

{-# LANGUAGE TypeFamilies #-}

{- | Source spans and trees-that-grow phase types for exactprint support.

The AST types in "Proto.IDL.AST" are parameterized by a phase @p@.
Type families map each phase to the appropriate annotation:

* 'Semantic' — no source information, used by codegen and analysis
* 'Parsed' — carries 'Span' for byte-accurate source reconstruction

Backward-compatible type aliases (@MessageDef = MessageDef' Semantic@, etc.)
keep existing consumer code unchanged.
-}
module Proto.IDL.AST.Span (
  -- * Phase types
  Parsed,
  Semantic,

  -- * Source spans
  SrcSpan (..),
  Span (..),
  noSpan,
  mkSpan,

  -- * Extension type families
  XNode,
) where

import Control.DeepSeq (NFData (..))
import GHC.Generics (Generic)


-- | Phase for parsed ASTs that carry source span information.
data Parsed


{- | Phase for semantic ASTs with no source location info.
This is the default used by codegen, analysis, and existing consumer code.
-}
data Semantic


-- | Byte-offset span into the original source text.
data SrcSpan = SrcSpan
  { spanStart :: {-# UNPACK #-} !Int
  -- ^ 0-based byte offset, inclusive
  , spanEnd :: {-# UNPACK #-} !Int
  -- ^ 0-based byte offset, exclusive
  }
  deriving stock (Show, Generic)


instance Eq SrcSpan where _ == _ = True


instance Ord SrcSpan where compare _ _ = EQ


instance NFData SrcSpan


{- | Optional source span, wrapping 'Maybe SrcSpan'.
'Eq' and 'Ord' are phantom (always equal) so derived instances
on AST types remain semantic.
-}
newtype Span = Span {unSpan :: Maybe SrcSpan}
  deriving stock (Show, Generic)


instance Eq Span where _ == _ = True


instance Ord Span where compare _ _ = EQ


instance NFData Span


-- | No source span (for programmatically constructed nodes).
noSpan :: Span
noSpan = Span Nothing


-- | Construct a span from start (inclusive) and end (exclusive) byte offsets.
mkSpan :: Int -> Int -> Span
mkSpan s e = Span (Just (SrcSpan s e))


{- | Extension type family: maps a phase to the node annotation type.

@XNode Parsed = Span@ — parsed nodes carry source spans.
@XNode Semantic = ()@ — semantic nodes carry no extra info.
-}
type family XNode (p :: *)


type instance XNode Parsed = Span


type instance XNode Semantic = ()