names ← {expr←0} ##.externs dfn             ⍝ External references from dfn ⍵.

By default, [externs] takes the _name_ of a dfn and returns a vector of the non-
local names it references.  If left argument [expr] is set, the  right  argument
character  vector is taken to be an expression, rather than a function name.

    externs'test'                   ⍝ external references from function "test"
┌───────┬────┬─────────┐
│scripts│disp│timestamp│
└───────┴────┴─────────┘

    1 externs'sum←⍵ ⋄ sum÷num'      ⍝ external references from expression
┌───┐
│num│
└───┘

See also →fnrefs←, which does a better job for tradfns but not so well for dfns.

Technical notes:

[externs]  uses 60⌶ to produce a nested vector of token vectors for the  subject
function ⍵.

    sample←{       ⍝ sample
        succ←{1+⍵}
        pred←{⍵-1}
        (aaa ccc)←⍺ ⍵
        aaa+bbb×succ pred ccc
    }

    60⌶⎕nr'sample'
┌─────────────────────┬──────────────────┬──────────────────┬───────────────────┬───────────────────────────┬───┐
│┌──────┬─┬─┬────────┐│┌────┬─┬─┬─┬─┬─┬─┐│┌────┬─┬─┬─┬─┬─┬─┐│┌─┬───┬───┬─┬─┬─┬─┐│┌───┬─┬───┬─┬────┬────┬───┐│┌─┐│
││sample│←│{│⍝ sample│││succ│←│{│1│+│⍵│}│││pred│←│{│⍵│-│1│}│││(│aaa│ccc│)│←│⍺│⍵│││aaa│+│bbb│×│succ│pred│ccc│││}││
│└──────┴─┴─┴────────┘│└────┴─┴─┴─┴─┴─┴─┘│└────┴─┴─┴─┴─┴─┴─┘│└─┴───┴───┴─┴─┴─┴─┘│└───┴─┴───┴─┴────┴────┴───┘│└─┘│
└─────────────────────┴──────────────────┴──────────────────┴───────────────────┴───────────────────────────┴───┘

[clean] takes these tokens vectors and joins them into a single vector of tokens
with diamonds between the lines.  In addition,  "comment" tokens and parenthesis
tokens are removed.  For the purposes of extern's analysis, the nesting of names
to  the left of an assignment arrow (such(as this))← is irrlevant and can be ig-
nored.

    clean toks
┌──────┬─┬─┬─┬────┬─┬─┬─┬─┬─┬─┬─┬────┬─┬─┬─┬─┬─┬─┬─┬───┬───┬─┬─┬─┬─┬───┬─┬───┬─┬────┬────┬───┬─┬─┐
│sample│←│{│⋄│succ│←│{│1│+│⍵│}│⋄│pred│←│{│⍵│-│1│}│⋄│aaa│ccc│←│⍺│⍵│⋄│aaa│+│bbb│×│succ│pred│ccc│⋄│}│
└──────┴─┴─┴─┴────┴─┴─┴─┴─┴─┴─┴─┴────┴─┴─┴─┴─┴─┴─┴─┴───┴───┴─┴─┴─┴─┴───┴─┴───┴─┴────┴────┴───┴─┴─┘

There may be a small performance gain to be had, at the expense of a little add-
itional complexity, by having [clean] remove surplus diamond tokens.

    ⋄ ⋄ → ⋄ ─┐
    ⋄ } → }  ├─ surplus diamond removal
    ( ⋄ → { ─┘

    rmsd←{(⍺⍺~(,¨⍺)⍷⍵)/⍵}           ⍝ without surplus diamonds
    rmdd←'⋄⋄'∘(⊢rmsd)               ⍝   ⋄⋄ → ⋄
    rmdb←'⋄}'∘(⊢rmsd)               ⍝   ⋄} → }
    rmbd←'{⋄'∘((¯1∘⌽)rmsd)          ⍝   {⋄ → {

[nest] folds the tokens vector so that inner dfns become items of their contain-
ing outer functions.

┌──────┬─┬─────────────────────────────────────────────────────────────────────────────────┐
│sample│←│┌─┬────┬─┬───────┬─┬────┬─┬───────┬─┬───┬───┬─┬─┬─┬─┬───┬─┬───┬─┬────┬────┬───┬─┐│
│      │ ││⋄│succ│←│┌─┬─┬─┐│⋄│pred│←│┌─┬─┬─┐│⋄│aaa│ccc│←│⍺│⍵│⋄│aaa│+│bbb│×│succ│pred│ccc│⋄││
│      │ ││ │    │ ││1│+│⍵││ │    │ ││⍵│-│1││ │   │   │ │ │ │ │   │ │   │ │    │    │   │ ││
│      │ ││ │    │ │└─┴─┴─┘│ │    │ │└─┴─┴─┘│ │   │   │ │ │ │ │   │ │   │ │    │    │   │ ││
│      │ │└─┴────┴─┴───────┴─┴────┴─┴───────┴─┴───┴───┴─┴─┴─┴─┴───┴─┴───┴─┴────┴────┴───┴─┘│
└──────┴─┴─────────────────────────────────────────────────────────────────────────────────┘

[nest] also reorganises token order so that inner dfn items  move  to  the  end.
This  is so that forward references from within such functions are not viewed as
external references. A similar techique is used in kind-colouring function →kk←.

    nest clean toks         ⍝ inner dfns moved to the end
┌──────┬─┬─────────────────────────────────────────────────────────────────────────────────┐
│sample│←│┌─┬────┬─┬─┬────┬─┬─┬───┬───┬─┬─┬─┬─┬───┬─┬───┬─┬────┬────┬───┬─┬───────┬───────┐│
│      │ ││⋄│succ│←│⋄│pred│←│⋄│aaa│ccc│←│⍺│⍵│⋄│aaa│+│bbb│×│succ│pred│ccc│⋄│┌─┬─┬─┐│┌─┬─┬─┐││
│      │ ││ │    │ │ │    │ │ │   │   │ │ │ │ │   │ │   │ │    │    │   │ ││1│+│⍵│││⍵│-│1│││
│      │ ││ │    │ │ │    │ │ │   │   │ │ │ │ │   │ │   │ │    │    │   │ │└─┴─┴─┘│└─┴─┴─┘││
│      │ │└─┴────┴─┴─┴────┴─┴─┴───┴───┴─┴─┴─┴─┴───┴─┴───┴─┴────┴────┴───┴─┴───────┴───────┘│
└──────┴─┴─────────────────────────────────────────────────────────────────────────────────┘

Finally, [exts] performs a depth-first traversal of the  nested  tokens  vector,
collecting external references.  This  is  achieved with a left-to-right →foldl←
reduction, with accumulating left argument tuple (A L G):

    X Extern names: those still pending at end-of-segment '⋄' or ':' token.
    L Local names: on finding a '←' token, pending names are moved here.
    P Pending names encountered in left-to-right traversal.

On completion of the depth-first traversal  of the whole function, any names re-
maining in the X accumulator are judged external and returned as result.

Bug:

[externs] is confused by some dotted expressions:

    memo←{                                        ⍝ Function memoization.
        ⍺←⊢                                       ⍝ ambi-valent.
        (⊂⍺ ⍵ ⍵)∊⍵⍵.keys:⍵⍵.((keys⍳⊂⍺ ⍵ ⍵)⊃vals)  ⍝ arg(s) known: fetch result.
        ↑⍬⍴⍵⍵.(vals keys),∘⊂←(⍺ ⍺⍺ ⍵)(⍺ ⍵ ⍵)      ⍝ else: calc & extend cache.
    }

    externs'memo'
┌────┐
│vals│
└────┘

Examples:

    externs'test'           ⍝ test refers to scripts, disp and timestamp
┌───────┬────┬─────────┐
│scripts│disp│timestamp│
└───────┴────┴─────────┘

    externs'externs'        ⍝ externs makes no external references


    ⍕↑{(×≢¨⍵)/↓⍉↑⍺⍵}∘(externs¨)⍨ ⎕nl -3 4   ⍝ all dfns/ops with extern refs
 UndoRedo   redo
 ascana     ascan
 cal        days  date
 compidn    days
 cxdraw     f.Coord
 defs       ⎕SE.Dyalog.Utils.repObj  externs
 esh        ratsum
 index      ltov  lcase  dxb
 joy        nats
 kk         kind  tokens
 memo       vals
 parse      disp  segs  subs
 rats       factors
 scc        dsp
 ssmat      ss
 ssword     words
 stamps     path
 test       scripts  disp  timestamp
 von        lcase  ucase
 wrapnote   vtrim  squeeze  wrap  justify
 xpower     xtimes

See also: defs fnrefs

Back to: contents

Back to: Workspaces