Expanded abbreviations in Haddock documentation
[ghc.git] / compiler / basicTypes / SrcLoc.hs
1 -- (c) The University of Glasgow, 1992-2006
2
3 {-# LANGUAGE DeriveDataTypeable #-}
4 {-# LANGUAGE StandaloneDeriving #-}
5 {-# LANGUAGE DeriveFunctor #-}
6 {-# LANGUAGE DeriveFoldable #-}
7 {-# LANGUAGE DeriveTraversable #-}
8 {-# LANGUAGE FlexibleInstances #-}
9 {-# OPTIONS_GHC -fno-omit-interface-pragmas #-}
10 -- Workaround for Trac #5252 crashes the bootstrap compiler without -O
11 -- When the earliest compiler we want to boostrap with is
12 -- GHC 7.2, we can make RealSrcLoc properly abstract
13
14 -- | This module contains types that relate to the positions of things
15 -- in source files, and allow tagging of those things with locations
16 module SrcLoc (
17 -- * SrcLoc
18 RealSrcLoc, -- Abstract
19 SrcLoc(..),
20
21 -- ** Constructing SrcLoc
22 mkSrcLoc, mkRealSrcLoc, mkGeneralSrcLoc,
23
24 noSrcLoc, -- "I'm sorry, I haven't a clue"
25 generatedSrcLoc, -- Code generated within the compiler
26 interactiveSrcLoc, -- Code from an interactive session
27
28 advanceSrcLoc,
29
30 -- ** Unsafely deconstructing SrcLoc
31 -- These are dubious exports, because they crash on some inputs
32 srcLocFile, -- return the file name part
33 srcLocLine, -- return the line part
34 srcLocCol, -- return the column part
35
36 -- * SrcSpan
37 RealSrcSpan, -- Abstract
38 SrcSpan(..),
39
40 -- ** Constructing SrcSpan
41 mkGeneralSrcSpan, mkSrcSpan, mkRealSrcSpan,
42 noSrcSpan,
43 wiredInSrcSpan, -- Something wired into the compiler
44 interactiveSrcSpan,
45 srcLocSpan, realSrcLocSpan,
46 combineSrcSpans,
47 srcSpanFirstCharacter,
48
49 -- ** Deconstructing SrcSpan
50 srcSpanStart, srcSpanEnd,
51 realSrcSpanStart, realSrcSpanEnd,
52 srcSpanFileName_maybe,
53 pprUserRealSpan,
54
55 -- ** Unsafely deconstructing SrcSpan
56 -- These are dubious exports, because they crash on some inputs
57 srcSpanFile,
58 srcSpanStartLine, srcSpanEndLine,
59 srcSpanStartCol, srcSpanEndCol,
60
61 -- ** Predicates on SrcSpan
62 isGoodSrcSpan, isOneLineSpan,
63 containsSpan,
64
65 -- * Located
66 Located,
67 RealLocated,
68 GenLocated(..),
69
70 -- ** Constructing Located
71 noLoc,
72 mkGeneralLocated,
73
74 -- ** Deconstructing Located
75 getLoc, unLoc,
76
77 -- ** Combining and comparing Located values
78 eqLocated, cmpLocated, combineLocs, addCLoc,
79 leftmost_smallest, leftmost_largest, rightmost,
80 spans, isSubspanOf, sortLocated
81 ) where
82
83 import Util
84 import Outputable
85 import FastString
86
87 import Control.DeepSeq
88 import Data.Bits
89 import Data.Data
90 import Data.List
91 import Data.Ord
92
93 {-
94 ************************************************************************
95 * *
96 \subsection[SrcLoc-SrcLocations]{Source-location information}
97 * *
98 ************************************************************************
99
100 We keep information about the {\em definition} point for each entity;
101 this is the obvious stuff:
102 -}
103
104 -- | Real Source Location
105 --
106 -- Represents a single point within a file
107 data RealSrcLoc
108 = SrcLoc FastString -- A precise location (file name)
109 {-# UNPACK #-} !Int -- line number, begins at 1
110 {-# UNPACK #-} !Int -- column number, begins at 1
111 deriving (Eq, Ord)
112
113 -- | Source Location
114 data SrcLoc
115 = RealSrcLoc {-# UNPACK #-}!RealSrcLoc
116 | UnhelpfulLoc FastString -- Just a general indication
117 deriving (Eq, Ord, Show)
118
119 {-
120 ************************************************************************
121 * *
122 \subsection[SrcLoc-access-fns]{Access functions}
123 * *
124 ************************************************************************
125 -}
126
127 mkSrcLoc :: FastString -> Int -> Int -> SrcLoc
128 mkSrcLoc x line col = RealSrcLoc (mkRealSrcLoc x line col)
129
130 mkRealSrcLoc :: FastString -> Int -> Int -> RealSrcLoc
131 mkRealSrcLoc x line col = SrcLoc x line col
132
133 -- | Built-in "bad" 'SrcLoc' values for particular locations
134 noSrcLoc, generatedSrcLoc, interactiveSrcLoc :: SrcLoc
135 noSrcLoc = UnhelpfulLoc (fsLit "<no location info>")
136 generatedSrcLoc = UnhelpfulLoc (fsLit "<compiler-generated code>")
137 interactiveSrcLoc = UnhelpfulLoc (fsLit "<interactive>")
138
139 -- | Creates a "bad" 'SrcLoc' that has no detailed information about its location
140 mkGeneralSrcLoc :: FastString -> SrcLoc
141 mkGeneralSrcLoc = UnhelpfulLoc
142
143 -- | Gives the filename of the 'RealSrcLoc'
144 srcLocFile :: RealSrcLoc -> FastString
145 srcLocFile (SrcLoc fname _ _) = fname
146
147 -- | Raises an error when used on a "bad" 'SrcLoc'
148 srcLocLine :: RealSrcLoc -> Int
149 srcLocLine (SrcLoc _ l _) = l
150
151 -- | Raises an error when used on a "bad" 'SrcLoc'
152 srcLocCol :: RealSrcLoc -> Int
153 srcLocCol (SrcLoc _ _ c) = c
154
155 -- | Move the 'SrcLoc' down by one line if the character is a newline,
156 -- to the next 8-char tabstop if it is a tab, and across by one
157 -- character in any other case
158 advanceSrcLoc :: RealSrcLoc -> Char -> RealSrcLoc
159 advanceSrcLoc (SrcLoc f l _) '\n' = SrcLoc f (l + 1) 1
160 advanceSrcLoc (SrcLoc f l c) '\t' = SrcLoc f l (((((c - 1) `shiftR` 3) + 1)
161 `shiftL` 3) + 1)
162 advanceSrcLoc (SrcLoc f l c) _ = SrcLoc f l (c + 1)
163
164 {-
165 ************************************************************************
166 * *
167 \subsection[SrcLoc-instances]{Instance declarations for various names}
168 * *
169 ************************************************************************
170 -}
171
172 sortLocated :: [Located a] -> [Located a]
173 sortLocated things = sortBy (comparing getLoc) things
174
175 instance Outputable RealSrcLoc where
176 ppr (SrcLoc src_path src_line src_col)
177 = hcat [ pprFastFilePath src_path <> colon
178 , int src_line <> colon
179 , int src_col ]
180
181 -- I don't know why there is this style-based difference
182 -- if userStyle sty || debugStyle sty then
183 -- hcat [ pprFastFilePath src_path, char ':',
184 -- int src_line,
185 -- char ':', int src_col
186 -- ]
187 -- else
188 -- hcat [text "{-# LINE ", int src_line, space,
189 -- char '\"', pprFastFilePath src_path, text " #-}"]
190
191 instance Outputable SrcLoc where
192 ppr (RealSrcLoc l) = ppr l
193 ppr (UnhelpfulLoc s) = ftext s
194
195 instance Data RealSrcSpan where
196 -- don't traverse?
197 toConstr _ = abstractConstr "RealSrcSpan"
198 gunfold _ _ = error "gunfold"
199 dataTypeOf _ = mkNoRepType "RealSrcSpan"
200
201 instance Data SrcSpan where
202 -- don't traverse?
203 toConstr _ = abstractConstr "SrcSpan"
204 gunfold _ _ = error "gunfold"
205 dataTypeOf _ = mkNoRepType "SrcSpan"
206
207 {-
208 ************************************************************************
209 * *
210 \subsection[SrcSpan]{Source Spans}
211 * *
212 ************************************************************************
213 -}
214
215 {- |
216 A 'RealSrcSpan' delimits a portion of a text file. It could be represented
217 by a pair of (line,column) coordinates, but in fact we optimise
218 slightly by using more compact representations for single-line and
219 zero-length spans, both of which are quite common.
220
221 The end position is defined to be the column /after/ the end of the
222 span. That is, a span of (1,1)-(1,2) is one character long, and a
223 span of (1,1)-(1,1) is zero characters long.
224 -}
225
226 -- | Real Source Span
227 data RealSrcSpan
228 = RealSrcSpan'
229 { srcSpanFile :: !FastString,
230 srcSpanSLine :: {-# UNPACK #-} !Int,
231 srcSpanSCol :: {-# UNPACK #-} !Int,
232 srcSpanELine :: {-# UNPACK #-} !Int,
233 srcSpanECol :: {-# UNPACK #-} !Int
234 }
235 deriving Eq
236
237 -- | Source Span
238 --
239 -- A 'SrcSpan' identifies either a specific portion of a text file
240 -- or a human-readable description of a location.
241 data SrcSpan =
242 RealSrcSpan !RealSrcSpan
243 | UnhelpfulSpan !FastString -- Just a general indication
244 -- also used to indicate an empty span
245
246 deriving (Eq, Ord, Show) -- Show is used by Lexer.x, because we
247 -- derive Show for Token
248
249 instance NFData SrcSpan where
250 rnf x = x `seq` ()
251
252 -- | Built-in "bad" 'SrcSpan's for common sources of location uncertainty
253 noSrcSpan, wiredInSrcSpan, interactiveSrcSpan :: SrcSpan
254 noSrcSpan = UnhelpfulSpan (fsLit "<no location info>")
255 wiredInSrcSpan = UnhelpfulSpan (fsLit "<wired into compiler>")
256 interactiveSrcSpan = UnhelpfulSpan (fsLit "<interactive>")
257
258 -- | Create a "bad" 'SrcSpan' that has not location information
259 mkGeneralSrcSpan :: FastString -> SrcSpan
260 mkGeneralSrcSpan = UnhelpfulSpan
261
262 -- | Create a 'SrcSpan' corresponding to a single point
263 srcLocSpan :: SrcLoc -> SrcSpan
264 srcLocSpan (UnhelpfulLoc str) = UnhelpfulSpan str
265 srcLocSpan (RealSrcLoc l) = RealSrcSpan (realSrcLocSpan l)
266
267 realSrcLocSpan :: RealSrcLoc -> RealSrcSpan
268 realSrcLocSpan (SrcLoc file line col) = RealSrcSpan' file line col line col
269
270 -- | Create a 'SrcSpan' between two points in a file
271 mkRealSrcSpan :: RealSrcLoc -> RealSrcLoc -> RealSrcSpan
272 mkRealSrcSpan loc1 loc2 = RealSrcSpan' file line1 col1 line2 col2
273 where
274 line1 = srcLocLine loc1
275 line2 = srcLocLine loc2
276 col1 = srcLocCol loc1
277 col2 = srcLocCol loc2
278 file = srcLocFile loc1
279
280 -- | 'True' if the span is known to straddle only one line.
281 isOneLineRealSpan :: RealSrcSpan -> Bool
282 isOneLineRealSpan (RealSrcSpan' _ line1 _ line2 _)
283 = line1 == line2
284
285 -- | 'True' if the span is a single point
286 isPointRealSpan :: RealSrcSpan -> Bool
287 isPointRealSpan (RealSrcSpan' _ line1 col1 line2 col2)
288 = line1 == line2 && col1 == col2
289
290 -- | Create a 'SrcSpan' between two points in a file
291 mkSrcSpan :: SrcLoc -> SrcLoc -> SrcSpan
292 mkSrcSpan (UnhelpfulLoc str) _ = UnhelpfulSpan str
293 mkSrcSpan _ (UnhelpfulLoc str) = UnhelpfulSpan str
294 mkSrcSpan (RealSrcLoc loc1) (RealSrcLoc loc2)
295 = RealSrcSpan (mkRealSrcSpan loc1 loc2)
296
297 -- | Combines two 'SrcSpan' into one that spans at least all the characters
298 -- within both spans. Assumes the "file" part is the same in both inputs
299 combineSrcSpans :: SrcSpan -> SrcSpan -> SrcSpan
300 combineSrcSpans (UnhelpfulSpan _) r = r -- this seems more useful
301 combineSrcSpans l (UnhelpfulSpan _) = l
302 combineSrcSpans (RealSrcSpan span1) (RealSrcSpan span2)
303 = RealSrcSpan (combineRealSrcSpans span1 span2)
304
305 -- | Combines two 'SrcSpan' into one that spans at least all the characters
306 -- within both spans. Assumes the "file" part is the same in both inputs
307 combineRealSrcSpans :: RealSrcSpan -> RealSrcSpan -> RealSrcSpan
308 combineRealSrcSpans span1 span2
309 = RealSrcSpan' file line_start col_start line_end col_end
310 where
311 (line_start, col_start) = min (srcSpanStartLine span1, srcSpanStartCol span1)
312 (srcSpanStartLine span2, srcSpanStartCol span2)
313 (line_end, col_end) = max (srcSpanEndLine span1, srcSpanEndCol span1)
314 (srcSpanEndLine span2, srcSpanEndCol span2)
315 file = srcSpanFile span1
316
317 -- | Convert a SrcSpan into one that represents only its first character
318 srcSpanFirstCharacter :: SrcSpan -> SrcSpan
319 srcSpanFirstCharacter l@(UnhelpfulSpan {}) = l
320 srcSpanFirstCharacter (RealSrcSpan span) = RealSrcSpan $ mkRealSrcSpan loc1 loc2
321 where
322 loc1@(SrcLoc f l c) = realSrcSpanStart span
323 loc2 = SrcLoc f l (c+1)
324 {-
325 ************************************************************************
326 * *
327 \subsection[SrcSpan-predicates]{Predicates}
328 * *
329 ************************************************************************
330 -}
331
332 -- | Test if a 'SrcSpan' is "good", i.e. has precise location information
333 isGoodSrcSpan :: SrcSpan -> Bool
334 isGoodSrcSpan (RealSrcSpan _) = True
335 isGoodSrcSpan (UnhelpfulSpan _) = False
336
337 isOneLineSpan :: SrcSpan -> Bool
338 -- ^ True if the span is known to straddle only one line.
339 -- For "bad" 'SrcSpan', it returns False
340 isOneLineSpan (RealSrcSpan s) = srcSpanStartLine s == srcSpanEndLine s
341 isOneLineSpan (UnhelpfulSpan _) = False
342
343 -- | Tests whether the first span "contains" the other span, meaning
344 -- that it covers at least as much source code. True where spans are equal.
345 containsSpan :: RealSrcSpan -> RealSrcSpan -> Bool
346 containsSpan s1 s2
347 = srcSpanFile s1 == srcSpanFile s2
348 && (srcSpanStartLine s1, srcSpanStartCol s1)
349 <= (srcSpanStartLine s2, srcSpanStartCol s2)
350 && (srcSpanEndLine s1, srcSpanEndCol s1)
351 >= (srcSpanEndLine s2, srcSpanEndCol s2)
352
353 {-
354 %************************************************************************
355 %* *
356 \subsection[SrcSpan-unsafe-access-fns]{Unsafe access functions}
357 * *
358 ************************************************************************
359 -}
360
361 srcSpanStartLine :: RealSrcSpan -> Int
362 srcSpanEndLine :: RealSrcSpan -> Int
363 srcSpanStartCol :: RealSrcSpan -> Int
364 srcSpanEndCol :: RealSrcSpan -> Int
365
366 srcSpanStartLine RealSrcSpan'{ srcSpanSLine=l } = l
367 srcSpanEndLine RealSrcSpan'{ srcSpanELine=l } = l
368 srcSpanStartCol RealSrcSpan'{ srcSpanSCol=l } = l
369 srcSpanEndCol RealSrcSpan'{ srcSpanECol=c } = c
370
371 {-
372 ************************************************************************
373 * *
374 \subsection[SrcSpan-access-fns]{Access functions}
375 * *
376 ************************************************************************
377 -}
378
379 -- | Returns the location at the start of the 'SrcSpan' or a "bad" 'SrcSpan' if that is unavailable
380 srcSpanStart :: SrcSpan -> SrcLoc
381 srcSpanStart (UnhelpfulSpan str) = UnhelpfulLoc str
382 srcSpanStart (RealSrcSpan s) = RealSrcLoc (realSrcSpanStart s)
383
384 -- | Returns the location at the end of the 'SrcSpan' or a "bad" 'SrcSpan' if that is unavailable
385 srcSpanEnd :: SrcSpan -> SrcLoc
386 srcSpanEnd (UnhelpfulSpan str) = UnhelpfulLoc str
387 srcSpanEnd (RealSrcSpan s) = RealSrcLoc (realSrcSpanEnd s)
388
389 realSrcSpanStart :: RealSrcSpan -> RealSrcLoc
390 realSrcSpanStart s = mkRealSrcLoc (srcSpanFile s)
391 (srcSpanStartLine s)
392 (srcSpanStartCol s)
393
394 realSrcSpanEnd :: RealSrcSpan -> RealSrcLoc
395 realSrcSpanEnd s = mkRealSrcLoc (srcSpanFile s)
396 (srcSpanEndLine s)
397 (srcSpanEndCol s)
398
399 -- | Obtains the filename for a 'SrcSpan' if it is "good"
400 srcSpanFileName_maybe :: SrcSpan -> Maybe FastString
401 srcSpanFileName_maybe (RealSrcSpan s) = Just (srcSpanFile s)
402 srcSpanFileName_maybe (UnhelpfulSpan _) = Nothing
403
404 {-
405 ************************************************************************
406 * *
407 \subsection[SrcSpan-instances]{Instances}
408 * *
409 ************************************************************************
410 -}
411
412 -- We want to order RealSrcSpans first by the start point, then by the
413 -- end point.
414 instance Ord RealSrcSpan where
415 a `compare` b =
416 (realSrcSpanStart a `compare` realSrcSpanStart b) `thenCmp`
417 (realSrcSpanEnd a `compare` realSrcSpanEnd b)
418
419 instance Show RealSrcLoc where
420 show (SrcLoc filename row col)
421 = "SrcLoc " ++ show filename ++ " " ++ show row ++ " " ++ show col
422
423 -- Show is used by Lexer.x, because we derive Show for Token
424 instance Show RealSrcSpan where
425 show span@(RealSrcSpan' file sl sc el ec)
426 | isPointRealSpan span
427 = "SrcSpanPoint " ++ show file ++ " " ++ intercalate " " (map show [sl,sc])
428
429 | isOneLineRealSpan span
430 = "SrcSpanOneLine " ++ show file ++ " "
431 ++ intercalate " " (map show [sl,sc,ec])
432
433 | otherwise
434 = "SrcSpanMultiLine " ++ show file ++ " "
435 ++ intercalate " " (map show [sl,sc,el,ec])
436
437
438 instance Outputable RealSrcSpan where
439 ppr span = pprUserRealSpan True span
440
441 -- I don't know why there is this style-based difference
442 -- = getPprStyle $ \ sty ->
443 -- if userStyle sty || debugStyle sty then
444 -- text (showUserRealSpan True span)
445 -- else
446 -- hcat [text "{-# LINE ", int (srcSpanStartLine span), space,
447 -- char '\"', pprFastFilePath $ srcSpanFile span, text " #-}"]
448
449 instance Outputable SrcSpan where
450 ppr span = pprUserSpan True span
451
452 -- I don't know why there is this style-based difference
453 -- = getPprStyle $ \ sty ->
454 -- if userStyle sty || debugStyle sty then
455 -- pprUserSpan True span
456 -- else
457 -- case span of
458 -- UnhelpfulSpan _ -> panic "Outputable UnhelpfulSpan"
459 -- RealSrcSpan s -> ppr s
460
461 pprUserSpan :: Bool -> SrcSpan -> SDoc
462 pprUserSpan _ (UnhelpfulSpan s) = ftext s
463 pprUserSpan show_path (RealSrcSpan s) = pprUserRealSpan show_path s
464
465 pprUserRealSpan :: Bool -> RealSrcSpan -> SDoc
466 pprUserRealSpan show_path span@(RealSrcSpan' src_path line col _ _)
467 | isPointRealSpan span
468 = hcat [ ppWhen show_path (pprFastFilePath src_path <> colon)
469 , int line <> colon
470 , int col ]
471
472 pprUserRealSpan show_path span@(RealSrcSpan' src_path line scol _ ecol)
473 | isOneLineRealSpan span
474 = hcat [ ppWhen show_path (pprFastFilePath src_path <> colon)
475 , int line <> colon
476 , int scol
477 , ppUnless (ecol - scol <= 1) (char '-' <> int (ecol - 1)) ]
478 -- For single-character or point spans, we just
479 -- output the starting column number
480
481 pprUserRealSpan show_path (RealSrcSpan' src_path sline scol eline ecol)
482 = hcat [ ppWhen show_path (pprFastFilePath src_path <> colon)
483 , parens (int sline <> comma <> int scol)
484 , char '-'
485 , parens (int eline <> comma <> int ecol') ]
486 where
487 ecol' = if ecol == 0 then ecol else ecol - 1
488
489 {-
490 ************************************************************************
491 * *
492 \subsection[Located]{Attaching SrcSpans to things}
493 * *
494 ************************************************************************
495 -}
496
497 -- | We attach SrcSpans to lots of things, so let's have a datatype for it.
498 data GenLocated l e = L l e
499 deriving (Eq, Ord, Data, Functor, Foldable, Traversable)
500
501 type Located e = GenLocated SrcSpan e
502 type RealLocated e = GenLocated RealSrcSpan e
503
504 unLoc :: GenLocated l e -> e
505 unLoc (L _ e) = e
506
507 getLoc :: GenLocated l e -> l
508 getLoc (L l _) = l
509
510 noLoc :: e -> Located e
511 noLoc e = L noSrcSpan e
512
513 mkGeneralLocated :: String -> e -> Located e
514 mkGeneralLocated s e = L (mkGeneralSrcSpan (fsLit s)) e
515
516 combineLocs :: Located a -> Located b -> SrcSpan
517 combineLocs a b = combineSrcSpans (getLoc a) (getLoc b)
518
519 -- | Combine locations from two 'Located' things and add them to a third thing
520 addCLoc :: Located a -> Located b -> c -> Located c
521 addCLoc a b c = L (combineSrcSpans (getLoc a) (getLoc b)) c
522
523 -- not clear whether to add a general Eq instance, but this is useful sometimes:
524
525 -- | Tests whether the two located things are equal
526 eqLocated :: Eq a => Located a -> Located a -> Bool
527 eqLocated a b = unLoc a == unLoc b
528
529 -- not clear whether to add a general Ord instance, but this is useful sometimes:
530
531 -- | Tests the ordering of the two located things
532 cmpLocated :: Ord a => Located a -> Located a -> Ordering
533 cmpLocated a b = unLoc a `compare` unLoc b
534
535 instance (Outputable l, Outputable e) => Outputable (GenLocated l e) where
536 ppr (L l e) = -- TODO: We can't do this since Located was refactored into
537 -- GenLocated:
538 -- Print spans without the file name etc
539 -- ifPprDebug (braces (pprUserSpan False l))
540 ifPprDebug (braces (ppr l))
541 $$ ppr e
542
543 {-
544 ************************************************************************
545 * *
546 \subsection{Ordering SrcSpans for InteractiveUI}
547 * *
548 ************************************************************************
549 -}
550
551 -- | Alternative strategies for ordering 'SrcSpan's
552 leftmost_smallest, leftmost_largest, rightmost :: SrcSpan -> SrcSpan -> Ordering
553 rightmost = flip compare
554 leftmost_smallest = compare
555 leftmost_largest a b = (srcSpanStart a `compare` srcSpanStart b)
556 `thenCmp`
557 (srcSpanEnd b `compare` srcSpanEnd a)
558
559 -- | Determines whether a span encloses a given line and column index
560 spans :: SrcSpan -> (Int, Int) -> Bool
561 spans (UnhelpfulSpan _) _ = panic "spans UnhelpfulSpan"
562 spans (RealSrcSpan span) (l,c) = realSrcSpanStart span <= loc && loc <= realSrcSpanEnd span
563 where loc = mkRealSrcLoc (srcSpanFile span) l c
564
565 -- | Determines whether a span is enclosed by another one
566 isSubspanOf :: SrcSpan -- ^ The span that may be enclosed by the other
567 -> SrcSpan -- ^ The span it may be enclosed by
568 -> Bool
569 isSubspanOf src parent
570 | srcSpanFileName_maybe parent /= srcSpanFileName_maybe src = False
571 | otherwise = srcSpanStart parent <= srcSpanStart src &&
572 srcSpanEnd parent >= srcSpanEnd src