From ad83630072b0efaa49c91fd86373e895bd59bfcf Mon Sep 17 00:00:00 2001 From: Jonah Jeleniewski Date: Tue, 8 Oct 2024 12:16:41 +1100 Subject: [PATCH] Fix parsing errors on `implementation` keywords in conditional branches --- CHANGELOG.md | 4 ++++ .../au/com/integradev/delphi/antlr/Delphi.g | 5 +++-- .../delphi/file/DelphiFileTest.java | 22 +++++++++++++++++-- .../delphi/file/SkipImplementation.pas | 9 ++++++++ ...SkipImplementationWithDirectiveNesting.pas | 14 ++++++++++++ 5 files changed, 50 insertions(+), 4 deletions(-) create mode 100644 delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementation.pas create mode 100644 delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementationWithDirectiveNesting.pas diff --git a/CHANGELOG.md b/CHANGELOG.md index 15ce12370..f6ea42b89 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +### Fixed + +- Parsing errors on `implementation` keywords nested in conditional branches. + ## [1.10.0] - 2024-10-01 ### Added diff --git a/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g b/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g index 3024c0c5e..b75d52505 100644 --- a/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g +++ b/delphi-frontend/src/main/antlr3/au/com/integradev/delphi/antlr/Delphi.g @@ -122,6 +122,7 @@ import au.com.integradev.delphi.antlr.ast.node.*; package au.com.integradev.delphi.antlr; +import org.apache.commons.lang3.StringUtils; } @lexer::members { @@ -1503,9 +1504,9 @@ COMMENT : '//' ~('\n'|'\r')* {$channel if ($text.startsWith(start + "\$")) { $type = TkCompilerDirective; - if ($text.startsWith(start + "\$endif") || $text.startsWith(start + "\$ifend")) { + if (StringUtils.startsWithIgnoreCase($text, start + "\$endif") || StringUtils.startsWithIgnoreCase($text, start + "\$ifend")) { --directiveNesting; - } else if ($text.startsWith(start + "\$if")) { + } else if (StringUtils.startsWithIgnoreCase($text, start + "\$if")) { ++directiveNesting; } } diff --git a/delphi-frontend/src/test/java/au/com/integradev/delphi/file/DelphiFileTest.java b/delphi-frontend/src/test/java/au/com/integradev/delphi/file/DelphiFileTest.java index af9b28311..faee59963 100644 --- a/delphi-frontend/src/test/java/au/com/integradev/delphi/file/DelphiFileTest.java +++ b/delphi-frontend/src/test/java/au/com/integradev/delphi/file/DelphiFileTest.java @@ -18,8 +18,7 @@ */ package au.com.integradev.delphi.file; -import static org.assertj.core.api.Assertions.assertThat; -import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.assertj.core.api.Assertions.*; import au.com.integradev.delphi.compiler.Platform; import au.com.integradev.delphi.core.Delphi; @@ -36,6 +35,8 @@ import java.nio.charset.StandardCharsets; import java.util.Collections; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import org.sonar.api.batch.fs.InputFile; import org.sonar.api.batch.fs.internal.TestInputFileBuilder; @@ -106,4 +107,21 @@ void testByteOrderMarkShouldBeStripped() { String firstLine = delphiFile.getSourceCodeFileLines().get(0); assertThat(firstLine).doesNotStartWith("\ufeff"); } + + @ParameterizedTest + @ValueSource(strings = {"SkipImplementation.pas", "SkipImplementationWithDirectiveNesting.pas"}) + void testShouldSkipImplementation(String filename) { + File file = DelphiUtils.getResource("/au/com/integradev/delphi/file/" + filename); + + DelphiFileConfig config = + DelphiFile.createConfig( + StandardCharsets.UTF_8.name(), + new DelphiPreprocessorFactory(Platform.WINDOWS), + TypeFactoryUtils.defaultFactory(), + SearchPath.create(Collections.emptyList()), + Collections.emptySet(), + true); + + assertThatNoException().isThrownBy(() -> DelphiFile.from(file, config)); + } } diff --git a/delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementation.pas b/delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementation.pas new file mode 100644 index 000000000..1d9bddbfd --- /dev/null +++ b/delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementation.pas @@ -0,0 +1,9 @@ +unit SkipImplementation; + +interface + +implementation + +ERROR + +end. diff --git a/delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementationWithDirectiveNesting.pas b/delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementationWithDirectiveNesting.pas new file mode 100644 index 000000000..cda577630 --- /dev/null +++ b/delphi-frontend/src/test/resources/au/com/integradev/delphi/file/SkipImplementationWithDirectiveNesting.pas @@ -0,0 +1,14 @@ +unit SkipImplementationWithDirectiveNesting; + +interface + +{$If False} +type + TFoo = ERROR class + emd; +implementation +{$eLsE} +implementation +{$endif} + +end.