Skip to content

feat(extract): add regex-based R (.r/.R) extractor (#1689)#1759

Open
Sanjays2402 wants to merge 1 commit into
Graphify-Labs:v8from
Sanjays2402:feat/r-extractor-1689
Open

feat(extract): add regex-based R (.r/.R) extractor (#1689)#1759
Sanjays2402 wants to merge 1 commit into
Graphify-Labs:v8from
Sanjays2402:feat/r-extractor-1689

Conversation

@Sanjays2402

@Sanjays2402 Sanjays2402 commented Jul 10, 2026

Copy link
Copy Markdown

Summary

Adds a real extractor for R (.r / .R), resolving the actionable half of #1689: R files were classified as code (.r is in CODE_EXTENSIONS) but had no extractor wired into _DISPATCH, so every R file silently contributed zero nodes to the graph. The #1689 warning (already at HEAD) surfaced the gap; this PR closes it.

Why regex, not tree-sitter

Unlike every other language graphify depends on, there is no standalone tree-sitter-r distribution on PyPI (tree-sitter-r / tree-sitter-rlang both 404; verified via the PyPI JSON API and pip index). The only pip-installable R grammar is the ~165-grammar tree-sitter-language-pack, which cuts hard against this repo's one-dedicated-wheel-per-language convention.

So this follows the existing regex-fallback precedent already used for Pascal (#781) and the non-tree-sitter path for DM (#1104): a self-contained, zero-dependency regex extractor in graphify/extractors/r.py. pyproject.toml is untouched — no new dependency.

An AST-quality upgrade is a clean future follow-up if/when a standalone R grammar wheel becomes available; the module is structured so that swap is localized.

What it extracts

Construct Example Emitted
Functions (all binding forms) f <- function(x), g = function(x), h <<- function(), k <- \(x) x contains node/edge
Package imports library(dplyr), require(ggplot2), requireNamespace(...), loadNamespace(...) imports (context=import)
File includes source("helpers.R") imports (context=import)
S4 / reference classes setClass("Circle", ...), setRefClass(...) contains node
S4 inheritance setClass("Circle", contains = "Shape") inherits edge
S4 generics setGeneric("area", ...) contains node
S4 methods setMethod("area", "Circle", ...) method edge (class → method)
Intra-file calls local fn → local fn calls (context=call)

The extractor is string- and comment-aware (a # inside a string literal is not a comment; braces/parens inside strings don't affect body-span matching), and skips accessor/namespace-qualified call targets (obj$m(), obj@m(), pkg::fn()) so only genuine local free-function calls become calls edges.

Wiring

  • graphify/extractors/r.py — new module (mirrors extractors/elixir.py layout, reuses base.py helpers _make_id / _file_stem).
  • extract.py — import + re-export extract_r; .r/.R_DISPATCH; language-name map entry; Rscript_SHEBANG_DISPATCH (so #!/usr/bin/env Rscript extensionless scripts route correctly); updated the #1689 warning comment (it no longer applies to .r).

Tests

  • tests/fixtures/sample.R — new fixture exercising every construct.
  • tests/test_languages.py12 new R tests (functions, \(x) lambda, imports incl. source(), S4 classes, inheritance, generics/methods, calls, call-context, no-dangling-edges).
  • tests/test_extract.py — updated the two tests that used .r/.R as their "code file with no AST extractor" example (that's no longer true) to use .ets (ArkTS), which remains genuinely unsupported.

Local run (on v8): tests/test_languages.py + tests/test_extract.py = 442 passed, 14 skipped, no regressions. The 12 new R tests and the two updated #1689 tests all pass.

Closes the extractor half of #1689.

@Sanjays2402 Sanjays2402 changed the base branch from main to v8 July 10, 2026 03:04
@Sanjays2402 Sanjays2402 force-pushed the feat/r-extractor-1689 branch from 648c4cd to 70159a1 Compare July 10, 2026 03:04
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.

1 participant