This is the first release of a small project of Ada syntax tree generation. I tried to implement everything specified in the annotated reference manual here. Yes, parallel constructs and iteration schemas are supported.
Some notes:
- It is a library, no executables involved.
- The analyzer parses the source and creates the syntax tree and cross reference of defining identifiers in the source.
- The cross reference contains the defining identifiers declared in the code and visibility scopes.
- The visibility scopes can be used for name resolution, e.g. finding all matching names visible at the location. Note that this does not cover use-clauses which need to be handed if the complete list required. Use clauses are linked in the list for each declaration context of the tree in order to ease the process.
- Both structures are allocated in an arena pool storage and can be released as a whole.
- The code source can be file, stream or a user-defined container implementing multi-line source interface. One can compile from a database or a git repository, if the interface is provided.
- There can be any number of compilation units in the source. One parsing call takes one unit from the source.
- Unicode is fully supported as well as Unicode identifiers normalization checks.
- Commutative operations are coalesced. E.g. A.B.C.D gives “.”(A,B,C,D) tree.
- Inverses are coalesced as well, e.g. A+B-C+D gives “+”(A,B,-(D),C).
- There is a text output of the tree in a normalized form. It is almost a legal Ada program with some operators added to for coalesced operations. E.g. A * B / C * D gives (A * B * ⅟C * D) to simplify the tree and ease optimization.
- Constant folding is supported. If enabled universal expressions and constant Boolean expressions are evaluated into constants.
- There is a text output in a tree form.
- Syntax trees can be compared for equality
- The tree and cross-reference can be serialized into a stream. The idea is that the packages like Standard, Ada.* or ones used in the with-clause can be parsed once, serialized and de-serialized later.
- There is a test suite comprised of ACATS tests related to the syntax (mostly, illegal code to be rejected) and ARM examples (see this project). The test suite is extensible, the test header syntax is described on the page.
10 Likes
I think the obvious question about this that most users will ask is “how does it compare to libadalang?”
I see a few differences in your list, and just by looking at yours I can tell that it won’t take tens of gigabytes of memory to compile like LAL does, however I think a more detailed comparison would be useful.
The short answer is that this was just for fun.
The longer one is that I do not know LAL well enough. From the documentation it creates a raw syntax tree which means that if you want to run some things like browsing you would spend a lot of performance. (The latest version in GNAT Studio works for eternity (1-2 minutes before the context menu shows) and then displays nothing on the choice.) Which is probably a bug. My parser builds a lot of internal upward links to speed up queries. E.g. links to the context parents, links from exit statements up to the loop statement it exits etc.
On the other hand I think that the primary goal of LAL was rather things like IDE support. My parser stops on the first error nor does it attempt to correct anything, except for malformed literals and identifiers. I could add even more checks possible on the single pass, but that would make the parser even less tolerant.
Yes, it meant to use resources sparingly. No Wide_Wide_String used. No Unbounded_String. No dynamic memory allocation beyond the memory pool and the twin-stack machine. The pool and the stacks can be pre-allocated if required. So yes, it can be used on an embedded target, I hope.
Thank’s Dimitry for the work.
Do you think we could use this to create a new, compiler indpendent, version of ASIS? 
That would be great. The code base is Ada 95. Though there is some use of generics, tried to make it working with a wide range of GNAT versions.
4 Likes
I’ve been using Libadalang recently, and I have to admit I was pleasantly surprised by how fast it is.
That said, it’s far from being ready to use out of the box, and I had quite a bit of trouble getting it to work the way I wanted—to create an API documentation generator for LibreFrame. Anyway, the final result is flawless, and you’ll be able to see it in LibreFrame’s first public release, coming before the end of the year.
I wish I’d discovered and started using your project some months ago, because I imagine it’s much lighter and better suited to my needs than the ‘army knife’ that is Libadalang — which isn’t without its own issues either.
2 Likes