Code architecture¶
{ #dev-architecture-code }
Stable ID: ARCH-CODE
-
We have chosen Python as the programming language for our implementation.
-
We have chosen the latest released version, currently 3.14, and when a new version is released we intend to follow within three months, given that resources permit.
-
We have chosen to use typing on all functions and their parameters. We use pyright as type checker.
-
Our code should adhere to the conventions of Python, such as philosophy, style, and documentation. We use ruff as code formatter and linter.
-
-
We enable analyses purely based on the AST as being insensitive to layout and comments signanficantly simplifies the development and maintenance of these analyses.
-
We do not limit analyses and transformations to the AST, as knowledge about the token and trivia is often also needed.
-
We defined AST Node as a Protocol (a.k.a. statically duck typing), with basic functionality and a back door:
get_original_nodeto obtain the AST node as provided by the parser. -
AST Nodes are read only and immutable.
-
AST Nodes are navigable, so parent must be present (except for the ATU / top node) and children are always present (although it might be an empty list).
-
Standard 'semantic' functions must be provided that when given a code snippet will return the variables read or written. Based on the output of these functions dependencies between code snippets are determined.
-
We enable syntax pattern matching and semantic filtering, see the Find, Filter, and Modify steps for details. In most cases, standard filter functions (as describe before) are enough, but we enable user specific filter functions that access the original AST.
-
We collect multiple transformations, we are syntax aware - to handle shared text boundaries, and then in one step rewrite the code text.
-
For general purpose, we don't mandate that the final text should be parsable. When chaining changes, all intermediate texts must be parsable - in case of transpilation, different parsers can be involved.
-
The project is kept as a single repository (archive), rather than being split into separate repositories per component, so that users and contributors have one place to clone, install, and version, instead of having to discover and align several small repositories.
-
Layers that are meant to be extended by third parties (currently: parser integrations, under
src/renaissance/integrations/) use an extendable directory structure: one subdirectory per contribution (e.g., one per parser), added alongside the existing ones without modifying the core or other contributions. -
A contribution subdirectory may carry its own license, distinct from the repository's overall license (via a
LICENSEfile and/or SPDX headers scoped to that subdirectory) - e.g., for an integration that wraps a GPL or proprietary parser. -
See ADR 14 for the full rationale and the directory layout (
renaissancecore,integrations/<parser>,recipes/<language>,rejuvenation/<language>).
-