@@ -3,18 +3,28 @@ use base64::engine::general_purpose::STANDARD;
33use clap:: { Arg , ArgAction , Command } ;
44
55use simplicityhl:: { Arguments , CompiledProgram } ;
6- use std:: env;
6+ use std:: { env, fmt } ;
77
8- // Directly returning Result<(), String> prints the error using Debug
9- // Add indirection via run() to print errors using Display
10- fn main ( ) {
11- if let Err ( error) = run ( ) {
12- eprintln ! ( "{error}" ) ;
13- std:: process:: exit ( 1 ) ;
8+ #[ cfg_attr( feature = "serde" , derive( serde:: Serialize ) ) ]
9+ /// The compilation output.
10+ struct Output {
11+ /// Simplicity program result, base64 encoded.
12+ program : String ,
13+ /// Simplicity witness result, base64 encoded, if the .wit file was provided.
14+ witness : Option < String > ,
15+ }
16+
17+ impl fmt:: Display for Output {
18+ fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
19+ writeln ! ( f, "Program:\n {}" , self . program) ?;
20+ if let Some ( witness) = & self . witness {
21+ writeln ! ( f, "Witness:\n {}" , witness) ?;
22+ }
23+ Ok ( ( ) )
1424 }
1525}
1626
17- fn run ( ) -> Result < ( ) , String > {
27+ fn main ( ) -> Result < ( ) , Box < dyn std :: error :: Error > > {
1828 let command = {
1929 Command :: new ( env ! ( "CARGO_BIN_NAME" ) )
2030 . about (
@@ -31,76 +41,82 @@ fn run() -> Result<(), String> {
3141 . action ( ArgAction :: Set )
3242 . help ( "SimplicityHL program file to build" ) ,
3343 )
34- } ;
35-
36- let command = {
37- command. arg (
38- Arg :: new ( "wit_file" )
39- . value_name ( "WITNESS_FILE" )
40- . action ( ArgAction :: Set )
41- . help ( "File containing the witness data" ) ,
42- )
43- } ;
44-
45- let matches = {
46- command
44+ . arg (
45+ Arg :: new ( "wit_file" )
46+ . value_name ( "WITNESS_FILE" )
47+ . action ( ArgAction :: Set )
48+ . help ( "File containing the witness data" ) ,
49+ )
4750 . arg (
4851 Arg :: new ( "debug" )
4952 . long ( "debug" )
5053 . action ( ArgAction :: SetTrue )
5154 . help ( "Include debug symbols in the output" ) ,
5255 )
53- . get_matches ( )
56+ . arg (
57+ Arg :: new ( "json" )
58+ . long ( "json" )
59+ . action ( ArgAction :: SetTrue )
60+ . help ( "Output in JSON" ) ,
61+ )
5462 } ;
5563
64+ let matches = command. get_matches ( ) ;
65+
5666 let prog_file = matches. get_one :: < String > ( "prog_file" ) . unwrap ( ) ;
5767 let prog_path = std:: path:: Path :: new ( prog_file) ;
5868 let prog_text = std:: fs:: read_to_string ( prog_path) . map_err ( |e| e. to_string ( ) ) ?;
5969 let include_debug_symbols = matches. get_flag ( "debug" ) ;
70+ let output_json = matches. get_flag ( "json" ) ;
6071
6172 let compiled = CompiledProgram :: new ( prog_text, Arguments :: default ( ) , include_debug_symbols) ?;
6273
6374 #[ cfg( feature = "serde" ) ]
64- let witness_opt = {
65- matches
66- . get_one :: < String > ( "wit_file" )
67- . map ( |wit_file| -> Result < simplicityhl:: WitnessValues , String > {
68- let wit_path = std:: path:: Path :: new ( wit_file) ;
69- let wit_text = std:: fs:: read_to_string ( wit_path) . map_err ( |e| e. to_string ( ) ) ?;
70- let witness =
71- serde_json:: from_str :: < simplicityhl:: WitnessValues > ( & wit_text) . unwrap ( ) ;
72- Ok ( witness)
73- } )
74- . transpose ( ) ?
75- } ;
75+ let witness_opt = matches
76+ . get_one :: < String > ( "wit_file" )
77+ . map ( |wit_file| -> Result < simplicityhl:: WitnessValues , String > {
78+ let wit_path = std:: path:: Path :: new ( wit_file) ;
79+ let wit_text = std:: fs:: read_to_string ( wit_path) . map_err ( |e| e. to_string ( ) ) ?;
80+ let witness = serde_json:: from_str :: < simplicityhl:: WitnessValues > ( & wit_text) . unwrap ( ) ;
81+ Ok ( witness)
82+ } )
83+ . transpose ( ) ?;
7684 #[ cfg( not( feature = "serde" ) ) ]
77- let witness_opt: Option < simplicityhl:: WitnessValues > = {
78- if matches. contains_id ( "wit_file" ) {
79- return Err (
80- "Program was compiled without the 'serde' feature and cannot process .wit files."
81- . into ( ) ,
82- ) ;
83- }
85+ let witness_opt = if matches. contains_id ( "wit_file" ) {
86+ return Err (
87+ "Program was compiled without the 'serde' feature and cannot process .wit files."
88+ . into ( ) ,
89+ ) ;
90+ } else {
8491 None
8592 } ;
8693
87- if let Some ( witness) = witness_opt {
88- let satisfied = compiled. satisfy ( witness) ?;
89- let ( program_bytes, witness_bytes) = satisfied. redeem ( ) . to_vec_with_witness ( ) ;
90- println ! (
91- "Program:\n {}" ,
92- Base64Display :: new( & program_bytes, & STANDARD )
93- ) ;
94- println ! (
95- "Witness:\n {}" ,
96- Base64Display :: new( & witness_bytes, & STANDARD )
94+ let ( program_bytes, witness_bytes) = match witness_opt {
95+ Some ( witness) => {
96+ let satisfied = compiled. satisfy ( witness) ?;
97+ let ( program_bytes, witness_bytes) = satisfied. redeem ( ) . to_vec_with_witness ( ) ;
98+ ( program_bytes, Some ( witness_bytes) )
99+ }
100+ None => {
101+ let program_bytes = compiled. commit ( ) . to_vec_without_witness ( ) ;
102+ ( program_bytes, None )
103+ }
104+ } ;
105+
106+ let output = Output {
107+ program : Base64Display :: new ( & program_bytes, & STANDARD ) . to_string ( ) ,
108+ witness : witness_bytes. map ( |bytes| Base64Display :: new ( & bytes, & STANDARD ) . to_string ( ) ) ,
109+ } ;
110+
111+ if output_json {
112+ #[ cfg( not( feature = "serde" ) ) ]
113+ return Err (
114+ "Program was compiled without the 'serde' feature and cannot output JSON." . into ( ) ,
97115 ) ;
116+ #[ cfg( feature = "serde" ) ]
117+ println ! ( "{}" , serde_json:: to_string( & output) ?) ;
98118 } else {
99- let program_bytes = compiled. commit ( ) . to_vec_without_witness ( ) ;
100- println ! (
101- "Program:\n {}" ,
102- Base64Display :: new( & program_bytes, & STANDARD )
103- ) ;
119+ println ! ( "{}" , output) ;
104120 }
105121
106122 Ok ( ( ) )
0 commit comments