Skip to content

(towards #3083) Extend treesitter frontend - #3558

Open
sergisiso wants to merge 29 commits into
masterfrom
continue_ts
Open

(towards #3083) Extend treesitter frontend#3558
sergisiso wants to merge 29 commits into
masterfrom
continue_ts

Conversation

@sergisiso

@sergisiso sergisiso commented Aug 13, 2026

Copy link
Copy Markdown
Collaborator

This PR focuses on extending the number of treesitter nodes that are recognised and handled, and adds many small Fortran snippets in the tests that are already parsable, but it is still:

  • ignoring the Reader arguments
  • not isolating fparser (so its performance penalty is still paid)
  • not tested with real world applications

@sergisiso sergisiso self-assigned this Aug 13, 2026
@LonelyCat124

Copy link
Copy Markdown
Collaborator

@sergisiso At some point (after this PR is merged) can I have a look at trying to get comments into this as well? Partly to try to undesrtand how this works and partly to try to keep our current level of comment support.

@codecov

codecov Bot commented Aug 13, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 100.00%. Comparing base (bb366f9) to head (5a717cb).
⚠️ Report is 24 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##            master     #3558    +/-   ##
==========================================
  Coverage   100.00%   100.00%            
==========================================
  Files          397       397            
  Lines        55758     56545   +787     
==========================================
+ Hits         55758     56545   +787     

☔ View full report in Codecov by Harness.
📢 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.

@sergisiso
sergisiso requested a review from LonelyCat124 August 17, 2026 11:57
@sergisiso

Copy link
Copy Markdown
Collaborator Author

@LonelyCat124 This is ready for review, I keep finding things that could be better but the PR is already huge and at some point I need to cut the PR. It supports a lot more Fortran now but it is not mature enough to replace workflows yet (real_application->transformation_script->backend is still fragile).

Note that I used AI assistance, I spent quite a bit of my effort getting the high level fronted design as I wanted (this is the _process_node, handler selection, using generators, utility methods, scoping with contextmanager, meaning of errors, ... I tried to document all these) but code inside the handlers and test is largely generated (just asking to follow certain patterns, e.g. 'test should start with real Fortran snippet and assert against the produced PSyIR'). Feel free to say if any large sections need to be changed.

@LonelyCat124 LonelyCat124 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the few comments I managed today, I'm going to be off the rest of the day again but I'll try to finish the review off tomorrow.

''' PSyIR TreeSitter Fortran reader '''
'''

PSyIR fronted to ingest Fortran using the TreeSitter parse generator.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/fronted/frontend

Also not sure "ingest" is a good word? But will leave that decision to yhou.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated this line.

https://github.com/stadelmanma/tree-sitter-fortran/blob/master/grammar.js

Note that psyclone is pinned to a particular version of treesitter (in
pyproject.toml), use that branch instead of master to follow the grammar.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have a plan on how we keep up-to-date with treesitter? How fast moving is the grammar?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Their grammar seems relatively stable nowadays, I would just update when we need a new feature.

I decided that pinning to a particular version (similar to what we do with fparser), to have a fixed grammar, and avoid lots of defensive checks that we would need to do if we cannot guarantee the exact children of each tsnode.

tsnode: Optional['TSNode'], types: Union[str, Container[str]]
) -> Generator['TSNode']:
''' Provides a generator to iterate over the provided tsnode
chidlren of the given type(s).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

children.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

)
children.append(code_block)
return None
if expect is not _NodeExpectation.LIST:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we do this check at the start of the routine instead since it doesn't rely on the result at all.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

@LonelyCat124 LonelyCat124 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I put a couple more comments - I'll have to review the rest later this week or next week when back to 100% to make sure I'm not missing anything.

'''
check_types = (types,) if isinstance(types, str) else types
if tsnode:
for child in tsnode.children:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure what the best way to do yield functions is - should the bulk of the cost be on the first call or is it expected for each call to be similar? Since you could do

for child in [child for child in tsnode.children if child.type in check_types]:
    yield child

And have all the computation's cost be at the start? Not sure which is better.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I don't even know if list comprehensions are done lazily with that or not...

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I googled a bit, so the list comprehension is not done lazily. If we did a generator statement (with ( instead of [) then it would be done lazily (and thus be similar to your current implementation) so that suggests to me that we should make the generator be lazy and not precompute it, so happy to leave this as is if you are.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the idea of the generator was precisely to not precompute things so when we search a tree we stop at the instance found instead of iterating the whole tree.

@LonelyCat124

Copy link
Copy Markdown
Collaborator

@sergisiso One comment I do have is that it might be worth splitting the tests up into more files (by input/output nodes) - I don't like having one large "generic test" file for treesitter like we have for fparser, I think some more modular would make it much easier.

@LonelyCat124 LonelyCat124 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sergisiso I didn't go through the tests yet, but I did finish fortran_tree_reader.py now. Most of the comments are either questioning the input source to reach certain failure states, or poor documentation or typehinting.

)
return code_block

def _get_handler(self, tsnode: 'TSNode') -> Callable:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Return type question here - We reach the end of this function and not return anything. First should we explicitly return None (so we always have coverage)? Return type should be Callable | None or Optional as you prefer.

def _translation_unit(self, tsnode: 'TSNode') -> nodes.Node:
# If at this point we still don't have a handler, it is unsupported
raise NotImplementedError(
f"Unsupported '{tsnode.type}' tree-sitter node.") from None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does this raise from None?


def _translation_unit_handler(
self, tsnode: 'TSNode'
) -> nodes.Node:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

returns a FileContainer not just nodes.Node - probably worth being specific wherever we can.

def _module_handler(self, tsnode: 'TSNode') -> nodes.Node:
def _module_handler(
self, tsnode: 'TSNode'
) -> nodes.Node:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nodes.Container

with self._using_scope(container.symbol_table):
visibility_map = self._process_access_statements(tsnode.children)

# This nodes are already processed

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you add what processes these to the comment?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment isn't quite accurate either as internal_procedures are handled after, not already processed.

return nodes.IntrinsicCall.create(intrinsic, args)
except (TypeError, ValueError):
raise NotImplementedError(
f"Unsupported operands for {intrinsic.name}") from None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

from None

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Test from this requires monkeypatching, is this actually reachable code we want to create a Codeblock for?

'''
ident = next(children_of_type(tsnode, "identifier"), None)
if ident is None:
raise NotImplementedError(

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What happens if we just allow this?

if before:
lower = self._process_nodes(
before[0], _NodeExpectation.EXPRESSION)
if not after:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this valid input source?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Split the tests please, I've not otherwise reviewed them yet.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Generally I'd like more comments/docstring explanations, A lot of the code is fairly understandable, but there is little discussion of the treesitter structure that it relies on, which is useful both for developers to understand from this file, but also makes it easier to diagnose issues if treesitter structures were to change in the future.

@LonelyCat124 LonelyCat124 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sergisiso I didn't go through the tests yet, but I did finish fortran_tree_reader.py now. Most of the comments are either questioning the input source to reach certain failure states, or poor documentation or typehinting.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants