How to read yaml file in Ada

Viewed 170

I'm trying to understand how to work with Ada and AdaYaml library (https://github.com/yaml/AdaYaml/). I have several yaml files and I need to transform them into Ada records for further processing.

After several hours of playing with library I have no clue how use Accessor to access yaml data.

My minimal somehow working code is

with Ada.Text_IO;
with Ada.Command_Line;

with Yaml.Source.File;
with Yaml.Source.Text_IO;
with Yaml.Dom.Loading;
with Yaml.Dom.Node;
with Yaml; use Yaml;
with Text; use Text;

procedure Load_Dom is
   Input : Source.Pointer;
begin
   
   if Ada.Command_Line.Argument_Count = 0 then
      Input := Yaml.Source.Text_IO.As_Source (Ada.Text_IO.Standard_Input);
   else
      Input := Yaml.Source.File.As_Source (Ada.Command_Line.Argument (1));
   end if;
   
   declare
      
      Document : Yaml.Dom.Document_Reference :=
        Yaml.Dom.Loading.From_Source (Input);
     
   begin
      Ada.Text_IO.Put_Line ("Root node is a " & Yaml.Dom.Node.Instance'(Document.Root.Value).Kind'Img);
      Ada.Text_IO.Put_Line ("Root node is a " & Yaml.Dom.Node.Instance'(Document.Root.Value).Tag);
      Ada.Text_IO.Put_Line ("Root node is a " & Yaml.Dom.Node.Instance'(Document.Root.Value).Mapping_Style'Img);
   end;
end Load_Dom;

I think the explicit conversion Yaml.Dom.Node.Instance'(Document.Root.Value) is not right and I must be missing something.

Any idea or code example how to read yaml file in correct way?

3 Answers

I am the author of AdaYaml.

The Accessor which is returned by Document.Root.Value is defined as follows:

type Accessor (Data : not null access Node.Instance) is limited private
     with Implicit_Dereference => Data;

As any type with a discriminant, you can access the Node.Instance via its name, Data. So this explicit expression retrieves the root node's kind:

Document.Root.Value.Data.all.Kind

Now Ada allows us to make the pointer dereference implicit, dropping the .all:

Document.Root.Value.Data.Kind

And the Implicit_Dereference attribute of Accessor allows us to drop the .Data:

Document.Root.Value.Kind

So what you want to do is

declare
   Document : Yaml.Dom.Document_Reference :=
      Yaml.Dom.Loading.From_Source (Input);
   Root : Yaml.Dom.Accessor := Document.Root.Value; 
begin
   Ada.Text_IO.Put_Line ("Root node is a " & Root.Kind'Img);
   Ada.Text_IO.Put_Line ("Root node is a " & Root.Tag);
   Ada.Text_IO.Put_Line ("Root node is a " & Root.Mapping_Style'Img);
end;

This is shown briefly in the documentation but not explained. For further reading, this gem might be of interest.

This is not an answer, but (for what it's worth) an addition to the comment I made to the answer of @flyx (an answer that actually seems correct). The problem with the compilation error (in GNAT CE 2020) seems to be triggered by the limited with Yaml.Dom.Node construct used in the package Yaml.Dom, together with the Implicit_Dereference aspect on the type Yaml.Dom.Accessor. The problem can be reproduced using the example below. I currently don't know if the error is actually legitimate.

parent.ads

limited with Parent.Child;

package Parent is

  type Accessor (Data : not null access Child.Instance) is null record
     with Implicit_Dereference => Data;

end Parent;

parent-child.ads

package Parent.Child is
   
   type Instance (Value : Integer) is null record;

end Parent.Child;

main.adb

with Ada.Text_IO;
with Parent;
with Parent.Child;

procedure Main is
   Ref : Parent.Accessor (new Parent.Child.Instance (0));   
begin
   Ada.Text_IO.Put_Line (Ref.Value'Image);       --  Error
   Ada.Text_IO.Put_Line (Ref.Data.Value'Image);  --  OK
end Main;

output (compiler)

$ gprbuild -P default.gpr 
Compile
   [Ada]          main.adb
main.adb:8:29: undefined selector "Value" for overloaded prefix
gprbuild: *** compilation phase failed

Here is the minimal example I managed to work

with Ada.Text_IO;
with Ada.Command_Line;

with Yaml; use Yaml; -- this line is missing in https://ada.yaml.io/doc/Yaml.Dom/

with Yaml.Source.Text_IO;
with Yaml.Source.File;
with Yaml.Dom.Loading;
with Yaml.Dom.Node;

pragma Unreferenced (Yaml.Dom.Node);

procedure Load_Dom is
   use type Dom.Node_Kind;

   Input : Source.Pointer :=
     (if Ada.Command_Line.Argument_Count = 0 then
         Source.Text_IO.As_Source (Ada.Text_IO.Standard_Input)
      else
         Source.File.As_Source (Ada.Command_Line.Argument (1)));
   
   Document : Yaml.Dom.Document_Reference :=
     Dom.Loading.From_Source (Input);
   
   Root : constant not null access Dom.Node.Instance
     := Document.Root.Value.Data;
   
begin
   Ada.Text_IO.Put_Line
     ("Root node is a " & Root.Kind'Img);
end Load_Dom;
Related