Skip to content

Commit

Permalink
Add parser diagnostics about END statement (#468)
Browse files Browse the repository at this point in the history
  • Loading branch information
MarkusAmshove committed Apr 15, 2024
2 parents 11967b6 + 8d0fcb6 commit 22d45ac
Show file tree
Hide file tree
Showing 18 changed files with 132 additions and 2 deletions.
Expand Up @@ -19,6 +19,7 @@ void raiseADiagnosticIfFilenameAndFunctionNameDiffer()
RETURNS (L)
FUNC := TRUE
END-FUNCTION
END
""",
expectDiagnostic(0, FunctionFilenameAnalyzer.FUNCTION_FILE_NAME_MISMATCH)
);
Expand All @@ -33,6 +34,7 @@ void raiseNoDiagnosticIfFilenameAndFunctionNameMatch()
RETURNS (L)
FUNC := TRUE
END-FUNCTION
END
""",
expectNoDiagnosticOfType(FunctionFilenameAnalyzer.FUNCTION_FILE_NAME_MISMATCH)
);
Expand Down
Expand Up @@ -20,6 +20,7 @@ void notRaiseADiagnosticIfNoAttributesArePresent()
DEFINE DATA LOCAL
END-DEFINE
DEFINE WORK FILE 1
END
""",
expectNoDiagnosticOfType(WorkFileAttributesAnalyzer.MULTIPLE_ATTRIBUTES_OF_SAME_TYPE)
);
Expand All @@ -34,6 +35,7 @@ void notRaiseADiagnosticIfAttributesAreAVariableReference()
1 #VAR (A10)
END-DEFINE
DEFINE WORK FILE 1 ATTRIBUTES #VAR
END
""",
expectNoDiagnosticOfType(WorkFileAttributesAnalyzer.MULTIPLE_ATTRIBUTES_OF_SAME_TYPE)
);
Expand All @@ -53,6 +55,7 @@ void notRaiseADiagnosticIfAttributesAreDifferentTypes(String attributes)
DEFINE DATA LOCAL
END-DEFINE
DEFINE WORK FILE 1 ATTRIBUTES '%s'
END
""".formatted(attributes),
expectNoDiagnosticOfType(WorkFileAttributesAnalyzer.MULTIPLE_ATTRIBUTES_OF_SAME_TYPE)
);
Expand All @@ -66,6 +69,7 @@ void raiseADiagnosticIfMultipleAttributesOfTheSameTypeArePresent()
DEFINE DATA LOCAL
END-DEFINE
DEFINE WORK FILE 1 ATTRIBUTES 'BOM,NOBOM'
END
""",
expectDiagnostic(2, WorkFileAttributesAnalyzer.MULTIPLE_ATTRIBUTES_OF_SAME_TYPE)
);
Expand Down
Expand Up @@ -211,6 +211,21 @@ private IStatementListNode parseBody(TokenList tokens, IModuleProvider modulePro

if (naturalModule.body() != null && naturalModule.file().getFiletype() != NaturalFileType.COPYCODE)
{
var endStatementFound = false;
for (var statement : naturalModule.body().statements())
{
if (endStatementFound)
{
reportNoSourceCodeAfterEndStatementAllowed(naturalModule, statement);
break;
}
endStatementFound = endStatementFound || (statement instanceof IEndNode);
}
if (!endStatementFound && naturalModule.body().statements().hasItems())
{
reportEndStatementMissing(naturalModule, naturalModule.body().statements().last());
}

var typer = new TypeChecker();
for (var diagnostic : typer.check(naturalModule.body()))
{
Expand Down Expand Up @@ -361,6 +376,18 @@ private void reportUnresolvedReference(NaturalModule module, ISymbolReferenceNod
module.addDiagnostic(diagnostic);
}

private void reportNoSourceCodeAfterEndStatementAllowed(NaturalModule module, IStatementNode statement)
{
var diagnostic = ParserErrors.noSourceCodeAllowedAfterEnd(statement);
module.addDiagnostic(diagnostic);
}

private void reportEndStatementMissing(NaturalModule module, IStatementNode statement)
{
var diagnostic = ParserErrors.endStatementMissing(statement);
module.addDiagnostic(diagnostic);
}

private boolean tryFindAndReference(String symbolName, ISymbolReferenceNode referenceNode, IDefineData defineData, NaturalModule module)
{
var foundVariables = ((DefineDataNode) defineData).findVariablesWithName(symbolName);
Expand Down
Expand Up @@ -56,7 +56,8 @@ public enum ParserError
VARIABLE_QUALIFICATION_NOT_ALLOWED("NPP051"),
INVALID_INPUT_STATEMENT_ATTRIBUTE("NPP052"),
INVALID_INPUT_ELEMENT_ATTRIBUTE("NPP053"),
;
NO_SOURCE_ALLOWED_AFTER_END_STATEMENT("NPP054"),
END_STATEMENT_MISSING("NPP055");

private final String id;

Expand Down
Expand Up @@ -680,4 +680,23 @@ public static IDiagnostic invalidInputElementAttribute(IAttributeNode attribute)
ParserError.INVALID_INPUT_ELEMENT_ATTRIBUTE
);
}

public static IDiagnostic noSourceCodeAllowedAfterEnd(IStatementNode statement)
{
return ParserDiagnostic.create(
"No source code allowed after the END statement",
statement,
ParserError.NO_SOURCE_ALLOWED_AFTER_END_STATEMENT
);
}

public static IDiagnostic endStatementMissing(IStatementNode statement)
{
return ParserDiagnostic.create(
"END statement missing after",
statement,
ParserError.END_STATEMENT_MISSING
);
}

}
Expand Up @@ -110,4 +110,19 @@ void raiseADiagnosticForCyclomaticCopycodes(@ProjectName("copycodetests") Natura
assertThat(subprogram.diagnostics().first().id()).isEqualTo(ParserError.CYCLOMATIC_INCLUDE.id());
assertThat(subprogram.diagnostics().first().message()).isEqualTo("Cyclomatic INCLUDE found. RECCC is recursively included multiple times.");
}

@Test
void notReportDiagnosticsForEndStatementMissingUsingCC(@ProjectName("copycodetests") NaturalProject project)
{
var subprogram = assertFileParsesAs(project.findModule("LIBONE", "NOENDSUB"), ISubprogram.class);
assertThat(subprogram.diagnostics()).isEmpty();
}

@Test
void raiseADiagnosticForDoubleEndStatementsUsingCC(@ProjectName("copycodetests") NaturalProject project)
{
var subprogram = assertFileParsesAs(project.findModule("LIBONE", "ENDSUB"), ISubprogram.class);
assertThat(subprogram.diagnostics()).isNotEmpty();
}

}
@@ -0,0 +1,13 @@
package org.amshove.natparse.parsing;

import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;

class EndStatementTests extends ResourceFolderBasedTest
{
@TestFactory
Iterable<DynamicTest> testForEndStatement()
{
return testFolder("endstatement");
}
}
Expand Up @@ -22,4 +22,5 @@ INSERT INTO ANOTHER-TABLE
(COL1) VALUES (VAL1)
FOR I4 = 1 TO 10
IGNORE
END-FOR
END-FOR
END
@@ -0,0 +1,3 @@
END
* This is a comment
ABC := 0 /* !{D:ERROR:NPP054}
@@ -0,0 +1,6 @@
END
* This is a comment
/* Comment another way
**Yet another
**ISN this is not *ISN
END /* !{D:ERROR:NPP054}
@@ -0,0 +1 @@
WRITE 'Hello' /* !{D:ERROR:NPP055}
@@ -0,0 +1,5 @@
END
* This is a comment
/* Comment another way
**Yet another
**ISN this is not *ISN
@@ -0,0 +1,3 @@
END
* This is a comment
WRITE 'Hello' /* !{D:ERROR:NPP054}
@@ -0,0 +1,5 @@
* >Natural Source Header 000000
* :Mode S
* :LineIncrement 10
* <Natural Source Header
END
@@ -0,0 +1,3 @@
* INCLUDE ENDCC activate this when CC are fully handled.
END /* Double END detected
END /* remove this when CC are fully handled.
@@ -0,0 +1,3 @@
INCLUDE DECLSUB
END
* INCLUDE ENDCC activate this when CC are fully handled.
12 changes: 12 additions & 0 deletions tools/ruletranslator/src/main/resources/rules/NPP054
@@ -0,0 +1,12 @@
name: No source allowed after the END statement
priority: BLOCKER
tags: compile-time
type: BUG
description:
The END statement indicates the end of the source of a Natural object.
No other statements or comment lines are allowed after the END
statement.

A probable cause of this error is the misspelling of a name or the
omission of 'PAGE', 'DATA', 'TRANSACTION' from the statements
AT END OF PAGE, AT END OF DATA, END TRANSACTION respectively.
7 changes: 7 additions & 0 deletions tools/ruletranslator/src/main/resources/rules/NPP055
@@ -0,0 +1,7 @@
name: END statement missing
priority: BLOCKER
tags: compile-time
type: BUG
description:
The last statement of a Natural program must always be END.
Alternatively, a period '.' may be used.

0 comments on commit 22d45ac

Please sign in to comment.