@@ -670,8 +670,13 @@ impl<'a, R: BufRead> Parser<'a, R> {
670
670
pub fn parse_problem ( & mut self ) -> CarcaraResult < Problem > {
671
671
self . problem = Some ( Problem :: new ( ) ) ;
672
672
673
+ // Some commands can only appear once in an SMT problem
674
+ let [ mut seen_check_sat, mut seen_exit, mut seen_get_proof, mut seen_set_logic] =
675
+ [ false ; 4 ] ;
676
+
673
677
while self . current_token != Token :: Eof {
674
678
self . expect_token ( Token :: OpenParen ) ?;
679
+ let pos = self . current_position ;
675
680
let command = self . expect_command ( ) ?;
676
681
match command {
677
682
Command :: DeclareFun => {
@@ -733,13 +738,17 @@ impl<'a, R: BufRead> Parser<'a, R> {
733
738
self . expect_token ( Token :: CloseParen ) ?;
734
739
self . premises ( ) . insert ( term) ;
735
740
}
736
- Command :: CheckSatAssuming => {
741
+ Command :: CheckSatAssuming if !seen_check_sat => {
742
+ seen_check_sat = true ;
743
+
737
744
self . expect_token ( Token :: OpenParen ) ?;
738
745
let terms = self . parse_sequence ( Self :: parse_term, true ) ?;
739
746
self . expect_token ( Token :: CloseParen ) ?;
740
747
self . premises ( ) . extend ( terms) ;
741
748
}
742
- Command :: SetLogic => {
749
+ Command :: SetLogic if !seen_set_logic => {
750
+ seen_set_logic = true ;
751
+
743
752
let logic = self . expect_symbol ( ) ?;
744
753
self . expect_token ( Token :: CloseParen ) ?;
745
754
self . prelude ( ) . logic = Some ( logic. clone ( ) ) ;
@@ -752,12 +761,65 @@ impl<'a, R: BufRead> Parser<'a, R> {
752
761
( logic. contains ( "LRA" ) || logic. contains ( "NRA" ) || logic. contains ( "RDL" ) )
753
762
&& !logic. contains ( 'I' ) ;
754
763
}
755
- // TODO: properly handle all commands
756
- _ => {
757
- // If the command is not one of the commands we care about, we just ignore it.
758
- // We do that by reading tokens until the command parenthesis is closed
764
+ Command :: CheckSat if !seen_check_sat => {
765
+ seen_check_sat = true ;
766
+ self . expect_token ( Token :: CloseParen ) ?;
767
+ }
768
+ Command :: Exit if !seen_exit => {
769
+ seen_exit = true ;
770
+ self . expect_token ( Token :: CloseParen ) ?;
771
+ }
772
+ Command :: GetProof if !seen_get_proof => {
773
+ seen_get_proof = true ;
774
+ self . expect_token ( Token :: CloseParen ) ?;
775
+ }
776
+
777
+ // We only have support for problems that include at most one of these commands. If
778
+ // they appear again, we must return an error
779
+ Command :: CheckSat
780
+ | Command :: CheckSatAssuming
781
+ | Command :: Exit
782
+ | Command :: GetProof
783
+ | Command :: SetLogic => {
784
+ return Err ( Error :: Parser (
785
+ ParserError :: CommandAppearsMoreThanOnce ( command) ,
786
+ pos,
787
+ ) ) ;
788
+ }
789
+
790
+ // We can safely ignore these commands, since they do not change the problem state
791
+ Command :: Echo
792
+ | Command :: GetAssertions
793
+ | Command :: GetAssignment
794
+ | Command :: GetInfo
795
+ | Command :: GetModel
796
+ | Command :: GetOption
797
+ | Command :: GetUnsatAssumptions
798
+ | Command :: GetUnsatCore
799
+ | Command :: GetValue
800
+ | Command :: SetInfo
801
+ | Command :: SetOption => {
759
802
self . ignore_until_close_parens ( ) ?;
760
803
}
804
+
805
+ // These commands are not supported by Carcara, and we must reject any problem that
806
+ // contains them
807
+ Command :: DeclareDatatype
808
+ | Command :: DeclareDatatypes
809
+ | Command :: Pop
810
+ | Command :: Push
811
+ | Command :: Reset
812
+ | Command :: ResetAssertions => {
813
+ return Err ( Error :: Parser ( ParserError :: UnsupportedCommand ( command) , pos) ) ;
814
+ }
815
+
816
+ // These commands are only allowed when parsing the proof, not the problem
817
+ Command :: Assume | Command :: Step | Command :: Anchor => {
818
+ return Err ( Error :: Parser (
819
+ ParserError :: ProofCommandInProblem ( command) ,
820
+ pos,
821
+ ) ) ;
822
+ }
761
823
}
762
824
}
763
825
Ok ( self . problem . take ( ) . unwrap ( ) )
@@ -831,10 +893,11 @@ impl<'a, R: BufRead> Parser<'a, R> {
831
893
next_subproof_context_id += 1 ;
832
894
continue ;
833
895
}
834
- // TODO: properly handle all commands
896
+
897
+ // All other commands can only appear in the problem, not the proof
835
898
_ => {
836
899
return Err ( Error :: Parser (
837
- ParserError :: UnexpectedToken ( Token :: Command ( command) ) ,
900
+ ParserError :: ProblemCommandInProof ( command) ,
838
901
position,
839
902
) ) ;
840
903
}
0 commit comments