awa_unit_2.4.0_59135a52/dynamo/src/yaml/yaml-lexer-evaluation.adb

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
--  part of AdaYaml, (c) 2017 Felix Krause
--  released under the terms of the MIT license, see the file "copying.txt"

with Ada.Strings.UTF_Encoding.Strings;
with Ada.Strings.UTF_Encoding.Wide_Strings;
with Ada.Strings.UTF_Encoding.Wide_Wide_Strings;

with Text.Builder;

package body Yaml.Lexer.Evaluation is
   -----------------------------------------------------------------------------
   --  constant UTF-8 strings that may be generated from escape sequences
   -----------------------------------------------------------------------------

   function Next_Line return Ada.Strings.UTF_Encoding.UTF_8_String is
     (Ada.Strings.UTF_Encoding.Strings.Encode ("" & Character'Val (16#85#)));
   function Non_Breaking_Space return Ada.Strings.UTF_Encoding.UTF_8_String is
     (Ada.Strings.UTF_Encoding.Strings.Encode ("" & Character'Val (16#A0#)));
   function Line_Separator return Ada.Strings.UTF_Encoding.UTF_8_String is
     (Ada.Strings.UTF_Encoding.Wide_Strings.Encode
       ("" & Wide_Character'Val (16#2028#)));
   function Paragraph_Separator return Ada.Strings.UTF_Encoding.UTF_8_String is
     (Ada.Strings.UTF_Encoding.Wide_Strings.Encode
       ("" & Wide_Character'Val (16#2029#)));

   -----------------------------------------------------------------------------
   --  implementation
   -----------------------------------------------------------------------------

   procedure Read_Plain_Scalar (L : in out Instance; T : out Token) is
      Target : Text.Builder.Reference := Text.Builder.Create (L.Pool);
      After_Newline_State : constant State_Type :=
        (if L.Flow_Depth + L.Annotation_Depth = 0 then Line_Indentation'Access
           else Flow_Line_Indentation'Access);
      Line_Start_Pos : Positive;
   begin
      L.Seen_Multiline := False;
      Start_Token (L);
      if L.Proposed_Indentation /= -1 then
         L.Indentation := L.Proposed_Indentation;
         L.Proposed_Indentation := -1;
      end if;
      T := (Start_Pos => L.Token_Start_Mark, End_Pos => <>,
            Kind => Plain_Scalar);
      Multiline_Loop : loop
         Line_Start_Pos := L.Pos - 1;
         Inline_Loop : loop
            L.Cur := Next (L);
            case L.Cur is
               when ' ' =>
                  T.End_Pos := Cur_Mark (L);
                  declare
                     Space_Start : constant Positive := L.Pos - 1;
                  begin
                     Space_Loop : loop
                        L.Cur := Next (L);
                        case L.Cur is
                           when Line_Feed | Carriage_Return =>
                              Target.Append
                                (L.Buffer (Line_Start_Pos .. Space_Start - 1));
                              exit Inline_Loop;
                           when End_Of_Input =>
                              Target.Append
                                (L.Buffer (Line_Start_Pos .. Space_Start - 1));
                              L.State := Stream_End'Access;
                              exit Multiline_Loop;
                           when '#' =>
                              Target.Append
                                (L.Buffer (Line_Start_Pos .. Space_Start - 1));
                              L.State := Expect_Line_End'Access;
                              exit Multiline_Loop;
                           when ':' =>
                              if not Next_Is_Plain_Safe (L) then
                                 Target.Append
                                   (L.Buffer (Line_Start_Pos .. Space_Start - 1));
                                 L.State := Inside_Line'Access;
                                 exit Multiline_Loop;
                              end if;
                              exit Space_Loop;
                           when Flow_Indicator =>
                              if L.Flow_Depth + L.Annotation_Depth > 0 then
                                 Target.Append
                                   (L.Buffer (Line_Start_Pos .. Space_Start - 1));
                                 L.State := Inside_Line'Access;
                                 exit Multiline_Loop;
                              end if;
                              exit Space_Loop;
                           when ')' =>
                              if L.Annotation_Depth > 0 then
                                 Target.Append
                                   (L.Buffer (Line_Start_Pos .. Space_Start - 1));
                                 L.State := Inside_Line'Access;
                                 exit Multiline_Loop;
                              end if;
                              exit Space_Loop;
                           when ' ' => null;
                           when others => exit Space_Loop;
                        end case;
                     end loop Space_Loop;
                  end;
               when ':' =>
                  if not Next_Is_Plain_Safe (L) then
                     Target.Append
                       (L.Buffer (Line_Start_Pos .. L.Pos - 2));
                     T.End_Pos := Cur_Mark (L);
                     L.State := Inside_Line'Access;
                     exit Multiline_Loop;
                  end if;
               when Flow_Indicator =>
                  if L.Flow_Depth + L.Annotation_Depth > 0 then
                     Target.Append
                       (L.Buffer (Line_Start_Pos .. L.Pos - 2));
                     T.End_Pos := Cur_Mark (L);
                     L.State := Inside_Line'Access;
                     exit Multiline_Loop;
                  end if;
               when ')' =>
                  if L.Annotation_Depth > 0 then
                     Target.Append
                       (L.Buffer (Line_Start_Pos .. L.Pos - 2));
                     T.End_Pos := Cur_Mark (L);
                     L.State := Inside_Line'Access;
                     exit Multiline_Loop;
                  end if;
               when Line_Feed | Carriage_Return =>
                  Target.Append
                    (L.Buffer (Line_Start_Pos .. L.Pos - 2));
                  T.End_Pos := Cur_Mark (L);
                  exit Inline_Loop;
               when End_Of_Input =>
                  Target.Append
                    (L.Buffer (Line_Start_Pos .. L.Pos - 2));
                  if L.Pos /= L.Line_Start then
                     T.End_Pos := Cur_Mark (L);
                  end if;
                  L.State := Stream_End'Access;
                  exit Multiline_Loop;
               when others => null;
            end case;
         end loop Inline_Loop;
         End_Line (L);
         declare
            Newlines : Positive := 1;
         begin
            Newline_Loop : loop
               case Start_Line (L) is
                  when Content =>
                     if L.Pos - L.Line_Start - 1 <= L.Indentation then
                        L.State := After_Newline_State;
                        exit Multiline_Loop;
                     end if;
                     exit Newline_Loop;
                  when Directives_End_Marker =>
                     L.State := Line_Dir_End'Access;
                     exit Multiline_Loop;
                  when Document_End_Marker =>
                     L.State := Line_Doc_End'Access;
                     exit Multiline_Loop;
                  when Stream_End =>
                     exit Multiline_Loop;
                  when Comment =>
                     End_Line (L);
                     L.State := Line_Start'Access;
                     exit Multiline_Loop;
                  when Newline =>
                     End_Line (L);
               end case;
               Newlines := Newlines + 1;
            end loop Newline_Loop;
            if
              (L.Cur = ':' and then not Next_Is_Plain_Safe (L)) or else
              L.Cur = '#' or else (L.Cur in Flow_Indicator and then
                                    L.Flow_Depth + L.Annotation_Depth > 0)
              or else (L.Cur = ')' and then L.Annotation_Depth > 0)
            then
               L.State := After_Newline_State;
               exit Multiline_Loop;
            end if;
            L.Seen_Multiline := True;
            if Newlines = 1 then
               Target.Append (' ');
            else
               Target.Append ((1 .. Newlines - 1 => Line_Feed));
            end if;
         end;
      end loop Multiline_Loop;
      L.Value := Target.Lock;
   end Read_Plain_Scalar;

   procedure Process_Quoted_Whitespace (L : in out Instance; Init : Natural;
                                        Target : in out Text.Builder.Reference);

   procedure Process_Quoted_Whitespace (L : in out Instance; Init : Natural;
                                        Target : in out Text.Builder.Reference) is
      Newlines : Natural := Init;
      First_Space : constant Positive := L.Pos - 1;
   begin
      loop
         case L.Cur is
            when ' ' => null;
            when Line_Feed =>
               Handle_LF (L);
               L.Cur := L.Next;
               exit;
            when Carriage_Return =>
               Handle_CR (L);
               L.Cur := L.Next;
               exit;
            when others =>
               Target.Append (L.Buffer (First_Space .. L.Pos - 2));
               return;
         end case;
         L.Cur := Next (L);
      end loop;
      L.Seen_Multiline := True;
      loop
         case Start_Line (L) is
            when Content | Comment => exit;
            when Directives_End_Marker =>
               raise Lexer_Error with "Illegal '---' within quoted scalar";
            when Document_End_Marker =>
               raise Lexer_Error with "Illegal '...' within quoted scalar";
            when Newline => End_Line (L);
            when Stream_End =>
               raise Lexer_Error with
                 "Unexpected end of input (quoted string not closed)";
         end case;
         Newlines := Newlines + 1;
      end loop;
      if Newlines = 0 then
         null;
      elsif Newlines = 1 then
         Target.Append (' ');
      else
         Target.Append ((1 .. Newlines - 1 => Line_Feed));
      end if;
   end Process_Quoted_Whitespace;

   procedure Read_Single_Quoted_Scalar (L : in out Instance; T : out Token) is
      Target : Text.Builder.Reference := Text.Builder.Create (L.Pool);
      Literal_Start : Positive;
   begin
      L.Seen_Multiline := False;
      Start_Token (L);
      if L.Proposed_Indentation /= -1 then
         L.Indentation := L.Proposed_Indentation;
         L.Proposed_Indentation := -1;
      end if;
      Literal_Start := L.Pos;
      L.Cur := Next (L);
      loop
         case L.Cur is
            when End_Of_Input =>
               raise Lexer_Error with
                 "Unexpected end of input (quoted string not closed)";
            when ''' =>
               Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
               L.Cur := Next (L);
               if L.Cur = ''' then
                  Target.Append (''');
                  Literal_Start := L.Pos;
                  L.Cur := Next (L);
               else
                  exit;
               end if;
            when ' ' | Line_Feed | Carriage_Return =>
               Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
               Process_Quoted_Whitespace (L, 1, Target);
               Literal_Start := L.Pos - 1;
            when others =>
               L.Cur := Next (L);
         end case;
      end loop;
      T := (Start_Pos => L.Token_Start_Mark, End_Pos => Cur_Mark (L),
            Kind => Single_Quoted_Scalar);
      L.Value := Target.Lock;
   end Read_Single_Quoted_Scalar;

   subtype Hex_Code_Point is Natural range 0 .. 16#1FFFFF#;

   procedure Read_Hex_Sequence (L : in out Instance; Length : Positive;
                                Target : in out Text.Builder.Reference);

   procedure Read_Hex_Sequence (L : in out Instance; Length : Positive;
                                Target : in out Text.Builder.Reference) is
      Char_Pos : Hex_Code_Point := 0;
      Start_Pos : constant Positive := L.Pos;
   begin
      --  first, we make sure that this is a valid escape sequence. it is
      --  important to not calculate its value directly because that may lead
      --  to an overflow before we checked that the escape sequence is
      --  syntactically correct. We only want to report that the value is out of
      --  range if it is a valid escape sequence.
      for I in 0 .. Length - 1 loop
         if not (L.Buffer (Start_Pos + I) in Digit | 'a' .. 'f' | 'A' .. 'F')
         then
            raise Lexer_Error with
                 "Invalid character in hex escape sequence: " &
              Escaped (L.Buffer (Start_Pos + I));
         end if;
      end loop;
      for Exponent in reverse 0 .. Length - 1 loop
         L.Cur := Next (L);
         case L.Cur is
            when Digit =>
               Char_Pos := Char_Pos + (16 ** Exponent) *
                 (Character'Pos (L.Cur) - Character'Pos ('0'));
            when 'a' .. 'f' =>
               Char_Pos := Char_Pos + (16 ** Exponent) *
                 (Character'Pos (L.Cur) - Character'Pos ('a') + 10);
            when 'A' .. 'F' =>
               Char_Pos := Char_Pos + (16 ** Exponent) *
                 (Character'Pos (L.Cur) - Character'Pos ('A') + 10);
            when others =>
               null; --  cannot happen because of the check above
         end case;
      end loop;
      Target.Append (Ada.Strings.UTF_Encoding.Wide_Wide_Strings.Encode (
           "" & Wide_Wide_Character'Val (Char_Pos)));
   exception
      when Constraint_Error =>
         raise Lexer_Error with
           "Invalid hex escape sequence (value too large): " &
           L.Buffer (Start_Pos .. Start_Pos + Length - 1);
   end Read_Hex_Sequence;

   procedure Read_Double_Quoted_Scalar (L : in out Instance; T : out Token) is
      Target : Text.Builder.Reference := Text.Builder.Create (L.Pool);
      Literal_Start : Positive;
   begin
      L.Seen_Multiline := False;
      Start_Token (L);
      if L.Proposed_Indentation /= -1 then
         L.Indentation := L.Proposed_Indentation;
         L.Proposed_Indentation := -1;
      end if;
      Literal_Start := L.Pos;
      L.Cur := Next (L);
      loop
         <<Handle_Char>>
         case L.Cur is
            when End_Of_Input =>
               raise Lexer_Error with
                 "Unexpected end of input (quoted string not closed)";
            when '\' =>
               Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
               L.Cur := Next (L);
               Literal_Start := L.Pos;
               case L.Cur is
                  when '0' => Target.Append (Character'Val (0));
                  when 'a' => Target.Append (Character'Val (7));
                  when 'b' => Target.Append (Character'Val (8));
                  when 't' | Character'Val (9) =>
                     Target.Append (Character'Val (9));
                  when 'n' => Target.Append (Line_Feed);
                  when 'v' => Target.Append (Character'Val (11));
                  when 'f' => Target.Append (Character'Val (12));
                  when 'r' => Target.Append (Carriage_Return);
                  when 'e' => Target.Append (Character'Val (27));
                  when ' ' | '"' | '/' | '\' => Target.Append (L.Cur);
                  when 'N' => Target.Append (Next_Line);
                  when '_' => Target.Append (Non_Breaking_Space);
                  when 'L' => Target.Append (Line_Separator);
                  when 'P' => Target.Append (Paragraph_Separator);
                  when 'x' =>
                     Read_Hex_Sequence (L, 2, Target);
                     Literal_Start := L.Pos;
                  when 'u' =>
                     Read_Hex_Sequence (L, 4, Target);
                     Literal_Start := L.Pos;
                  when 'U' =>
                     Read_Hex_Sequence (L, 8, Target);
                     Literal_Start := L.Pos;
                  when Line_Feed | Carriage_Return =>
                     Process_Quoted_Whitespace (L, 0, Target);
                     Literal_Start := L.Pos - 1;
                     goto Handle_Char;
                  when others =>
                     raise Lexer_Error with
                       "Illegal character in escape sequence: " &
                       Escaped (L.Cur);
               end case;
            when '"' =>
               Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
               exit;
            when ' ' | Line_Feed | Carriage_Return =>
               Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
               Process_Quoted_Whitespace (L, 1, Target);
               Literal_Start := L.Pos - 1;
               goto Handle_Char;
            when others => null;
         end case;
         L.Cur := Next (L);
      end loop;
      L.Cur := Next (L);
      T := (Start_Pos => L.Token_Start_Mark, End_Pos => Cur_Mark (L),
            Kind => Double_Quoted_Scalar);
      L.Value := Target.Lock;
   end Read_Double_Quoted_Scalar;

   procedure Read_Block_Scalar (L : in out Instance; T : out Token) is
      type Chomp_Style is (Clip, Strip, Keep);

      Chomp : Chomp_Style := Clip;
      Indent : Natural := 0;
      Separation_Lines : Natural := 0;

      Content_Start : Positive;
      Target : Text.Builder.Reference := Text.Builder.Create (L.Pool);
   begin
      Start_Token (L);
      T := (Start_Pos => L.Token_Start_Mark, End_Pos => <>,
            Kind => (if L.Cur = '>' then Folded_Scalar else Literal_Scalar));

      --  header
      loop
         L.Cur := Next (L);
         case L.Cur is
            when '+' =>
               if Chomp /= Clip then
                  raise Lexer_Error with "Multiple chomping indicators!";
               end if;
               Chomp := Keep;
            when '-' =>
               if Chomp /= Clip then
                  raise Lexer_Error with "Multiple chomping indicators!";
               end if;
               Chomp := Strip;
            when '1' .. '9' =>
               if Indent /= 0 then
                  raise Lexer_Error with "Multiple indentation indicators!";
               end if;
               Indent := Natural'Max (0, L.Indentation) +
                 Character'Pos (L.Cur) - Character'Pos ('0');
            when ' ' =>
               while L.Cur = ' ' loop
                  L.Cur := Next (L);
               end loop;
               if not (L.Cur in Comment_Or_Line_End) then
                  raise Lexer_Error with
                    "Illegal character after block scalar header: " &
                    Escaped (L.Cur);
               end if;
               exit;
            when Line_End => exit;
            when others =>
               raise Lexer_Error with
                 "Illegal character in block scalar header: " & Escaped (L.Cur);
         end case;
      end loop;
      End_Line (L);

      --  determining indentation and leading empty lines
      declare
         Max_Leading_Spaces : Natural := 0;
      begin
         loop
            if Indent = 0 then
               while L.Cur = ' ' loop
                  L.Cur := Next (L);
               end loop;
            else
               Max_Leading_Spaces := L.Line_Start + Indent;
               while L.Cur = ' ' and then L.Pos <= Max_Leading_Spaces loop
                  L.Cur := Next (L);
               end loop;
            end if;
            case L.Cur is
               when Line_Feed | Carriage_Return =>
                  T.End_Pos := Cur_Mark (L);
                  Max_Leading_Spaces :=
                    Natural'Max (Max_Leading_Spaces, L.Pos - 1 - L.Line_Start);
                  End_Line (L);
                  Separation_Lines := Separation_Lines + 1;
               when End_Of_Input =>
                  L.State := Stream_End'Access;
                  goto End_Of_Input_Target;
               when others =>
                  if Indent = 0 then
                     Indent := L.Pos - L.Line_Start - 1;
                     if Indent <= Indentation_Type'Max (0, L.Indentation) then
                        L.State := Line_Indentation'Access;
                        goto Finalize;
                     elsif Indent < Max_Leading_Spaces then
                        raise Lexer_Error with
                          "Leading all-spaces line contains too many spaces.";
                     end if;
                  elsif L.Pos - L.Line_Start - 1 < Indent then
                     goto Finalize;
                  end if;
                  exit;
            end case;
         end loop;
         if Separation_Lines > 0 then
            Target.Append ((1 .. Separation_Lines => Line_Feed));
         end if;
      end;

      --  read block scalar content
      Block_Content : loop
         --  content of line
         Content_Start := L.Pos - 1;
         while not (L.Cur in Line_End) loop
            L.Cur := Next (L);
         end loop;
         Target.Append (L.Buffer (Content_Start .. L.Pos - 2));
         Separation_Lines := 0;
         if L.Cur = End_Of_Input then
            L.State := Stream_End'Access;
            goto End_Of_Input_Target;
         end if;
         Separation_Lines := Separation_Lines + 1;
         T.End_Pos := Cur_Mark (L);
         End_Line (L);

         --  empty lines and indentation of next line
         loop
            declare
               Indent_Pos : constant Natural := L.Line_Start + Indent;
            begin
               while L.Cur = ' ' and then L.Pos - 1 < Indent_Pos loop
                  L.Cur := Next (L);
               end loop;
               case L.Cur is
                  when Carriage_Return | Line_Feed =>
                     T.End_Pos := Cur_Mark (L);
                     Separation_Lines := Separation_Lines + 1;
                     End_Line (L);
                  when End_Of_Input =>
                     L.State := Stream_End'Access;
                     goto End_Of_Input_Target;
                  when others =>
                     if L.Pos - 1 < Indent_Pos then
                        exit Block_Content;
                     else
                        exit;
                     end if;
               end case;
            end;
         end loop;

         --  line folding
         if T.Kind = Literal_Scalar then
            Target.Append ((1 .. Separation_Lines  => Line_Feed));
         elsif Separation_Lines = 1 then
            Target.Append (' ');
         else
            Target.Append ((1 .. Separation_Lines - 1 => Line_Feed));
         end if;
      end loop Block_Content;

      if L.Pos - L.Line_Start - 1 > Indentation_Type'Max (0, L.Indentation) then
         if L.Cur = '#' then
            L.State := Expect_Line_End'Access;
         else
            raise Lexer_Error with
              "This line at " & Escaped (L.Cur) & " is less indented than necessary."
              & L.Cur_Line'Img;
         end if;
      elsif L.Pos = L.Line_Start + 1 then
         L.State := Line_Start'Access;
      else
         L.State := Line_Indentation'Access;
      end if;

      <<Finalize>>
      T.End_Pos := Cur_Mark (L);
      goto Finish;

      <<End_Of_Input_Target>>

      --  if we encounter the stream end directly after a newline character,
      --  we must have stored the T.End_Pos beforehand because we cannot
      --  calculate it back (we do not know how long the recent line was).
      if L.Pos /= L.Line_Start + 1 then
         T.End_Pos := Cur_Mark (L);
         --  the generated End_Pos is *after* the stream end char, which is one
         --  too far; compensate here.
         T.End_Pos.Index := T.End_Pos.Index - 1;
         T.End_Pos.Column := T.End_Pos.Column - 1;
      end if;

      <<Finish>>

      T.End_Pos := Cur_Mark (L);

      --  handling trailing empty lines
      case Chomp is
         when Strip => null;
         when Clip =>
            if Target.Length > 0 then
               Target.Append (Line_Feed);
            end if;
         when Keep => Target.Append ((1 .. Separation_Lines => Line_Feed));
      end case;

      L.Value := Target.Lock;
   end Read_Block_Scalar;

   procedure Read_URI (L : in out Instance; Restricted : Boolean) is
      Target : Text.Builder.Reference := Text.Builder.Create (L.Pool);
      End_With_Space : constant Boolean := L.Cur /= '<';
      Literal_Start : Positive;
   begin
      if End_With_Space then
         if (not Restricted) and then L.Cur in '[' | ']' | ',' then
            raise Lexer_Error with "Flow indicator cannot start tag prefix";
         end if;
         Literal_Start := L.Pos - 1;
      else
         Literal_Start := L.Pos;
         L.Cur := Next (L);
      end if;
      loop
         case L.Cur is
            when Space_Or_Line_End =>
               if End_With_Space then
                  Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
                  exit;
               else
                  raise Lexer_Error with "Unclosed verbatim tag";
               end if;
            when '%' =>
               Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
               Read_Hex_Sequence (L, 2, Target);
               Literal_Start := L.Pos;
            when Tag_Char => null;
            when '[' | ']' | ',' =>
               if Restricted then
                  Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
                  exit;
               end if;
            when '!' =>
               if Restricted then
                  raise Lexer_Error with "Illegal '!' in tag suffix!";
               end if;
            when '>' =>
               if End_With_Space then
                  raise Lexer_Error with "Illegal character in URI: "">""";
               else
                  Target.Append (L.Buffer (Literal_Start .. L.Pos - 2));
                  L.Cur := Next (L);
                  exit;
               end if;
            when others =>
               raise Lexer_Error with "Illegal character in URI: " &
                 Escaped (L.Cur);
         end case;
         L.Cur := Next (L);
      end loop;
      L.Value := Target.Lock;
   end Read_URI;

end Yaml.Lexer.Evaluation;