Skip to content

Commit 507f8c9

Browse files
committed
feat: Support the compiler directive statements eclipse-che4z#116
Signed-off-by: ap891843 <[email protected]>
1 parent feb2887 commit 507f8c9

22 files changed

+530
-80
lines changed

server/src/main/antlr4/org/eclipse/lsp/cobol/core/parser/CICSParser.g4

+1-1
Original file line numberDiff line numberDiff line change
@@ -931,7 +931,7 @@ cobolWord
931931
| ABEND | ABORT | AS | ASCII | ASSOCIATED_DATA | ASSOCIATED_DATA_LENGTH | ATTACH
932932
| BINARY | BIND | BIT | BLOB | BOUNDS
933933
| CAPABLE | CCSVERSION | CHANGE | CHANGED | CHANNEL | CHECK | CLOB | CLOSE_DISPOSITION | COBOL | CODE | COMMIT | COMMITMENT | CONVENTION | COUNT | CRUNCH | CURRENT | CURSOR
934-
| DBCLOB | DEFAULT | DEFAULT_DISPLAY | DEFINITION | DFHRESP | DFHVALUE | DISK | DOUBLE | DUMP
934+
| DBNAME | DBCLOB | DEFAULT | DEFAULT_DISPLAY | DEFINITION | DFHRESP | DFHVALUE | DISK | DOUBLE | DUMP
935935
| EBCDIC | ENTER | ERASE | ESCAPE | EVENT | EXCLUSIVE | EXITS | EXTENDED
936936
| FINISH | FUNCTION_POINTER
937937
| IDMS | IGNORED | IMPLICIT | INTEGER | INVOKED| IN

server/src/main/antlr4/org/eclipse/lsp/cobol/core/parser/CobolLexer.g4

+71-1
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,59 @@
1515
lexer grammar CobolLexer;
1616
import CICSLexer;
1717
channels{TECHNICAL}
18+
@header {
19+
import java.util.regex.Matcher;
20+
import java.util.regex.Pattern;
21+
import org.apache.commons.lang3.StringUtils;
22+
}
23+
@lexer::members {
24+
private Pattern titlePattern = Pattern.compile("TITLE\\s*(.*?)\\.?\\s\\n.*", Pattern.CASE_INSENSITIVE);
25+
private void isTitlePresent() {
26+
String input = _input.getText(Interval.of(_tokenStartCharIndex, _input.index()));
27+
if(input!=null) {
28+
Matcher matcher = titlePattern.matcher(input);
29+
if(matcher.matches()){
30+
String matchedTitle = matcher.group(1);
31+
if(matchedTitle.isEmpty())
32+
reportWrongArguments("lexer.titleCompilerDirective");
33+
}
34+
}
35+
}
36+
private void reportWrongArguments(String msg) {
37+
ANTLRErrorListener listener = getErrorListenerDispatch();
38+
String text = _input.getText(Interval.of(_tokenStartCharIndex, _input.index()));
39+
int stop = _input.index();
40+
if(text.contains("\r")) {
41+
stop--;
42+
}
43+
CommonToken lspToken = new CommonTokenFactory().create(_tokenFactorySourcePair, _type, text,
44+
_channel, _input.index()-text.length()+1,
45+
stop,
46+
_tokenStartLine, _tokenStartCharPositionInLine);
47+
lspToken.setTokenIndex(_tokenStartCharPositionInLine);
48+
lspToken.setText(text.replace("\r","").replace("\n",""));
49+
listener.syntaxError(this, lspToken, _tokenStartLine,
50+
_tokenStartCharPositionInLine, msg, null);
51+
}
1852

19-
TITLESTATEMENT : (T I T L E ' '+ .*? NEWLINE) -> skip;
53+
private void isLanguageNamePresent() {
54+
String input = _input.getText(Interval.of(_tokenStartCharIndex, _input.index()))
55+
.replace("\r","").replace("\n","").trim();
56+
if(StringUtils.isBlank(input.substring(5, input.length()-1))) {
57+
reportWrongArguments("lexer.langMissingEnterDirective");
58+
}
59+
}
60+
}
2061

62+
// compiler directive tokens
63+
TITLESTATEMENT : (T I T L E ' '+ .*? NEWLINE) {isTitlePresent();} -> channel(TECHNICAL);
64+
65+
CONTROL_DIRECTIVE: ASTERISKCHAR (CONTROL | C B L) ((' '| COMMACHAR)
66+
(SOURCE | NO SOURCE | LIST | NO LIST | MAP | NO MAP
67+
| IDENTIFIER? {reportWrongArguments("lexer.controlDirectiveWrongArgs");})
68+
)+ DOT?-> channel(TECHNICAL);
69+
70+
ENTER_STMT: E N T E R ' '+ IDENTIFIER? {isLanguageNamePresent();} IDENTIFIER? DOT -> channel(TECHNICAL);
2171

2272
// keywords
2373
ACCEPT : A C C E P T;
@@ -49,6 +99,7 @@ BOTTOM : B O T T O M;
4999
BOUNDS : B O U N D S;
50100
BYFUNCTION : B Y F U N C T I O N;
51101
BYTITLE : B Y T I T L E;
102+
CALC : C A L C;
52103
CANCEL : C A N C E L;
53104
CAPABLE : C A P A B L E;
54105
CCSVERSION : C C S V E R S I O N;
@@ -91,7 +142,10 @@ CURRENCY : C U R R E N C Y;
91142
DATE_COMPILED : D A T E MINUSCHAR C O M P I L E D;
92143
DATE_WRITTEN : D A T E MINUSCHAR W R I T T E N;
93144
DAY_OF_WEEK : D A Y MINUSCHAR O F MINUSCHAR W E E K;
145+
DB_KEY : D B MINUSCHAR K E Y;
94146
DBCS : D B C S;
147+
DBNAME : D B N A M E;
148+
DBNODE : D B N O D E;
95149
DEBUGGING : D E B U G G I N G;
96150
DEBUG_CONTENTS : D E B U G MINUSCHAR C O N T E N T S;
97151
DEBUG_ITEM : D E B U G MINUSCHAR I T E M;
@@ -108,12 +162,15 @@ DEPENDING : D E P E N D I N G;
108162
DESCENDING : D E S C E N D I N G;
109163
DFHRESP : D F H R E S P;
110164
DFHVALUE : D F H V A L U E;
165+
DICTNAME : D I C T N A M E;
166+
DICTNODE : D I C T N O D E;
111167
DISK : D I S K;
112168
DISPLAY : D I S P L A Y;
113169
DISPLAY_1 : D I S P L A Y MINUSCHAR '1';
114170
DIVIDE : D I V I D E;
115171
DIVISION : D I V I S I O N;
116172
DOWN : D O W N;
173+
DUPLICATE : D U P L I C A T E;
117174
DUPLICATES : D U P L I C A T E S;
118175
EGCS : E G C S;
119176
EGI : E G I;
@@ -155,6 +212,7 @@ FD : F D;
155212
FILE_CONTROL : F I L E MINUSCHAR C O N T R O L;
156213
FILLER : F I L L E R;
157214
FINISH : F I N I S H;
215+
FIND : F I N D;
158216
FOOTING : F O O T I N G;
159217
FUNCTION_POINTER : F U N C T I O N MINUSCHAR P O I N T E R;
160218
GIVING : G I V I N G;
@@ -210,7 +268,9 @@ LR : L R;
210268
MAPS : M A P S;
211269
MAP_BINDS : MAP MINUSCHAR B I N D S;
212270
MANUAL : M A N U A L;
271+
MEMBERS : M E M B E R S;
213272
MEMORY : M E M O R Y;
273+
MODIFY : M O D I F Y;
214274
MODULES : M O D U L E S;
215275
MORE_LABELS : M O R E MINUSCHAR L A B E L S;
216276
MULTIPLE : M U L T I P L E;
@@ -225,6 +285,7 @@ NUMERIC_DATE : N U M E R I C MINUSCHAR D A T E;
225285
NUMERIC_EDITED : N U M E R I C MINUSCHAR E D I T E D;
226286
NUMERIC_TIME : N U M E R I C MINUSCHAR T I M E;
227287
OBJECT_COMPUTER : O B J E C T MINUSCHAR C O M P U T E R;
288+
OBTAIN : O B T A I N;
228289
OCCURS : O C C U R S;
229290
ODT : O D T;
230291
OMITTED : O M I T T E D;
@@ -235,8 +296,10 @@ OWN : O W N;
235296
PACKED_DECIMAL : P A C K E D MINUSCHAR D E C I M A L;
236297
PADDING : P A D D I N G;
237298
PAGE_COUNTER : P A G E MINUSCHAR C O U N T E R;
299+
PAGE_INFO : P A G E MINUSCHAR I N F O;
238300
PARSE: P A R S E;
239301
PERFORM : P E R F O R M;
302+
PERMANENT: P E R M A N E N T;
240303
PIC : P I C -> pushMode(PICTURECLAUSE);
241304
PICTURE : P I C T U R E -> pushMode(PICTURECLAUSE);
242305
POINTER : P O I N T E R;
@@ -250,13 +313,15 @@ PROCEDURE_POINTER : P R O C E D U R E MINUSCHAR P O I N T E R;
250313
PROCEED : P R O C E E D;
251314
PROCESSING: P R O C E S S I N G;
252315
PROGRAM_ID : P R O G R A M MINUSCHAR I D;
316+
PROTECTED : P R O T E C T E D;
253317
PTERM : P T E R M;
254318
PURGE : P U R G E;
255319
QUEUE : Q U E U E;
256320
QUOTE : Q U O T E;
257321
QUOTES : Q U O T E S;
258322
RANDOM : R A N D O M;
259323
READER : R E A D E R;
324+
READY : R E A D Y;
260325
RECEIVED : R E C E I V E D;
261326
RECORDING : R E C O R D I N G;
262327
RECURSIVE : R E C U R S I V E;
@@ -273,17 +338,20 @@ REPORTING : R E P O R T I N G;
273338
REPORTS : R E P O R T S;
274339
RERUN : R E R U N;
275340
RESERVE : R E S E R V E;
341+
RETRIEVAL : R E T R I E V A L;
276342
RETURNING: R E T U R N I N G;
277343
RETURN_CODE : R E T U R N MINUSCHAR C O D E;
278344
REVERSED : R E V E R S E D;
279345
ROUNDED : R O U N D E D;
346+
RUN_UNIT : R U N MINUSCHAR U N I T;
280347
SAME : S A M E;
281348
SAVE : S A V E;
282349
SCRATCH : S C R A T C H;
283350
SCREENSIZE : S C R E E N S I Z E;
284351
SD : S D;
285352
SEGMENT : S E G M E N T;
286353
SEGMENT_LIMIT : S E G M E N T MINUSCHAR L I M I T;
354+
SELECTIVE : S E L E C T I V E;
287355
SENTENCE : S E N T E N C E;
288356
SEPARATE : S E P A R A T E;
289357
SEQUENTIAL : S E Q U E N T I A L;
@@ -306,6 +374,7 @@ SORT_RETURN : S O R T MINUSCHAR R E T U R N;
306374
SOURCE_COMPUTER : S O U R C E MINUSCHAR C O M P U T E R;
307375
SPACES : S P A C E S;
308376
SPECIAL_NAMES : S P E C I A L MINUSCHAR N A M E S;
377+
STORE : S T O R E;
309378
SQLIMS : S Q L I M S;
310379
SUBSCHEMA_AREANAMES : SSMinusChar A R E A N A M E S;
311380
SUBSCHEMA_BINDS : SSMinusChar B I N D S;
@@ -356,6 +425,7 @@ UNIT : U N I T;
356425
UNSTRING : U N S T R I N G;
357426
UP : U P;
358427
UPON : U P O N;
428+
USAGE_MODE : U S A G E MINUSCHAR M O D E;
359429
UTF_8 : U T F MINUSCHAR '8';
360430
VALIDATING: V A L I D A T I N G;
361431
VIRTUAL : V I R T U A L;

server/src/main/antlr4/org/eclipse/lsp/cobol/core/parser/CobolParser.g4

+1-1
Original file line numberDiff line numberDiff line change
@@ -2232,4 +2232,4 @@ abbreviation
22322232
// comment entry
22332233
commentEntry
22342234
: COMMENTENTRYLINE+
2235-
;
2235+
;

server/src/main/antlr4/org/eclipse/lsp/cobol/core/parser/CobolPreprocessor.g4

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ parser grammar CobolPreprocessor;
1111
options {tokenVocab = CobolPreprocessorLexer;}
1212

1313
startRule
14-
: .*? ((compilerOptions | copyStatement | includeStatement | replaceArea)+ .*?)+ EOF
14+
: .*? ((compilerOptions | copyStatement | includeStatement | replaceArea )+ .*?)* EOF
1515
;
1616

1717
// compiler options

server/src/main/antlr4/org/eclipse/lsp/cobol/core/parser/CobolPreprocessorLexer.g4

+8
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,14 @@ lexer grammar CobolPreprocessorLexer;
2222
lastTokenText = token.getText();
2323
}
2424
}
25+
// compiler directive tokens
26+
TITLESTATEMENT : (T I T L E ' '+ .*? NEWLINE) ;
27+
28+
CONTROL_DIRECTIVE: ASTERISKCHAR (C O N T R O L | C B L) ((' '| COMMACHAR)
29+
(SOURCE | NO SOURCE | LIST | NO LIST | MAP | NO MAP
30+
| IDENTIFIER? ))+ DOT?;
31+
32+
ENTER_STMT: E N T E R ' '+ IDENTIFIER? IDENTIFIER? DOT ;
2533

2634
// keywords
2735
ACTIVITY : A C T I V I T Y {!sqlFlag}?;

server/src/main/java/org/eclipse/lsp/cobol/core/engine/CobolLanguageEngine.java

+40-3
Original file line numberDiff line numberDiff line change
@@ -39,10 +39,12 @@
3939
import org.antlr.v4.runtime.DefaultErrorStrategy;
4040
import org.antlr.v4.runtime.Token;
4141
import org.antlr.v4.runtime.tree.ParseTreeListener;
42+
import org.apache.commons.lang3.StringUtils;
4243

4344
import java.util.ArrayList;
4445
import java.util.List;
4546
import java.util.Map;
47+
import java.util.Optional;
4648
import java.util.function.Function;
4749
import java.util.function.Predicate;
4850
import java.util.stream.Stream;
@@ -104,6 +106,7 @@ public ResultWithErrors<SemanticContext> run(
104106

105107
CommonTokenStream tokens = new CommonTokenStream(lexer);
106108
ParserListener listener = new ParserListener();
109+
lexer.addErrorListener(listener);
107110

108111
CobolParser parser = getCobolParser(tokens);
109112
parser.removeErrorListeners();
@@ -157,7 +160,42 @@ private List<SyntaxError> finalizeErrors(
157160

158161
@NonNull
159162
private Function<SyntaxError, SyntaxError> convertError(@NonNull Map<Token, Locality> mapping) {
160-
return err -> err.toBuilder().locality(mapping.get(err.getOffendedToken())).build();
163+
return err ->
164+
err.toBuilder()
165+
.locality(
166+
mapping.getOrDefault(
167+
err.getOffendedToken(), getNearestLocality(err.getOffendedToken(), mapping)))
168+
.suggestion(convertErrorMessage(err.getSuggestion()))
169+
.build();
170+
}
171+
172+
private Locality getNearestLocality(
173+
@NonNull Token referenceToken, @NonNull Map<Token, Locality> mapping) {
174+
Optional<Locality> nearestToken =
175+
mapping.entrySet().stream()
176+
.filter(
177+
entry ->
178+
StringUtils.normalizeSpace(entry.getKey().getText())
179+
.contains(StringUtils.normalizeSpace(referenceToken.getText()))
180+
&& entry.getKey().getCharPositionInLine()
181+
== referenceToken.getCharPositionInLine()
182+
&& entry.getKey().getLine() == referenceToken.getLine()
183+
&& entry.getKey().getStartIndex() <= referenceToken.getStartIndex()
184+
&& entry.getKey().getStopIndex() >= referenceToken.getStopIndex())
185+
.map(Map.Entry::getValue)
186+
.findFirst();
187+
188+
return nearestToken.orElse(null); // null is safe here.
189+
}
190+
191+
private String convertErrorMessage(String suggestion) {
192+
String errorMessage;
193+
try {
194+
errorMessage = messageService.getMessage(suggestion);
195+
} catch (Exception e) {
196+
errorMessage = suggestion;
197+
}
198+
return errorMessage;
161199
}
162200

163201
private List<SyntaxError> collectErrorsForCopybooks(
@@ -174,8 +212,7 @@ private List<SyntaxError> raiseError(SyntaxError error, Map<String, Locality> co
174212
.filter(shouldRaise())
175213
.map(err -> err.toBuilder().locality(copyStatements.get(err.getLocality().getCopybookId())))
176214
.map(SyntaxError.SyntaxErrorBuilder::build)
177-
.map(err -> Stream.concat(raiseError(err, copyStatements).stream(), Stream.of(err)))
178-
.flatMap(Function.identity())
215+
.flatMap(err -> Stream.concat(raiseError(err, copyStatements).stream(), Stream.of(err)))
179216
.collect(toList());
180217
}
181218

server/src/main/java/org/eclipse/lsp/cobol/core/preprocessor/delegates/reader/CobolLineReaderDelegate.java

+23-8
Original file line numberDiff line numberDiff line change
@@ -15,19 +15,34 @@
1515

1616
package org.eclipse.lsp.cobol.core.preprocessor.delegates.reader;
1717

18+
import org.eclipse.lsp.cobol.core.model.ResultWithErrors;
1819
import lombok.NonNull;
1920

21+
import java.util.Collections;
22+
2023
/**
2124
* This interface represents a reader delegate that may apply some special operations over Strings
2225
*/
2326
public interface CobolLineReaderDelegate {
2427

25-
/**
26-
* Convert the line and apply any transformations if needed.
27-
*
28-
* @param line the initial line
29-
* @return converting result
30-
*/
31-
@NonNull
32-
String apply(@NonNull String line);
28+
/**
29+
* Convert the line and apply any transformations if needed.
30+
*
31+
* @param line the initial line
32+
* @return converting result
33+
*/
34+
@NonNull
35+
String apply(@NonNull String line);
36+
37+
/**
38+
*
39+
* @param line the initial line
40+
* @param uri document uri
41+
* @param lineNumber the lineNumber
42+
* @return converting result
43+
*/
44+
@NonNull
45+
default ResultWithErrors<String> apply(@NonNull String line, @NonNull String uri, @NonNull int lineNumber) {
46+
return new ResultWithErrors<>(apply(line), Collections.emptyList());
47+
}
3348
}

server/src/main/java/org/eclipse/lsp/cobol/core/preprocessor/delegates/reader/CobolLineReaderImpl.java

+14-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import org.eclipse.lsp4j.Position;
2525
import org.eclipse.lsp4j.Range;
2626

27+
import java.lang.invoke.MethodHandles;
2728
import java.util.*;
2829
import java.util.regex.Matcher;
2930
import java.util.regex.Pattern;
@@ -80,8 +81,9 @@ public ResultWithErrors<List<CobolLine>> processLines(
8081

8182
while (scanner.hasNextLine()) {
8283
currentLine = scanner.nextLine();
84+
String processedLine = delegate.apply(currentLine, documentURI, lineNumber).unwrap(accumulatedErrors::addAll);
8385
CobolLine currentCobolLine =
84-
parseLine(delegate.apply(currentLine), documentURI, lineNumber)
86+
parseLine(processedLine, documentURI, lineNumber)
8587
.unwrap(accumulatedErrors::addAll);
8688

8789
currentCobolLine.setPredecessor(lastCobolLine);
@@ -150,8 +152,17 @@ private ResultWithErrors<CobolLineTypeEnum> determineType(
150152
INDICATOR_AREA_INDEX + 1))));
151153
}
152154

155+
/**
156+
*
157+
* @param uri the document URI
158+
* @param message the error message
159+
* @param lineNumber the error lineNumber
160+
* @param start the error start position
161+
* @param stop the error stop position
162+
* @return the {@link SyntaxError}
163+
*/
153164
@NonNull
154-
private SyntaxError createError(
165+
public static SyntaxError createError(
155166
@NonNull String uri, @NonNull String message, int lineNumber, int start, int stop) {
156167
SyntaxError error =
157168
SyntaxError.syntaxError()
@@ -162,7 +173,7 @@ private SyntaxError createError(
162173
.uri(uri)
163174
.range(
164175
new Range(new Position(lineNumber, start), new Position(lineNumber, stop)))
165-
.recognizer(getClass())
176+
.recognizer(MethodHandles.lookup().lookupClass())
166177
.build())
167178
.build();
168179

0 commit comments

Comments
 (0)