Where did you COME FROM? INTERCAL is a wonderful language, but it is not always easy to understand other people's code. This is particularly the case if they use the COME FROM statement.



Challenge definition


Write a program or function which take the source code of an INTERCAL program as a text/data stream. If you write a function it is recommended that you also provide a program to call the function, but it will not count towards your score.
The function output will be a text/data stream of the jumps that program makes, according to the following instructions. The output does not need to be printed, but it does need to be a single text, not an array of strings (for example).
Each line of output will consist of the statement which will be COME FROM and the line number of its COME FROM statement, separated by a -&gt;. An example:

(310)   DO .4 &lt;- .3 -&gt; 55

You can trim these lines of source code, but it is not necessary to.
The test cases will only consist of noncomputed labels (i.e., integer labels).
The output must be sorted by the source code order of the statements which will be COME FROM, not their label, nor the order of the COME FROM statements or their labels.
It is possible for multiple statements to COME FROM the same label. In such cases the COME FROM line numbers must be sorted, and separated by commas.
It is possible for a statement to COME FROM itself.
A COME FROM statement may be prefixed with a NOT statement. In such cases the line number must be wrapped in square brackets.
The words COME FROM can appear in a comment and must be ignored. You do not need to fully parse the file: if they are followed by a label (a number in parentheses) then you can assume it is a real statement.


Scoring

Entrants will be scored by the character length of their program or function.

Test cases

These test cases all come from the calvinmetcalf/intercal Github repo. Although any useful application will safely accept any input, for the purposes of this challenge you need only account for these five test cases.

rot13.i

(10) PLEASE DON'T GIVE UP -&gt; 87
(33) DON'T GIVE UP -&gt; 92


primes.i

(15)    DO (13) NEXT -&gt; 26
(16)    DO .12 &lt;- .1 -&gt; 6
(23)    DO (21) NEXT -&gt; 3


unlambda.i

(7202)  DO RETRIEVE .203+,202 -&gt; 75
(4202)  DO ,202SUB.201.202#7 &lt;- ,201SUB.201.202#7 -&gt; 108
(6202)  DO ,201SUB.201.202#7 &lt;- ,202SUB.201.202#7 -&gt; 117
(4203)  DO READ OUT ,201SUB.201.202#7 -&gt; 133
(4302)  DO .302 &lt;- .2 -&gt; 181
(5410)  DO ,400SUB#124 &lt;- #4 $ #17 -&gt; 293
(3410)  PLEASE (4410) NEXT -&gt; 288
(5402)  DO (412) NEXT -&gt; 328
(4412)  PLEASE (3412) NEXT -&gt; 334
(3423)  DO FORGET #2 -&gt; 375
(4404)  DO RETRIEVE .311+.312 -&gt; 411
(5404)  PLEASE DO (414) NEXT -&gt; 430
(4434)  DO FORGET #1 -&gt; 441
(3454)  DO (103) NEXT -&gt; 451
(5502)  DO .512 &lt;- .312 -&gt; 520
(8503)  PLEASE RETRIEVE .311+.312 -&gt; 621
(7503)  DO (302) NEXT -&gt; 515
(3622)  DO (302) NEXT -&gt; 514
(603)   PLEASE FORGET #2 -&gt; 622


pass.i

(10)    DO  NOTHING -&gt; 5, 11
(20)    PLEASE  (100) NEXT -&gt; 6
(30)    PLEASE  (200) NEXT -&gt; 12
(103)   DO  (104) NEXT -&gt; 27
(104)   DO  (105) NEXT -&gt; 19
(1) DO  (2) NEXT -&gt; 36
(2) DO  (105) NEXT -&gt; 194
(202)   DO NOT  .2 &lt;- #2 AGAIN -&gt; [196]
(203)   DO  (204) NEXT -&gt; 167
(204)   DO  (205) NEXT -&gt; 159


continuation.i

(8201)  DO NOTHING -&gt; 165, 271
(8202)  PLEASE NOTE Fork threads, one dormant, one alive -&gt; 53, 58
(8211)  DO COME FROM (8211) -&gt; 60
(8216)  DO NOTHING -&gt; 71
(8215)  DO NOTHING -&gt; 68
(8217)  DO COME FROM (8217) AGAIN -&gt; 118
(8299)  DO COME FROM (8299) AGAIN -&gt; 141
(8274)  DO (8273) NEXT ONCE -&gt; 158
(8259)  PLEASE DO NOTHING -&gt; 166
(8276)  DO COME FROM (8276) AGAIN -&gt; 199
(8278)  PLEASE DO COME FROM (8278) AGAIN -&gt; 237
JavaScript, 232 bytes

function c(d){for(var l,o,f,c,p=/^.(\d+).+?$/gm,a=/(T\s+)?C.{7}M .(\d+)/g,r='';l=p.exec(d);)for(f=0;o=a.exec(d);)o[2]==l[1]&amp;&amp;(c=d.slice(0,o.index).split('\n').length,r+=f++?', ':'\n'+l[0]+' -&gt; ',r+=o[1]?'['+c+']':c);return r.trim()}


To be called with

var data = require( 'fs' ).readFileSync( process.argv[2] ).toString();
console.log( c( data ) );


Explanation

function c(d){
    for(
        // Initialise variables
        var l,o,f,c,p=/^.(\d+).+?$/gm,a=/(T\s+)?C.{7}M .(\d+)/g,r='';
        // Find lines beginning with a label
        l=p.exec(d);)
            for(
                // Reset a have-we-output-this-line flag
                f=0;
                // Find CALL FROM statements
                o=a.exec(d);)
                    // Filter to CALL FROM statements which have the current line
                    o[2]==l[1]&amp;&amp;(
                        // Calculate the line number of this CALL FROM statement
                        c=d.slice(0,o.index).split('\n').length,
                        // Concat the output for this line
                        r+=f++?', ':'\n'+l[0]+' -&gt; ',r+=o[1]?'['+c+']':c);
    // Trim an initial new line
    return r.trim()}