adayaml_0.3.0_ab19e387/src/implementation/yaml-events-store.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
--  part of AdaYaml, (c) 2017 Felix Krause
--  released under the terms of the MIT license, see the file "copying.txt"

package body Yaml.Events.Store is
   function New_Store return Reference is
      Ptr : constant not null access Instance := new Instance;
   begin
      return (Ada.Finalization.Controlled with Data => Ptr);
   end New_Store;

   function Value (Object : Reference) return Accessor is
     ((Data => Object.Data));

   function Value (Object : Optional_Reference) return Accessor is
     ((Data => Object.Data));

   function Optional (Object : Reference'Class) return Optional_Reference is
   begin
      Increase_Refcount (Object.Data);
      return (Ada.Finalization.Controlled with Data => Object.Data);
   end Optional;

   function Required (Object : Optional_Reference'Class) return Reference is
   begin
      Increase_Refcount (Object.Data);
      return (Ada.Finalization.Controlled with Data => Object.Data);
   end Required;

   procedure Memorize (Object : in out Instance; Item : Event; Force : Boolean)
   is
      use type Text.Reference;
   begin
      if Object.Stream_Count > 0 then
         raise State_Error with
           "cannot manipulate event queue while a Stream_Instance exists";
      end if;
      case Item.Kind is
         when Annotation_Start =>
            if Item.Annotation_Properties.Anchor /= Text.Empty then
               Object.Anchor_Map.Include
                 (Item.Annotation_Properties.Anchor,
                  (Position => Object.Length + 1, Has_Been_Output => False));
            elsif Object.Depth = 0 and not Force then
               return;
            end if;
            if Object.Depth = After_Annotation_End then
               Object.Depth := 1;
            else
               Object.Depth := Object.Depth + 1;
            end if;
         when Scalar =>
            if Item.Scalar_Properties.Anchor /= Text.Empty then
               Object.Anchor_Map.Include
                 (Item.Scalar_Properties.Anchor,
                  (Position => Object.Length + 1,
                   Has_Been_Output => False));
            elsif Object.Depth = 0 and not Force then
               return;
            end if;
            if Object.Depth = After_Annotation_End then
               Object.Depth := 0;
            end if;
         when Mapping_Start =>
            if Item.Collection_Properties.Anchor /= Text.Empty then
               Object.Anchor_Map.Include
                 (Item.Collection_Properties.Anchor,
                  (Position => Object.Length + 1,
                   Has_Been_Output => False));
            elsif Object.Depth = 0 and not Force then
               return;
            end if;
            if Object.Depth = After_Annotation_End then
               Object.Depth := 1;
            else
               Object.Depth := Object.Depth + 1;
            end if;
         when Sequence_Start =>
            if Item.Collection_Properties.Anchor /= Text.Empty then
               Object.Anchor_Map.Include
                 (Item.Collection_Properties.Anchor,
                  (Position => Object.Length + 1,
                   Has_Been_Output => False));
            elsif Object.Depth = 0 and not Force then
               return;
            end if;
            if Object.Depth = After_Annotation_End then
               Object.Depth := 1;
            else
               Object.Depth := Object.Depth + 1;
            end if;
         when Mapping_End | Sequence_End =>
            if Object.Depth = 0 and not Force then
               return;
            end if;
            Object.Depth := Object.Depth - 1;
         when Annotation_End =>
            if Object.Depth = 0 and not Force then
               return;
            end if;
            Object.Depth := Object.Depth - 1;
            if Object.Depth = 0 then
               Object.Depth := After_Annotation_End;
            end if;
         when others =>
            if Object.Depth = 0 and not Force then
               return;
            elsif Object.Depth = After_Annotation_End then
               Object.Depth := 0;
            end if;
      end case;
      if Object.Length = Object.Data.all'Length then
         Object.Grow;
      end if;
      Object.Length := Object.Length + 1;
      Object.Data (Object.Length) := Item;
   end Memorize;

   procedure Memorize (Object : in out Instance; Item : Event) is
   begin
      Memorize (Object, Item, False);
   end Memorize;

   procedure Force_Memorize (Object : in out Instance; Item : Event;
                             Position : out Element_Cursor) is
   begin
      Memorize (Object, Item, True);
      Position := Element_Cursor (Object.Length);
   end Force_Memorize;

   function Find (Object : Instance; Alias : Text.Reference)
                  return Anchor_Cursor is
      (Anchor_Cursor (Object.Anchor_Map.Find (Alias)));

   function Exists_In_Output (Position : Anchor_Cursor) return Boolean is
     (Anchor_To_Index.Element
        (Anchor_To_Index.Cursor (Position)).Has_Been_Output);

   procedure Set_Exists_In_Output (Object : in out Instance;
                                   Position : Anchor_Cursor) is
      procedure Process (Key : Text.Reference;
                         Element : in out Anchor_Info) is
         pragma Unreferenced (Key);
      begin
         Element.Has_Been_Output := True;
      end Process;
   begin
      Anchor_To_Index.Update_Element (Object.Anchor_Map,
                                      Anchor_To_Index.Cursor (Position),
                                      Process'Access);
   end Set_Exists_In_Output;

   procedure Advance (Position : in out Element_Cursor) is
   begin
      Position := Element_Cursor'Succ (Position);
   end Advance;

   procedure Advance_At_Same_Level (Object : Instance;
                                    Position : in out Element_Cursor) is
      Depth : Natural := 0;
   begin
      loop
         case Object.Data (Positive (Position)).Kind is
            when Annotation_Start | Sequence_Start | Mapping_Start |
                 Document_Start =>
               Depth := Depth + 1;
            when Annotation_End =>
               Depth := Depth - 1;
            when Sequence_End | Mapping_End | Document_End =>
               Depth := Depth - 1;
               if Depth = 0 then
                  Position := Element_Cursor'Succ (Position);
                  return;
               end if;
            when Scalar | Alias =>
               if Depth = 0 then
                  Position := Element_Cursor'Succ (Position);
                  return;
               end if;
            when Stream_Start | Stream_End =>
               raise Stream_Error with "Unexpected event inside stream: " &
                 Object.Data (Positive (Position)).Kind'Img;
         end case;
         Position := Element_Cursor'Succ (Position);
      end loop;
   end Advance_At_Same_Level;

   procedure Clear (Object : in out Instance) is
   begin
      if Object.Stream_Count > 0 then
         raise State_Error with
           "cannot manipulate event queue while a Stream_Instance exists";
      end if;
      Object.Anchor_Map.Clear;
      Object.Depth := 0;
   end Clear;

   procedure Copy (Source : in Instance; Target : in out Instance) is
   begin
      if Target.Data.all'Length /= Source.Data.all'Length then
         Target.Finalize;
         Target.Data := new Event_Array (Source.Data.all'Range);
      end if;
      Target.Data.all := Source.Data.all;
      Target.Length := Source.Length;
      Target.Anchor_Map := Source.Anchor_Map;
      Target.Depth := Source.Depth;
   end Copy;

   function Retrieve (Object : Reference'Class; Position : Anchor_Cursor)
                         return Stream_Reference is
      Ptr : constant not null access Stream_Instance :=
        new Stream_Instance'(Refcount_Base with Object => Reference (Object),
                             Depth => 0, Current => Anchor_To_Index.Element
                               (Anchor_To_Index.Cursor (Position)).Position);
   begin
      Object.Data.Stream_Count := Object.Data.Stream_Count + 1;
      return Stream_Reference'(Ada.Finalization.Controlled with Data => Ptr);
   end Retrieve;

   function Retrieve (Object : Reference'Class; Position : Element_Cursor)
                      return Stream_Reference is
      Ptr : constant not null access Stream_Instance :=
        new Stream_Instance'(Refcount_Base with Object => Reference (Object),
                             Depth => 0, Current => Positive (Position));
   begin
      Object.Data.Stream_Count := Object.Data.Stream_Count + 1;
      return Stream_Reference'(Ada.Finalization.Controlled with Data => Ptr);
   end Retrieve;

   function Value (Object : Stream_Reference) return Stream_Accessor is
      ((Data => Object.Data));

   function Next (Object : in out Stream_Instance) return Event is
   begin
      if Object.Depth = 1 then
         raise Constraint_Error with
           "tried to query item after end of anchored node";
      end if;
      return Item : constant Event := Object.Object.Data.Data (Object.Current) do
         case Item.Kind is
            when Scalar => Object.Depth := Natural'Max (1, Object.Depth);
            when Mapping_Start | Sequence_Start =>
               Object.Depth := Natural'Max (2, Object.Depth + 1);
            when others => null;
         end case;
         Object.Current := Object.Current + 1;
      end return;
   end Next;

   function Exists (Object : Optional_Stream_Reference) return Boolean is
     (Object.Data /= null);

   function Value (Object : Optional_Stream_Reference) return Stream_Accessor is
     ((Data => Object.Data));

   function Optional (Object : Stream_Reference'Class)
                      return Optional_Stream_Reference is
   begin
      Object.Data.Refcount := Object.Data.Refcount + 1;
      return (Ada.Finalization.Controlled with Data => Object.Data);
   end Optional;

   procedure Clear (Object : in out Optional_Stream_Reference) is
   begin
      if Object.Data /= null then
         Decrease_Refcount (Object.Data);
         Object.Data := null;
      end if;
   end Clear;

   function First (Object : Instance; Position : Anchor_Cursor) return Event is
     (Object.Data (Anchor_To_Index.Element (Anchor_To_Index.Cursor
                                            (Position)).Position));

   function Element (Object : Instance; Position : Element_Cursor)
                     return Event is
     (Object.Data (Positive (Position)));

   procedure Adjust (Object : in out Reference) is
   begin
      Increase_Refcount (Object.Data);
   end Adjust;

   procedure Finalize (Object : in out Reference) is
   begin
      Decrease_Refcount (Object.Data);
   end Finalize;

   procedure Adjust (Object : in out Optional_Reference) is
   begin
      if Object.Data /= null then
         Increase_Refcount (Object.Data);
      end if;
   end Adjust;

   procedure Finalize (Object : in out Optional_Reference) is
   begin
      if Object.Data /= null then
         Decrease_Refcount (Object.Data);
      end if;
   end Finalize;

   procedure Finalize (Object : in out Stream_Instance) is
   begin
      Object.Object.Data.Stream_Count := Object.Object.Data.Stream_Count - 1;
   end Finalize;

   procedure Adjust (Object : in out Stream_Reference) is
   begin
      Increase_Refcount (Object.Data);
   end Adjust;

   procedure Finalize (Object : in out Stream_Reference) is
   begin
      Decrease_Refcount (Object.Data);
   end Finalize;

   procedure Adjust (Object : in out Optional_Stream_Reference) is
   begin
      if Object.Data /= null then
         Increase_Refcount (Object.Data);
      end if;
   end Adjust;

   procedure Finalize (Object : in out Optional_Stream_Reference) is
   begin
      if Object.Data /= null then
         Decrease_Refcount (Object.Data);
      end if;
   end Finalize;

   function To_Element_Cursor (Position : Anchor_Cursor) return Element_Cursor
   is (if Position = No_Anchor then No_Element else
          Element_Cursor (Anchor_To_Index.Element (Anchor_To_Index.Cursor
                                                   (Position)).Position));
end Yaml.Events.Store;