From 250b082479f354e6fd6f1a07088efd98d6b21bb7 Mon Sep 17 00:00:00 2001 From: Iurii Shchekochikhin Date: Wed, 29 May 2024 17:29:27 +0200 Subject: [PATCH] wip: implement some rules with nester statements for experimental parser --- .../lsp/cobol/core/visitor/CobolVisitor.java | 46 ++-- .../eclipse/lsp/cobol/cst/base/CstNode.java | 3 +- .../cobol/parser/hw/lexer/TokenScanner.java | 10 + .../lsp/cobol/parser/hw/lexer/TokenType.java | 1 + .../lsp/cobol/rules/CobolLanguage.java | 26 ++- .../lsp/cobol/rules/SourceUnitRule.java | 4 +- .../procedure/ArithmeticExpressionRule.java | 89 +++++++ .../procedure/ConditionExpressionRule.java | 69 +++--- .../cobol/rules/procedure/IdentifierRule.java | 81 +++++++ .../procedure/ProcedureDivisionRule.java | 2 +- .../cobol/rules/procedure/SentenceRule.java | 155 ++++++++++++- .../rules/procedure/statements/AddRule.java | 128 +++++++++++ .../rules/procedure/statements/CallRule.java | 217 ++++++++++++++++++ .../procedure/statements/ComputeRule.java | 81 +++++++ .../procedure/statements/DeleteRule.java | 79 +++++++ .../procedure/statements/DivideRule.java | 119 ++++++++++ .../procedure/statements/EvaluateRule.java | 135 +++++++++++ .../rules/procedure/statements/IfRule.java | 73 ++++++ .../statements/ImperativeStatementRule.java | 82 ------- .../procedure/statements/MultiplyRule.java | 81 +++++++ .../procedure/statements/PerformRule.java | 35 ++- .../rules/procedure/statements/ReadRule.java | 107 +++++++++ .../procedure/statements/ReturnRule.java | 77 +++++++ .../procedure/statements/RewriteRule.java | 77 +++++++ .../procedure/statements/SearchRule.java | 113 +++++++++ .../rules/procedure/statements/StartRule.java | 117 ++++++++++ .../procedure/statements/StringRule.java | 99 ++++++++ .../procedure/statements/SubtractRule.java | 121 ++++++++++ .../procedure/statements/UnstringRule.java | 144 ++++++++++++ .../rules/procedure/statements/WriteRule.java | 131 +++++++++++ .../java/org/eclipse/lsp/cobol/Case1Test.java | 77 +++++++ .../cobol/divisions/procedure/AddTest.java | 91 ++++++++ .../cobol/divisions/procedure/CallTest.java | 111 +++++++++ .../divisions/procedure/ComputeTest.java | 61 +++++ .../cobol/divisions/procedure/DeleteTest.java | 43 ++++ .../cobol/divisions/procedure/DivideTest.java | 76 ++++++ .../divisions/procedure/EndProgramTest.java | 10 +- .../divisions/procedure/EvaluateTest.java | 99 ++++++++ .../lsp/cobol/divisions/procedure/IfTest.java | 110 +++++++++ .../divisions/procedure/MultiplyTest.java | 55 +++++ .../cobol/divisions/procedure/ReadTest.java | 43 ++++ .../cobol/divisions/procedure/ReturnTest.java | 43 ++++ .../divisions/procedure/RewriteTest.java | 43 ++++ .../cobol/divisions/procedure/SearchTest.java | 62 +++++ .../cobol/divisions/procedure/StartTest.java | 73 ++++++ .../cobol/divisions/procedure/StringTest.java | 44 ++++ .../divisions/procedure/SubtractTest.java | 112 +++++++++ .../divisions/procedure/UnstringTest.java | 49 ++++ .../cobol/divisions/procedure/WriteTest.java | 55 +++++ .../PerformBasicStatementTest.java | 2 +- .../PerformTimesStatementTest.java | 2 +- .../PerformUntilStatementTest.java | 2 +- .../PerformVaryingStatementTest.java | 2 +- .../lsp/cobol/lexer/HwCobolLexerTest.java | 9 + .../cobol/lexer/NonNumericLiteralTest.java | 6 +- 55 files changed, 3586 insertions(+), 196 deletions(-) create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ArithmeticExpressionRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/IdentifierRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/AddRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/CallRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ComputeRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DeleteRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DivideRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/EvaluateRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/IfRule.java delete mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ImperativeStatementRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/MultiplyRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReadRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReturnRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/RewriteRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SearchRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StartRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StringRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SubtractRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/UnstringRule.java create mode 100644 server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/WriteRule.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/Case1Test.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/AddTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/CallTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ComputeTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DeleteTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DivideTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EvaluateTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/IfTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/MultiplyTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReadTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReturnTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/RewriteTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SearchTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StartTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StringTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SubtractTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/UnstringTest.java create mode 100644 server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/WriteTest.java rename server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/{ => perform}/PerformBasicStatementTest.java (97%) rename server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/{ => perform}/PerformTimesStatementTest.java (97%) rename server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/{ => perform}/PerformUntilStatementTest.java (99%) rename server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/{ => perform}/PerformVaryingStatementTest.java (98%) diff --git a/server/engine/src/main/java/org/eclipse/lsp/cobol/core/visitor/CobolVisitor.java b/server/engine/src/main/java/org/eclipse/lsp/cobol/core/visitor/CobolVisitor.java index ba190a0761..5f03abd07d 100644 --- a/server/engine/src/main/java/org/eclipse/lsp/cobol/core/visitor/CobolVisitor.java +++ b/server/engine/src/main/java/org/eclipse/lsp/cobol/core/visitor/CobolVisitor.java @@ -15,25 +15,8 @@ package org.eclipse.lsp.cobol.core.visitor; -import static java.util.Collections.emptyList; -import static java.util.Optional.ofNullable; -import static java.util.stream.Collectors.toList; -import static org.antlr.v4.runtime.Lexer.HIDDEN; -import static org.eclipse.lsp.cobol.common.OutlineNodeNames.FILLER_NAME; -import static org.eclipse.lsp.cobol.common.VariableConstants.*; -import static org.eclipse.lsp.cobol.core.CobolParser.*; -import static org.eclipse.lsp.cobol.core.visitor.VisitorHelper.*; - import com.google.common.collect.ImmutableList; - -import java.util.*; -import java.util.function.Function; -import java.util.function.Predicate; -import java.util.stream.Collectors; - -import lombok.Getter; import lombok.NonNull; -import lombok.extern.slf4j.Slf4j; import org.antlr.v4.runtime.CommonTokenStream; import org.antlr.v4.runtime.ParserRuleContext; import org.antlr.v4.runtime.RuleContext; @@ -44,13 +27,13 @@ import org.apache.commons.lang3.tuple.ImmutablePair; import org.eclipse.lsp.cobol.common.SubroutineService; import org.eclipse.lsp.cobol.common.dialects.CobolDialect; +import org.eclipse.lsp.cobol.common.dialects.CobolProgramLayout; import org.eclipse.lsp.cobol.common.error.ErrorSeverity; import org.eclipse.lsp.cobol.common.error.ErrorSource; import org.eclipse.lsp.cobol.common.error.SyntaxError; import org.eclipse.lsp.cobol.common.mapping.ExtendedDocument; import org.eclipse.lsp.cobol.common.message.MessageService; import org.eclipse.lsp.cobol.common.model.*; -import org.eclipse.lsp.cobol.common.model.SectionType; import org.eclipse.lsp.cobol.common.model.tree.*; import org.eclipse.lsp.cobol.common.model.tree.statements.SetToBooleanStatement; import org.eclipse.lsp.cobol.common.model.tree.statements.SetToOnOffStatement; @@ -61,19 +44,29 @@ import org.eclipse.lsp.cobol.common.utils.ImplicitCodeUtils; import org.eclipse.lsp.cobol.common.utils.StringUtils; import org.eclipse.lsp.cobol.core.*; -import org.eclipse.lsp.cobol.core.CobolDataDivisionParser; -import org.eclipse.lsp.cobol.core.CobolIdentificationDivisionParser; -import org.eclipse.lsp.cobol.core.CobolParser; -import org.eclipse.lsp.cobol.core.CobolParserBaseVisitor; import org.eclipse.lsp.cobol.core.semantics.CopybooksRepository; import org.eclipse.lsp.cobol.dialects.ibm.experimental.visitors.CobolDataDivisionVisitor; import org.eclipse.lsp.cobol.dialects.ibm.experimental.visitors.CobolIdentificationDivisionVisitor; import org.eclipse.lsp.cobol.dialects.ibm.experimental.visitors.CobolProcedureDivisionVisitor; import org.eclipse.lsp.cobol.service.settings.CachingConfigurationService; -import org.eclipse.lsp.cobol.common.dialects.CobolProgramLayout; import org.eclipse.lsp4j.Location; import org.eclipse.lsp4j.Position; import org.eclipse.lsp4j.Range; +import org.slf4j.Logger; + +import java.util.*; +import java.util.function.Function; +import java.util.function.Predicate; +import java.util.stream.Collectors; + +import static java.util.Collections.emptyList; +import static java.util.Optional.ofNullable; +import static java.util.stream.Collectors.toList; +import static org.antlr.v4.runtime.Lexer.HIDDEN; +import static org.eclipse.lsp.cobol.common.OutlineNodeNames.FILLER_NAME; +import static org.eclipse.lsp.cobol.common.VariableConstants.*; +import static org.eclipse.lsp.cobol.core.CobolParser.*; +import static org.eclipse.lsp.cobol.core.visitor.VisitorHelper.*; /** * This extension of {@link CobolParserBaseVisitor} applies the semantic analysis based on the @@ -81,10 +74,9 @@ * elements to add the usages or throw a warning on an invalid definition. If there is a misspelled * keyword, the visitor finds it and throws a warning. */ -@Slf4j public class CobolVisitor extends CobolParserBaseVisitor> { - @Getter + private static final Logger LOG = org.slf4j.LoggerFactory.getLogger(CobolVisitor.class); protected final List errors = new ArrayList<>(); protected final CopybooksRepository copybooks; protected final CommonTokenStream tokenStream; @@ -1488,4 +1480,8 @@ private Locality locationToLocality(Location location) { .copybookId(copybooks.getCopybookIdByUri(location.getUri())) .build(); } + + public List getErrors() { + return this.errors; + } } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/cst/base/CstNode.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/cst/base/CstNode.java index df44a77d1a..065600f094 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/cst/base/CstNode.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/cst/base/CstNode.java @@ -46,9 +46,8 @@ default List list(Class clazz) { for (CstNode child : getChildren()) { if (clazz.isInstance(child)) { result.add((T) child); - } else { - result.addAll(child.list(clazz)); } + result.addAll(child.list(clazz)); } return result; } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenScanner.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenScanner.java index a55b8c7384..986ad31b06 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenScanner.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenScanner.java @@ -91,6 +91,13 @@ public Token next() { } return start.produceToken(TokenType.OTHER); } + if (match('*')) { + forward(); + if (match('*')) { + forward(); + } + return start.produceToken(TokenType.OTHER); + } return cobolWord(start); } @@ -171,6 +178,9 @@ private Token cobolWord(Position start) { } } while (!isAtEnd() && isCobolWordSymbol()); + if (currentPosition.index - start.index == 1 && source.charAt(currentPosition.index - 1) == '.') { + return start.produceToken(TokenType.DOT); + } return start.produceToken(TokenType.COBOL_WORD); } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenType.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenType.java index 26d0d1b770..a40e57208e 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenType.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/parser/hw/lexer/TokenType.java @@ -25,6 +25,7 @@ public enum TokenType { NUMBER_LITERAL, COBOL_WORD, NEW_LINE, + DOT, OTHER, EOF } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/CobolLanguage.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/CobolLanguage.java index 1eeca0bc18..8d12dff6b8 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/CobolLanguage.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/CobolLanguage.java @@ -19,9 +19,7 @@ import org.eclipse.lsp.cobol.rules.environment.EnvironmentDivisionRule; import org.eclipse.lsp.cobol.rules.identification.IdentificationDivisionRule; import org.eclipse.lsp.cobol.rules.procedure.*; -import org.eclipse.lsp.cobol.rules.procedure.statements.ImperativeStatementRule; -import org.eclipse.lsp.cobol.rules.procedure.statements.MoveRule; -import org.eclipse.lsp.cobol.rules.procedure.statements.PerformRule; +import org.eclipse.lsp.cobol.rules.procedure.statements.*; /** A container for COBOL language grammar rules. */ public class CobolLanguage { @@ -42,10 +40,30 @@ public CobolLanguage() { languageRules.put(IdentificationDivisionRule.class, new IdentificationDivisionRule()); languageRules.put(SectionRule.class, new SectionRule()); languageRules.put(SentenceRule.class, new SentenceRule()); + languageRules.put(AddRule.class, new AddRule()); + languageRules.put(MultiplyRule.class, new MultiplyRule()); + languageRules.put(ComputeRule.class, new ComputeRule()); languageRules.put(PerformRule.class, new PerformRule()); + languageRules.put(IfRule.class, new IfRule()); languageRules.put(MoveRule.class, new MoveRule()); - languageRules.put(ImperativeStatementRule.class, new ImperativeStatementRule()); + languageRules.put(EvaluateRule.class, new EvaluateRule()); + languageRules.put(StringRule.class, new StringRule()); + languageRules.put(UnstringRule.class, new UnstringRule()); + languageRules.put(SearchRule.class, new SearchRule()); + languageRules.put(SubtractRule.class, new SubtractRule()); + languageRules.put(CallRule.class, new CallRule()); + languageRules.put(DivideRule.class, new DivideRule()); + languageRules.put(StartRule.class, new StartRule()); + languageRules.put(ReadRule.class, new ReadRule()); + languageRules.put(ReturnRule.class, new ReturnRule()); + languageRules.put(DeleteRule.class, new DeleteRule()); + languageRules.put(WriteRule.class, new WriteRule()); + languageRules.put(RewriteRule.class, new RewriteRule()); + + // Fragments languageRules.put(ConditionExpressionRule.class, new ConditionExpressionRule()); + languageRules.put(ArithmeticExpressionRule.class, new ArithmeticExpressionRule()); + languageRules.put(IdentifierRule.class, new IdentifierRule()); //// Reserved Words P. 761 // Arithmetic operator diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/SourceUnitRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/SourceUnitRule.java index dc9665b9f4..cec84d32ef 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/SourceUnitRule.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/SourceUnitRule.java @@ -20,8 +20,6 @@ import org.eclipse.lsp.cobol.parser.hw.lexer.Token; import org.eclipse.lsp.cobol.parser.hw.lexer.TokenType; -import java.util.Objects; - /** * COBOL language grammar rule class. */ @@ -66,7 +64,7 @@ private void synchronize(ParsingContext ctx) { } private boolean isContinuationSymbol(Token t) { - return Objects.equals(t.getLexeme(), "."); + return t.getType() == TokenType.DOT; } } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ArithmeticExpressionRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ArithmeticExpressionRule.java new file mode 100644 index 0000000000..125858c632 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ArithmeticExpressionRule.java @@ -0,0 +1,89 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure; + +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.parser.hw.lexer.TokenType; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; + +/** p. 266 */ +public class ArithmeticExpressionRule implements LanguageRule { + + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + arithmeticExpression(ctx, language); + } + + private void arithmeticExpression(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("(")) { + ctx.consume("("); + do { + arithmeticExpression(ctx, language); + } while (!ctx.match(")")); + ctx.consume(")"); + ctx.spaces(); + // p. 267 + if (ctx.match("+", "-", "*", "/", "**")) { + ctx.or("+", "-", "*", "/", "**"); + ctx.spaces(); + arithmeticExpression(ctx, language); + } + return; + } + + if (ctx.getLexer().peek().getType() == TokenType.NUMBER_LITERAL) { + ctx.consume(); + ctx.spaces(); + } else { + language.parseRule(IdentifierRule.class, ctx); + } + // p. 267 + if (ctx.match("+", "-", "*", "/", "**")) { + ctx.or("+", "-", "*", "/", "**"); + ctx.spaces(); + arithmeticExpression(ctx, language); + } + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + // An arithmetic expression can consist of any of the following items: + // 1. An identifier described as a numeric elementary item (including numeric functions) + if (language.tryMatchRule(IdentifierRule.class, ctx)) { + return true; + } + // 2. A numeric literal + if (ctx.getLexer().peek().getType() == TokenType.NUMBER_LITERAL) { + return true; + } + // 3. The figurative constant ZERO + if (ctx.match("ZERO")) { + return true; + } + // 4. Identifiers and literals, as defined in items 1, 2, and 3, separated by arithmetic + // operators + // 5. Two arithmetic expressions, as defined in items 1, 2, 3, or 4, separated by an arithmetic + // operator + // 6. An arithmetic expression, as defined in items 1, 2, 3, 4, or 5, enclosed in parentheses + if (ctx.match("(")) { + return true; + } + // Any arithmetic expression can be preceded by a unary operator. + if (ctx.match("+", "-")) { + return true; + } + return false; + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ConditionExpressionRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ConditionExpressionRule.java index a7eb3a8bba..60195ba9b6 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ConditionExpressionRule.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ConditionExpressionRule.java @@ -78,26 +78,7 @@ public void parse(ParsingContext ctx, CobolLanguage language) { } private void conditionOperand(ParsingContext ctx, CobolLanguage language) { - if (ctx.match("(")) { - ctx.consume("("); - do { - conditionOperand(ctx, language); - } while (!ctx.match(")")); - ctx.consume(")"); - ctx.spaces(); - return; - } - if (ctx.match("FUNCTION")) { - functionIdentifier(ctx); - return; - } - identifier(ctx); - // p. 267 - if (ctx.match("+", "-", "*", "/", "**")) { - ctx.or("+", "-", "*", "/", "**"); - ctx.spaces(); - conditionOperand(ctx, language); - } + language.parseRule(ArithmeticExpressionRule.class, ctx); } private void compositeCondition(ParsingContext ctx, CobolLanguage language) { @@ -177,30 +158,36 @@ private void functionIdentifier(ParsingContext ctx) { // TODO: optional reference-modifier } - // TODO: move to rule? - private void identifier(ParsingContext ctx) { - ctx.consume(); - ctx.spaces(); - if (ctx.match("(")) { - ctx.consume("("); - ctx.spaces(); - do { - ctx.consume(); // indexes - ctx.spaces(); - } while (!ctx.match(")")); - ctx.consume(")"); // index - ctx.spaces(); - } - } - @Override public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { - // TODO TBD - return isClassCondition(ctx); + // operand-1 + // Can be an identifier, literal, function-identifier, arithmetic expression, or index-name. + if (language.tryMatchRule(ArithmeticExpressionRule.class, ctx)) { + return true; + } + if (ctx.matchSeq(null, "IS") + || ctx.matchSeq(null, "GREATER") + || ctx.matchSeq(null, "NOT", "GREATER") + || ctx.matchSeq(null, ">") + || ctx.matchSeq(null, "NOT", ">") + || ctx.matchSeq(null, "<") + || ctx.matchSeq(null, "NOT", "<") + || ctx.matchSeq(null, "=") + || ctx.matchSeq(null, "NOT", "=") + || ctx.matchSeq(null, "LESS") + || ctx.matchSeq(null, "NOT", "LESS") + || ctx.matchSeq(null, "EQUAL") + || ctx.matchSeq(null, "NOT", "EQUAL") + || ctx.matchSeq(null, "<=") + || ctx.matchSeq(null, ">=")) { + return true; + } + return false; + // return isClassCondition(ctx); } // P. 268 - private boolean isClassCondition(ParsingContext ctx) { - return true; - } + // private boolean isClassCondition(ParsingContext ctx) { + // return true; + // } } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/IdentifierRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/IdentifierRule.java new file mode 100644 index 0000000000..e30a5a042c --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/IdentifierRule.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure; + +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.parser.hw.lexer.TokenType; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; + +/** A rule for Identifier */ +public class IdentifierRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("FUNCTION")) { + function(ctx, language); + return; + } + ctx.consume(); + ctx.spaces(); + while (ctx.match("OF", "IN")) { + ctx.or("OF", "IN"); + ctx.spaces(); + ctx.consume(); + ctx.spaces(); + } + if (ctx.match("(")) { + ctx.consume("("); + ctx.spaces(); + do { + ctx.consume(); // indexes + ctx.spaces(); + } while (!ctx.match(")")); + ctx.consume(")"); // index + ctx.spaces(); + } + } + + private void function(ParsingContext ctx, CobolLanguage language) { + ctx.consume("FUNCTION"); + ctx.spaces(); + ctx.consume(); // function-name-1 + ctx.spaces(); + if (ctx.match("(")) { + ctx.consume("("); + ctx.spaces(); + // consume arguments + do { + if (language.tryParseRule(ArithmeticExpressionRule.class, ctx).isPresent()) { + continue; + } + ctx.consume(); + ctx.spaces(); + } while (!ctx.match(")")); + ctx.consume(")"); + ctx.spaces(); + // TODO: what is reference-modifier? + } + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("FUNCTION")) { + return true; + } + if (ctx.getLexer().peek().getType() == TokenType.COBOL_WORD) { + return true; + } + return false; + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ProcedureDivisionRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ProcedureDivisionRule.java index f0955bb5da..dd82783d3e 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ProcedureDivisionRule.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/ProcedureDivisionRule.java @@ -40,7 +40,7 @@ public void parse(ParsingContext ctx, CobolLanguage language) { } else if (language.tryMatchRule(SectionRule.class, ctx)) { language.tryParseRule(SectionRule.class, ctx); } else { - language.tryParseRule(SentenceRule.class, ctx); + language.parseRule(SentenceRule.class, ctx); } ctx.spaces(); } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/SentenceRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/SentenceRule.java index eaab7ae676..135979183e 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/SentenceRule.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/SentenceRule.java @@ -19,37 +19,180 @@ import org.eclipse.lsp.cobol.rules.CobolLanguage; import org.eclipse.lsp.cobol.rules.CobolLanguageUtils; import org.eclipse.lsp.cobol.rules.LanguageRule; -import org.eclipse.lsp.cobol.rules.procedure.statements.PerformRule; +import org.eclipse.lsp.cobol.rules.procedure.statements.*; /** COBOL language grammar rule class. */ +// TODO: make sure if naming is fine. public class SentenceRule implements LanguageRule { @Override public void parse(ParsingContext ctx, CobolLanguage language) { + if (language.tryParseRule(AddRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(ComputeRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(DivideRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(CallRule.class, ctx).isPresent()) { + return; + } if (language.tryParseRule(PerformRule.class, ctx).isPresent()) { return; } -// if (language.tryParseRule(MoveRule.class, ctx).isPresent()) { -// return; -// } + if (language.tryParseRule(StringRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(EvaluateRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(IfRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(SearchRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(MultiplyRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(SubtractRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(StartRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(ReadRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(UnstringRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(ReturnRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(DeleteRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(WriteRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(RewriteRule.class, ctx).isPresent()) { + return; + } + // if (language.tryParseRule(MoveRule.class, ctx).isPresent()) { + // return; + // } ctx.push(new Statement()); try { while (!ctx.match(".") + // This one should go away if we will have all statements implemented + && !(ctx.match("ELSE", "WHEN") && !ctx.peek().getChildren().isEmpty()) && !CobolLanguageUtils.isNextDivisionEofOrEop(ctx) && !language.tryMatchRule(ParagraphRule.class, ctx) && !language.tryMatchRule(SectionRule.class, ctx) && !CobolLanguageUtils.isEndOfProgram(ctx)) { ctx.consume(); + // next sentence + if (tryMatch(ctx, language) && isEndToken(ctx)) { + break; + } } ctx.optional("."); + ctx.spaces(); } finally { ctx.popAndAttach(); } } + private boolean isEndToken(ParsingContext ctx) { + return !ctx.match( + "END-ADD", + "END-CALL", + "END-COMPUTE", + "END-DELETE", + "END-DIVIDE", + "END-EVALUATE", + "END-IF", + "END-INVOKE", + "END-JSON", + "END-MULTIPLY", + "END-PERFORM", + "END-READ", + "END-RETURN", + "END-REWRITE" + "END-SEARCH", + "END-START", + "END-STRING", + "END-SUBTRACT", + "END-UNSTRING", + "END-WRITE", + "END-XML"); + } + @Override public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { - // For now, it can be anything. - return true; + // Decision + if (language.tryMatchRule(IfRule.class, ctx)) { + return true; + } + if (language.tryMatchRule(EvaluateRule.class, ctx)) { + return true; + } + + if (ctx.match("XML") && (ctx.matchSeq("XML", "GENERATE") || ctx.matchSeq("XML", "PARSE"))) { + return true; + } + + return ctx.match( + // Arithmetic + "ADD", + "COMPUTE", + "DIVIDE", + "MULTIPLY", + "SUBTRACT", + // Data movement + "ACCEPT", // Input-output too + "INITIALIZE", + "INSPECT", + "SET", + "MOVE", + "STRING", + "UNSTRING", + // Ending + "GOBACK", + // Input-output + "CLOSE", + "DELETE", + "DISPLAY", + "OPEN", + "READ", + "REWRITE", + "START", + "STOP", + "WRITE", + // Ordering + "ALLOCATE", + "SORT", // Format 1 SORT? + "FREE", + "MERGE", + "RELEASE", + "RETURN", + // Procedure-branching + "ALTER", + "CONTINUE", + "EXIT", // Format 1 EXIT? + "PERFORM", + // Program or method linkage + "CALL", + "CANCEL", + "INVOKE", + // Table-handling + // Format 2 SORT (table SORT) + "SET") + || ctx.matchSeq("STOP", "RUN") + || ctx.matchSeq("EXIT", "PROGRAM") + || ctx.matchSeq("EXIT", "METHOD") + || ctx.matchSeq("GO", "TO"); } } diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/AddRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/AddRule.java new file mode 100644 index 0000000000..a50a02f16c --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/AddRule.java @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p.331 */ +public class AddRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("ADD"); + ctx.spaces(); + if (ctx.match("CORR", "CORRESPONDING")) { + format3(ctx, language); + onSizeError(ctx, language); + ctx.optional("END-ADD"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + return; + } + idOrLiteralSequence(ctx, language); + ctx.optional("TO"); + ctx.spaces(); + if (ctx.matchSeq(null, "GIVING")) { + // format 2 + language.parseRule(IdentifierRule.class, ctx); // identifier-2 or literal-2 + ctx.spaces(); + ctx.consume("GIVING"); + ctx.spaces(); + idOrLiteralSequence(ctx, language); + onSizeError(ctx, language); + ctx.optional("END-ADD"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + return; + } + idOrLiteralSequence(ctx, language); + onSizeError(ctx, language); + ctx.optional("END-ADD"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private void onSizeError(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "SIZE")) { + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + } + + private void idOrLiteralSequence(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(IdentifierRule.class, ctx); + ctx.optional("ROUNDED"); + ctx.spaces(); + } while (!ctx.match("TO", "GIVING", "ROUNDED", "ON", "SIZE", ".") + && ctx.getLexer().hasMore() + && !language.tryMatchRule(SentenceRule.class, ctx)); + } + + private void format3(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("CORR")) { + ctx.consume("CORR"); + } else { + ctx.consume("CORRESPONDING"); + } + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + ctx.consume("TO"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + ctx.optional("ROUNDED"); + ctx.spaces(); + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("ADD"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/CallRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/CallRule.java new file mode 100644 index 0000000000..05f1a18cfc --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/CallRule.java @@ -0,0 +1,217 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.parser.hw.lexer.TokenType; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 318 */ +public class CallRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("CALL"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + using(ctx, language); + if (ctx.match("RETURNING")) { + ctx.consume("RETURNING"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + exceptionPhrases(ctx, language); + ctx.optional("END-CALL"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private void using(ParsingContext ctx, CobolLanguage language) { + if (!ctx.match("USING")) { + ctx.spaces(); // expect no spaces after using call + return; + } + ctx.consume("USING"); + ctx.spaces(); + do { + ctx.optional("BY"); + ctx.spaces(); + if (ctx.match("VALUE")) { + usingValue(ctx, language); + } + if (ctx.match("CONTENT")) { + usingContent(ctx, language); + continue; + } + usingReference(ctx, language); + + } while (!language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.match("OVERFLOW", "RETURNING", "END-CALL") + && !ctx.matchSeq("ON", "OVERFLOW") + && ctx.getLexer().hasMore()); + } + + private void usingReference(ParsingContext ctx, CobolLanguage language) { + ctx.optional("REFERENCE"); + ctx.spaces(); + do { + if (ctx.match("OMITTED")) { + ctx.consume("OMITTED"); + ctx.spaces(); + continue; + } + addressOffOpt(ctx); + language.parseRule(IdentifierRule.class, ctx); + fixedPhrase(ctx); + } while (!usagePartOver(ctx, language)); + ctx.optional(","); + ctx.optional(";"); + ctx.spaces(); + } + + private void usingContent(ParsingContext ctx, CobolLanguage language) { + ctx.consume("CONTENT"); + ctx.spaces(); + + do { + if (ctx.match("OMITTED")) { + ctx.consume("OMITTED"); + ctx.spaces(); + continue; + } + addressOffOpt(ctx); + lengthOfOpt(ctx); + language.parseRule(IdentifierRule.class, ctx); + fixedPhrase(ctx); + } while (!usagePartOver(ctx, language)); + ctx.optional(","); + ctx.spaces(); + } + + private void usingValue(ParsingContext ctx, CobolLanguage language) { + ctx.consume("VALUE"); + ctx.spaces(); + do { + addressOffOpt(ctx); + lengthOfOpt(ctx); + + language.parseRule(IdentifierRule.class, ctx); + + } while (!usagePartOver(ctx, language)); + ctx.optional(","); + ctx.spaces(); + } + + private static boolean usagePartOver(ParsingContext ctx, CobolLanguage language) { + if (ctx.matchSeq("ADDRESS", "OF")) return false; + if (ctx.match("OMITTED")) return false; + + if (ctx.getLexer().peek().getType() == TokenType.DOT) return true; + if (ctx.matchSeq("ON", "OVERFLOW")) return true; + if (language.tryMatchRule(SentenceRule.class, ctx)) return true; + return ctx.match( + "BY", "CONTENT", "VALUE", "REFERENCE", ",", ";", "OVERFLOW", "RETURNING", "END-CALL"); + } + + private static void lengthOfOpt(ParsingContext ctx) { + if (ctx.matchSeq("LENGTH", "OF")) { + ctx.consume("LENGTH"); + ctx.spaces(); + ctx.consume("OF"); + ctx.spaces(); + } + } + + private static void addressOffOpt(ParsingContext ctx) { + if (ctx.matchSeq("ADDRESS", "OF")) { + ctx.consume("ADDRESS"); + ctx.spaces(); + ctx.consume("OF"); + ctx.spaces(); + } + } + + private static void addressOfOpt(ParsingContext ctx) { + if (ctx.matchSeq("ADDRESS", "OF")) { + ctx.consume("ADDRESS"); + ctx.spaces(); + ctx.consume("OF"); + ctx.spaces(); + } + } + + private static void fixedPhrase(ParsingContext ctx) { + if (ctx.matchSeq("AS", "FIXED", "LENGTH")) { + ctx.consume("AS"); + ctx.spaces(); + ctx.consume("FIXED"); + ctx.spaces(); + ctx.consume("LENGTH"); + ctx.spaces(); + ctx.consume(); // integer-4 + ctx.spaces(); + } + } + + private void exceptionPhrases(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "EXCEPTION", "OVERFLOW")) { + ctx.optional("ON"); + ctx.spaces(); + if (ctx.match("EXCEPTION")) { + ctx.consume("EXCEPTION"); + ctx.spaces(); + imperativeStatements(ctx, language); + if (ctx.match("NOT")) { + notExceptionPhrase(ctx, language); + } + } + if (ctx.match("OVERFLOW")) { + ctx.consume("OVERFLOW"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + } + } + + private void notExceptionPhrase(ParsingContext ctx, CobolLanguage language) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("EXCEPTION"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("CALL"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ComputeRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ComputeRule.java new file mode 100644 index 0000000000..b7c202ef17 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ComputeRule.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.ArithmeticExpressionRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 330 */ +public class ComputeRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("COMPUTE"); + ctx.spaces(); + ids(ctx, language); + ctx.or("=", "EQUAL"); + ctx.spaces(); + language.parseRule(ArithmeticExpressionRule.class, ctx); + onSizeError(ctx, language); + end(ctx); + } finally { + ctx.popAndAttach(); + } + } + + private void ids(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(IdentifierRule.class, ctx); + ctx.optional("ROUNDED"); + ctx.spaces(); + } while (!ctx.match("=", "EQUAL") && ctx.getLexer().hasMore()); + } + + private void end(ParsingContext ctx) { + ctx.optional("END-COMPUTE"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("COMPUTE"); + } + + private void onSizeError(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "SIZE")) { + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DeleteRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DeleteRule.java new file mode 100644 index 0000000000..83e9a23d49 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DeleteRule.java @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p.332 */ +public class DeleteRule implements LanguageRule { + + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("DELETE"); + ctx.spaces(); + ctx.consume(); // file-name-1 + ctx.spaces(); + ctx.optional("RECORD"); + ctx.spaces(); + invalidNotInvalidKey(ctx, language); + ctx.optional("END-DELETE"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("DELETE"); + } + + private void invalidNotInvalidKey(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("INVALID")) { + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + if (ctx.matchSeq("NOT", "INVALID")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DivideRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DivideRule.java new file mode 100644 index 0000000000..39e0289279 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/DivideRule.java @@ -0,0 +1,119 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 335 */ +public class DivideRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("DIVIDE"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + + ctx.or("INTO", "BY"); + ctx.spaces(); + + if (ctx.matchSeq(null, "GIVING")) { + language.parseRule(IdentifierRule.class, ctx); + ctx.consume("GIVING"); + ctx.spaces(); + } + idRounded(ctx, language); + + if (ctx.match("REMINDER")) { + ctx.consume("REMINDER"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + + onSizeErrorOrNot(ctx, language); + ctx.optional("END-DIVIDE"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private void format3(ParsingContext ctx, CobolLanguage language) { + ctx.consume("BY"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + ctx.consume("GIVING"); + ctx.spaces(); + idRounded(ctx, language); + onSizeErrorOrNot(ctx, language); + } + + private static void idRounded(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(IdentifierRule.class, ctx); + ctx.optional("ROUNDED"); + ctx.spaces(); + } while (language.tryMatchRule(IdentifierRule.class, ctx) + && !ctx.match("REMINDER") + && !ctx.matchSeq("SIZE", "ERROR") + && !ctx.matchSeq("ON", "SIZE", "ERROR") + && !ctx.matchSeq("NOT", "SIZE", "ERROR") + && !ctx.matchSeq("NOT", "ON", "SIZE", "ERROR") + ); + } + + private void onSizeErrorOrNot(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "SIZE")) { + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("DIVIDE"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/EvaluateRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/EvaluateRule.java new file mode 100644 index 0000000000..638b14431c --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/EvaluateRule.java @@ -0,0 +1,135 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.parser.hw.lexer.TokenType; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.ArithmeticExpressionRule; +import org.eclipse.lsp.cobol.rules.procedure.ConditionExpressionRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** Evaluate rule p. 340 */ +public class EvaluateRule implements LanguageRule { + + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("EVALUATE"); + ctx.spaces(); + do { + operand(ctx, language); + } while (ctx.match("ALSO")); + + do { + ctx.consume("WHEN"); + ctx.spaces(); + phrase(ctx, language); + while (ctx.match("ALSO")) { + phrase(ctx, language); + } + if (ctx.match("WHEN")) { + continue; + } + imperativeStatments(ctx, language); + } while (ctx.match("WHEN")); + if (ctx.matchSeq("WHEN", "OTHER")) { + ctx.consume("WHEN"); + ctx.spaces(); + ctx.consume("OTHER"); + ctx.spaces(); + imperativeStatments(ctx, language); // imperative-statement-2 + } + ctx.optional("END-EVALUATE"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private static void imperativeStatments(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + + private void operand(ParsingContext ctx, CobolLanguage language) { + if (language.tryParseRule(ConditionExpressionRule.class, ctx).isPresent()) { + return; + } + if (language.tryParseRule(IdentifierRule.class, ctx).isPresent()) { + return; + } + TokenType tokenType = ctx.getLexer().peek().getType(); + if (tokenType == TokenType.NUMBER_LITERAL || tokenType == TokenType.STRING_LITERAL) { + ctx.consume(); + ctx.spaces(); + } + } + + private void phrase(ParsingContext ctx, CobolLanguage language) { + if (ctx.matchSeq("ANY", "TRUE", "FALSE")) { + ctx.or("ANY", "TRUE", "FALSE"); + ctx.spaces(); + return; + } + + language.tryParseRule(ConditionExpressionRule.class, ctx); + + ctx.optional("NOT"); + ctx.spaces(); + + if (ctx.match("THROUGH", "THRU")) { + ctx.or("THROUGH", "THRU"); + ctx.spaces(); + language.parseRule(ArithmeticExpressionRule.class, ctx); + } + } + + private void idOrExpr(ParsingContext ctx) { + if (ctx.match("(")) { + ctx.consume("("); + ctx.spaces(); + idOrExpr(ctx); + ctx.consume(")"); + ctx.spaces(); + return; + } + // p. 267 + if (ctx.match("+", "-", "*", "/", "**")) { + ctx.or("+", "-", "*", "/", "**"); + ctx.spaces(); + idOrExpr(ctx); + return; + } + ctx.consume(); + ctx.spaces(); + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("EVALUATE"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/IfRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/IfRule.java new file mode 100644 index 0000000000..815a09c30b --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/IfRule.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.ConditionExpressionRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** If rule */ +public class IfRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("IF"); + ctx.spaces(); + language.tryParseRule(ConditionExpressionRule.class, ctx); + ctx.optional("THEN"); + ctx.spaces(); + branch(ctx, language); + if (ctx.match("ELSE")) { + ctx.consume("ELSE"); + ctx.spaces(); + branch(ctx, language); + } + ctx.optional("END-IF"); + ctx.spaces(); + ctx.optional("."); + } finally { + ctx.popAndAttach(); + } + } + + private static void branch(ParsingContext ctx, CobolLanguage language) { + if (ctx.matchSeq("NEXT", "SENTENCE")) { + ctx.consume("NEXT"); + ctx.spaces(); + ctx.consume("SENTENCE"); + ctx.spaces(); + } else { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.match("ELSE") + && !lastStatementEndsWithDot(ctx)); + + } + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("IF"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ImperativeStatementRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ImperativeStatementRule.java deleted file mode 100644 index b7bf91e656..0000000000 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ImperativeStatementRule.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2024 Broadcom. - * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. - * - * This program and the accompanying materials are made - * available under the terms of the Eclipse Public License 2.0 - * which is available at https://www.eclipse.org/legal/epl-2.0/ - * - * SPDX-License-Identifier: EPL-2.0 - * - * Contributors: - * Broadcom, Inc. - initial API and implementation - */ -package org.eclipse.lsp.cobol.rules.procedure.statements; - -import org.eclipse.lsp.cobol.parser.hw.ParsingContext; -import org.eclipse.lsp.cobol.rules.CobolLanguage; -import org.eclipse.lsp.cobol.rules.LanguageRule; - -/** Imperative Statements */ -public class ImperativeStatementRule implements LanguageRule { - @Override - public void parse(ParsingContext ctx, CobolLanguage language) { - throw new UnsupportedOperationException("Not implemented yet"); - } - - @Override - public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { - return ctx.match( - // Arithmetic - "ADD", - "COMPUTE", - "DIVIDE", - "MULTIPLY", - "SUBTRACT", - // Data movement - "ACCEPT", // Input-output too - "INITIALIZE", - "INSPECT", - "SET", - "MOVE", - "STRING", - "UNSTRING", - // Ending - "GOBACK", - // Input-output - "CLOSE", - "DELETE", - "DISPLAY", - "OPEN", - "READ", - "REWRITE", - "START", - "STOP", - "WRITE", - // Ordering - "ALLOCATE", - "SORT", // Format 1 SORT? - "FREE", - "MERGE", - "RELEASE", - "RETURN", - // Procedure-branching - "ALTER", - "CONTINUE", - "EXIT", // Format 1 EXIT? - "PERFORM", - // Program or method linkage - "CALL", - "CANCEL", - "INVOKE", - // Table-handling - // Format 2 SORT (table SORT) - "SET") - || ctx.matchSeq("XML", "GENERATE") - || ctx.matchSeq("XML", "PARSE") - || ctx.matchSeq("STOP", "RUN") - || ctx.matchSeq("EXIT", "PROGRAM") - || ctx.matchSeq("EXIT", "METHOD") - || ctx.matchSeq("GO", "TO"); - } -} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/MultiplyRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/MultiplyRule.java new file mode 100644 index 0000000000..de83f67016 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/MultiplyRule.java @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.parser.hw.lexer.TokenType; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 406 */ +public class MultiplyRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("MULTIPLY"); + ctx.spaces(); + + language.parseRule(IdentifierRule.class, ctx); + + ctx.consume("BY"); + ctx.spaces(); + + language.parseRule(IdentifierRule.class, ctx); + + ctx.optional("GIVING"); + ctx.spaces(); + + if (!ctx.match("ON", "NOT", "SIZE")) { + do { + language.parseRule(IdentifierRule.class, ctx); + } while (ctx.getLexer().peek().getType() != TokenType.DOT + && ctx.getLexer().hasMore() + && !ctx.match("ON", "NOT", "SIZE") + && !language.tryMatchRule(SentenceRule.class, ctx)); + } + + onSizeError(ctx, language); + } finally { + ctx.popAndAttach(); + } + } + + private void onSizeError(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "SIZE")) { + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("MULTIPLY"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/PerformRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/PerformRule.java index 380e7383db..f99f794604 100644 --- a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/PerformRule.java +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/PerformRule.java @@ -18,6 +18,8 @@ import org.eclipse.lsp.cobol.rules.CobolLanguage; import org.eclipse.lsp.cobol.rules.LanguageRule; import org.eclipse.lsp.cobol.rules.procedure.ConditionExpressionRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; /** Perform rule at P. 412 */ public class PerformRule implements LanguageRule { @@ -30,7 +32,7 @@ public void parse(ParsingContext ctx, CobolLanguage language) { ctx.spaces(); // basic inline case - if (language.tryMatchRule(ImperativeStatementRule.class, ctx)) { + if (language.tryMatchRule(SentenceRule.class, ctx)) { consumeUntilEndPerform(ctx); return; } @@ -62,7 +64,8 @@ public void parse(ParsingContext ctx, CobolLanguage language) { } if (isTimesPrefix(ctx)) { - identifier(ctx); // identifier-1 or integer-1 + // identifier-1 or integer-1 + language.parseRule(IdentifierRule.class, ctx); ctx.consume("TIMES"); ctx.spaces(); ctx.optional("."); @@ -105,7 +108,8 @@ private static void consumeUntilEndPerform(ParsingContext ctx) { } private void inlineTimes(ParsingContext ctx, CobolLanguage language) { - identifier(ctx); // identifier-1 or integer-1 + // identifier-1 or integer-1 + language.parseRule(IdentifierRule.class, ctx); ctx.consume("TIMES"); ctx.spaces(); } @@ -126,22 +130,6 @@ private static boolean isUntilPhrase1(ParsingContext ctx) { || ctx.matchSeq("WITH", "TEST", null, "UNTIL"); } - // TODO: move to rule? - private void identifier(ParsingContext ctx) { - ctx.consume(); - ctx.spaces(); - if (ctx.match("(")) { - ctx.consume("("); - ctx.spaces(); - do { - ctx.consume(); // indexes - ctx.spaces(); - } while (!ctx.match(")")); - ctx.consume(")"); // index - ctx.spaces(); - } - } - private void procedureName(ParsingContext ctx) { ctx.consume(); ctx.spaces(); @@ -184,13 +172,16 @@ private void phraseVarying1(ParsingContext ctx, CobolLanguage language) { withTestBeforeAfter(ctx); ctx.consume("VARYING"); ctx.spaces(); - identifier(ctx); // identifier-2 or index-name-1 + // identifier-2 or index-name-1 + language.parseRule(IdentifierRule.class, ctx); ctx.consume("FROM"); ctx.spaces(); - identifier(ctx); // identifier-3 or index-name-2 or literal-1 + // identifier-3 or index-name-2 or literal-1 + language.parseRule(IdentifierRule.class, ctx); ctx.consume("BY"); ctx.spaces(); - identifier(ctx); // identifier-4 or literal-2 + // identifier-4 or literal-2 + language.parseRule(IdentifierRule.class, ctx); ctx.consume("UNTIL"); ctx.spaces(); language.parseRule(ConditionExpressionRule.class, ctx); // condition-1 diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReadRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReadRule.java new file mode 100644 index 0000000000..045c7d6056 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReadRule.java @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** 424 */ +public class ReadRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("READ"); + ctx.spaces(); + ctx.consume(); // file-name-1 + ctx.spaces(); + ctx.optional("NEXT"); + ctx.spaces(); + ctx.optional("RECORD"); + ctx.spaces(); + if (ctx.match("INTO")) { + ctx.consume("INTO"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + atEnd(ctx, language); + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + atEnd(ctx, language); + } + + if (ctx.match("KEY")) { + ctx.consume("KEY"); + ctx.spaces(); + ctx.optional("IS"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + + if (ctx.match("INVALID")) { + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + if (ctx.matchSeq("NOT", "INVALID")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + ctx.optional("END-READ"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private static void atEnd(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("AT", "END")) { + ctx.optional("AT"); + ctx.spaces(); + ctx.consume("END"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("READ"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReturnRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReturnRule.java new file mode 100644 index 0000000000..205c65ba2c --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/ReturnRule.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 430 */ +public class ReturnRule implements LanguageRule { + + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("RETURN"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); // file-name-1 + ctx.optional("RECORD"); + ctx.spaces(); + if (ctx.match("INTO")) { + ctx.consume("INTO"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + if (ctx.match("AT", "END")) { + ctx.optional("AT"); + ctx.spaces(); + ctx.consume("END"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.optional("AT"); + ctx.spaces(); + ctx.consume("END"); + imperativeStatements(ctx, language); + } + + ctx.optional("END-RETURN"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("RETURN"); + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } + +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/RewriteRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/RewriteRule.java new file mode 100644 index 0000000000..0d40585800 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/RewriteRule.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p.432 */ +public class RewriteRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("REWRITE"); + ctx.spaces(); + ctx.consume(); // record-name-1 + ctx.spaces(); + if (ctx.match("FROM")) { + ctx.consume("FROM"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + if (ctx.match("INVALID")) { + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + + if (ctx.matchSeq("NOT", "INVALID")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + ctx.optional("END-REWRITE"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("REWRITE"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SearchRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SearchRule.java new file mode 100644 index 0000000000..210ac68a2f --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SearchRule.java @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.ConditionExpressionRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 434 */ +public class SearchRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("SEARCH"); + ctx.spaces(); + if (ctx.match("ALL")) { + ctx.consume("ALL"); + ctx.spaces(); + format2(ctx, language); + } else { + format1(ctx, language); + } + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private void format1(ParsingContext ctx, CobolLanguage language) { + language.parseRule(IdentifierRule.class, ctx); + if (ctx.match("VARYING")) { + ctx.consume("VARYING"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + atEnd(ctx, language); + do { + ctx.consume("WHEN"); + ctx.spaces(); + language.parseRule(ConditionExpressionRule.class, ctx); + if (ctx.matchSeq("NEXT", "SENTENCE")) { + ctx.consume("NEXT"); + ctx.spaces(); + ctx.consume("SENTENCE"); + ctx.spaces(); + } else { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + } while (ctx.match("WHEN")); + ctx.optional("END-SEARCH"); + } + + private void format2(ParsingContext ctx, CobolLanguage language) { + language.parseRule(IdentifierRule.class, ctx); + atEnd(ctx, language); + ctx.consume("WHEN"); + ctx.spaces(); + // TODO: im not sure if it's really condition exptession here + language.parseRule(ConditionExpressionRule.class, ctx); + if (ctx.matchSeq("NEXT", "SENTENCE")) { + ctx.consume("NEXT"); + ctx.spaces(); + ctx.consume("SENTENCE"); + ctx.spaces(); + } else { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + ctx.optional("END-SEARCH"); + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + + private static void atEnd(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("AT", "END")) { + ctx.optional("AT"); + ctx.spaces(); + ctx.consume("END"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("SEARCH"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StartRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StartRule.java new file mode 100644 index 0000000000..ddbfeaa11e --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StartRule.java @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 455 */ +public class StartRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("START"); + ctx.spaces(); + ctx.consume(); // file-name-1 + ctx.spaces(); + if (ctx.match("KEY")) { + ctx.consume("KEY"); + ctx.spaces(); + ctx.optional("IS"); + ctx.spaces(); + if (ctx.match("=", ">", ">=")) { + ctx.or("=", ">", ">="); + ctx.spaces(); + } else if (ctx.match("EQUAL")) { + ctx.consume("EQUAL"); + ctx.spaces(); + ctx.optional("TO"); + ctx.spaces(); + } else if (ctx.matchSeq("NOT", "<")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.consume("<"); + ctx.spaces(); + } else if (ctx.matchSeq("NOT", "LESS")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.consume("LESS"); + ctx.spaces(); + ctx.optional("THAN"); + ctx.spaces(); + } else if (ctx.match("GREATER")) { + ctx.consume("GREATER"); + ctx.spaces(); + ctx.optional("THAN"); + ctx.spaces(); + if (ctx.matchSeq("OR", "EQUAL")) { + ctx.consume("OR"); + ctx.spaces(); + ctx.consume("EQUAL"); + ctx.spaces(); + ctx.optional("TO"); + ctx.spaces(); + } + } + language.parseRule(IdentifierRule.class, ctx); // data-name-1 + ctx.spaces(); + } + invalidNotInvalidKey(ctx, language); + ctx.optional("END-START"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("START"); + } + + private void invalidNotInvalidKey(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("INVALID")) { + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + if (ctx.matchSeq("NOT", "INVALID")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StringRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StringRule.java new file mode 100644 index 0000000000..cb8903cd75 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/StringRule.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** 457 */ +public class StringRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("STRING"); + ctx.spaces(); + do { + do { + language.parseRule(IdentifierRule.class, ctx); + } while (!ctx.match("DELIMITED")); + ctx.consume("DELIMITED"); + ctx.spaces(); + ctx.optional("BY"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } while (!ctx.match("INTO")); + ctx.consume("INTO"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + pointer(ctx, language); + onOverflow(ctx, language); + endOfStatement(ctx); + } finally { + ctx.popAndAttach(); + } + } + + private void onOverflow(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "OVERFLOW")) { + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("OVERFLOW"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("OVERFLOW"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + } + + private void pointer(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("WITH", "POINTER")) { + ctx.optional("WITH"); + ctx.spaces(); + ctx.consume("POINTER"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + } + + private void endOfStatement(ParsingContext ctx) { + ctx.optional("END-STRING"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("STRING"); + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SubtractRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SubtractRule.java new file mode 100644 index 0000000000..b3939d71a0 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/SubtractRule.java @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 462 */ +public class SubtractRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("SUBTRACT"); + ctx.spaces(); + if (ctx.match("CORR", "CORRESPONDING")) { + format3(ctx, language); + onSizeError(ctx, language); + endOfStatement(ctx); + return; + } + idOrLiteralSequence(ctx, language); + ctx.consume("FROM"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + if (ctx.match("GIVING")) { + // format 2 + ctx.consume("GIVING"); + ctx.spaces(); + } + idOrLiteralSequence(ctx, language); + onSizeError(ctx, language); + endOfStatement(ctx); + } finally { + ctx.popAndAttach(); + } + } + + private static void endOfStatement(ParsingContext ctx) { + ctx.optional("END-SUBTRACT"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } + + private void onSizeError(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "SIZE")) { + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("SIZE"); + ctx.spaces(); + ctx.consume("ERROR"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + } + + private void idOrLiteralSequence(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(IdentifierRule.class, ctx); + ctx.optional("ROUNDED"); + ctx.spaces(); + } while (!ctx.match("FROM", "GIVING", "ROUNDED", "ON", "SIZE", ".") + && ctx.getLexer().hasMore() + && !language.tryMatchRule(SentenceRule.class, ctx)); + } + + private void format3(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("CORR")) { + ctx.consume("CORR"); + } else { + ctx.consume("CORRESPONDING"); + } + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + ctx.consume("FROM"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + ctx.optional("ROUNDED"); + ctx.spaces(); + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("SUBTRACT"); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/UnstringRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/UnstringRule.java new file mode 100644 index 0000000000..6da0af45a9 --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/UnstringRule.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** 464 */ +public class UnstringRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("UNSTRING"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + if (ctx.match("DELIMITED")) { + delimited(ctx, language); + } + ctx.consume("INTO"); + intoIds(ctx, language); + pointer(ctx, language); + tallying(ctx, language); + onOverflow(ctx, language); + endOfStatement(ctx); + } finally { + ctx.popAndAttach(); + } + } + + private void onOverflow(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("ON", "OVERFLOW")) { + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("OVERFLOW"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.optional("ON"); + ctx.spaces(); + ctx.consume("OVERFLOW"); + ctx.spaces(); + imperativeStatements(ctx, language); + } + } + + private void tallying(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("TALLYING")) { + ctx.consume("TALLYING"); + ctx.spaces(); + ctx.optional("IN"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + } + + private void pointer(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("WITH", "POINTER")) { + ctx.optional("WITH"); + ctx.spaces(); + ctx.consume("POINTER"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + } + + private void intoIds(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(IdentifierRule.class, ctx); + if (ctx.match("DELIMITER")) { + ctx.consume("DELIMITER"); + ctx.spaces(); + ctx.optional("IN"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + + if (ctx.match("COUNT")) { + ctx.consume("COUNT"); + ctx.spaces(); + ctx.optional("IN"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + + } while (!ctx.match("WITH", "POINTER", "TALLYING", "ON", "OVERFLOW", "END-UNSTRING", ".") + && ctx.getLexer().hasMore() + && !language.tryMatchRule(SentenceRule.class, ctx)); + } + + private void delimited(ParsingContext ctx, CobolLanguage language) { + ctx.consume("DELIMITED"); + ctx.spaces(); + ctx.optional("BY"); + ctx.spaces(); + ctx.optional("ALL"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + while (ctx.match("OR")) { + ctx.consume("OR"); + ctx.spaces(); + ctx.optional("ALL"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + } + + private void endOfStatement(ParsingContext ctx) { + ctx.optional("END-UNSTRING"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("UNSTRING"); + } + + private void imperativeStatements(ParsingContext ctx, CobolLanguage language) { + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) + && !ctx.peek().toText().trim().endsWith(".")); + } +} diff --git a/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/WriteRule.java b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/WriteRule.java new file mode 100644 index 0000000000..d6a5ae927c --- /dev/null +++ b/server/parser/src/main/java/org/eclipse/lsp/cobol/rules/procedure/statements/WriteRule.java @@ -0,0 +1,131 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.rules.procedure.statements; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.ParsingContext; +import org.eclipse.lsp.cobol.rules.CobolLanguage; +import org.eclipse.lsp.cobol.rules.LanguageRule; +import org.eclipse.lsp.cobol.rules.procedure.IdentifierRule; +import org.eclipse.lsp.cobol.rules.procedure.SentenceRule; + +/** p. 471 */ +public class WriteRule implements LanguageRule { + @Override + public void parse(ParsingContext ctx, CobolLanguage language) { + try { + ctx.push(new Statement()); + ctx.consume("WRITE"); + ctx.spaces(); + ctx.consume(); // record-name-1 + ctx.spaces(); + from(ctx, language); + if (ctx.match("INVALID")) { + invalidNotInvalidKey(ctx, language); + } else { + beforeAfter(ctx, language); + phrase1(ctx, language); + } + ctx.optional("END-WRITE"); + ctx.spaces(); + ctx.optional("."); + ctx.spaces(); + } finally { + ctx.popAndAttach(); + } + } + + private void phrase1(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("AT", "END-OF-PAGE", "EOP")) { + atAndImp(ctx, language); + } + if (ctx.match("NOT")) { + ctx.consume("NOT"); + ctx.spaces(); + atAndImp(ctx, language); + } + } + + private static void atAndImp(ParsingContext ctx, CobolLanguage language) { + ctx.optional("AT"); + ctx.spaces(); + ctx.or("END-OF-PAGE", "EOP"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + + private void beforeAfter(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("BEFORE", "AFTER")) { + ctx.or("BEFORE", "AFTER"); + ctx.spaces(); + ctx.optional("ADVANCING"); + ctx.spaces(); + if (ctx.match("PAGE")) { + ctx.consume("PAGE"); + ctx.spaces(); + return; + } + language.parseRule(IdentifierRule.class, ctx); + if (ctx.match("LINE", "LINES")) { + ctx.or("LINE", "LINES"); + ctx.spaces(); + } + } + } + + private void invalidNotInvalidKey(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("INVALID")) { + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + if (ctx.matchSeq("NOT", "INVALID")) { + ctx.consume("NOT"); + ctx.spaces(); + ctx.consume("INVALID"); + ctx.spaces(); + ctx.optional("KEY"); + ctx.spaces(); + do { + language.parseRule(SentenceRule.class, ctx); + } while (language.tryMatchRule(SentenceRule.class, ctx) && !lastStatementEndsWithDot(ctx)); + } + + } + + private static boolean lastStatementEndsWithDot(ParsingContext ctx) { + // TODO: it should be a better way to check it. + return ctx.peek().toText().trim().endsWith("."); + } + + + private void from(ParsingContext ctx, CobolLanguage language) { + if (ctx.match("FROM")) { + ctx.consume("FROM"); + ctx.spaces(); + language.parseRule(IdentifierRule.class, ctx); + } + } + + @Override + public boolean tryMatch(ParsingContext ctx, CobolLanguage language) { + return ctx.match("WRITE"); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/Case1Test.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/Case1Test.java new file mode 100644 index 0000000000..1169225c60 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/Case1Test.java @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.Skipped; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** A test for skipped tokens */ +class Case1Test { + @Test + void test() { + String source = + " IDENTIFICATION DIVISION.\n" + + " PROGRAM-ID.\n" + + " IC401M IS INITIAL.\n" + + " ENVIRONMENT DIVISION.\n" + + " CONFIGURATION SECTION.\n" + + " SOURCE-COMPUTER.\n" + + " XXXXX082.\n" + + " OBJECT-COMPUTER.\n" + + " XXXXX083.\n" + + " DATA DIVISION.\n" + + " WORKING-STORAGE SECTION.\n" + + " 01 GLOB IS GLOBAL PIC IS X(2) VALUE IS \"HI\".\n" + + " 01 EXTE IS EXTERNAL PIC IS X(5).\n" + + " PROCEDURE DIVISION.\n" + + " DECLARATIVES.\n" + + " IC401M-USE SECTION.\n" + + " USE GLOBAL AFTER STANDARD ERROR PROCEDURE ON I-O.\n" + + " END DECLARATIVES.\n" + + " IC401M-NONDECL SECTION.\n" + + " IC401M-CONTROL.\n" + + " PERFORM IC401M-CANCEL THRU IC401M-BYCONT.\n" + + " STOP RUN.\n" + + " IC401M-CANCEL.\n" + + " CANCEL \"NESTEDPROG\".\n" + + " IC401M-BYREF.\n" + + " CALL \"NESTEDPROG\" USING BY REFERENCE GLOB.\n" + + " IC401M-BYCONT.\n" + + " CALL \"FIC401M\" USING BY CONTENT GLOB.\n" + + " IDENTIFICATION DIVISION.\n" + + " PROGRAM-ID.\n" + + " NESTEDPROG IS COMMON.\n" + + " ENVIRONMENT DIVISION.\n" + + " DATA DIVISION.\n" + + " LINKAGE SECTION.\n" + + " 01 GLOB-2 PIC X(2).\n" + + " PROCEDURE DIVISION USING GLOB-2.\n" + + " DUMMY-PARA.\n" + + " DISPLAY \"HELLO\".\n" + + " END-PARA.\n" + + " END PROGRAM NESTEDPROG.\n" + + " END PROGRAM IC401M.\n"; + + ParseResult result = new CobolParser(new CobolLexer(source), new ParserSettings()).parse(); + assertEquals(0, result.getDiagnostics().size(), result.getDiagnostics().toString()); + assertEquals(0, result.getSourceUnit().list(Skipped.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/AddTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/AddTest.java new file mode 100644 index 0000000000..dad9f2a694 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/AddTest.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Call statement */ +public class AddTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " ADD DNAME-1\n" + + " DNAME-2\n" + + " DNAME-3\n" + + " DNAME-4\n" + + " DNAME-5\n" + + " DNAME-6\n" + + " DNAME-7\n" + + " DNAME-8\n" + + " DNAME-9\n" + + " DNAME-10 TO ACCUM-1 ROUNDED ON SIZE ERROR\n" + + " MOVE 0 TO ACCUM-1."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals( + 1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case2() { + String source = HEADER + " ADD 01 TO INVKEY-COUNTER."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case3() { + String source = + HEADER + " ADD CORRESPONDING GRP-FOR-ADD-CORR-1 TO GRP-FOR-ADD-CORR-R."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case4() { + String source = + HEADER + + " ADD CORRESPONDING CORR-DATA-7 TO CORR-DATA-5 ROUNDED\n" + + " ON SIZE ERROR MOVE \"W\" TO WRK-AN-00001."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals( + 1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/CallTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/CallTest.java new file mode 100644 index 0000000000..a15b90b30d --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/CallTest.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Call statement */ +public class CallTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " CALL \"IC223A-1\" USING REFERENCE DN1, DN2, DN3, DN4;\n" + + " ON OVERFLOW MOVE \"OVERFLOW SHOULD NOT OCCUR\" TO RE-MARK\n" + + " GO TO CALL-FAIL-03-01\n" + + " END-CALL."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals( + 2, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + + } + + @Test + void case2() { + String source = HEADER + " CALL \"FIC401M\" USING BY CONTENT GLOB."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size(), result.getDiagnostics().toString()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + } + + @Test + void case3() { + String source = HEADER + " CALL \"IC111A\" USING LS1 GRP-01 WS2. DISPLAY A"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size(), result.getDiagnostics().toString()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + } + + @Test + void case4() { + String source = + HEADER + + " CALL \"IC225A-1\" USING REFERENCE DN1,\n" + + " CONTENT DN2,\n" + + " REFERENCE DN3,\n" + + " CONTENT DN4,\n" + + " OVERFLOW MOVE \"OVERFLOW SHOULD NOT OCCUR\" TO RE-MARK\n" + + " PERFORM FAIL\n" + + " PERFORM PRINT-DETAIL.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size(), result.getDiagnostics().toString()); + assertEquals(4, result.getSourceUnit().list(Statement.class).size()); + assertEquals( + 3, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case5() { + String source = + HEADER + + " CALL \"CEEDAYS\" USING\n" + + " WS-DATE-TO-TEST,\n" + + " WS-DATE-FORMAT,\n" + + " OUTPUT-LILLIAN,\n" + + " FEEDBACK-CODE\n" + + " MOVE WS-DATE-TO-TEST O WS-DATE"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size(), result.getDiagnostics().toString()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + } + + @Test + void case6() { + String source = HEADER + " CALL \"FIC401M\" USING BY CONTENT GLOB.\n ID DIVISION"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size(), result.getDiagnostics().toString()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ComputeTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ComputeTest.java new file mode 100644 index 0000000000..2de39624b0 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ComputeTest.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Compute statement */ +public class ComputeTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = HEADER + " COMPUTE TEMP = FUNCTION NUMVAL (\"9\") DISPLAY ABC.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + } + + @Test + void case2() { + String source = + HEADER + + " COMPUTE COMPUTE-10 = COMPUTE-1A + COMPUTE-6A ON SIZE ERROR\n" + + " MOVE \"R\" TO XRAY.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case3() { + String source = HEADER + " COMPUTE COMPUTE-7 = 2.0 ** 4.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DeleteTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DeleteTest.java new file mode 100644 index 0000000000..fdc222e096 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DeleteTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Delete statement */ +public class DeleteTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " DELETE IX-1 RECORD INVALID KEY GO TO DEL01.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DivideTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DivideTest.java new file mode 100644 index 0000000000..d6ba659d9c --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/DivideTest.java @@ -0,0 +1,76 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Read statement */ +public class DivideTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " DIVINIT.\n" + + " DIVIDE 64.3 INTO WRK9.\n" + + " MOVE 1620.36 TO DIV1."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + @Test + void case2() { + String source = + HEADER + + " DIVIDE AD\n" + + " INTO WRK9 ROUNDED\n" + + " ON SIZE ERROR\n" + + " MOVE \"1\" TO WRK01\n" + + " NOT ON SIZE ERROR\n" + + " MOVE \"2\" TO WRK01."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(2, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case3() { + String source = + HEADER + + " DIVIDE A BY B GIVING ACCUMULATOR1.\n" + + " IF ACCUMULATOR1 EQUAL TO 1 GO TO DIV-WRITE-F3-1."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(1).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EndProgramTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EndProgramTest.java index fcba635fe7..616cdf5d74 100644 --- a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EndProgramTest.java +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EndProgramTest.java @@ -10,9 +10,6 @@ * * Contributors: * Broadcom, Inc. - initial API and implementation - * DAF Trucks NV – implementation of DaCo COBOL statements - * and DAF development standards - * */ package org.eclipse.lsp.cobol.divisions.procedure; @@ -26,6 +23,8 @@ import org.eclipse.lsp.cobol.parser.hw.ParserSettings; import org.junit.jupiter.api.Test; +import java.util.List; + import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; @@ -49,8 +48,9 @@ void test() { ProgramUnit pu = (ProgramUnit) parseResult.getSourceUnit().getChildren().get(0); ProcedureDivision pd = pu.list(ProcedureDivision.class).get(0); assertEquals(2, pd.getChildren().stream().filter(Paragraph.class::isInstance).count()); - Paragraph p1 = (Paragraph) pd.getChildren().get(9); - Paragraph p2 = (Paragraph) pd.getChildren().get(10); + List paragraphs = pd.list(Paragraph.class); + Paragraph p1 = paragraphs.get(0); + Paragraph p2 = paragraphs.get(1); assertEquals(1, pd.getChildren().stream().filter(Statement.class::isInstance).count()); assertEquals(1, p1.getChildren().stream().filter(Statement.class::isInstance).count()); assertEquals(1, p2.getChildren().stream().filter(Statement.class::isInstance).count()); diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EvaluateTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EvaluateTest.java new file mode 100644 index 0000000000..f8a33fb237 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/EvaluateTest.java @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test EVALUATE statement */ +public class EvaluateTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " EVALUATE TRUE\n" + + " WHEN FK\n" + + " CONTINUE"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case2() { + String source = + HEADER + + " 10-SETUP\n." + + " EVALUATE TRUE\n" + + " WHEN FK\n" + + " WHEN FK1\n" + + " CONTINUE\n" + + " WHEN FK2 AND FK3\n" + + " IF CASHOWN AND CAEXIST\n " + + " SET CASHOWN TO TRUE\n" + + " MOVE 'NO MORE PAGES TO DISPLAY' TO ERROR\n" + + " END-IF" + + " WHEN OTHER\n" + + " SET WS TO TRUE\n" + + " END-EVALUATE"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(6, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case3() { + String source = + HEADER + + " EVALUATE A\n" + + " WHEN FK2 AND FK3\n" + + " PERFORM PASS\n" + + " WHEN OTHER\n" + + " PERFORM FAIL.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + @Test + + void case4() { + String source = + HEADER + + " EVALUATE FUNCTION ACOS(0)\n" + + " WHEN 1.57076 THRU 1.57082\n" + + " PERFORM PASS\n" + + " WHEN OTHER\n" + + " PERFORM FAIL.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/IfTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/IfTest.java new file mode 100644 index 0000000000..162511e9f8 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/IfTest.java @@ -0,0 +1,110 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test if statement */ +public class IfTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " IF C NOT EQUAL TO SPACE \n" + + " MOVE LT TO CD\n" + + " GO TO B-WRITE" + + " ELSE" + + " GO TO B-ERROR\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(4, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case2() { + String source = + HEADER + + " SET WF TO TRUE\n" + + " IF C NOT EQUAL TO SPACE \n" + + " MOVE LT TO CD\n" + + " GO TO B-WRITE" + + " ELSE\n" + + " MOVE D (1:LENGTH OF CC) TO CAR-COM\n" + + " GO TO B-ERROR\n" + + " END-IF\n" + + " PERFORM Y-S-P THRU Y-S-P-EXIT"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(7, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case3() { + String source = + HEADER + + " IF A OF b = '*'\n" + + " MOVE LOW-VALUES TO CC-ACC CCID\n" + + " ELSE\n" + + " MOVE AC OF CCI TO CC-ACCT-ID CCUP-NEW-ACCTID\n" + + " END-IF"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case4() { + String source = + HEADER + + " IF C NOT EQUAL TO SPACE GO TO FAIL-ROUTINE-WRITE.\n" + + " MOVE A TO B.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + // IF has only one statement in it + assertEquals( + 1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case5() { + String source = HEADER + " IF ACCUMULATOR1 EQUAL TO 10 PERFORM PASS."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // IF has only one statement in it + assertEquals( + 1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/MultiplyTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/MultiplyTest.java new file mode 100644 index 0000000000..1282f18c61 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/MultiplyTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Multiply statement */ +public class MultiplyTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " MULTIPLY TABLE1-NUM (INDEX1) BY NUM-9V9 ON SIZE ERROR\n" + + " PERFORM PASS\n" + + " GO TO IND-WRITE-GF-3-1.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + @Test + void case2() { + String source = + HEADER + + " MULTIPLY 3 BY PERFORM2. DIASPLAY A\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReadTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReadTest.java new file mode 100644 index 0000000000..e7272c6019 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReadTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Read statement */ +public class ReadTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " READ RAW-DATA INVALID KEY GO TO EE1.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReturnTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReturnTest.java new file mode 100644 index 0000000000..2acd87bafe --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/ReturnTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Return statement */ +public class ReturnTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " RETURN SORTFILE-1H AT END GO TO RETURN-ERROR."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/RewriteTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/RewriteTest.java new file mode 100644 index 0000000000..2088a56697 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/RewriteTest.java @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Rewrite statement */ +public class RewriteTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " REWRITE RAW-DATA-SATZ INVALID KEY GO TO END-E-1.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SearchTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SearchTest.java new file mode 100644 index 0000000000..3bac3a6171 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SearchTest.java @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Search statement */ +public class SearchTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " SEARCH ALL TE AT END GO TO I1\n" + + " WHEN DKEY (I1) EQUAL TO \"BB\" NEXT SENTENCE.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case2() { + String source = + HEADER + + " SEARCH E VARYING IDX-2 AT END\n" + + " GO TO IDX-FAIL\n" + + " WHEN DKEY (IDX-2) EQUAL TO \"KK\"\n" + + " PERFORM PASS\n" + + " GO TO IDX-WRITE.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(4, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(3, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StartTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StartTest.java new file mode 100644 index 0000000000..71233bb6fa --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StartTest.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Start statement */ +public class StartTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " START IX1 KEY IS EQUAL TO IX03\n" + + " INVALID KEY GO TO START-01.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals( + 1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case2() { + String source = HEADER + " START IX-FS1 INVALID KEY ADD 01 TO INVKEY-COUNTER."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals( + 1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case3() { + String source = + HEADER + + " START IX-FD3 KEY IS EQUAL TO IX-FD3-KEY IN IX-FD3-RECKEY-AREA INVALID KEY PERFORM PASS\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals( + 1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StringTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StringTest.java new file mode 100644 index 0000000000..3789aec00d --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/StringTest.java @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Return statement */ +public class StringTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " STRING \"LEADER-\" ODO-GRP-00009 DELIMITED BY SIZE INTO WRK-XN-00010\n" + + " ON OVERFLOW GO TO STR-FAIL-GF-4.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SubtractTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SubtractTest.java new file mode 100644 index 0000000000..5009b04814 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/SubtractTest.java @@ -0,0 +1,112 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Subtract statement */ +public class SubtractTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " SUBTRACT A99-DS-02V00 FROM WRK-DS-02V00 ON SIZE ERROR\n" + + " PERFORM PASS GO TO SUB-WRITE-F1-8-1."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(2, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case2() { + String source = + HEADER + + " SUBTRACT CORRESPONDING GRP-FOR-ADD-CORR-1 FROM GRP-FOR-ADD-CORR-R.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case3() { + String source = + HEADER + + " SUBTRACT CORRESPONDING SUBTR-12 FROM SUBTR-16 ROUNDED ON \n" + + " SIZE ERROR MOVE \"G\" TO WRK-AN-00001.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case4() { + String source = + HEADER + + " SUBTRACT TBL-ITEM-1 OF TABLE-LEVEL-1A IN TABLE-LEVEL-2A OF\n" + + " TABLE-LEVEL-3A IN TABLE-LEVEL-4A OF TABLE-LEVEL-5A\n" + + " FROM TBL-ITEM-1 OF TABLE-LEVEL-1A IN TABLE-LEVEL-2A OF\n" + + " TABLE-LEVEL-3A IN TABLE-LEVEL-4A OF TABLE-LEVEL-5B\n" + + " GIVING ACCUMULATOR1.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case5() { + String source = + HEADER + + " SUBTRACT TABLE1-NUM (INDEX1) FROM NUM-9V9."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + + @Test + void case6() { + String source = + HEADER + + " SUBTRACT A FROM B DISPLAY A"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/UnstringTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/UnstringTest.java new file mode 100644 index 0000000000..ac612bf160 --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/UnstringTest.java @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Return statement */ +public class UnstringTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " UNSTRING ID1-XN-7 DELIMITED BY ZERO\n" + + " INTO ID4-X DELIMITER IN ID5-XN-4\n" + + " COUNT IN ID6-DU-2V0\n" + + " WITH POINTER ID10-DU-2V0\n" + + " TALLYING ID11-DU-2V0\n" + + " ON OVERFLOW PERFORM PASS\n" + + " GO TO UST-WRITE-GF-1.\n"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(3, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(2, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/WriteTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/WriteTest.java new file mode 100644 index 0000000000..744aa3ffcd --- /dev/null +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/WriteTest.java @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2024 Broadcom. + * The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries. + * + * This program and the accompanying materials are made + * available under the terms of the Eclipse Public License 2.0 + * which is available at https://www.eclipse.org/legal/epl-2.0/ + * + * SPDX-License-Identifier: EPL-2.0 + * + * Contributors: + * Broadcom, Inc. - initial API and implementation + */ +package org.eclipse.lsp.cobol.divisions.procedure; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.eclipse.lsp.cobol.cst.procedure.Statement; +import org.eclipse.lsp.cobol.parser.hw.CobolParser; +import org.eclipse.lsp.cobol.parser.hw.ParseResult; +import org.eclipse.lsp.cobol.parser.hw.ParserSettings; +import org.eclipse.lsp.cobol.parser.hw.lexer.CobolLexer; +import org.junit.jupiter.api.Test; + +/** Test Write statement */ +public class WriteTest { + private static final String HEADER = + " ID DIVISION. PROGRAM-ID. perf.\n" + " PROCEDURE DIVISION.\n"; + + @Test + void case1() { + String source = + HEADER + + " WRITE IX FROM WORK-RECORD INVALID KEY\n" + + " ADD 1 TO IN-COUNTER."; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(2, result.getSourceUnit().list(Statement.class).size()); + // Statement should be nested + assertEquals(1, result.getSourceUnit().list(Statement.class).get(0).list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } + @Test + void case2() { + String source = + HEADER + + " WRITE DUMMY-RECORD AFTER ADVANCING PAGE"; + CobolParser parser = new CobolParser(new CobolLexer(source), new ParserSettings()); + ParseResult result = parser.parse(); + assertEquals(0, result.getDiagnostics().size()); + assertEquals(1, result.getSourceUnit().list(Statement.class).size()); + assertEquals(source, result.getSourceUnit().toText()); + } +} diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformBasicStatementTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformBasicStatementTest.java similarity index 97% rename from server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformBasicStatementTest.java rename to server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformBasicStatementTest.java index 8e5f3445b0..0fc7fc6955 100644 --- a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformBasicStatementTest.java +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformBasicStatementTest.java @@ -11,7 +11,7 @@ * Contributors: * Broadcom, Inc. - initial API and implementation */ -package org.eclipse.lsp.cobol.divisions.procedure; +package org.eclipse.lsp.cobol.divisions.procedure.perform; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformTimesStatementTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformTimesStatementTest.java similarity index 97% rename from server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformTimesStatementTest.java rename to server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformTimesStatementTest.java index 5c98996496..4b32589378 100644 --- a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformTimesStatementTest.java +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformTimesStatementTest.java @@ -11,7 +11,7 @@ * Contributors: * Broadcom, Inc. - initial API and implementation */ -package org.eclipse.lsp.cobol.divisions.procedure; +package org.eclipse.lsp.cobol.divisions.procedure.perform; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformUntilStatementTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformUntilStatementTest.java similarity index 99% rename from server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformUntilStatementTest.java rename to server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformUntilStatementTest.java index fae84fbdcc..4f932ea8c9 100644 --- a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformUntilStatementTest.java +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformUntilStatementTest.java @@ -11,7 +11,7 @@ * Contributors: * Broadcom, Inc. - initial API and implementation */ -package org.eclipse.lsp.cobol.divisions.procedure; +package org.eclipse.lsp.cobol.divisions.procedure.perform; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformVaryingStatementTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformVaryingStatementTest.java similarity index 98% rename from server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformVaryingStatementTest.java rename to server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformVaryingStatementTest.java index 0dd2b5e809..a77bf09ad0 100644 --- a/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/PerformVaryingStatementTest.java +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/divisions/procedure/perform/PerformVaryingStatementTest.java @@ -11,7 +11,7 @@ * Contributors: * Broadcom, Inc. - initial API and implementation */ -package org.eclipse.lsp.cobol.divisions.procedure; +package org.eclipse.lsp.cobol.divisions.procedure.perform; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/HwCobolLexerTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/HwCobolLexerTest.java index 20efe2ffd6..723cd0ea6b 100644 --- a/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/HwCobolLexerTest.java +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/HwCobolLexerTest.java @@ -17,6 +17,8 @@ import static org.junit.jupiter.api.Assertions.*; +import org.eclipse.lsp.cobol.parser.hw.lexer.Token; +import org.eclipse.lsp.cobol.parser.hw.lexer.TokenType; import org.junit.jupiter.api.Test; import static org.eclipse.lsp.cobol.lexer.LexerTestUtils.*; @@ -90,6 +92,13 @@ void doubleQuotesEscape() { assertFalse(lexer.hasMore()); } + @Test + void dotIsNotAWord() { + CobolLexer lexer = new CobolLexer("."); + Token dot = lexer.forward(); + assertNotEquals(TokenType.COBOL_WORD, dot.getType()); + } + @Test void peekTest() { CobolLexer lexer = new CobolLexer("Aa\n B"); diff --git a/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/NonNumericLiteralTest.java b/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/NonNumericLiteralTest.java index 686890fc21..b2713b6fed 100644 --- a/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/NonNumericLiteralTest.java +++ b/server/parser/src/test/java/org/eclipse/lsp/cobol/lexer/NonNumericLiteralTest.java @@ -74,7 +74,7 @@ void symbols() { @Test void operands() { - CobolLexer lexer = new CobolLexer("<= >= =< =>"); + CobolLexer lexer = new CobolLexer("<= >= =< => * **"); assertToken(lexer.forward(), "<=", 0, 0, 0); assertToken(lexer.forward(), " ", 0, 2, 2); assertToken(lexer.forward(), ">=", 0, 3, 3); @@ -84,6 +84,10 @@ void operands() { assertToken(lexer.forward(), " ", 0, 8, 8); assertToken(lexer.forward(), "=", 0, 9, 9); assertToken(lexer.forward(), ">", 0, 10, 10); + assertToken(lexer.forward(), " ", 0, 11, 11); + assertToken(lexer.forward(), "*", 0, 12, 12); + assertToken(lexer.forward(), " ", 0, 13, 13); + assertToken(lexer.forward(), "**", 0, 14, 14); } }