Einführung#

Schwierigkeit: Anfänger

Dieses Tutorial bietet eine einfache Einführung in die Benutzung von TOML Fortran. Das Lesen und Schreiben von TOML Datenstrukturen wird behandelt, sowie die Erstellung von Datenstrukturen aus TOML Dokumenten außerdem wird diskutiert wie eine Datenstruktur aus einem TOML Dokument erstellt wird oder wieder in ein TOML Dokument konvertiert wird.

Für dieses Projekt werden wir mit fpm arbeiten, aber Du kannst jedes Build-Tool verwenden, mit dem Du dich gut zurecht kommst, schau Dir die Integrations-Anleitung an, um einen passenden Setup zu finden. Wir starten mit der Erstellung eines minimalen Paketmanifests, um TOML Fortran in unserem fpm Projekt zu benutzen.

fpm.toml#
name = "demo"

[dependencies]
toml-f.git = "https://github.com/toml-f/toml-f.git"

Die öffentliche TOML Fortran API wird in dem Modul tomlf definiert, und wir werden nur dieses Modul für diesen gesamten Kurs brauchen. Die Hauptdatenstruktur, mit der wir uns in diesem Kurs konkret kommunizieren wird toml_table und toml_array Instanzen, die wir mit dem generischen interface get_value manipulieren können.

src/reader.f90#
module reader
  use tomlf, only : toml_table, toml_array, get_value, len
  implicit none
  private

  public :: read_data

contains

  subroutine read_data(table, title, spectrum)
    type(toml_table), intent(inout) :: table
    character(len=:), allocatable, intent(out) :: title
    real, allocatable, intent(out) :: spectrum(:)

    type(toml_table), pointer :: child
    type(toml_array), pointer :: array
    logical :: reverse
    integer :: ival

    ! Get character value from entry "title"
    call get_value(table, "title", title)

    ! Get subtable reference from entry "spectrum"
    call get_value(table, "spectrum", child)

    ! Get array reference from entry "data"
    call get_value(child, "data", array)

    ! Read all values from the data array
    allocate(spectrum(len(array)))
    do ival = 1, size(spectrum)
      call get_value(array, ival, spectrum(ival))
    end do

    ! Data is stored in reverse order
    call get_value(child, "reverse", reverse, .false.)
    if (reverse) spectrum(:) = spectrum(size(spectrum):1:-1)
  end subroutine read_data

end module reader

Hinweis: Wir deklarieren die TOML Datenstruktur als mutable, d.h. intent(inout) statt nur intent(in), da das get_value interface die Datenstruktur verändern kann. Wir beginnen mit einem einfachen Testprogramm, welches nicht einmal ein TOML Dokument liest, sondern nur eine leere Tabelle an den Reader weitergeben.

app/defaults.f90#
program defaults
  use reader, only : read_data
  use tomlf, only : toml_table
  implicit none

  type(toml_table), allocatable :: table
  character(len=:), allocatable :: title
  real, allocatable :: spectrum(:)

  table = toml_table()

  call read_data(table, title, spectrum)

  if (allocated(title)) then
    print '(a)', "Title: '"//title//"'"
  end if

  print '(*(g0, 1x))', "Entries:", size(spectrum)
  if (size(spectrum) > 0) then
    print '(*(g0, 1x))', "Spectrum:", spectrum
  end if
end program defaults

Das get_value interface für die Verarbeitung der TOML Datenstruktur stellt sicher, dass die Datenstruktur vollständig durch den gesamten Prozess gelesen wird und fügt die gewünschten Knoten hinzu, wenn sie nicht vorhanden sind oder füllt sie mit Standardwerten aus. Überzeuge Dich, dass die leere Tabelle während des Lesens wirklich geändert wurde, indem Du einen Serializer an die Datenstruktur übergibst.

block
  use tomlf, only : toml_serialize

  print '(a)', "# Final TOML data structure"
  print '(a)', toml_serialize(table)
end block
! Expected output:
! # Final TOML data structure
! [spectrum]
! data = [ ]
! reverse = false

Dieses Verhalten ist sehr einfach, da wir unsere Standardwerte definieren können, während wir definieren, wie wir die TOML Datenstruktur lesen.

Bemerkung

Das get_value build interface ist nur eine der Möglichkeiten, um auf die TOML Datenstruktur mit TOML Fortran zuzugreifen. Es nimmt eine opionierten Ansicht auf, wie die Datenstruktur gelesen und verändert werden soll, was für einen Großteil der Anwendungen funktioniert.

Wir lesen jetzt ein echtes TOML Dokument und übergeben es an den Reader.

input.toml#
title = "Example"
spectrum.data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]

Wir adaptieren unseren Befehlszeilen-Driver, um die Datei input.toml zu lesen und die Werte wie vorher auszugeben.

app/readin.f90#
program readin
  use reader, only : read_data
  use tomlf, only : toml_table, toml_parse, toml_error
  implicit none

  type(toml_table), allocatable :: table
  character(len=:), allocatable :: title
  real, allocatable :: spectrum(:)


  block
    integer :: io
    type(toml_error), allocatable :: error

    open(file="input.toml", newunit=io, status="old")
    call toml_parse(table, io, error)
    close(io)
    if (allocated(error)) then
      print '(a)', "Error: "//error%message
      stop 1
    end if
  end block

  call read_data(table, title, spectrum)

  if (allocated(title)) then
    print '(a)', "Title: '"//title//"'"
  end if

  print '(*(g0, 1x))', "Entries:", size(spectrum)
  if (size(spectrum) > 0) then
    print '(*(g0, 1x))', "Spectrum:", spectrum
  end if
end program readin

Durch das Ausführen des Programms mit fpm kannst Du sehen, dass wir die korrekten Werte aus dem Dokument gelesen haben.

❯ fpm run readin
Title: 'Example'
Entries: 10
Spectrum: 0.00000000 1.00000000 2.00000000 3.00000000 4.00000000 5.00000000 6.00000000 7.00000000 8.00000000 9.00000000

Du kannst das Serializer noch einmal verwenden, um die finale Datenstruktur zu schreiben, wenn Du möchtest, ob das get_value interface Standardwerte hinzugefügt hat.

Wichtig

In diesem Tutorial hast Du gelernt, einfache Datenstrukturen aus TOML Dokumenten zu lesen. Du kannst nun

  • die Logik zum Lesen von Daten aus TOML Strukturen definieren

  • Standardwerte in Deinen Parsern definieren, wenn Du die Eingabestruktur definierst

  • ein echtes TOML Dokument aus einer Datei lesen

  • aus Deinen Datenstrukturen TOML Dokumente schreiben