Skip to content
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
wants to merge 43 commits into
base: main
Choose a base branch
from
Draft

Conversation

hendrikvanantwerpen
Copy link
Collaborator

No description provided.

@hendrikvanantwerpen hendrikvanantwerpen changed the base branch from main to dev-deps May 12, 2023 12:36
@hendrikvanantwerpen
Copy link
Collaborator Author

@rewinfrey The project configuration I used doesn't work with main, but was based on the changes in #245. I've rebased and changed the target to that branch, and now the build errors are gone.

Base automatically changed from dev-deps to main May 12, 2023 17:18
hendrikvanantwerpen and others added 16 commits May 15, 2023 17:08
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.
hendrikvanantwerpen and others added 16 commits May 17, 2023 14:57
Modules behave very similarly to classes. For now we treat them the same
and share the logic for modules and classes.
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.
…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
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants