goto/jump/label support
ukanuk opened this issue · 1 comments
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
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] ;