andymass/vim-matchup

goto/jump/label support

Opened this issue · 1 comments

ukanuk commented

Is your feature request related to a problem? Please describe.
Goto/label statements are available in C++, Visual Basic, and other languages, too. I work with the FANUC TP language which unfortunately does not have good support for more sophisticated control structures and therefore goto/label statements are often more readable.

Describe the solution you'd like
A unique word or number allows goto statements and associated labels to be associated with each other. Matchup should highlight this association, and vim should let me jump between them with %. Note there can be multiple goto statements but only one label; with multiple goto statements, % should cycle through all the goto's and the label similar to how it cycles through an if-elseif-elseif-else-endif statement.

Describe alternatives you've considered
The best I've come up so far is this (for FANUC TP language), but it only highlights previous matches when I select the final LBL. It will not find the final label when I select initial JMP LBL statements. It works as expected for multiline IF statements and FOR loops (note FANUC TP also supports single-line IF statements, where if the result is true then it executes the following instruction which is JMP in this sample code).

let b:match_ignorecase = 1
let b:match_words = '\<IF\>.*:\<ELSE\>.*:\<ENDIF\>.*,'
  \ . '\<FOR\>.*:\<ENDFOR\>.*,'
  \ . 'LBL\[\(\d\+\):LBL\[\1'

Additional context
Goto/label statements in C++ https://en.cppreference.com/w/cpp/language/goto

#include <iostream>
 
struct Object
{
    // non-trivial destructor
    ~Object() { [std::cout](https://en.cppreference.com/w/cpp/io/cout) << 'd'; }
};
 
struct Trivial
{
    double d1;
    double d2;
}; // trivial ctor and dtor
 
int main()
{
    int a = 10;
 
    // loop using goto
label:
    Object obj;
    [std::cout](https://en.cppreference.com/w/cpp/io/cout) << a << ' ';
    a -= 2;
 
    if (a != 0)
        goto label;  // jumps out of scope of obj, calls obj destructor
    [std::cout](https://en.cppreference.com/w/cpp/io/cout) << '\n';
 
    // goto can be used to efficiently leave a multi-level (nested) loops
    for (int x = 0; x < 3; ++x)
        for (int y = 0; y < 3; ++y)
        {
            [std::cout](https://en.cppreference.com/w/cpp/io/cout) << '(' << x << ',' << y << ") " << '\n';
            if (x + y >= 3)
                goto endloop;
        }
 
endloop:
    [std::cout](https://en.cppreference.com/w/cpp/io/cout) << '\n';
 
    goto label2; // jumps into the scope of n and t
 
    [[maybe_unused]] int n; // no initializer
 
    [[maybe_unused]] Trivial t; // trivial ctor/dtor, no initializer
 
//  int x = 1;   // error: has initializer
//  Object obj2; // error: non-trivial dtor
 
label2:
    {
        Object obj3;
        goto label3; // jumps forward, out of scope of obj3
    }
 
label3:
    [std::cout](https://en.cppreference.com/w/cpp/io/cout) << '\n';
}

Goto/label statements in Visual Basic https://learn.microsoft.com/en-us/dotnet/visual-basic/language-reference/statements/goto-statement

Sub GoToStatementDemo()
        Dim number As Integer = 1
        Dim sampleString As String
        ' Evaluate number and branch to appropriate label.
        If number = 1 Then GoTo Line1 Else GoTo Line2
Line1:
        sampleString = "Number equals 1"
        GoTo LastLine
Line2:
        ' The following statement never gets executed because number = 1.
        sampleString = "Number equals 2"
LastLine:
        ' Write "Number equals 1" in the Debug window.
        Debug.WriteLine(sampleString)
    End Sub

JMP/LBL statements in FANUC TP sample code with valid syntax (yes, including the hardcoded line numbers starting partway through). Syntax is already mostly supported by https://github.com/KnoP-01/vim-tp, but I opened an issue with that project to improve matchup support.

/PROG  JMOVE
/ATTR
OWNER		= MNEDITOR;
COMMENT		= "";
PROG_SIZE	= 202;
CREATE		= DATE 23-06-22  TIME 09:24:12;
MODIFIED	= DATE 23-06-22  TIME 09:24:20;
FILE_NAME	= ;
VERSION		= 0;
LINE_COUNT	= 1;
MEMORY_SIZE	= 570;
PROTECT		= READ_WRITE;
TCD:  STACK_SIZE	= 0,
      TASK_PRIORITY	= 50,
      TIME_SLICE	= 0,
      BUSY_LAMP_OFF	= 0,
      ABORT_REQUEST	= 0,
      PAUSE_REQUEST	= 0;
DEFAULT_GROUP	= 1,*,*,*,*;
CONTROL_CODE	= 00000000 00000000;
LOCAL_REGISTERS	= 0,0,0;
/APPL
  SPOT Welding Equipment Number : 1 ;
/MN
   1:  !******************** ;
   2:  !MAIN SEQUENCE ;
   3:   ;
   4:  LBL[11:Main process] ;
   5:  !Do stuff ;
   6:   ;
   7:  !Error if timeout waiting for END ;
   8:  LBL[12] ;
   9:  WAIT (DI[1105:SIGNAL END]=ON) TIMEOUT,LBL[91] ;
  10:   ;
  11:  ! Good result = skip to end ;
  12:  LBL[13] ;
  13:  IF (DI[1118:RESULT GOOD]),JMP LBL[19] ;
  14:   ;
  15:  ! End of process cleanup ;
  16:  IF (GO[30:POSITION]<>0) THEN ;
  17:  FOR R[1]=1 TO 5 ;
  18:  !Do stuff ;
  19:  !Wait for input 1114 else error ;
  20:  LBL[17] ;
  21:  WAIT (DI[1114:PARTIAL POSITION]) TIMEOUT,LBL[92] ;
  22:  ENDFOR ;
  23:  ELSE ;
  24:  !Wait for positon=0 else error ;
  25:  LBL[18] ;
  26:  WAIT (DI[1113:HOME POSITION]) TIMEOUT,LBL[93] ;
  27:  ENDIF ;
  28:   ;
  29:  !End program normally ;
  30:  LBL[19:END PROCESS] ;
  31:  END ;
  32:   ;
  33:  !******************** ;
  34:  !ERROR HANDLING ;
  35:   ;
  36:  LBL[91:ERROR0] ;
  37:  LBL[92:ERROR1] ;
  38:  !Do error handling, then restart ;
  39:  JMP LBL[11] ;
  40:   ;
  41:  LBL[93:ERROR2] ;
  42:  !Do error handling, then resume ;
  43:  JMP LBL[12] ;
/POS
/END
ukanuk commented

Simplified FANUC TP example:

LBL[11:Main process] ;
WAIT (DI[1105:SIGNAL END]=ON) TIMEOUT,LBL[91] ;
WAIT (DI[1106:SIGNAL START]=OFF) TIMEOUT,LBL[91] ;
LBL[12] ;
IF (DI[1118:RESULT GOOD]),JMP LBL[19] ;
WAIT (DI[1114:PARTIAL POSITION]) TIMEOUT,LBL[92] ;
WAIT (DI[1113:HOME POSITION]) TIMEOUT,LBL[93] ;
LBL[19:END PROCESS] ;
END ;
LBL[91:ERROR0] ;
LBL[92:ERROR1] ;
JMP LBL[11] ;
LBL[93:ERROR2] ;
JMP LBL[12] ;