Getting started
Getting started#
This tutorial provides a gentle introduction to the use of TOML Fortran. It will deal with reading as well as creating TOML data structures using the high-level build interface and discuss how to obtain a data structure from a TOML document or turn a data structure to TOML document again.
For this project we will be working with fpm, however you can use any build tool you are familar with, checkout the integration guide to find a matching setup. We start with creating a minimal package manifest to use TOML Fortran in our fpm project.
name = "demo"
[dependencies]
toml-f.git = "https://github.com/toml-f/toml-f.git"
The public TOML Fortran API is defined in the tomlf
module, we will only use this module for this entire course.
The main data structures we are going to interact with are toml_table
and toml_array
instances, which we can conveniently manipulate with the generic interface get_value
.
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
Note that we declare the TOML data structure as mutable, i.e. intent(inout)
rather than just intent(in)
, as the get_value
interface can modify the data structure.
We start with a simple test program which is not actually reading any TOML document, but just passing an empty table to our reader.
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
The get_value
interface for processing the TOML data structure ensures that the data structure is complete throughout the whole process of reading it and will add the requested nodes if there are not present or will fill them in with default values.
Convince yourself that the empty table indeed changed while reading by passing a serializer to it.
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
This behavior is very convenient because it allows us to define our default values while defining how we read the TOML data structure.
Note
The get_value
build interface is only one way of accessing the TOML data structure provided by TOML Fortran.
It takes an opinionated approach towards reading and modifying the data structure, which is suitable the majority of applications.
Now we will actually read a TOML document and pass it to our reader.
title = "Example"
spectrum.data = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0]
We adapt our command line driver to read the file input.toml
and output the values as before
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
Running the program with fpm shows that we were able to read the correct values from the document
❯ 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
You can again use the serializer to write the final data structure, if you want to check whether the get_value
interface has added default values.
Important
In this tutorial you have learned out to read simple data structures from TOML documents. You can now
define the logic to read data from TOML structures
provide default values in your parser as you define the input structure
read an actual TOML document from a file
write TOML documents from your data structures