1 {-# LANGUAGE DuplicateRecordFields #-}
2 {-# LANGUAGE FlexibleInstances #-}
3 {-# LANGUAGE FlexibleContexts #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 module Hdoc.DTC.Check where
7 -- import Control.Category
8 -- import Data.Char (Char)
9 -- import Data.Monoid (Monoid(..))
10 -- import Data.TreeMap.Strict (TreeMap(..))
11 -- import qualified Data.Char as Char
12 -- import qualified Data.Text.Lazy as TL
13 -- import qualified Data.TreeSeq.Strict as TreeSeq
14 -- import qualified Hjugement as MJ
15 import Control.Applicative (Applicative(..))
16 import Control.Monad (Monad(..))
18 import Data.Default.Class (Default(..))
20 import Data.Foldable (Foldable(..))
21 import Data.Function (($), const, flip)
22 import Data.Functor ((<$>))
23 import Data.IntMap.Strict (IntMap)
24 import Data.Map.Strict (Map)
25 import Data.Maybe (Maybe(..), maybe)
26 import Data.Semigroup (Semigroup(..))
27 import Data.Sequence (Seq)
28 import Data.Traversable (Traversable(..))
29 import Data.TreeSeq.Strict (Tree(..), tree0)
30 import Data.Tuple (snd)
31 import Text.Show (Show)
32 import qualified Control.Monad.Trans.State as S
33 import qualified Data.HashMap.Strict as HM
34 import qualified Data.IntMap.Strict as IntMap
35 import qualified Data.List as List
36 import qualified Data.Map.Strict as Map
37 import qualified Data.Sequence as Seq
38 import qualified Data.Strict.Maybe as Strict
39 import qualified Data.TreeMap.Strict as TreeMap
40 import qualified Prelude (error)
42 import Hdoc.DTC.Document
44 import Hdoc.DTC.Collect
45 import qualified Hdoc.TCT.Cell as TCT
46 import qualified Hdoc.XML as XML
50 { state_section :: Maybe Section -- RO
51 , state_irefs :: Irefs
52 , state_rrefs :: HM.HashMap Ident [(Maybe Section, Nat1)]
53 -- , state_refs :: AnchorByIdent
54 , state_notes :: NotesBySection
56 , state_errors :: Errors
57 , state_collect :: All
59 instance Default State where
62 , state_irefs = TreeMap.empty
71 -- ** Type 'AnchorByIdent'
72 type AnchorByIdent = HM.HashMap Ident [Anchor]
75 type Notes = IntMap [Para]
77 -- *** Type 'NotesBySection'
78 type NotesBySection = Map XML.Ancestors Notes
82 { errors_tag_unknown :: HM.HashMap Title (Seq TCT.Location)
83 , errors_tag_ambiguous :: HM.HashMap Title (Seq TCT.Location)
84 , errors_rref_unknown :: HM.HashMap Ident (Seq TCT.Location)
85 , errors_reference_ambiguous :: HM.HashMap Ident (Seq TCT.Location)
87 instance Default Errors where
89 { errors_tag_unknown = def
90 , errors_tag_ambiguous = def
91 , errors_rref_unknown = def
92 , errors_reference_ambiguous = def
97 check :: a -> S.State State a
98 instance Check a => Check (Maybe a) where
99 check = traverse check
100 instance Check Body where
101 check = traverse check
102 instance Check (Tree BodyNode) where
106 BodySection section@Section{..} -> do
107 before@State{state_section} <- S.get
108 S.put before{state_section = Just section}
109 t <- Tree <$> check n <*> check ts
110 S.modify' $ \s -> s{state_section}
112 BodyBlock{} -> tree0 <$> check n
113 instance Check BodyNode where
115 BodySection s -> BodySection <$> check s
116 BodyBlock b -> BodyBlock <$> check b
117 instance Check Section where
122 <*> traverse check judgments
123 instance Check Block where
125 BlockPara p -> BlockPara <$> check p
126 b@BlockBreak{} -> return b
127 b@BlockToC{} -> return b
128 b@BlockToF{} -> return b
129 b@BlockIndex{} -> return b
131 BlockAside xmlPos attrs
132 <$> traverse check blocks
134 BlockFigure xmlPos type_ attrs
136 <*> traverse check paras
137 BlockReferences{..} ->
138 BlockReferences xmlPos attrs
139 <$> traverse check refs
141 BlockJudges xmlPos attrs
142 <$> traverse check jury
144 BlockGrades xmlPos attrs
145 <$> traverse check scale
146 instance Check Para where
148 ParaItem{..} -> ParaItem <$> check item
149 ParaItems{..} -> ParaItems xmlPos attrs <$> traverse check items
150 instance Check ParaItem where
152 ParaPlain plain -> ParaPlain <$> check plain
153 ParaOL items -> ParaOL <$> traverse check items
154 ParaUL items -> ParaUL <$> traverse (traverse check) items
155 ParaQuote{..} -> ParaQuote type_ <$> traverse check paras
156 p@ParaArtwork{} -> return p
157 p@ParaComment{} -> return p
158 ParaJudgment j -> ParaJudgment <$> check j
159 instance Check ListItem where
160 check ListItem{..} = ListItem name <$> traverse check paras
161 instance Check Plain where
162 check = traverse check
163 instance Check (Tree PlainNode) where
164 check (Tree n ts) = do
165 st@State{state_collect=All{..}, ..} <- S.get
168 | not $ null state_irefs
169 , Just words <- pathFromWords term
170 , Strict.Just anchs <- TreeMap.lookup words state_irefs -> do
171 -- NOTE: Insert new anchor for this index ref.
172 let count = case anchs of [] -> def; Anchor{count=c}:_ -> succNat1 c
173 let anch = Anchor{count, section=maybe def (xmlPos::Section -> XML.Pos) state_section}
175 { state_irefs = TreeMap.insert const words (anch:anchs) state_irefs }
176 Tree PlainIref{term, anchor=Just anch}
177 <$> traverse check ts
179 | not $ null state_irefs -> do
180 -- NOTE: Find indexed words in this text.
181 let (irefs,para) = indexifyWords (maybe def (xmlPos::Section -> XML.Pos) state_section) state_irefs (wordify txt)
183 { state_irefs = irefs }
184 return $ Tree PlainGroup para
186 -- NOTE: Insert new note for this section.
187 let section = XML.pos_ancestors $ maybe def (xmlPos::Section -> XML.Pos) state_section
189 { state_note = succNat1 state_note }
190 note' <- traverse check note
191 let noteByNumber = IntMap.singleton (unNat1 state_note) note'
192 State{state_notes=notes} <- S.get
194 { state_notes = Map.insertWith (<>) section noteByNumber notes }
195 Tree PlainNote{number=Just state_note, note=note'}
196 <$> traverse check ts -- NOTE: normally ts is empty anyway
198 let targets = HM.lookupDefault Seq.empty to all_reference
199 case toList targets of
202 HM.insertWith (flip (<>)) to (pure locTCT) $
203 errors_rref_unknown state_errors
205 { state_errors = state_errors
206 { errors_rref_unknown = err }
208 Tree PlainRref{error = Just $ ErrorTarget_Unknown $ Nat1 $ length $ err HM.!to, ..}
209 <$> traverse check ts
211 let rrefs = HM.insertWith
213 let (_sec,num) = List.head old in
214 (state_section, succNat1 num) : old)
215 to [(state_section, Nat1 1)]
218 { state_rrefs = rrefs }
219 Tree PlainRref{error = Nothing, number = Just $ snd $ List.head $ rrefs HM.!to, ..}
220 <$> traverse check ts
222 -- NOTE: ambiguity is checked when checking 'Reference'.
223 Tree PlainRref{error = Just $ ErrorTarget_Ambiguous Nothing, number = Nothing, ..}
224 <$> traverse check ts
225 PlainTag{locTCT} -> do
227 let targets = HM.lookupDefault Seq.empty to all_section
228 case toList targets of
231 HM.insertWith (flip (<>)) to (pure locTCT) $
232 errors_tag_unknown state_errors
234 { state_errors = state_errors
235 { errors_tag_unknown = err }
237 Tree PlainTag{error = Just $ ErrorTarget_Unknown $ Nat1 $ length $ err HM.!to, ..}
238 <$> traverse check ts
240 Tree PlainTag{error = Nothing, ..}
241 <$> traverse check ts
244 HM.insertWith (flip (<>)) to (pure locTCT) $
245 errors_tag_ambiguous state_errors
247 { state_errors = state_errors
248 { errors_tag_ambiguous = err }
250 Tree PlainTag{error = Just $ ErrorTarget_Ambiguous $ Just $ Nat1 $ length $ err HM.!to, ..}
251 <$> traverse check ts
252 _ -> Tree n <$> traverse check ts
253 instance Check Title where
254 check (Title p) = Title <$> check p
255 instance Check About where
258 <$> traverse check titles
260 <*> traverse check authors
261 <*> traverse check editor
262 <*> traverse check date
266 <*> traverse check includes
267 instance Check Entity where
268 check = return -- TODO: to be coded
269 instance Check Date where
270 check = return -- TODO: to be coded
271 instance Check Include where
272 check = return -- TODO: to be coded
273 instance Check Reference where
274 check Reference{..} = do
275 st@State{state_collect=All{..}, ..} <- S.get
276 let targets = HM.lookupDefault Seq.empty id all_reference
277 case toList targets of
278 [] -> Prelude.error "[BUG] check Reference"
280 about' <- check about
281 return $ Reference{error=Nothing, about=about', ..}
284 HM.insertWith (flip (<>)) id (pure locTCT) $
285 errors_reference_ambiguous state_errors
287 { state_errors = state_errors
288 { errors_reference_ambiguous = err }
290 about' <- check about
291 return $ Reference{error=Just $ ErrorAnchor_Ambiguous $ Nat1 $ length $ err HM.!id, about=about', ..}
292 instance Check Judgment where
294 Judgment opinionsByChoice judges grades importance
296 <*> traverse check choices
297 instance Check Choice where
301 <*> traverse check opinions
302 instance Check Opinion where
304 Opinion judge grade importance
306 instance Check Grade where
308 Grade xmlPos name color isDefault
310 instance Check Judge where
314 <*> pure defaultGrades