11#![ allow( clippy:: print_stdout, clippy:: print_stderr, clippy:: exit) ]
22
33use crate :: docs:: docs;
4- use anyhow:: { Context , anyhow} ;
5- use clap:: { Parser , Subcommand } ;
4+ use anyhow:: anyhow;
5+ use clap:: { Args , Parser , Subcommand } ;
66use highlighter:: AndycppHighlighter ;
77use ndc_interpreter:: Interpreter ;
88use phase_timing:: write_phase_timings;
@@ -34,25 +34,8 @@ enum Command {
3434 /// Execute an .ndc file or start the repl (this default action may be omitted)
3535 Run {
3636 file : Option < PathBuf > ,
37- /// Print total time spent in each interpreter phase
38- #[ arg( long) ]
39- time : bool ,
40- /// Print each instruction as it is dispatched
41- #[ cfg( feature = "trace" ) ]
42- #[ arg( long) ]
43- trace_print : bool ,
44- /// Print a histogram of instruction dispatch counts
45- #[ cfg( feature = "trace" ) ]
46- #[ arg( long) ]
47- trace_histogram : bool ,
48- /// Print cumulative time spent per instruction type
49- #[ cfg( feature = "trace" ) ]
50- #[ arg( long) ]
51- trace_time : bool ,
52- /// Render source as a heat map colored by time spent per span
53- #[ cfg( feature = "trace" ) ]
54- #[ arg( long) ]
55- trace_span : bool ,
37+ #[ command( flatten) ]
38+ options : RunOptions ,
5639 } ,
5740 /// Output an .ndc file using the built-in syntax highlighting engine
5841 Highlight { file : PathBuf } ,
@@ -79,19 +62,42 @@ enum Command {
7962 Unknown ( Vec < String > ) ,
8063}
8164
65+ #[ derive( Args , Clone , Copy , Default ) ]
66+ struct RunOptions {
67+ /// Print total time spent in each interpreter phase
68+ #[ arg( long) ]
69+ time : bool ,
70+ /// Print each instruction as it is dispatched
71+ #[ cfg( feature = "trace" ) ]
72+ #[ arg( long) ]
73+ trace_print : bool ,
74+ /// Print a histogram of instruction dispatch counts
75+ #[ cfg( feature = "trace" ) ]
76+ #[ arg( long) ]
77+ trace_histogram : bool ,
78+ /// Print cumulative time spent per instruction type
79+ #[ cfg( feature = "trace" ) ]
80+ #[ arg( long) ]
81+ trace_time : bool ,
82+ /// Render source as a heat map colored by time spent per span
83+ #[ cfg( feature = "trace" ) ]
84+ #[ arg( long) ]
85+ trace_span : bool ,
86+ }
87+
88+ #[ derive( Parser ) ]
89+ #[ command( name = "ndc" , disable_help_subcommand = true ) ]
90+ struct ImplicitRunArgs {
91+ file : PathBuf ,
92+ #[ command( flatten) ]
93+ options : RunOptions ,
94+ }
95+
8296impl Default for Command {
8397 fn default ( ) -> Self {
8498 Self :: Run {
8599 file : None ,
86- time : false ,
87- #[ cfg( feature = "trace" ) ]
88- trace_print : false ,
89- #[ cfg( feature = "trace" ) ]
90- trace_histogram : false ,
91- #[ cfg( feature = "trace" ) ]
92- trace_time : false ,
93- #[ cfg( feature = "trace" ) ]
94- trace_span : false ,
100+ options : RunOptions :: default ( ) ,
95101 }
96102 }
97103}
@@ -100,15 +106,7 @@ enum Action {
100106 RunLsp ,
101107 RunFile {
102108 path : PathBuf ,
103- time : bool ,
104- #[ cfg( feature = "trace" ) ]
105- trace_print : bool ,
106- #[ cfg( feature = "trace" ) ]
107- trace_histogram : bool ,
108- #[ cfg( feature = "trace" ) ]
109- trace_time : bool ,
110- #[ cfg( feature = "trace" ) ]
111- trace_span : bool ,
109+ options : RunOptions ,
112110 } ,
113111 DisassembleFile ( PathBuf ) ,
114112 HighlightFile ( PathBuf ) ,
@@ -126,51 +124,22 @@ impl TryFrom<Command> for Action {
126124 let action = match value {
127125 Command :: Run {
128126 file : Some ( file) ,
129- time,
130- #[ cfg( feature = "trace") ]
131- trace_print,
132- #[ cfg( feature = "trace") ]
133- trace_histogram,
134- #[ cfg( feature = "trace") ]
135- trace_time,
136- #[ cfg( feature = "trace") ]
137- trace_span,
138- } => Self :: RunFile {
139- path : file,
140- time,
141- #[ cfg( feature = "trace" ) ]
142- trace_print,
143- #[ cfg( feature = "trace" ) ]
144- trace_histogram,
145- #[ cfg( feature = "trace" ) ]
146- trace_time,
147- #[ cfg( feature = "trace" ) ]
148- trace_span,
149- } ,
127+ options,
128+ } => Self :: RunFile { path : file, options } ,
150129 Command :: Run { file : None , .. } => Self :: StartRepl ,
151130 Command :: Lsp { stdio : _ } => Self :: RunLsp ,
152131 Command :: Disassemble { file } => Self :: DisassembleFile ( file) ,
153132 Command :: Highlight { file } => Self :: HighlightFile ( file) ,
154133 Command :: Docs { query, no_color } => Self :: Docs { query, no_color } ,
155134 Command :: Unknown ( args) => {
156- match args. len ( ) {
157- 0 => {
158- // This case should have defaulted to `Command::Run { file: None }`
159- unreachable ! ( "fallback case reached with 0 arguments (should never happen)" )
160- }
161- 1 => Self :: RunFile {
162- path : args[ 0 ] . parse :: < PathBuf > ( ) . context ( "invalid path" ) ?,
163- time : false ,
164- #[ cfg( feature = "trace" ) ]
165- trace_print : false ,
166- #[ cfg( feature = "trace" ) ]
167- trace_histogram : false ,
168- #[ cfg( feature = "trace" ) ]
169- trace_time : false ,
170- #[ cfg( feature = "trace" ) ]
171- trace_span : false ,
172- } ,
173- n => return Err ( anyhow ! ( "invalid number of arguments: {n}" ) ) ,
135+ let implicit_run = ImplicitRunArgs :: try_parse_from (
136+ std:: iter:: once ( "ndc" ) . chain ( args. iter ( ) . map ( String :: as_str) ) ,
137+ )
138+ . map_err ( |err| anyhow ! ( err. render( ) . to_string( ) ) ) ?;
139+
140+ Self :: RunFile {
141+ path : implicit_run. file ,
142+ options : implicit_run. options ,
174143 }
175144 }
176145 } ;
@@ -186,15 +155,7 @@ fn main() -> anyhow::Result<()> {
186155 match action {
187156 Action :: RunFile {
188157 path,
189- time,
190- #[ cfg( feature = "trace") ]
191- trace_print,
192- #[ cfg( feature = "trace") ]
193- trace_histogram,
194- #[ cfg( feature = "trace") ]
195- trace_time,
196- #[ cfg( feature = "trace") ]
197- trace_span,
158+ options,
198159 } => {
199160 let filename = path
200161 . file_name ( )
@@ -210,16 +171,16 @@ fn main() -> anyhow::Result<()> {
210171 {
211172 use ndc_interpreter:: tracer;
212173 let mut tracers: Vec < Box < dyn tracer:: VmTracer > > = Vec :: new ( ) ;
213- if trace_print {
174+ if options . trace_print {
214175 tracers. push ( Box :: new ( tracer:: PrintTracer ) ) ;
215176 }
216- if trace_histogram {
177+ if options . trace_histogram {
217178 tracers. push ( Box :: new ( tracer:: HistogramTracer :: new ( ) ) ) ;
218179 }
219- if trace_time {
180+ if options . trace_time {
220181 tracers. push ( Box :: new ( tracer:: TimingTracer :: new ( ) ) ) ;
221182 }
222- if trace_span {
183+ if options . trace_span {
223184 tracers. push ( Box :: new ( span_tracer:: SpanTracer :: new ( ) ) ) ;
224185 }
225186 if !tracers. is_empty ( ) {
@@ -228,16 +189,19 @@ fn main() -> anyhow::Result<()> {
228189 }
229190
230191 let name = filename. as_deref ( ) . unwrap_or ( "<input>" ) ;
231- match interpreter . eval_named_with_timings ( name , & string ) {
232- Ok ( ( _ , timings ) ) => {
233- if time {
192+ if options . time {
193+ match interpreter . eval_named_with_timings ( name , & string ) {
194+ Ok ( ( _ , timings ) ) => {
234195 write_phase_timings ( & mut std:: io:: stderr ( ) , & timings) ?;
235196 }
197+ Err ( err) => {
198+ diagnostic:: emit_error ( interpreter. source_db ( ) , err) ;
199+ process:: exit ( 1 ) ;
200+ }
236201 }
237- Err ( err) => {
238- diagnostic:: emit_error ( interpreter. source_db ( ) , err) ;
239- process:: exit ( 1 ) ;
240- }
202+ } else if let Err ( err) = interpreter. eval_named ( name, & string) {
203+ diagnostic:: emit_error ( interpreter. source_db ( ) , err) ;
204+ process:: exit ( 1 ) ;
241205 }
242206 }
243207 Action :: DisassembleFile ( path) => {
@@ -289,11 +253,29 @@ fn start_lsp() {
289253#[ cfg( test) ]
290254mod test {
291255 use clap:: CommandFactory ;
256+ use std:: path:: PathBuf ;
292257
293- use crate :: Cli ;
258+ use crate :: { Action , Cli , Command } ;
294259
295260 #[ test]
296261 fn test_clap ( ) {
297262 Cli :: command ( ) . debug_assert ( ) ;
298263 }
264+
265+ #[ test]
266+ fn implicit_run_honors_time_flag ( ) {
267+ let action = Action :: try_from ( Command :: Unknown ( vec ! [
268+ "script.ndc" . to_string( ) ,
269+ "--time" . to_string( ) ,
270+ ] ) )
271+ . expect ( "implicit run flags should parse" ) ;
272+
273+ match action {
274+ Action :: RunFile { path, options } => {
275+ assert_eq ! ( path, PathBuf :: from( "script.ndc" ) ) ;
276+ assert ! ( options. time) ;
277+ }
278+ _ => panic ! ( "expected run action" ) ,
279+ }
280+ }
299281}
0 commit comments