0 | module Text.YAML.Lexer
2 | import public Text.Lex.Manual
3 | import Text.YAML.Types
13 | public export %inline
14 | isBreak : Char -> Bool
19 | public export %inline
20 | isWhite : Char -> Bool
27 | isFlowInd : Char -> Bool
28 | isFlowInd ',' = True
29 | isFlowInd '[' = True
30 | isFlowInd ']' = True
31 | isFlowInd '{' = True
32 | isFlowInd '}' = True
37 | isIndicator : Char -> Bool
38 | isIndicator '-' = True
39 | isIndicator '?' = True
40 | isIndicator ':' = True
41 | isIndicator '#' = True
42 | isIndicator '&' = True
43 | isIndicator '*' = True
44 | isIndicator '!' = True
45 | isIndicator '|' = True
46 | isIndicator '>' = True
47 | isIndicator '\'' = True
48 | isIndicator '"' = True
49 | isIndicator '%' = True
50 | isIndicator '@' = True
51 | isIndicator '`' = True
52 | isIndicator c = isFlowInd c
58 | isPlainSafe : (inFlow : Bool) -> Char -> Bool
59 | isPlainSafe inFlow c =
60 | not (isWhite c || isBreak c || isControl c || (inFlow && isFlowInd c))
65 | isPlainFirst : (inFlow : Bool) -> Char -> List Char -> Bool
66 | isPlainFirst inFlow '-' (c :: _) = isPlainSafe inFlow c
67 | isPlainFirst inFlow '?' (c :: _) = isPlainSafe inFlow c
68 | isPlainFirst inFlow ':' (c :: _) = isPlainSafe inFlow c
69 | isPlainFirst inFlow c _ =
70 | not (isIndicator c || isWhite c || isBreak c || isControl c)
79 | wordEnd : List Char -> Bool
81 | wordEnd (c :: _) = isWhite c || isBreak c
85 | data LineKind : Type where
90 | LDocStart : LineKind
112 | record SkipRes (cs : List Char) where
116 | prf : Suffix False rem cs
127 | skipToContent : (cs : List Char) -> SkipRes cs
128 | skipToContent cs = line cs Same
133 | line : (rem : List Char) -> Suffix False rem cs -> SkipRes cs
134 | line ('-' :: '-' :: '-' :: t) p =
136 | then SR (L 0 LDocStart False) ('-' :: '-' :: '-' :: t) p
137 | else indent 0 ('-' :: '-' :: '-' :: t) p
138 | line ('.' :: '.' :: '.' :: t) p =
140 | then SR (L 0 LDocEnd False) ('.' :: '.' :: '.' :: t) p
141 | else indent 0 ('.' :: '.' :: '.' :: t) p
142 | line rem p = indent 0 rem p
145 | indent : Nat -> (rem : List Char) -> Suffix False rem cs -> SkipRes cs
146 | indent n (' ' :: t) p = indent (S n) t (Uncons p)
147 | indent n rem p = white n False rem p
151 | white : Nat -> (tb : Bool) -> (rem : List Char) -> Suffix False rem cs -> SkipRes cs
152 | white n tb ('\t' :: t) p = white n True t (Uncons p)
153 | white n tb (' ' :: t) p = white n tb t (Uncons p)
154 | white n tb ('\n' :: t) p = line t (Uncons p)
155 | white n tb ('#' :: t) p = comment t (Uncons p)
156 | white n tb [] p = SR (L 0 LEnd False) [] p
157 | white n tb rem p = SR (L n LContent tb) rem p
160 | comment : (rem : List Char) -> Suffix False rem cs -> SkipRes cs
161 | comment ('\n' :: t) p = line t (Uncons p)
162 | comment (_ :: t) p = comment t (Uncons p)
163 | comment [] p = SR (L 0 LEnd False) [] p
168 | record Inl (cs : List Char) where
174 | prf : Suffix False rem cs
178 | inlineWhite : (cs : List Char) -> Inl cs
179 | inlineWhite cs = go 0 False cs Same
182 | go : Nat -> Bool -> (rem : List Char) -> Suffix False rem cs -> Inl cs
183 | go n tb (' ' :: t) p = go (S n) tb t (Uncons p)
184 | go n tb ('\t' :: t) p = go (S n) True t (Uncons p)
185 | go n tb rem p = IL n tb rem p
193 | isUriChar : Char -> Bool
194 | isUriChar '#' = True
195 | isUriChar ';' = True
196 | isUriChar '/' = True
197 | isUriChar '?' = True
198 | isUriChar ':' = True
199 | isUriChar '@' = True
200 | isUriChar '&' = True
201 | isUriChar '=' = True
202 | isUriChar '+' = True
203 | isUriChar '$' = True
204 | isUriChar ',' = True
205 | isUriChar '-' = True
206 | isUriChar '_' = True
207 | isUriChar '.' = True
208 | isUriChar '!' = True
209 | isUriChar '~' = True
210 | isUriChar '*' = True
211 | isUriChar '\'' = True
212 | isUriChar '(' = True
213 | isUriChar ')' = True
214 | isUriChar '[' = True
215 | isUriChar ']' = True
216 | isUriChar '%' = True
217 | isUriChar c = isAlphaNum c
221 | isWordChar : Char -> Bool
222 | isWordChar '-' = True
223 | isWordChar c = isAlphaNum c
227 | isTagChar : Char -> Bool
228 | isTagChar '!' = False
229 | isTagChar c = isUriChar c && not (isFlowInd c)
234 | anchorName : Tok True YErr String
235 | anchorName (c :: cs) = go [<] cs
238 | go : SnocList Char -> AutoTok YErr String
240 | if isPlainSafe True x
241 | then go (acc :< x) xs
244 | _ => Succ (cast acc) (x :: xs)
245 | go acc [] = case acc of
247 | _ => Succ (cast acc) []
249 | anchorName [] = eoiAt Same
255 | tagToken : Tok True YErr (Either Tag (String, String))
256 | tagToken ('!' :: '<' :: cs) = verb [<] cs
259 | verb : SnocList Char -> AutoTok YErr (Either Tag (String, String))
260 | verb acc ('>' :: t) = case acc of
262 | _ => Succ (Left (Verbatim (cast acc))) t
263 | verb acc ('%' :: x :: y :: t) =
264 | if isHexDigit x && isHexDigit y
265 | then verb (acc :< chr (cast $
hexDigit x * 16 + hexDigit y)) t
266 | else invalidEscape p t
267 | verb acc (x :: t) =
268 | if isUriChar x then verb (acc :< x) t else fail p
269 | verb acc [] = eoiAt p
271 | tagToken ('!' :: cs) = sh [<] True cs
275 | suff : String -> SnocList Char -> AutoTok YErr (Either Tag (String, String))
276 | suff h acc ('%' :: x :: y :: t) =
277 | if isHexDigit x && isHexDigit y
278 | then suff h (acc :< chr (cast $
hexDigit x * 16 + hexDigit y)) t
279 | else invalidEscape p t
280 | suff h acc (x :: t) =
281 | if isTagChar x && x /= '%'
282 | then suff h (acc :< x) t
285 | _ => Succ (Right (h, cast acc)) (x :: t)
286 | suff h acc [] = case acc of
288 | _ => Succ (Right (h, cast acc)) []
292 | sh : SnocList Char -> (word : Bool) -> AutoTok YErr (Either Tag (String, String))
293 | sh acc word ('!' :: t) =
294 | if word then suff ("!" ++ cast acc ++ "!") [<] t else fail p
295 | sh acc word ('%' :: x :: y :: t) =
296 | if isHexDigit x && isHexDigit y
297 | then sh (acc :< chr (cast $
hexDigit x * 16 + hexDigit y)) False t
298 | else invalidEscape p t
299 | sh acc word (x :: t) =
300 | if isTagChar x && x /= '%'
301 | then sh (acc :< x) (word && isWordChar x) t
303 | [<] => Succ (Left NonSpec) (x :: t)
304 | _ => Succ (Right ("!", cast acc)) (x :: t)
305 | sh acc word [] = case acc of
306 | [<] => Succ (Left NonSpec) []
307 | _ => Succ (Right ("!", cast acc)) []
309 | tagToken cs = fail Same
314 | dirLine : Tok True YErr String
315 | dirLine (c :: cs) = go [<c] cs
318 | go : SnocList Char -> AutoTok YErr String
319 | go acc ('\n' :: t) = Succ (cast acc) t
320 | go acc (x :: t) = go (acc :< x) t
321 | go acc [] = Succ (cast acc) []
323 | dirLine [] = eoiAt Same
332 | isDocMarker : List Char -> Bool
333 | isDocMarker ('-' :: '-' :: '-' :: t) = wordEnd t
334 | isDocMarker ('.' :: '.' :: '.' :: t) = wordEnd t
335 | isDocMarker _ = False
338 | addNl : SnocList Char -> Nat -> SnocList Char
340 | addNl acc (S k) = addNl (acc :< '\n') k
343 | foldNl : SnocList Char -> Nat -> SnocList Char
344 | foldNl acc 0 = acc :< ' '
345 | foldNl acc k = addNl acc k
352 | singleQuoted : (mi : Nat) -> Tok True YErr String
353 | singleQuoted mi ('\'' :: cs) = go [<] [<] cs
359 | go : (acc, pend : SnocList Char) -> AutoTok YErr String
360 | go acc pend ('\'' :: '\'' :: t) = go ((acc ++ pend) :< '\'') [<] t
361 | go acc pend ('\'' :: t) = Succ (cast (acc ++ pend)) t
362 | go acc pend ('\n' :: t) = lines acc 0 0 t
363 | go acc pend (' ' :: t) = go acc (pend :< ' ') t
364 | go acc pend ('\t' :: t) = go acc (pend :< '\t') t
365 | go acc pend (c :: t) =
367 | then single (InvalidControl c) p
368 | else go ((acc ++ pend) :< c) [<] t
369 | go acc pend [] = eoiAt p
372 | lines : (acc : SnocList Char) -> (k, ind : Nat) -> AutoTok YErr String
373 | lines acc k ind ('\n' :: t) = lines acc (S k) 0 t
374 | lines acc k ind (' ' :: t) = lines acc k (S ind) t
375 | lines acc k ind ('\t' :: t) =
376 | if ind >= mi then sep acc k t else single (Custom TabIndent) p
377 | lines acc k ind [] = eoiAt p
378 | lines acc k ind (c :: t) =
379 | if ind == 0 && isDocMarker (c :: t)
380 | then single (Unknown "document marker") p
382 | then single (Custom BadIndent) p
383 | else go (foldNl acc k) [<] (c :: t)
386 | sep : (acc : SnocList Char) -> (k : Nat) -> AutoTok YErr String
387 | sep acc k (' ' :: t) = sep acc k t
388 | sep acc k ('\t' :: t) = sep acc k t
389 | sep acc k ('\n' :: t) = lines acc (S k) 0 t
390 | sep acc k [] = eoiAt p
391 | sep acc k (c :: t) = go (foldNl acc k) [<] (c :: t)
393 | singleQuoted _ cs = fail Same
400 | doubleQuoted : (mi : Nat) -> Tok True YErr String
401 | doubleQuoted mi ('"' :: cs) = go [<] [<] cs
404 | escChar : Char -> Maybe Char
405 | escChar '0' = Just '\0'
406 | escChar 'a' = Just '\x07'
407 | escChar 'b' = Just '\b'
408 | escChar 't' = Just '\t'
409 | escChar '\t' = Just '\t'
410 | escChar 'n' = Just '\n'
411 | escChar 'v' = Just '\x0b'
412 | escChar 'f' = Just '\x0c'
413 | escChar 'r' = Just '\r'
414 | escChar 'e' = Just '\x1b'
415 | escChar ' ' = Just ' '
416 | escChar '"' = Just '"'
417 | escChar '/' = Just '/'
418 | escChar '\\' = Just '\\'
419 | escChar 'N' = Just '\x85'
420 | escChar '_' = Just '\xa0'
421 | escChar 'L' = Just '\x2028'
422 | escChar 'P' = Just '\x2029'
423 | escChar _ = Nothing
425 | toChar : Nat -> Maybe Char
427 | if n > 0x10ffff || (n >= 0xd800 && n <= 0xdfff)
429 | else Just (chr $
cast n)
432 | go : (acc, pend : SnocList Char) -> AutoTok YErr String
433 | go acc pend ('"' :: t) = Succ (cast (acc ++ pend)) t
434 | go acc pend ('\\' :: c :: t) = case c of
437 | '\n' => lines (acc ++ pend) True 0 0 t
438 | 'x' => hex (acc ++ pend) 2 0 t
439 | 'u' => hex (acc ++ pend) 4 0 t
440 | 'U' => hex (acc ++ pend) 8 0 t
441 | _ => case escChar c of
442 | Just ch => go ((acc ++ pend) :< ch) [<] t
443 | Nothing => invalidEscape p t
444 | go acc pend ('\\' :: []) = invalidEscape p []
445 | go acc pend ('\n' :: t) = lines acc False 0 0 t
446 | go acc pend (' ' :: t) = go acc (pend :< ' ') t
447 | go acc pend ('\t' :: t) = go acc (pend :< '\t') t
448 | go acc pend (c :: t) =
450 | then single (InvalidControl c) p
451 | else go ((acc ++ pend) :< c) [<] t
452 | go acc pend [] = eoiAt p
455 | hex : (acc : SnocList Char) -> (k, val : Nat) -> AutoTok YErr String
456 | hex acc 0 val cs2 = case toChar val of
457 | Just ch => go (acc :< ch) [<] cs2
458 | Nothing => invalidEscape p cs2
459 | hex acc (S k) val (c :: t) =
461 | then hex acc k (val * 16 + hexDigit c) t
462 | else invalidEscape p t
463 | hex acc (S k) val [] = eoiAt p
467 | lines : (acc : SnocList Char) -> (eb : Bool) -> (k, ind : Nat) -> AutoTok YErr String
468 | lines acc eb k ind ('\n' :: t) = lines acc eb (S k) 0 t
469 | lines acc eb k ind (' ' :: t) = lines acc eb k (S ind) t
470 | lines acc eb k ind ('\t' :: t) =
471 | if ind >= mi then sep acc eb k t else single (Custom TabIndent) p
472 | lines acc eb k ind [] = eoiAt p
473 | lines acc eb k ind (c :: t) =
474 | if ind == 0 && isDocMarker (c :: t)
475 | then single (Unknown "document marker") p
477 | then single (Custom BadIndent) p
478 | else go (if eb then addNl acc k else foldNl acc k) [<] (c :: t)
481 | sep : (acc : SnocList Char) -> (eb : Bool) -> (k : Nat) -> AutoTok YErr String
482 | sep acc eb k (' ' :: t) = sep acc eb k t
483 | sep acc eb k ('\t' :: t) = sep acc eb k t
484 | sep acc eb k ('\n' :: t) = lines acc eb (S k) 0 t
485 | sep acc eb k [] = eoiAt p
486 | sep acc eb k (c :: t) = go (if eb then addNl acc k else foldNl acc k) [<] (c :: t)
488 | doubleQuoted _ cs = fail Same
497 | data Chomp = Strip | Clip | Keep
507 | blockScalar : (folded : Bool) -> (mi : Nat) -> Tok True YErr String
508 | blockScalar folded mi (c :: cs) = hdr Nothing Nothing cs
513 | fin : Chomp -> (acc : SnocList Char) -> (brk : Nat) -> String
514 | fin Strip acc _ = cast acc
515 | fin Keep acc brk = cast (addNl acc brk)
516 | fin Clip acc brk = case acc of
518 | _ => if brk > 0 then cast (acc :< '\n') else cast acc
523 | (prev : Maybe Bool)
526 | -> (acc, line : SnocList Char)
528 | contrib prev brk spaced acc line =
529 | let joined := case prev of
530 | Nothing => addNl acc brk
532 | if folded && not pSp && not spaced
533 | then (if brk == 1 then acc :< ' ' else addNl acc (brk `minus` 1))
539 | data Ci = Fixed Nat | Auto Nat
544 | data PLine = PBlank Nat | PEnd Nat | PCont Nat Bool Bool
546 | peek : Nat -> List Char -> PLine
547 | peek n (' ' :: t) = peek (S n) t
548 | peek n ('\n' :: _) = PBlank n
550 | peek n cs2@(x :: _) = PCont n (n == 0 && isDocMarker cs2) (x == '\t')
552 | startCi : Maybe Nat -> Ci
553 | startCi Nothing = Auto 0
554 | startCi (Just d) = Fixed ((mi + d) `minus` 1)
560 | Chomp -> Ci -> (prev : Maybe Bool) -> (acc : SnocList Char)
561 | -> (brk : Nat) -> AutoTok YErr String
562 | atLine ch ci prev acc brk cs2 = case peek 0 cs2 of
563 | PEnd n => case ci of
568 | then capture ch n2 prev acc brk 0 [<] cs2
569 | else Succ (fin ch acc (if n > 0 then S brk else brk)) cs2
570 | Auto _ => Succ (fin ch acc (if n > 0 then S brk else brk)) cs2
571 | PBlank n => case ci of
572 | Auto mb => blank ch (Auto $ max mb n) prev acc brk cs2
575 | then capture ch n2 prev acc brk 0 [<] cs2
576 | else blank ch (Fixed n2) prev acc brk cs2
577 | PCont n marker tab => case ci of
580 | then range (Custom TabIndent) p cs2
581 | else if n < mi || marker
582 | then Succ (fin ch acc brk) cs2
585 | else capture ch n prev acc brk 0 [<] cs2
588 | then range (Custom TabIndent) p cs2
589 | else if n < n2 || marker
590 | then Succ (fin ch acc brk) cs2
591 | else capture ch n2 prev acc brk 0 [<] cs2
595 | Chomp -> Ci -> (prev : Maybe Bool) -> (acc : SnocList Char)
596 | -> (brk : Nat) -> AutoTok YErr String
597 | blank ch ci prev acc brk (' ' :: t) = blank ch ci prev acc brk t
598 | blank ch ci prev acc brk ('\n' :: t) = atLine ch ci prev acc (S brk) t
599 | blank ch ci prev acc brk (_ :: t) = fail Same
600 | blank ch ci prev acc brk [] = Succ (fin ch acc brk) []
605 | Chomp -> (n : Nat) -> (prev : Maybe Bool) -> (acc : SnocList Char)
606 | -> (brk, m : Nat) -> (line : SnocList Char) -> AutoTok YErr String
607 | capture ch n prev acc brk m line (' ' :: t) =
609 | then capture ch n prev acc brk (S m) (line :< ' ') t
610 | else capture ch n prev acc brk (S m) line t
611 | capture ch n prev acc brk m line ('\t' :: t) =
613 | then capLine ch n prev acc brk True (line :< '\t') t
614 | else single (Custom TabIndent) p
615 | capture ch n prev acc brk m line ('\n' :: t) =
616 | let spaced := m > n
617 | in atLine ch (Fixed n) (Just spaced) (contrib prev brk spaced acc line) 1 t
618 | capture ch n prev acc brk m line [] =
621 | let spaced := m > n
622 | in Succ (fin ch (contrib prev brk spaced acc line) 1) []
623 | capture ch n prev acc brk m line (x :: t) =
625 | then single (InvalidControl x) p
626 | else capLine ch n prev acc brk (m > n) (line :< x) t
630 | Chomp -> (n : Nat) -> (prev : Maybe Bool) -> (acc : SnocList Char)
631 | -> (brk : Nat) -> (spaced : Bool) -> (line : SnocList Char)
632 | -> AutoTok YErr String
633 | capLine ch n prev acc brk spaced line ('\n' :: t) =
634 | atLine ch (Fixed n) (Just spaced) (contrib prev brk spaced acc line) 1 t
635 | capLine ch n prev acc brk spaced line (x :: t) =
636 | if isControl x && x /= '\t'
637 | then single (InvalidControl x) p
638 | else capLine ch n prev acc brk spaced (line :< x) t
639 | capLine ch n prev acc brk spaced line [] =
640 | Succ (fin ch (contrib prev brk spaced acc line) 1) []
644 | hdr : (d : Maybe Nat) -> (ch : Maybe Chomp) -> AutoTok YErr String
645 | hdr d ch ('-' :: t) = case ch of
646 | Nothing => hdr d (Just Strip) t
647 | Just _ => fail Same
648 | hdr d ch ('+' :: t) = case ch of
649 | Nothing => hdr d (Just Keep) t
650 | Just _ => fail Same
651 | hdr d ch ('\n' :: t) = atLine (maybe Clip id ch) (startCi d) Nothing [<] 0 t
652 | hdr d ch (' ' :: t) = hdrEnd d ch t
653 | hdr d ch ('\t' :: t) = hdrEnd d ch t
654 | hdr d ch [] = Succ (fin (maybe Clip id ch) [<] 0) []
655 | hdr d ch (x :: t) =
656 | if isDigit x && x /= '0'
658 | Nothing => hdr (Just $
digit x) ch t
659 | Just _ => fail Same
663 | hdrEnd : (d : Maybe Nat) -> (ch : Maybe Chomp) -> AutoTok YErr String
664 | hdrEnd d ch (' ' :: t) = hdrEnd d ch t
665 | hdrEnd d ch ('\t' :: t) = hdrEnd d ch t
666 | hdrEnd d ch ('#' :: t) = hdrCom d ch t
667 | hdrEnd d ch ('\n' :: t) = atLine (maybe Clip id ch) (startCi d) Nothing [<] 0 t
668 | hdrEnd d ch [] = Succ (fin (maybe Clip id ch) [<] 0) []
669 | hdrEnd d ch (x :: t) = fail Same
672 | hdrCom : (d : Maybe Nat) -> (ch : Maybe Chomp) -> AutoTok YErr String
673 | hdrCom d ch ('\n' :: t) = atLine (maybe Clip id ch) (startCi d) Nothing [<] 0 t
674 | hdrCom d ch (_ :: t) = hdrCom d ch t
675 | hdrCom d ch [] = Succ (fin (maybe Clip id ch) [<] 0) []
677 | blockScalar _ _ [] = eoiAt Same
685 | data Cont : (cs : List Char) -> Type where
691 | More : (blanks : Nat) -> (rem : List Char) -> Suffix True rem cs -> Cont cs
702 | plainCont : (inFlow : Bool) -> (mi : Nat) -> (cs : List Char) -> Cont cs
703 | plainCont inFlow mi cs = pre cs Same
706 | isMarker : List Char -> Bool
707 | isMarker ('-' :: '-' :: '-' :: t) = wordEnd t
708 | isMarker ('.' :: '.' :: '.' :: t) = wordEnd t
713 | contFirst : Char -> List Char -> Bool
714 | contFirst '#' _ = False
715 | contFirst ':' (n :: _) = isPlainSafe inFlow n
716 | contFirst ':' [] = False
717 | contFirst c _ = not (inFlow && isFlowInd c)
721 | line : Nat -> (rem : List Char) -> Suffix True rem cs -> Cont cs
722 | line k rem p = if isMarker rem then Stop else indent k 0 rem p
725 | indent : Nat -> Nat -> (rem : List Char) -> Suffix True rem cs -> Cont cs
726 | indent k n (' ' :: t) p = indent k (S n) t (Uncons p)
727 | indent k n rem p = white k n rem p
730 | white : Nat -> Nat -> (rem : List Char) -> Suffix True rem cs -> Cont cs
731 | white k n ('\t' :: t) p = white k n t (Uncons p)
732 | white k n (' ' :: t) p = white k n t (Uncons p)
733 | white k n ('\n' :: t) p = line (S k) t (Uncons p)
734 | white k n [] p = Stop
735 | white k n (c :: t) p =
736 | if n >= mi && contFirst c t then More k (c :: t) p else Stop
739 | pre : (rem : List Char) -> Suffix False rem cs -> Cont cs
740 | pre (' ' :: t) p = pre t (Uncons p)
741 | pre ('\t' :: t) p = pre t (Uncons p)
742 | pre ('\n' :: t) p = line 0 t (Uncons p)
755 | plainSegment : (inFlow : Bool) -> Tok True YErr String
756 | plainSegment inFlow (c :: cs) =
757 | if isControl c then single (InvalidControl c) Same else go [<c] cs
762 | colonCont : List Char -> Bool
763 | colonCont (n :: _) = isPlainSafe inFlow n
764 | colonCont [] = False
768 | cont : List Char -> Bool
770 | if isWhite x then cont xs
771 | else if isBreak x then False
774 | ':' => colonCont xs
775 | _ => not (inFlow && isFlowInd x)
778 | go : SnocList Char -> AutoTok YErr String
779 | go acc [] = Succ (cast acc) []
782 | if cont xs then go (acc :< x) xs else Succ (cast acc) (x :: xs)
783 | else if isBreak x then Succ (cast acc) (x :: xs)
784 | else if x == ':' then
786 | then go (acc :< ':') xs
787 | else Succ (cast acc) (x :: xs)
788 | else if inFlow && isFlowInd x then Succ (cast acc) (x :: xs)
789 | else if isControl x then single (InvalidControl x) p
790 | else go (acc :< x) xs
792 | plainSegment _ [] = eoiAt Same