From 12406c787b5acc0cef4b7e699db8b54a3908c78e Mon Sep 17 00:00:00 2001 From: Riccardo Azzolini Date: Mon, 9 Sep 2019 18:32:18 +0200 Subject: [PATCH] Ensure that lex and parse methods are only called once per instance --- .../warppi/math/rules/dsl/frontend/Lexer.java | 7 +++++++ .../warppi/math/rules/dsl/frontend/Parser.java | 7 +++++++ .../warppi/math/rules/dsl/frontend/LexerTest.java | 7 +++++++ .../warppi/math/rules/dsl/frontend/ParserTest.java | 10 ++++++++++ 4 files changed, 31 insertions(+) diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Lexer.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Lexer.java index 7c4ba517..f49cb681 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Lexer.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Lexer.java @@ -29,6 +29,7 @@ public class Lexer { private final String source; private final Consumer errorReporter; + private boolean used = false; private final List tokens = new ArrayList<>(); private int startOfLexeme = 0; private int curPosition = 0; @@ -55,8 +56,14 @@ public class Lexer { * If any errors are reported, this list should not be considered to represent a valid set of DSL rules, * but it can still be parsed to potentially find additional errors (which may allow the user to fix more * errors before having to rerun the Lexer). + * @throws IllegalStateException if called multiple times on the same instance. */ public List lex() { + if (used) { + throw new IllegalStateException("Lexer.lex can only be called once per instance"); + } + used = true; + while (!atEnd()) { startOfLexeme = curPosition; lexAndHandleErrors(); diff --git a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Parser.java b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Parser.java index a9699981..d2eabbd0 100644 --- a/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Parser.java +++ b/core/src/main/java/it/cavallium/warppi/math/rules/dsl/frontend/Parser.java @@ -29,6 +29,7 @@ public class Parser { private final List tokens; private final Consumer errorReporter; + private boolean used = false; private int currentIndex = 0; // For error reporting @@ -57,8 +58,14 @@ public class Parser { * but each rule can still be analyzed to look for undefined sub-functions in replacement patterns and * report them (which may allow the user to fix more errors before having to rerun the Lexer * and Parser). + * @throws IllegalStateException if called multiple times on the same instance. */ public List parse() { + if (used) { + throw new IllegalStateException("Parser.parse can only be called once per instance"); + } + used = true; + return rules(); } diff --git a/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/LexerTest.java b/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/LexerTest.java index d96c9d2d..2aa35674 100644 --- a/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/LexerTest.java +++ b/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/LexerTest.java @@ -29,6 +29,13 @@ class LexerTest { assertEquals(expected, lexer.lex()); } + @Test + void multipleLexCalls() { + final Lexer lexer = new Lexer("", errors::add); + lexer.lex(); + assertThrows(IllegalStateException.class, lexer::lex); + } + @Test void validRule() { final Lexer lexer = new Lexer( diff --git a/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/ParserTest.java b/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/ParserTest.java index 4554c264..6157e2db 100644 --- a/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/ParserTest.java +++ b/core/src/test/java/it/cavallium/warppi/math/rules/dsl/frontend/ParserTest.java @@ -38,6 +38,16 @@ class ParserTest { assertEquals(Collections.emptyList(), parser.parse()); } + @Test + void multipleParseCalls() { + final List tokens = Collections.singletonList( + new Token(EOF, "", 0) + ); + final Parser parser = new Parser(tokens, errors::add); + parser.parse(); + assertThrows(IllegalStateException.class, parser::parse); + } + @Test void validRuleMultipleReplacements() { final List tokens = Arrays.asList(