Addressing Section List Values without an Index

This is a special behavior in ELCL that applies only in configuration documents — not in parser APIs. If a name path refers to a section list, and the next segment in the path is a regular name rather than an index, the path automatically points to the last entry in the list.

In other words:

  • In a configuration file, when no index is given,

  • the next name in the path refers to a child value or section inside the last added entry of the section list.

Example: Single Section List

The configuration below defines a section list named server.connection with two entries:

[main]
user: "example"

[server]
threads: 4
startup delay: 20 s

*[server.connection]
port: 8080
interface: "web"

*[server.connection]
port: 9000
interface: "api"

[server.backend.filter]
reject: "bad"
accept: "good"

The resulting value tree shows how the name path server.connection.port resolves:

Path: server.connection.port

(root)                    <== Document ( size=2 ) 
── [main]                  <== SectionWithNames ( size=1 ) 
└── user                    <== Text ( "example" ) 
┗━━ [server]                <== SectionWithNames ( size=4 ) 
    ── [backend]               <== IntermediateSection (  ) 
    └── [filter]                <== SectionWithNames ( size=2 ) 
        ├── accept                  <== Text ( "good" ) 
        └── reject                  <== Text ( "bad" ) 
    ┡━━ *[connection]           <== SectionList ( size=2 ) 
    ── [0]                     <== SectionWithNames ( size=2 ) 
    ├── interface               <== Text ( "web" ) 
    └── port                    <== Integer ( 8080 ) 
    ┗━━ [1]                     <== SectionWithNames ( size=2 ) 
        ── interface               <== Text ( "api" ) 
        ┗━━ port                    <== Integer ( 9000 ) 
    ├── startup_delay           <== TimeDelta ( Not supported ) 
    └── threads                 <== Integer ( 4 ) 

Here, the path server.connection.port points to the port value of the last entry in the connection list — the one that holds the value 9000.

Why This Rule Exists

At first glance, this rule may seem unusual — especially when working with a single-level list. However, it becomes intuitive and very useful in nested list structures, such as when building hierarchies dynamically.

Example: Nested Section Lists

Here is a configuration with nested section lists. Each place may optionally define a list of tree sections:

---*[place]*---
name: "example01"

---*[place]*---
name: "example02"

*[place.tree]
fruit: "apple"

*[place.tree]
fruit: "pear"

---*[place]*---
name: "example03"

*[place.tree]
fruit: "cherry"

*[place.tree]
fruit: "apricot"

The configuration expands into the following value tree:

(root)                    <== Document ( size=1 ) 
└── *[place]                <== SectionList ( size=3 ) 
    ├── [0]                     <== SectionWithNames ( size=1 ) 
    └── name                    <== Text ( "example01" ) 
    ├── [1]                     <== SectionWithNames ( size=2 ) 
    ├── *[tree]                 <== SectionList ( size=2 ) 
    ├── [0]                     <== SectionWithNames ( size=1 ) 
    └── fruit                   <== Text ( "apple" ) 
    └── [1]                     <== SectionWithNames ( size=1 ) 
        └── fruit                   <== Text ( "pear" ) 
    └── name                    <== Text ( "example02" ) 
    └── [2]                     <== SectionWithNames ( size=2 ) 
        ├── *[tree]                 <== SectionList ( size=2 ) 
        ├── [0]                     <== SectionWithNames ( size=1 ) 
        └── fruit                   <== Text ( "cherry" ) 
        └── [1]                     <== SectionWithNames ( size=1 ) 
            └── fruit                   <== Text ( "apricot" ) 
        └── name                    <== Text ( "example03" ) 

The tree shows how entries are added to the place list and how tree sections belong to the last added place.

Let’s highlight the relevant part:

13---*[place]*---
14name: "example03"
15
16*[place.tree]
17fruit: "cherry"

Even though place is a list, we didn’t provide an index in place.tree. Therefore, the configuration implicitly attaches the tree entry to the last place — in this case, the one with name example03.

Note

In this example, the full path place.tree is used for clarity. In real-world configurations, it’s typically better to use relative name paths like .tree instead.

Clarifying Name Path Semantics

  • In configuration files, name paths like place.tree automatically refer to the last entry in a list when no index is given.

  • In parser APIs, this automatic behavior may or may not apply. Instead, you get explicit control over which element in a list you want to access.