-
Notifications
You must be signed in to change notification settings - Fork 57
620 smtlib2 parser tokenizer wrongly rejects set logic commands and has a non helpful error message for parse for 1 items #621
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
baierd
wants to merge
12
commits into
master
Choose a base branch
from
620-smtlib2-parser-tokenizer-wrongly-rejects-set-logic-commands-and-has-a-non-helpful-error-message-for-parse-for-1-items
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
2190f46
Add check to parse() to return a proper error message in case only 1 …
baierd cf191f3
Add SMTLIB2 tokenizer for set-info command
baierd 62a97f9
Allow set-logic in all cases in
baierd 237a4b5
Add simplification to Bitwuzlas option resolving so that we don't eva…
baierd 1d589d9
Refactor some SanitizerTest tests into dedicated test cases and refle…
baierd ce363b6
Disable a VariableNamesTest for Boolector, as it returns an empty string
baierd 4b9656a
Add a SMTLIB2 state-machine according to the standard with some optio…
baierd 9a93da1
Merge branch 'master' into 620-smtlib2-parser-tokenizer-wrongly-rejec…
baierd 6af7ff2
Remove wrongfully pushed debug code ;D
baierd 7ae56bb
Format
baierd 4d71f4c
Remove assertion added with new smtlib state machine that prevents em…
baierd 1dba0bb
Apply checkstyle suggestions to AbstractFormulaManager and switch if …
baierd File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,6 +10,12 @@ | |
|
|
||
| import static com.google.common.base.Preconditions.checkArgument; | ||
| import static com.google.common.base.Preconditions.checkNotNull; | ||
| import static org.sosy_lab.java_smt.basicimpl.AbstractFormulaManager.SMTLIB2ProgramState.ASSERT_MODE; | ||
| import static org.sosy_lab.java_smt.basicimpl.AbstractFormulaManager.SMTLIB2ProgramState.EXITED_STATE; | ||
| import static org.sosy_lab.java_smt.basicimpl.AbstractFormulaManager.SMTLIB2ProgramState.RESULT_MODE; | ||
| import static org.sosy_lab.java_smt.basicimpl.AbstractFormulaManager.SMTLIB2ProgramState.SAT_MODE; | ||
| import static org.sosy_lab.java_smt.basicimpl.AbstractFormulaManager.SMTLIB2ProgramState.START_MODE; | ||
| import static org.sosy_lab.java_smt.basicimpl.AbstractFormulaManager.SMTLIB2ProgramState.UNSAT_MODE; | ||
|
|
||
| import com.google.common.annotations.VisibleForTesting; | ||
| import com.google.common.base.CharMatcher; | ||
|
|
@@ -396,21 +402,38 @@ private String sanitize(String formulaStr) { | |
| List<String> tokens = Tokenizer.tokenize(formulaStr); | ||
|
|
||
| StringBuilder builder = new StringBuilder(); | ||
| int pos = 0; // index of the current token | ||
|
|
||
| // SMTLIB2ProgramState tracks that the SMTLIB2 query conforms to the rules outlined in the | ||
| // standard. SMTLIB2ProgramStateMachine models the | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This comment seems to have been cut off |
||
| SMTLIB2ProgramStateMachine smtLibStateMachine = new SMTLIB2ProgramStateMachine(false); | ||
|
|
||
| for (String token : tokens) { | ||
| if (Tokenizer.isSetLogicToken(token)) { | ||
| // Skip the (set-logic ...) command at the beginning of the input | ||
| Preconditions.checkArgument(pos == 0); | ||
| if (Tokenizer.isSetInfoToken(token)) { | ||
| // set-info call is allowed to be the very first command in the benchmark, but can also | ||
| // appear repeatedly throughout a SMT2 program | ||
| // Technically it is even required to be the very first command, and it must set the | ||
| // :smt-lib-version attribute. See SMT-LIB 2.7 §3.11.3 | ||
| // TODO: check that version >= 2 for attribute :smt-lib-version? | ||
| smtLibStateMachine.applyGSIOCommand(); | ||
|
|
||
| } else if (Tokenizer.isSetLogicToken(token)) { | ||
| // (set-logic ...) commands must appear before an assertion is made. They may appear | ||
| // throughout an SMT-LIB2 program to set the 'current logic' to a new logic, but the 'reset' | ||
| // command has to be used before doing so every time. | ||
| // The logic 'ALL' is the logic describing all available logics of a solver. | ||
| // The following commands are allowed to be used before the very first 'set-logic': | ||
| // echo, reset, reset-assertions, get-info, get-option, set-info, set-option | ||
| smtLibStateMachine.applySetLogicCommand(); | ||
|
|
||
| } else if (Tokenizer.isExitToken(token)) { | ||
| // Skip the (exit) command at the end of the input | ||
| Preconditions.checkArgument(pos == tokens.size() - 1); | ||
| smtLibStateMachine.applyExitCommand(); | ||
|
|
||
| } else if (Tokenizer.isDeclarationToken(token) | ||
| || Tokenizer.isDefinitionToken(token) | ||
| || Tokenizer.isAssertToken(token)) { | ||
| // Keep only declaration, definitions and assertion | ||
| smtLibStateMachine.applyAssertDeclareCommands(); | ||
| builder.append(token).append('\n'); | ||
|
|
||
| } else if (Tokenizer.isForbiddenToken(token)) { | ||
|
|
@@ -421,25 +444,29 @@ private String sanitize(String formulaStr) { | |
| // moment. If needed, this feature can still be added later. | ||
| String message; | ||
| if (Tokenizer.isPushToken(token)) { | ||
| smtLibStateMachine.applyPCommand(); | ||
| message = "(push ...)"; | ||
| } else if (Tokenizer.isPopToken(token)) { | ||
| smtLibStateMachine.applyPCommand(); | ||
| message = "(pop ...)"; | ||
| } else if (Tokenizer.isResetAssertionsToken(token)) { | ||
| smtLibStateMachine.applyResetAssertionsCommand(); | ||
| message = "(reset-assertions)"; | ||
| } else if (Tokenizer.isResetToken(token)) { | ||
| smtLibStateMachine.applyResetCommand(); | ||
| message = "(reset)"; | ||
| } else { | ||
| // Should be unreachable | ||
| throw new UnsupportedOperationException(); | ||
| throw new UnsupportedOperationException("Unknown token " + checkNotNull(token)); | ||
| } | ||
| throw new IllegalArgumentException( | ||
| String.format("SMTLIB command '%s' is not supported when parsing formulas.", message)); | ||
|
|
||
| } else { | ||
| // Remove everything else, such as unknown or solver-specific commands, comments, etc. | ||
| } | ||
| pos++; | ||
| } | ||
|
|
||
| return builder.toString(); | ||
| } | ||
|
|
||
|
|
@@ -811,4 +838,213 @@ public final String unescape(String pVar) { | |
| } | ||
| return pVar; // unchanged | ||
| } | ||
|
|
||
| public enum SMTLIB2ProgramState { | ||
| /** Initial state. Can be re-entered using the 'reset' command. */ | ||
| START_MODE, | ||
| /** | ||
| * Mode entered after the initial setup is done by executing the 'set-logic' command. In this | ||
| * state, formulas can be defined/asserted etc. | ||
| */ | ||
| ASSERT_MODE, | ||
| /** Mode entered after SAT has been returned after calling 'check-set'. */ | ||
| SAT_MODE, | ||
| /** Mode entered after UNSAT has been returned after calling 'check-set'. */ | ||
| UNSAT_MODE, | ||
| /** | ||
| * Joined alternative to SAT_MODE and UNSAT_MODE. Used if we don't solve, i.e. don't know | ||
| * whether we are in a SAT/UNSAT state after 'check-sat'. | ||
| */ | ||
| RESULT_MODE, | ||
| /** | ||
| * State after 'exit' has been called. No operations are possible anymore and everything ends in | ||
| * an error. | ||
| */ | ||
| EXITED_STATE | ||
| } | ||
|
|
||
| /** | ||
| * As defined by the <a | ||
| * href="https://smt-lib.org/papers/smt-lib-reference-v2.6-r2021-05-12.pdf">SMT-LIB2 standard</a> | ||
| * an SMT-LIB2 program is allowed to utilize certain commands only if certain preconditions are | ||
| * met. This state-machine models this in two ways: | ||
| * | ||
| * <p>- a lenient parse mode, that replaces the SAT_MODE and UNSAT_MODE with a joined RESULT_MODE, | ||
| * as we are only interested in the resulting {@link BooleanFormula}s and don't solve the queries, | ||
| * hence we can't decide whether we are in SAT/UNSAT_MODE. | ||
| * | ||
| * <p>- parsing including solving utilizes the SAT_MODE and UNSAT_MODE after 'check-sat'. | ||
| * | ||
| * <p>All methods return either the new state (which may be equal to the old), or throw a {@link | ||
| * IllegalArgumentException} with an error message explaining the problem. | ||
| */ | ||
| static class SMTLIB2ProgramStateMachine { | ||
|
|
||
| private SMTLIB2ProgramState state = START_MODE; | ||
|
|
||
| private final boolean strictLogicSelectionRequired; | ||
|
|
||
| // TODO: track current logic | ||
| // private LOGIC currentLogic; | ||
|
|
||
| private static final String EXIT_ERROR_MSG = | ||
| "It is not allowed to call any more SMT-LIB2 commands " + "after 'exit' has been used"; | ||
|
|
||
| /** | ||
| * Creates a new SMTLIB2ProgramStateMachine for a new SMTLIB2 query (parsing or dumping). | ||
| * | ||
| * @param pRequiresStrictLogicSelection if false, no logic has to be set before switching to | ||
| * assertion mode, assuming logic 'ALL' implicitly. If true, logic selection is strictly | ||
| * required before defining, declaring or asserting terms etc., as specified by the SMT-LIB2 | ||
| * standard. | ||
| */ | ||
| SMTLIB2ProgramStateMachine(boolean pRequiresStrictLogicSelection) { | ||
| strictLogicSelectionRequired = pRequiresStrictLogicSelection; | ||
| } | ||
|
|
||
| /** | ||
| * Transitions into the SMTLIB2 program state after the 'exit' command, that disallows any | ||
| * further commands. | ||
| */ | ||
| void applyExitCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| state = EXITED_STATE; | ||
| } | ||
|
|
||
| /** | ||
| * Used to get the new SMTLIB2 program state for commands: 'declare-*', 'define-*', and | ||
| * 'assert'. | ||
| */ | ||
| void applyAssertDeclareCommands() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| if (state != START_MODE) { | ||
| state = ASSERT_MODE; | ||
| } else if (!strictLogicSelectionRequired) { | ||
| checkArgument(state == START_MODE); | ||
| // Not part of the logic above as we still want to reject later 'set-logic' commands! | ||
| state = ASSERT_MODE; | ||
| } else { | ||
| throw new IllegalArgumentException( | ||
| "SMT-LIB2 command 'assert', or any of the 'declare-*' and 'define-*' commands are only" | ||
| + " allowed to be used after a logic has been set via the 'set-logic' command"); | ||
| } | ||
| } | ||
|
|
||
| /** Used to get the new SMTLIB2 program state for command: 'check-sat'. */ | ||
| void applyCheckSatCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| if (state != START_MODE || !strictLogicSelectionRequired) { | ||
| // Switches to SAT or UNSAT mode, but we don't solve, we parse, | ||
| // hence we use a collective state. | ||
| // Also, if we allow implicit logic selection, no assertion is required for trivial results | ||
| state = RESULT_MODE; | ||
| } else { | ||
| throw new IllegalArgumentException( | ||
| "SMT-LIB2 command 'check-sat' is only allowed to be used after a logic has been set via" | ||
| + " the 'set-logic' command"); | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Used to get the new SMTLIB2 program state for the 'echo' command. This options transition | ||
| * always into the current state and calling this method is not necessary. | ||
| */ | ||
| void applyEchoCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| } | ||
|
|
||
| /** Used to transition into the new SMTLIB2 program state for the 'get-assertion' command. */ | ||
| void applyGetAssertionCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| // Funnily, you are allowed to use 'get-assertion' without asserting something. | ||
| // TODO: Section 4.1.7 of the standard (2.6) says: | ||
| // "The command can be issued only if the :produce-assertions option, which is set to | ||
| // false by default, is set to true." | ||
| checkArgument( | ||
| state != START_MODE || !strictLogicSelectionRequired, | ||
| "SMT-LIB2 command 'get-assertion' is only allowed to be used after a logic has been set" | ||
| + " via the 'set-logic' command"); | ||
| /* | ||
| checkArgument(options.contains(PRODUCE_ASSERTIONS), | ||
| "SMT-LIB2 command 'get-assertion' is only allowed to be used after the " | ||
| + ":produce-assertions option has been set"); | ||
| */ | ||
| } | ||
|
|
||
| /** | ||
| * Used to transition into the new SMTLIB2 program state for commands: 'get-assignment', | ||
| * 'get-model', and 'get-value'. | ||
| */ | ||
| void applyGAMVCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| checkArgument( | ||
| state == SAT_MODE || state == RESULT_MODE, | ||
| "SMT-LIB2 commands 'get-model', 'get-assignment', and 'get-value' are only allowed to be" | ||
| + " used after 'check-sat' has been called and returned SAT"); | ||
| } | ||
|
|
||
| /** | ||
| * Used to transition into the new SMTLIB2 program state for commands: 'get-info', 'get-option', | ||
| * 'set-info', 'set-option'. These options transition always into the current state and calling | ||
| * this method is not necessary. | ||
| */ | ||
| void applyGSIOCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| } | ||
|
|
||
| /** | ||
| * Used to transition into the new SMTLIB2 program state for commands: 'get-unsat-*', | ||
| * 'get-proof'. | ||
| */ | ||
| void applyGPUCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| checkArgument( | ||
| state == UNSAT_MODE || state == RESULT_MODE, | ||
| "SMT-LIB2 command 'get-proof' and all 'get-unsat-*' commands are only allowed to be" | ||
| + " used after 'check-sat' has been called and returned UNSAT"); | ||
| } | ||
|
|
||
| /** Used to transition into the new SMTLIB2 program state for the 'push' and 'pop' commands. */ | ||
| void applyPCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| if (state != START_MODE || !strictLogicSelectionRequired) { | ||
| state = ASSERT_MODE; | ||
| } else { | ||
| throw new IllegalArgumentException( | ||
| "SMT-LIB2 commands 'push' and 'pop' are only allowed to " | ||
| + "be used once a logic has been set"); | ||
| } | ||
| } | ||
|
|
||
| /** Used to transition into the new SMTLIB2 program state for the 'reset' command. */ | ||
| void applyResetCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| state = START_MODE; | ||
| } | ||
|
|
||
| /** Used to transition into the new SMTLIB2 program state for the 'reset-assertions' command. */ | ||
| void applyResetAssertionsCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| if (state != START_MODE && state != ASSERT_MODE) { | ||
| state = ASSERT_MODE; | ||
| } | ||
| } | ||
|
|
||
| /** Used to transition into the new SMTLIB2 program state for the 'set-logic' command. */ | ||
| void applySetLogicCommand() { | ||
| checkArgument(state != EXITED_STATE, EXIT_ERROR_MSG); | ||
| if (state == START_MODE) { | ||
| state = ASSERT_MODE; | ||
| } else if (!strictLogicSelectionRequired) { | ||
| // We allowed implicit logic selection and assumed 'ALL' already (by asserting or defining) | ||
| throw new IllegalArgumentException( | ||
| "SMT-LIB2 command 'set-logic' is not allowed to be used after declaring, defining or " | ||
| + "asserting terms"); | ||
| } else { | ||
| throw new IllegalArgumentException( | ||
| "SMT-LIB2 command 'set-logic' is not allowed to be used more than once without calling" | ||
| + " 'reset' first"); | ||
| } | ||
| } | ||
| } | ||
| } | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
String concatenation not required. Remove the PLUS.