@@ -26,6 +26,7 @@ use ast::{DeclKind, Diagnostic, FileId};
2626use clap:: { crate_description, Args , CommandFactory , Parser , Subcommand , ValueEnum } ;
2727use driver:: { Item , SourceUnit , VerifyUnit } ;
2828use intrinsic:: { annotations:: init_calculi, distributions:: init_distributions, list:: init_lists} ;
29+ use mc:: run_storm:: { run_storm, storm_result_to_diagnostic} ;
2930use proof_rules:: init_encodings;
3031use regex:: Regex ;
3132use resource_limits:: { await_with_resource_limits, LimitError , LimitsRef } ;
@@ -185,6 +186,17 @@ pub struct ResourceLimitOptions {
185186 pub mem_limit : u64 ,
186187}
187188
189+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Default , ValueEnum ) ]
190+ pub enum RunWhichStorm {
191+ /// Look for the Storm binary in the PATH.
192+ #[ default]
193+ Path ,
194+ /// Run Storm using Docker, with the `movesrwth/storm:stable` image.
195+ DockerStable ,
196+ /// Run Storm using Docker, with the `movesrwth/storm:ci` image.
197+ DockerCI ,
198+ }
199+
188200#[ derive( Debug , Default , Clone , Args ) ]
189201#[ command( next_help_heading = "JANI Output Options" ) ]
190202pub struct JaniOptions {
@@ -204,6 +216,26 @@ pub struct JaniOptions {
204216 /// checking quite a bit. To disable this behavior, use this flag.
205217 #[ arg( long) ]
206218 pub jani_uninit_outputs : bool ,
219+
220+ /// Run Storm, indicating which version to execute.
221+ #[ arg( long) ]
222+ pub run_storm : Option < RunWhichStorm > ,
223+
224+ /// Pass the `--exact` flag to Storm. Otherwise Storm will use floating
225+ /// point numbers, which may be arbitrarily imprecise (but are usually good
226+ /// enough).
227+ #[ arg( long) ]
228+ pub storm_exact : bool ,
229+
230+ /// Pass the `--state-limit [number]` option to Storm. This is useful to
231+ /// approximate infinite-state models.
232+ #[ arg( long) ]
233+ pub storm_state_limit : Option < usize > ,
234+
235+ /// Pass the `--constants [constants]` option to Storm, containing values
236+ /// for constants in the model.
237+ #[ arg( long) ]
238+ pub storm_constants : Option < String > ,
207239}
208240
209241#[ derive( Debug , Default , Args ) ]
@@ -717,15 +749,13 @@ fn verify_files_main(
717749 }
718750
719751 // write to JANI if requested
720- for source_unit in & mut source_units {
721- let source_unit = source_unit. enter ( ) ;
722- let jani_res = source_unit. write_to_jani_if_requested ( & options. jani_options , & tcx) ;
723- match jani_res {
724- Err ( VerifyError :: Diagnostic ( diagnostic) ) => server. add_diagnostic ( diagnostic) ?,
725- Err ( err) => Err ( err) ?,
726- _ => ( ) ,
727- }
728- }
752+ to_jani_main (
753+ & options. jani_options ,
754+ & mut source_units,
755+ server,
756+ & tcx,
757+ false ,
758+ ) ?;
729759
730760 // Desugar encodings from source units. They might generate new source
731761 // units (for side conditions).
@@ -883,36 +913,78 @@ fn run_to_jani_main(options: ToJaniCommand) -> ExitCode {
883913 Ok ( value) => value,
884914 Err ( value) => return value,
885915 } ;
886- let res = to_jani_main ( & options, user_files, & server) . map ( |_| true ) ;
916+ let res = to_jani_loader ( & options, user_files, & server) . map ( |_| true ) ;
887917 finalize_verify_result ( server, & options. rlimit_options , res)
888918}
889919
890- fn to_jani_main (
920+ fn to_jani_loader (
891921 options : & ToJaniCommand ,
892922 user_files : Vec < FileId > ,
893- server : & SharedServer ,
923+ server : & Mutex < dyn Server > ,
894924) -> Result < ( ) , VerifyError > {
895- let mut server = server. lock ( ) . unwrap ( ) ;
925+ let mut server_lock = server. lock ( ) . unwrap ( ) ;
896926 let ( mut source_units, tcx) = parse_and_tycheck (
897927 & options. input_options ,
898928 & options. debug_options ,
899- & mut * server ,
929+ & mut * server_lock ,
900930 & user_files,
901931 ) ?;
902- if options. jani_options . jani_dir . is_none ( ) {
903- return Err ( VerifyError :: UserError (
904- "--jani-dir is required for the to-jani command." . into ( ) ,
905- ) ) ;
932+ to_jani_main (
933+ & options. jani_options ,
934+ & mut source_units,
935+ server_lock. deref_mut ( ) ,
936+ & tcx,
937+ true ,
938+ )
939+ }
940+
941+ fn to_jani_main (
942+ options : & JaniOptions ,
943+ source_units : & mut Vec < Item < SourceUnit > > ,
944+ server : & mut dyn Server ,
945+ tcx : & TyCtx ,
946+ is_jani_command : bool ,
947+ ) -> Result < ( ) , VerifyError > {
948+ let mut options = options. clone ( ) ;
949+
950+ let mut temp_dir = None ;
951+ if options. jani_dir . is_none ( ) {
952+ if is_jani_command && options. run_storm . is_none ( ) {
953+ return Err ( VerifyError :: UserError (
954+ "--jani-dir is required for the to-jani command." . into ( ) ,
955+ ) ) ;
956+ } else {
957+ temp_dir = Some ( tempfile:: tempdir ( ) . map_err ( |err| {
958+ VerifyError :: UserError (
959+ format ! ( "Could not create temporary directory: {}" , err) . into ( ) ,
960+ )
961+ } ) ?) ;
962+ options. jani_dir = temp_dir. as_ref ( ) . map ( |dir| dir. path ( ) . to_owned ( ) ) ;
963+ }
906964 }
907- for source_unit in & mut source_units {
965+ for source_unit in source_units {
908966 let source_unit = source_unit. enter ( ) ;
909- let jani_res = source_unit. write_to_jani_if_requested ( & options. jani_options , & tcx) ;
967+ let jani_res = source_unit. write_to_jani_if_requested ( & options, tcx) ;
910968 match jani_res {
911969 Err ( VerifyError :: Diagnostic ( diagnostic) ) => server. add_diagnostic ( diagnostic) ?,
912970 Err ( err) => Err ( err) ?,
913- Ok ( ( ) ) => ( ) ,
971+ Ok ( Some ( path) ) => {
972+ tracing:: debug!( file=?path. display( ) , "wrote JANI file" ) ;
973+ if let Some ( which_storm) = options. run_storm {
974+ let res = run_storm ( & options, which_storm, & path, vec ! [ "reward" . to_owned( ) ] ) ;
975+ server. add_diagnostic ( storm_result_to_diagnostic (
976+ & res,
977+ source_unit. diagnostic_span ( ) ,
978+ ) ) ?;
979+ }
980+ }
981+ Ok ( None ) => ( ) ,
914982 }
915983 }
984+
985+ // only drop (and thus remove) the temp dir after we're done using it.
986+ drop ( temp_dir) ;
987+
916988 Ok ( ( ) )
917989}
918990
0 commit comments