Skip to content

Fix indexed array assignment + indexed derived types and a bit more#184

Open
ken-lauer wants to merge 16 commits into
marshallward:mainfrom
ken-lauer:fix_indexed_array_assignment
Open

Fix indexed array assignment + indexed derived types and a bit more#184
ken-lauer wants to merge 16 commits into
marshallward:mainfrom
ken-lauer:fix_indexed_array_assignment

Conversation

@ken-lauer

Copy link
Copy Markdown

Context

Closes #110
Closes #127
And maybe others?

f90nml was failing miserably for namelists from this charged particle physics simulation library Bmad, and this PR is the result of my poking around into trying to address that. (See all of the tao.init files in that repository, they are all Fortran namelists, many of which fail to parse with the current master)

So this ended up being a big set of changes and fixes. I started out with attempting this entirely manually, but admittedly did get Claude's help here. If that's against your contribution rules, I completely understand! Perhaps it at least can be a basis for a better fix.

If that's still OK, then I expect you might want me to try breaking up this PR into several. I can make an attempt, if there's a greater chance for these changes to get merged.

Changes / fixes

  • Parent-indexed derived-type slice assignment: arr(1:N)%foo = v1, ..., vN now parses into arr.foo = [...] and round-trips back to the slice form.

  • Open-ended parent-indexed bound:
    var(1:)%ele_name = ... (and var(:N)%...)
    gets the bound inferred from the value count instead of crashing/dropping data.

  • Single-value open-ended slice:
    var(1:)%ele_name = 'x' correctly produces a one-element list

  • Sliced field plus per-element field on the same array:

    var(1:6)%ele_name = ...
    var(1)%low_lim = 0.001
    var(3)%low_lim = 0.001
    
  • Positional derived-type rows, which can have mixed types:

    datum(1) = 'a', '', 'M1', 4.5
    
  • Positional then field on the same index - this is stored as _positional_row:

    design_lattice(1) = 'bmad.lat'
    design_lattice(1)%dynamic_aperture_calc = .true. now keeps both
    
  • Unindexed positional then field:

    f = 'hello'
    f%x = 42
    
  • Data getting scattered into different, previously-parsed derived type lists:
    For example, after var(1)%ele_name, var(2)%ele_name, var(3)%ele_name are set, a follow-up var(1:3)%attribute = 'k1', 'k2', 'k3' distributes values
    into the existing elements rather than overwriting them.

  • Nested parent-indexed derived types, along with deeper nesting (hopefully):

    arr(1:2)%inner%foo = 1.0, 2.0
    
  • Strided parent index:

    arr(1:5:2)%foo = 10.0, 30.0, 50.0
    

    Parses into [10, None, 30, None, 50] and round-trips back to the strided form with a bit of stride detection logic.

  • Multi-value indexed assignment:

    var(N) = v1, v2, ..., vK
    

    This is treated as a positional row N instead of a flat one-dimensional vector starting at N.

  • FIndex debug repr: added __str__ so I could see what was going on with it.

There's additional metadata for keeping track of what's positional, when slicing was used, when parent-based indexing was used. The "_positional_row" value is special in the value dictionary, as when you combine positional derived type setting and fieldname-based settings they can clash (... why do people do this and why does Fortran allow it? Ugh.).

The additional metadata helps with round-tripping back to namelist files especially.

I admittedly did not get to testing patching with these, but it's past 5PM on a Friday. So I think that's good enough for now.

@codecov

codecov Bot commented May 2, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 97.29%. Comparing base (34da4c8) to head (044ffec).

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #184      +/-   ##
==========================================
+ Coverage   97.22%   97.29%   +0.06%     
==========================================
  Files           9        9              
  Lines        2166     2365     +199     
  Branches      361      416      +55     
==========================================
+ Hits         2106     2301     +195     
- Misses         35       39       +4     
  Partials       25       25              
Flag Coverage Δ
python2.7 ?
python3.5 ?

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@marshallward

marshallward commented May 2, 2026

Copy link
Copy Markdown
Owner

Thank you so much, this is an epic contribution. Derived type array assignment has been ignored for a very long time because the original code was never designed to handle it, and it happened to be rare enough that there wasn't much demand.

It will take me some time to process all of it, but overall it looks good to me.

As for acknowledging Claude, this advice seems like the best to me:

https://docs.kernel.org/process/coding-assistants.html

Something in the commit log like this

Assisted-by: Claude:claude-3-opus

should be more than enough. If you tell me the LLM that was used, I can squash the commits and append it to the end. (Or, if you wanted to rebase the commits with documented commit messages, that would also be great, but not necessary.)

@ken-lauer ken-lauer force-pushed the fix_indexed_array_assignment branch from 01fef02 to b1e51ad Compare May 4, 2026 16:19
@ken-lauer

Copy link
Copy Markdown
Author

Thank you so much, this is an epic contribution. Derived type array assignment has been ignored for a very long time because the original code was never designed to handle it, and it happened to be rare enough that there wasn't much demand.

I'm glad you think so - and I hope this is a good basis for full support. It's pretty close, I think.

It will take me some time to process all of it, but overall it looks good to me.

I completely understand. I would typically complain if someone gave me such a large PR to review, and here I am proposing this as a first time contributor...

As for acknowledging Claude, this advice seems like the best to me:
[...]

I rebased and marked the commits that were largely LLM-assisted as you requested. If this ends up getting squashed into one commit with that attribution, that's OK with me - it's your call as to if/when/how to take this in.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Parsing error using array assignment in namelist f90nml fails to read namelist entries for Fortran90 structure variables

2 participants