mirror of https://github.com/yaml/AdaYaml
303 lines
12 KiB
Ada
303 lines
12 KiB
Ada
-- part of AdaYaml, (c) 2017 Felix Krause
|
|
-- released under the terms of the MIT license, see the file "copying.txt"
|
|
|
|
with Ada.Unchecked_Deallocation;
|
|
|
|
-- we need to explicitly with all annotations because their package
|
|
-- initialization adds them to the annotation map.
|
|
with Yaml.Transformator.Annotation.Identity;
|
|
with Yaml.Transformator.Annotation.Concatenation;
|
|
with Yaml.Transformator.Annotation.Vars;
|
|
with Yaml.Transformator.Annotation.For_Loop;
|
|
pragma Unreferenced (Yaml.Transformator.Annotation.Concatenation);
|
|
pragma Unreferenced (Yaml.Transformator.Annotation.Vars);
|
|
pragma Unreferenced (Yaml.Transformator.Annotation.For_Loop);
|
|
|
|
package body Yaml.Transformator.Annotation_Processor is
|
|
use type Text.Reference;
|
|
|
|
procedure Free_Array is new Ada.Unchecked_Deallocation
|
|
(Node_Array, Node_Array_Pointer);
|
|
procedure Free_Transformator is new Ada.Unchecked_Deallocation
|
|
(Transformator.Instance'Class, Transformator.Pointer);
|
|
|
|
function New_Processor
|
|
(Pool : Text.Pool.Reference;
|
|
Externals : Events.Store.Reference := Events.Store.New_Store)
|
|
return Pointer is
|
|
(new Instance'(Ada.Finalization.Limited_Controlled with Pool => Pool,
|
|
Context => Events.Context.Create (Externals),
|
|
others => <>));
|
|
|
|
procedure Finalize_Finished_Annotation_Impl (Object : in out Instance) is
|
|
begin
|
|
if Object.Depth = Object.Annotations (Object.Count).Depth
|
|
and then not Object.Annotations (Object.Count).Impl.Has_Next then
|
|
if Object.Annotations (Object.Count).Impl.Swallows_Document then
|
|
Object.Current_State := Swallowing_Document_End;
|
|
Object.Current :=
|
|
(Kind => Document_End, others => <>);
|
|
end if;
|
|
Free_Transformator (Object.Annotations
|
|
(Object.Count).Impl);
|
|
Object.Count := Object.Count - 1;
|
|
end if;
|
|
end Finalize_Finished_Annotation_Impl;
|
|
|
|
procedure Append (Object : in out Instance; E : Event; Start : Natural) is
|
|
begin
|
|
if Object.Current_State = Existing_But_Held_Back then
|
|
Object.Held_Back := Object.Current;
|
|
Object.Current := E;
|
|
else
|
|
declare
|
|
Cur_Annotation : Natural := Start;
|
|
Cur_Event : Event := E;
|
|
begin
|
|
while Cur_Annotation > 0 loop
|
|
Object.Annotations (Cur_Annotation).Impl.Put (Cur_Event);
|
|
if Object.Annotations (Cur_Annotation).Impl.Has_Next then
|
|
Cur_Event := Object.Annotations (Cur_Annotation).Impl.Next;
|
|
if (Cur_Annotation = Object.Count and
|
|
E.Kind in Sequence_End | Mapping_End | Scalar | Alias)
|
|
then
|
|
Finalize_Finished_Annotation_Impl (Object);
|
|
end if;
|
|
Cur_Annotation := Cur_Annotation - 1;
|
|
else
|
|
loop
|
|
Cur_Annotation := Cur_Annotation + 1;
|
|
if Cur_Annotation > Object.Count then
|
|
if E.Kind /= Annotation_End then
|
|
Finalize_Finished_Annotation_Impl (Object);
|
|
end if;
|
|
return;
|
|
end if;
|
|
if Object.Annotations (Cur_Annotation).Impl.Has_Next then
|
|
Cur_Event :=
|
|
Object.Annotations (Cur_Annotation).Impl.Next;
|
|
if (Cur_Annotation = Object.Count and
|
|
E.Kind in Sequence_End | Mapping_End | Scalar | Alias)
|
|
then
|
|
Finalize_Finished_Annotation_Impl (Object);
|
|
end if;
|
|
Cur_Annotation := Cur_Annotation - 1;
|
|
exit;
|
|
end if;
|
|
end loop;
|
|
end if;
|
|
end loop;
|
|
Object.Current := Cur_Event;
|
|
Object.Current_State := Existing;
|
|
end;
|
|
end if;
|
|
end Append;
|
|
|
|
procedure Put (Object : in out Instance; E : Event) is
|
|
Locals : constant Events.Store.Accessor := Object.Context.Document_Store;
|
|
begin
|
|
case E.Kind is
|
|
when Annotation_Start =>
|
|
Locals.Memorize (E);
|
|
declare
|
|
use type Annotation.Maps.Cursor;
|
|
Pos : constant Annotation.Maps.Cursor :=
|
|
(if E.Namespace = Standard_Annotation_Namespace then
|
|
Annotation.Map.Find (E.Name.Value) else
|
|
Annotation.Maps.No_Element);
|
|
begin
|
|
if Object.Count = Object.Annotations.all'Length then
|
|
declare
|
|
Old_Array : Node_Array_Pointer := Object.Annotations;
|
|
begin
|
|
Object.Annotations := new Node_Array (1 .. Object.Count * 2);
|
|
Object.Annotations (1 .. Object.Count) := Old_Array.all;
|
|
Free_Array (Old_Array);
|
|
end;
|
|
end if;
|
|
Object.Count := Object.Count + 1;
|
|
declare
|
|
Impl : constant Transformator.Pointer :=
|
|
(if Pos = Annotation.Maps.No_Element then
|
|
Annotation.Identity.New_Identity else
|
|
Annotation.Maps.Element (Pos).all
|
|
(Object.Pool, Object.Context));
|
|
begin
|
|
Object.Annotations (Object.Count) :=
|
|
(Impl => Impl, Depth => Object.Depth);
|
|
Impl.Put (E);
|
|
if Impl.Swallows_Document then
|
|
if Object.Current_State /= Existing_But_Held_Back then
|
|
raise Annotation_Error with
|
|
E.Namespace & E.Name &
|
|
" may only be applied on the root node of a document";
|
|
end if;
|
|
Object.Current_State := Absent;
|
|
elsif Impl.Has_Next then
|
|
Object.Append (Impl.Next, Object.Count - 1);
|
|
elsif Object.Current_State = Existing_But_Held_Back then
|
|
Object.Current_State := Existing;
|
|
end if;
|
|
end;
|
|
end;
|
|
when Annotation_End =>
|
|
Locals.Memorize (E);
|
|
Object.Append (E, Object.Count);
|
|
when Document_Start =>
|
|
Locals.Clear;
|
|
Object.Current := E;
|
|
Object.Current_State := Existing_But_Held_Back;
|
|
when Mapping_Start | Sequence_Start =>
|
|
Object.Depth := Object.Depth + 1;
|
|
Locals.Memorize (E);
|
|
Object.Append (E, Object.Count);
|
|
when Mapping_End | Sequence_End =>
|
|
Object.Depth := Object.Depth - 1;
|
|
Locals.Memorize (E);
|
|
Object.Append (E, Object.Count);
|
|
when Document_End =>
|
|
if Object.Current_State = Swallowing_Document_End then
|
|
Object.Current_State := Absent;
|
|
else
|
|
Object.Current := E;
|
|
Object.Current_State := Existing;
|
|
end if;
|
|
when Scalar | Alias =>
|
|
Locals.Memorize (E);
|
|
Object.Append (E, Object.Count);
|
|
when others =>
|
|
Object.Append (E, Object.Count);
|
|
end case;
|
|
end Put;
|
|
|
|
function Has_Next (Object : Instance) return Boolean is
|
|
(Object.Current_State = Existing or
|
|
(Object.Current_State = Existing_But_Held_Back and
|
|
Object.Current.Kind /= Document_Start) or
|
|
(Object.Current_State = Swallowing_Document_End and
|
|
Object.Current.Kind /= Document_End));
|
|
|
|
function Next (Object : in out Instance) return Event is
|
|
use type Events.Context.Location_Type;
|
|
|
|
procedure Look_For_Additional_Element is
|
|
begin
|
|
if Object.Count > 0 and then
|
|
Object.Annotations (1).Impl.Has_Next
|
|
then
|
|
Object.Current := Object.Annotations (1).Impl.Next;
|
|
if Object.Count = 1 then
|
|
Finalize_Finished_Annotation_Impl (Object);
|
|
end if;
|
|
else
|
|
Object.Current_State := Absent;
|
|
end if;
|
|
end Look_For_Additional_Element;
|
|
|
|
procedure Update_Exists_In_Output (Anchor : Text.Reference) is
|
|
use type Events.Context.Cursor;
|
|
begin
|
|
if Anchor /= Text.Empty then
|
|
declare
|
|
Pos : Events.Context.Cursor :=
|
|
Events.Context.Position (Object.Context, Anchor);
|
|
begin
|
|
if Pos /= Events.Context.No_Element then
|
|
declare
|
|
Referenced : constant Event := Events.Context.First (Pos);
|
|
begin
|
|
if
|
|
Referenced.Start_Position =
|
|
Object.Current.Start_Position and
|
|
Referenced.Kind = Object.Current.Kind then
|
|
Events.Context.Set_Exists_In_Output (Pos);
|
|
end if;
|
|
end;
|
|
end if;
|
|
end;
|
|
end if;
|
|
end Update_Exists_In_Output;
|
|
begin
|
|
case Object.Current_State is
|
|
when Existing =>
|
|
case Object.Current.Kind is
|
|
when Alias =>
|
|
declare
|
|
Pos : Events.Context.Cursor :=
|
|
Events.Context.Position
|
|
(Object.Context, Object.Current.Target);
|
|
begin
|
|
if not Events.Context.Exists_In_Ouput (Pos) then
|
|
Events.Context.Set_Exists_In_Output (Pos);
|
|
Object.Current_Stream :=
|
|
Events.Context.Retrieve (Pos).Optional;
|
|
return Ret : constant Event :=
|
|
Object.Current_Stream.Value.Next do
|
|
case Ret.Kind is
|
|
when Scalar =>
|
|
Object.Current_Stream.Clear;
|
|
Look_For_Additional_Element;
|
|
when Mapping_Start | Sequence_Start =>
|
|
Object.Current_State := Localizing_Alias;
|
|
Object.Stream_Depth := Object.Stream_Depth + 1;
|
|
when others =>
|
|
raise Program_Error with
|
|
"alias refers to " & Object.Current.Kind'Img;
|
|
end case;
|
|
end return;
|
|
end if;
|
|
end;
|
|
when Scalar =>
|
|
Update_Exists_In_Output
|
|
(Object.Current.Scalar_Properties.Anchor);
|
|
when Mapping_Start | Sequence_Start =>
|
|
Update_Exists_In_Output
|
|
(Object.Current.Collection_Properties.Anchor);
|
|
when others => null;
|
|
end case;
|
|
return Ret : constant Event := Object.Current do
|
|
Look_For_Additional_Element;
|
|
end return;
|
|
when Existing_But_Held_Back =>
|
|
if Object.Current.Kind = Document_Start then
|
|
raise Constraint_Error with "no event to retrieve";
|
|
end if;
|
|
Object.Current_State := Existing;
|
|
return Object.Held_Back;
|
|
when Localizing_Alias =>
|
|
return Ret : constant Event := Object.Current_Stream.Value.Next do
|
|
case Ret.Kind is
|
|
when Mapping_Start | Sequence_Start =>
|
|
Object.Stream_Depth := Object.Stream_Depth + 1;
|
|
when Mapping_End | Sequence_End =>
|
|
Object.Stream_Depth := Object.Stream_Depth - 1;
|
|
if Object.Stream_Depth = 0 then
|
|
Object.Current_Stream.Clear;
|
|
Look_For_Additional_Element;
|
|
end if;
|
|
when others => null;
|
|
end case;
|
|
end return;
|
|
when Swallowing_Document_End =>
|
|
if Object.Current.Kind = Document_End then
|
|
raise Constraint_Error with "no event to retrieve";
|
|
else
|
|
return Ret : constant Event := Object.Current do
|
|
Object.Current := (Kind => Document_End, others => <>);
|
|
end return;
|
|
end if;
|
|
when Absent =>
|
|
raise Constraint_Error with "no event to retrieve";
|
|
end case;
|
|
end Next;
|
|
|
|
procedure Finalize (Object : in out Instance) is
|
|
Ptr : Node_Array_Pointer := Object.Annotations;
|
|
begin
|
|
for I in 1 .. Object.Count loop
|
|
Free_Transformator (Object.Annotations (I).Impl);
|
|
end loop;
|
|
Free_Array (Ptr);
|
|
end Finalize;
|
|
end Yaml.Transformator.Annotation_Processor;
|