1 {-# LANGUAGE AllowAmbiguousTypes #-}
2 {-# LANGUAGE ConstraintKinds #-}
3 {-# LANGUAGE DeriveFunctor #-}
4 {-# LANGUAGE OverloadedStrings #-}
5 {-# LANGUAGE Rank2Types #-}
6 {-# LANGUAGE StrictData #-}
7 {-# LANGUAGE UndecidableInstances #-}
8 {-# OPTIONS_GHC -fno-warn-orphans #-}
9 module Symantic.XML.Tree.Source where
11 import Control.Applicative (Applicative(..))
13 import Data.Eq (Eq(..))
14 import Data.Function (($), (.), const)
15 import Data.Functor (Functor)
16 import Data.Functor.Identity (Identity(..))
17 import Data.Monoid (Monoid(..))
18 import Data.Ord (Ord(..))
19 import Data.Semigroup (Semigroup(..))
20 import Data.List.NonEmpty (NonEmpty(..))
21 import Prelude (Num(..), Int)
22 import System.IO (FilePath)
23 import Text.Show (Show(..), shows, showChar, showParen, showString)
25 -- * Type family 'Source'
26 type family Source (src :: * -> *) :: *
27 type instance Source (Sourced src) = src
28 type instance Source Identity = ()
31 class NoSource src where
32 noSource :: a -> src a
33 nullSource :: Source src -> Bool
38 nullSource = (==) (sourceOf @src (noSource @src ()))
39 instance NoSource Identity where
41 nullSource = const True
44 class UnSource src where
45 unSource :: src a -> a
46 instance UnSource Identity where
47 unSource = runIdentity
50 class SourceOf src where
51 sourceOf :: src a -> Source src
52 instance SourceOf Identity where
55 -- * Type 'FileSource'
56 newtype FileSource pos
57 = FileSource (NonEmpty (FileRange pos))
59 instance Show (FileRange pos) => Show (FileSource pos) where
60 showsPrec _p (FileSource (s:|[])) = shows s
61 showsPrec _p (FileSource (s:|s1:ss)) =
62 shows s . showString "\n in " .
63 shows (FileSource (s1:|ss))
65 -- ** Type 'FileSourced'
66 type FileSourced = Sourced (FileSource Offset)
68 -- ** Type 'FileRange'
71 { fileRange_path :: FilePath
72 , fileRange_begin :: pos
73 , fileRange_end :: pos
75 instance Show (FileRange Offset) where
76 showsPrec _p FileRange{..} =
77 showString fileRange_path . showString " at char position " .
78 showsPrec 10 fileRange_begin . showString " to " .
79 showsPrec 10 fileRange_end
80 instance Show (FileRange LineColumn) where
81 showsPrec _p FileRange{..} =
82 showString fileRange_path . showString " at line:column position " .
83 showsPrec 10 fileRange_begin . showString " to " .
84 showsPrec 10 fileRange_end
87 newtype Offset = Offset Int
89 instance Show Offset where
90 showsPrec p (Offset o) = showsPrec p o
91 instance Semigroup Offset where
92 Offset x <> Offset y = Offset (x+y)
93 instance Monoid Offset where
97 -- *** Type 'LineColumn'
98 -- | Absolute text file position.
99 data LineColumn = LineColumn
100 { lineNum :: {-# UNPACK #-} Offset
101 , colNum :: {-# UNPACK #-} Offset
103 instance Show LineColumn where
104 showsPrec _p LineColumn{..} =
105 showsPrec 11 lineNum .
115 instance UnSource (Sourced src) where
117 instance NoSource (Sourced (FileSource Offset)) where
118 noSource = Sourced $ FileSource $ pure $ FileRange mempty mempty mempty
119 instance SourceOf (Sourced src) where
120 sourceOf (Sourced src _a) = src
122 instance Eq a => Eq (Sourced src a) where
123 x == y = unSourced x == unSourced y
125 instance Ord a => Ord (Sourced src a) where
126 x `compare` y = unSourced x `compare` unSourced y
128 (Show src, Show a, NoSource (Sourced src)) =>
129 Show (Sourced src a) where
130 showsPrec p (Sourced src a)
131 | nullSource @(Sourced src) src = showsPrec p a
135 showString " in " . showsPrec 10 src
136 instance Semigroup a => Semigroup (Sourced (FileSource Offset) a) where
138 (Sourced rx@(FileSource (FileRange xf xb xe :| xs)) x)
139 (Sourced (FileSource (FileRange yf yb ye :| _ys)) y)
140 | xf == yf && xe == yb =
141 Sourced (FileSource (FileRange xf xb ye :| xs)) $ x<>y
142 | otherwise = Sourced rx (x<>y)