-
Notifications
You must be signed in to change notification settings - Fork 143
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add initial Ruby support #270
Draft
hendrikvanantwerpen
wants to merge
43
commits into
main
Choose a base branch
from
rubies-are-forever
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This reverts commit b922492.
hendrikvanantwerpen
force-pushed
the
rubies-are-forever
branch
from
May 12, 2023 11:59
6a4b5b7
to
afd5f1a
Compare
@rewinfrey The project configuration I used doesn't work with |
A program's lexical scope has an edge to the ROOT NODE, and an edge is added from the ROOT NODE to a newly added pop symbol node "<::>" representing the "root scope". The root scope node has an edge to the program's defs. I considered an edge from the root scope to the program's lexical scope, but that causes the resulting complete path to cycle, and it also allows the root scope node access it doesn't strictly require (at least so far), whereas the root scope node only for now needs access to the program's definitions. This produces a shorter path.
The scoping that is visible in Ruby sources, as determined by the nesting of classes and modules, is independent of the source file organization. Therefore, we expose all top-level definitions in the global scope directly. A program's lexical scope inherits the global scope, thus having access to all available definitions in the repository. Additionally, the global scope is accessible via the <::> marker, which is used to ensure a name of the form ::NAME is resolved from the root and not from an intermediate definition that happens to be in scope. Later we may consider introducing a notion of a project to isolate groups of files from each other. This would be modeled as definitions and references between the global and the program scope.
Identifiers (`constant` and `scope_resolution`) can appear in both reference and definition positions. To distinguish between these cases, the rules would need to include the context, i.e., the surrounding term. This works poorly with the recursive nature of `scope_resolution`, which can only be expressed generally with top-level rules. Including context would require explicit unfolding of the recursion (up to a fixed depth). Instead of the unfolding, we introduce top-level rules which create both reference and definition nodes. The terms using these names can chose to use the definition or the reference, or both, if they wish.
Definitions in the root scope (with names starting with `::`) can appear inside nested classes and modules. To support this, the `.defs` property has been split into `.lexical_defs` and `.root_defs`. The former behaves the same as `.defs` did, containing the definitions that are part of the enclosing construct. The latter contains definitions that instead escape that context and bubble up to the root.
Class variables are visible in the class body, even if the class definition is split. To support that, a class definition not only introduces a definition, but also imports a reference (for its own name) into the lexical scope of the body.
Modules behave very similarly to classes. For now we treat them the same and share the logic for modules and classes.
Co-authored-by: Hendrik van Antwerpen <[email protected]>
Co-authored-by: Hendrik van Antwerpen <[email protected]>
To distinguish between instance and static methods within class bodies, statements and expressions now by default have static_defs and instance_defs scoped variables. This allows the stanza for handling instance method declarations to only create an edge between the method node's instance_defs to its associated identifier node. This works in the same way for static method declarations, in which a static method's static_defs is connected via an edge to its identifier node. I think this will also allow instances of classes to create edges between the class instance value and the lhs of an assignment's instance_defs, but I have not progressed that far yet.
With the new `.instance_defs` and `.static_defs`, the `.lexical_defs` has become obsolete, since it was only used for static and instance definitions. We will probably reintroduce it later to model proper lexical definitions (i.e., local variables).
Use `.def_value` instead of `.body` and `.ref_value` instead of `.value` to mirror `.def` and .ref`. This frees up `.value` which we can use instead of `.expr_value`.
Local variables are only visible in the block they are defined, and only after they've been assigned. Statements are chained, by conencting their `.lexical_scope` to the `.lexical_scope` and the `.local_defs` of the preceding statement. Since the chaining behavior of statements is the same in a program and in a `body_statement`, this is factored out into shared stanzas.
Refinements are part of modules that provide additional instance methods on classes that can be brought into scope by `using` the module. Because refinements are not globally available, method resolution must carry scope of the call to allow finding refinements at the call site. A detailed example of refinement with the corresponding stack graph is included in `doc/refinement.png`.
Adds precedence attributes to prefer local definitions (inside a module or class body) over definitions from the surrounding context. It also makes nested class or module definitions available in the lexical scope of the containing class or module body, so they can be referred to unqualified.
… test for method nemaes
…xt is not refined. An additional "<using>" pop symbol node is added as a guard to prevent path searches from exploring "<refine>" subgraphs when not needed (i.e. when the reference context is not using a refinement). Co-authored-by: Hendrik van Antwerpen <[email protected]>
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
No description provided.