Skip to content

[Query] Inspect Recursive Functions

github-actions[bot] edited this page Oct 30, 2026 · 1 revision

Generated from 'wiki-query.ts' on 2026-10-27, 21:18:48 UTC (v2.16.7), do not edit directly.

Inspect Recursive Functions Query [overview]

Determine whether functions are recursive
This query is requested with the type inspect-recursion.
Run in the REPL: :query @inspect-recursion [(<crit>;...)] <code | file://path>

With this query you can identify which functions in the code are recursive. Please note, that functions that may be recursive due to indirect calls are also considered recursive.

Using the example code fact <- function(n) { if(n <= 1) 1 else n * fact(n - 1) } the following query returns the information for all identified function definitions whether they are recursive:

[ { "type": "inspect-recursion" } ]

(This can be shortened to @inspect-recursion when used with the REPL command :query).

Results (prettified and summarized):

Query: inspect-recursion
  - Function 21 (1.9-57) is recursive

Show Detailed Results as Json

The analysis ran (including parsing and normalization and the query) within the generation environment.

The JSON contains the ids of the nodes in question (see the Interface wiki page).

{"inspect-recursion":{".meta":{},"recursive":{"21":true}},".meta":{}}
Original Code
fact <- function(n) { if(n <= 1) 1 else n * fact(n - 1) }
Dataflow Graph of the R Code

The analysis ran (parse and normalize with the r-shell engine) in the generation environment. No signature database is mounted, so library() attaches no exports (base-R names are still qualified, e.g., stats::acf). We encountered no unknown side effects during the analysis.

flowchart LR
    21["`*#91;RFunctionDefinition#93;* **function**
      *1.9-57* (**id: 21**)`"]

subgraph "flow-21" [function 21]
    1["`*#91;RSymbol#93;* **n**
      *1.18* (**id: 1**, v: )`"]
    5(["`*#91;RSymbol#93;* **n**
      *1.26* (**id: 5**)`"])
    6{{"`*#91;RNumber#93;* **1**
      *1.31* (**id: 6**)`"}}
    7[["`*#91;RBinaryOp#93;* base#58;#58;**#60;=**
      *1.26-31* (**id: 7**)
    arg: (5, 6)`"]]
    built-in:_60__61_["`Built-In:
#60;=`"]
    style built-in:_60__61_ stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    8{{"`*#91;RNumber#93;* **1**
      *1.34* (**id: 8**, 19+)`"}}
    10(["`*#91;RSymbol#93;* **n**
      *1.41* (**id: 10**)`"])
    12(["`*#91;RSymbol#93;* **n**
      *1.50* (**id: 12**, 16+)`"])
    13{{"`*#91;RNumber#93;* **1**
      *1.54* (**id: 13**, 16+)`"}}
    14[["`*#91;RBinaryOp#93;* base#58;#58;**#45;**
      *1.50-54* (**id: 14**, 16+, 19-)
    arg: (12, 13)`"]]
    built-in:-["`Built-In:
#45;`"]
    style built-in:- stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    %% Environment of 16 [level: 1]:
    %% Built-in
    %% 1----------------------------------------
    %% 2----------------------------------------
    %%   n: {**n** (id: 1, type: Parameter, def. @2)}
    16[["`*#91;RFunctionCall#93;* **fact**
      *1.45-55* (**id: 16**, 19-)
    arg: (14)`"]]
    17[["`*#91;RBinaryOp#93;* base#58;#58;**#42;**
      *1.41-55* (**id: 17**, 19-)
    arg: (10, 16)`"]]
    built-in:_42_["`Built-In:
#42;`"]
    style built-in:_42_ stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    19[["`*#91;RIfThenElse#93;* base#58;#58;**if**
      *1.23-55* (**id: 19**)
    arg: (7, 8, 17)`"]]
    built-in:if["`Built-In:
if`"]
    style built-in:if stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    20[["`*#91;RExpressionList#93;* base#58;#58;**#123;**
      *1.21* (**id: 20**)
    arg: (19)`"]]
    built-in:_123_["`Built-In:
#123;`"]
    style built-in:_123_ stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    style 8 stroke:purple,stroke-width:4px; 
end
    0["`*#91;RSymbol#93;* **fact**
      *1.1-4* (**id: 0**, v: 21)`"]
    22[["`*#91;RBinaryOp#93;* base#58;#58;**#60;#45;**
      *1.1-57* (**id: 22**)
    arg: (0, 21)`"]]
    built-in:_60_-["`Built-In:
#60;#45;`"]
    style built-in:_60_- stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    1 -.->|"flow"| 5
    linkStyle 0 stroke:gray,color:gray;
    1 -->|"def-by-on-call"| 14
    5 -->|"reads"| 1
    5 -.->|"flow"| 6
    linkStyle 3 stroke:gray,color:gray;
    6 -.->|"flow"| 7
    linkStyle 4 stroke:gray,color:gray;
    7 -->|"reads, arg"| 5
    7 -->|"reads, arg"| 6
    7 -.->|"branch (when: true)"| 8
    linkStyle 7 stroke:gray,color:gray;
    7 -.->|"branch (when: false)"| 10
    linkStyle 8 stroke:gray,color:gray;
    7 -.->|"reads, calls"| built-in:_60__61_
    linkStyle 9 stroke:gray;
    8 -.->|"flow"| 19
    linkStyle 10 stroke:gray,color:gray;
    10 -->|"reads"| 1
    10 -.->|"flow"| 12
    linkStyle 12 stroke:gray,color:gray;
    12 -->|"reads"| 1
    12 -.->|"flow"| 13
    linkStyle 14 stroke:gray,color:gray;
    13 -.->|"flow"| 14
    linkStyle 15 stroke:gray,color:gray;
    14 -->|"reads, arg"| 12
    14 -->|"reads, arg"| 13
    14 -.->|"reads, calls"| built-in:-
    linkStyle 18 stroke:gray;
    14 -.->|"flow"| 16
    linkStyle 19 stroke:gray,color:gray;
    14 -->|"def-on-call"| 1
    16 -->|"reads, arg"| 14
    16 -.->|"flow"| 17
    linkStyle 22 stroke:gray,color:gray;
    16 -->|"calls"| 21
    16 -->|"returns"| 19
    17 -->|"reads, arg"| 10
    17 -->|"reads, arg"| 16
    17 -.->|"reads, calls"| built-in:_42_
    linkStyle 27 stroke:gray;
    17 -.->|"flow"| 19
    linkStyle 28 stroke:gray,color:gray;
    19 -->|"returns, arg"| 8
    19 -->|"returns, arg"| 17
    19 -->|"reads, arg"| 7
    19 -.->|"reads, calls"| built-in:if
    linkStyle 32 stroke:gray;
    19 -.->|"flow"| 20
    linkStyle 33 stroke:gray,color:gray;
    20 -->|"returns, arg"| 19
    20 -.->|"reads, calls"| built-in:_123_
    linkStyle 35 stroke:gray;
21 -.-|function| flow-21

    21 -.->|"flow"| 0
    linkStyle 37 stroke:gray,color:gray;
    0 -->|"defined-by, flow"| 22
    0 -->|"defined-by"| 21
    22 -->|"reads, arg"| 21
    22 -->|"returns, arg"| 0
    22 -.->|"reads, calls"| built-in:_60_-
    linkStyle 42 stroke:gray;
Loading

This query also supports a slicing criterion based query mode that only returns information for functions matching the given criteria:

[
  {
    "type": "inspect-recursion",
    "filter": [
      "1@function"
    ]
  }
]

(This can be shortened to @inspect-recursion (1@function) "fact <- function(n) { if(n <= 1) 1 else n * fact(n - 1) }" when used with the REPL command :query).

Results (prettified and summarized):

Query: inspect-recursion
  - Function 21 (1.9-57) is recursive

Show Detailed Results as Json

The analysis ran (including parsing and normalization and the query) within the generation environment.

The JSON contains the ids of the nodes in question (see the Interface wiki page).

{"inspect-recursion":{".meta":{},"recursive":{"21":true}},".meta":{}}
Original Code
fact <- function(n) { if(n <= 1) 1 else n * fact(n - 1) }
Dataflow Graph of the R Code

The analysis ran (parse and normalize with the r-shell engine) in the generation environment. No signature database is mounted, so library() attaches no exports (base-R names are still qualified, e.g., stats::acf). We encountered no unknown side effects during the analysis.

flowchart LR
    21["`*#91;RFunctionDefinition#93;* **function**
      *1.9-57* (**id: 21**)`"]

subgraph "flow-21" [function 21]
    1["`*#91;RSymbol#93;* **n**
      *1.18* (**id: 1**, v: )`"]
    5(["`*#91;RSymbol#93;* **n**
      *1.26* (**id: 5**)`"])
    6{{"`*#91;RNumber#93;* **1**
      *1.31* (**id: 6**)`"}}
    7[["`*#91;RBinaryOp#93;* base#58;#58;**#60;=**
      *1.26-31* (**id: 7**)
    arg: (5, 6)`"]]
    built-in:_60__61_["`Built-In:
#60;=`"]
    style built-in:_60__61_ stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    8{{"`*#91;RNumber#93;* **1**
      *1.34* (**id: 8**, 19+)`"}}
    10(["`*#91;RSymbol#93;* **n**
      *1.41* (**id: 10**)`"])
    12(["`*#91;RSymbol#93;* **n**
      *1.50* (**id: 12**, 16+)`"])
    13{{"`*#91;RNumber#93;* **1**
      *1.54* (**id: 13**, 16+)`"}}
    14[["`*#91;RBinaryOp#93;* base#58;#58;**#45;**
      *1.50-54* (**id: 14**, 16+, 19-)
    arg: (12, 13)`"]]
    built-in:-["`Built-In:
#45;`"]
    style built-in:- stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    %% Environment of 16 [level: 1]:
    %% Built-in
    %% 1----------------------------------------
    %% 2----------------------------------------
    %%   n: {**n** (id: 1, type: Parameter, def. @2)}
    16[["`*#91;RFunctionCall#93;* **fact**
      *1.45-55* (**id: 16**, 19-)
    arg: (14)`"]]
    17[["`*#91;RBinaryOp#93;* base#58;#58;**#42;**
      *1.41-55* (**id: 17**, 19-)
    arg: (10, 16)`"]]
    built-in:_42_["`Built-In:
#42;`"]
    style built-in:_42_ stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    19[["`*#91;RIfThenElse#93;* base#58;#58;**if**
      *1.23-55* (**id: 19**)
    arg: (7, 8, 17)`"]]
    built-in:if["`Built-In:
if`"]
    style built-in:if stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    20[["`*#91;RExpressionList#93;* base#58;#58;**#123;**
      *1.21* (**id: 20**)
    arg: (19)`"]]
    built-in:_123_["`Built-In:
#123;`"]
    style built-in:_123_ stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    style 8 stroke:purple,stroke-width:4px; 
end
    0["`*#91;RSymbol#93;* **fact**
      *1.1-4* (**id: 0**, v: 21)`"]
    22[["`*#91;RBinaryOp#93;* base#58;#58;**#60;#45;**
      *1.1-57* (**id: 22**)
    arg: (0, 21)`"]]
    built-in:_60_-["`Built-In:
#60;#45;`"]
    style built-in:_60_- stroke:gray,fill:gray,stroke-width:2px,opacity:.8;
    1 -.->|"flow"| 5
    linkStyle 0 stroke:gray,color:gray;
    1 -->|"def-by-on-call"| 14
    5 -->|"reads"| 1
    5 -.->|"flow"| 6
    linkStyle 3 stroke:gray,color:gray;
    6 -.->|"flow"| 7
    linkStyle 4 stroke:gray,color:gray;
    7 -->|"reads, arg"| 5
    7 -->|"reads, arg"| 6
    7 -.->|"branch (when: true)"| 8
    linkStyle 7 stroke:gray,color:gray;
    7 -.->|"branch (when: false)"| 10
    linkStyle 8 stroke:gray,color:gray;
    7 -.->|"reads, calls"| built-in:_60__61_
    linkStyle 9 stroke:gray;
    8 -.->|"flow"| 19
    linkStyle 10 stroke:gray,color:gray;
    10 -->|"reads"| 1
    10 -.->|"flow"| 12
    linkStyle 12 stroke:gray,color:gray;
    12 -->|"reads"| 1
    12 -.->|"flow"| 13
    linkStyle 14 stroke:gray,color:gray;
    13 -.->|"flow"| 14
    linkStyle 15 stroke:gray,color:gray;
    14 -->|"reads, arg"| 12
    14 -->|"reads, arg"| 13
    14 -.->|"reads, calls"| built-in:-
    linkStyle 18 stroke:gray;
    14 -.->|"flow"| 16
    linkStyle 19 stroke:gray,color:gray;
    14 -->|"def-on-call"| 1
    16 -->|"reads, arg"| 14
    16 -.->|"flow"| 17
    linkStyle 22 stroke:gray,color:gray;
    16 -->|"calls"| 21
    16 -->|"returns"| 19
    17 -->|"reads, arg"| 10
    17 -->|"reads, arg"| 16
    17 -.->|"reads, calls"| built-in:_42_
    linkStyle 27 stroke:gray;
    17 -.->|"flow"| 19
    linkStyle 28 stroke:gray,color:gray;
    19 -->|"returns, arg"| 8
    19 -->|"returns, arg"| 17
    19 -->|"reads, arg"| 7
    19 -.->|"reads, calls"| built-in:if
    linkStyle 32 stroke:gray;
    19 -.->|"flow"| 20
    linkStyle 33 stroke:gray,color:gray;
    20 -->|"returns, arg"| 19
    20 -.->|"reads, calls"| built-in:_123_
    linkStyle 35 stroke:gray;
21 -.-|function| flow-21

    21 -.->|"flow"| 0
    linkStyle 37 stroke:gray,color:gray;
    0 -->|"defined-by, flow"| 22
    0 -->|"defined-by"| 21
    22 -->|"reads, arg"| 21
    22 -->|"returns, arg"| 0
    22 -.->|"reads, calls"| built-in:_60_-
    linkStyle 42 stroke:gray;
Loading
Implementation Details

The Inspect Recursive Functions Query is executed by executor.

Clone this wiki locally