@@ -93,25 +93,34 @@ pub fn main() !void {
9393 return ;
9494 }
9595
96- // Parse arguments with enhanced MLIR support
96+ // Parse arguments with compiler-style CLI
9797 var output_dir : ? []const u8 = null ;
98- var no_cst : bool = false ;
99- var command : ? []const u8 = null ;
98+ var command : ? []const u8 = null ; // For legacy commands (lex, parse, etc.)
10099 var input_file : ? []const u8 = null ;
100+
101+ // Compilation stage control (--emit-X flags)
102+ var emit_tokens : bool = false ;
103+ var emit_ast : bool = false ;
101104 var emit_mlir : bool = false ;
105+ var emit_yul : bool = false ;
106+ var emit_bytecode : bool = false ;
107+
108+ // MLIR options
102109 var mlir_verify : bool = false ;
103110 var mlir_passes : ? []const u8 = null ;
104111 var mlir_opt_level : ? []const u8 = null ;
105112 var mlir_timing : bool = false ;
106113 var mlir_print_ir : bool = false ;
107114 var mlir_use_pipeline : bool = false ;
108115
109- // Artifact saving options
116+ // Artifact saving options (for --save-all)
110117 var save_tokens : bool = false ;
111118 var save_ast : bool = false ;
112119 var save_mlir : bool = false ;
113120 var save_yul : bool = false ;
114121 var save_bytecode : bool = false ;
122+
123+ // var verbose: bool = false; // TODO: implement verbose mode
115124 var i : usize = 1 ;
116125
117126 while (i < args .len ) {
@@ -122,12 +131,33 @@ pub fn main() !void {
122131 }
123132 output_dir = args [i + 1 ];
124133 i += 2 ;
125- } else if (std .mem .eql (u8 , args [i ], "--no-cst" )) {
126- no_cst = true ;
134+ // New --emit-X flags
135+ } else if (std .mem .eql (u8 , args [i ], "--emit-tokens" )) {
136+ emit_tokens = true ;
137+ i += 1 ;
138+ } else if (std .mem .eql (u8 , args [i ], "--emit-ast" )) {
139+ emit_ast = true ;
127140 i += 1 ;
128141 } else if (std .mem .eql (u8 , args [i ], "--emit-mlir" )) {
129142 emit_mlir = true ;
130143 i += 1 ;
144+ } else if (std .mem .eql (u8 , args [i ], "--emit-yul" )) {
145+ emit_yul = true ;
146+ i += 1 ;
147+ } else if (std .mem .eql (u8 , args [i ], "--emit-bytecode" )) {
148+ emit_bytecode = true ;
149+ i += 1 ;
150+ // Optimization level flags (-O0, -O1, -O2)
151+ } else if (std .mem .eql (u8 , args [i ], "-O0" ) or std .mem .eql (u8 , args [i ], "-Onone" )) {
152+ mlir_opt_level = "none" ;
153+ i += 1 ;
154+ } else if (std .mem .eql (u8 , args [i ], "-O1" ) or std .mem .eql (u8 , args [i ], "-Obasic" )) {
155+ mlir_opt_level = "basic" ;
156+ i += 1 ;
157+ } else if (std .mem .eql (u8 , args [i ], "-O2" ) or std .mem .eql (u8 , args [i ], "-Oaggressive" )) {
158+ mlir_opt_level = "aggressive" ;
159+ i += 1 ;
160+ // MLIR options
131161 } else if (std .mem .eql (u8 , args [i ], "--mlir-verify" )) {
132162 mlir_verify = true ;
133163 i += 1 ;
@@ -154,6 +184,7 @@ pub fn main() !void {
154184 } else if (std .mem .eql (u8 , args [i ], "--mlir-pipeline" )) {
155185 mlir_use_pipeline = true ;
156186 i += 1 ;
187+ // Legacy --save-X flags
157188 } else if (std .mem .eql (u8 , args [i ], "--save-tokens" )) {
158189 save_tokens = true ;
159190 i += 1 ;
@@ -176,10 +207,21 @@ pub fn main() !void {
176207 save_yul = true ;
177208 save_bytecode = true ;
178209 i += 1 ;
179- } else if (command == null ) {
210+ // Debug/verbose
211+ } else if (std .mem .eql (u8 , args [i ], "--verbose" ) or std .mem .eql (u8 , args [i ], "-v" )) {
212+ // verbose = true; // TODO: implement verbose mode
213+ i += 1 ;
214+ // Legacy commands (lex, parse, ast, compile, mlir)
215+ } else if (std .mem .eql (u8 , args [i ], "lex" ) or
216+ std .mem .eql (u8 , args [i ], "parse" ) or
217+ std .mem .eql (u8 , args [i ], "ast" ) or
218+ std .mem .eql (u8 , args [i ], "compile" ) or
219+ std .mem .eql (u8 , args [i ], "mlir" ))
220+ {
180221 command = args [i ];
181222 i += 1 ;
182- } else if (input_file == null ) {
223+ // Input file
224+ } else if (input_file == null and ! std .mem .startsWith (u8 , args [i ], "-" )) {
183225 input_file = args [i ];
184226 i += 1 ;
185227 } else {
@@ -188,14 +230,20 @@ pub fn main() !void {
188230 }
189231 }
190232
191- if (command == null or input_file == null ) {
233+ // Require input file
234+ if (input_file == null ) {
192235 try printUsage ();
193236 return ;
194237 }
195238
196- const cmd = command .? ;
197239 const file_path = input_file .? ;
198240
241+ // Determine compilation mode
242+ // If no --emit-X flag is set and no legacy command, default to bytecode
243+ if (! emit_tokens and ! emit_ast and ! emit_mlir and ! emit_yul and ! emit_bytecode and command == null ) {
244+ emit_bytecode = true ; // Default: compile to bytecode
245+ }
246+
199247 // Create MLIR options structure
200248 const mlir_options = MlirOptions {
201249 .emit_mlir = emit_mlir ,
@@ -218,24 +266,44 @@ pub fn main() !void {
218266 .output_dir = output_dir ,
219267 };
220268
221- if (std .mem .eql (u8 , cmd , "lex" )) {
222- try runLexer (allocator , file_path , artifact_options );
223- } else if (std .mem .eql (u8 , cmd , "parse" )) {
224- try runParser (allocator , file_path , ! no_cst , artifact_options );
225- } else if (std .mem .eql (u8 , cmd , "ast" )) {
226- try runASTGeneration (allocator , file_path , output_dir , ! no_cst , artifact_options );
227- } else if (std .mem .eql (u8 , cmd , "compile" )) {
228- if (mlir_options .emit_mlir or artifact_options .save_mlir or artifact_options .save_yul or artifact_options .save_bytecode ) {
229- // If MLIR, Yul, or bytecode is requested, use the advanced MLIR pipeline with Yul conversion
230- try runMlirEmitAdvanced (allocator , file_path , mlir_options , artifact_options );
269+ // Handle legacy commands first
270+ if (command ) | cmd | {
271+ if (std .mem .eql (u8 , cmd , "lex" )) {
272+ try runLexer (allocator , file_path , artifact_options );
273+ } else if (std .mem .eql (u8 , cmd , "parse" )) {
274+ try runParser (allocator , file_path , artifact_options );
275+ } else if (std .mem .eql (u8 , cmd , "ast" )) {
276+ try runASTGeneration (allocator , file_path , output_dir , artifact_options );
277+ } else if (std .mem .eql (u8 , cmd , "compile" )) {
278+ if (mlir_options .emit_mlir or artifact_options .save_mlir or artifact_options .save_yul or artifact_options .save_bytecode ) {
279+ try runMlirEmitAdvanced (allocator , file_path , mlir_options , artifact_options );
280+ } else {
281+ try runFullCompilation (allocator , file_path , mlir_options , artifact_options );
282+ }
283+ } else if (std .mem .eql (u8 , cmd , "mlir" )) {
284+ try runMlirEmitAdvancedWithYul (allocator , file_path , mlir_options , artifact_options , false );
231285 } else {
232- // Otherwise, use the basic frontend compilation
233- try runFullCompilation (allocator , file_path , ! no_cst , mlir_options , artifact_options );
286+ try printUsage ();
234287 }
235- } else if (std .mem .eql (u8 , cmd , "mlir" )) {
288+ return ;
289+ }
290+
291+ // New compiler-style behavior: process --emit-X flags
292+ // Stop at the earliest stage specified, but save later stages if --save-X is set
293+ // TODO: Use verbose flag for detailed output
294+
295+ if (emit_tokens ) {
296+ // Stop after lexer
297+ try runLexer (allocator , file_path , artifact_options );
298+ } else if (emit_ast ) {
299+ // Stop after parser
300+ try runParser (allocator , file_path , artifact_options );
301+ } else if (emit_mlir or emit_yul or emit_bytecode ) {
302+ // Run full MLIR pipeline (includes Yul and bytecode if needed)
236303 try runMlirEmitAdvancedWithYul (allocator , file_path , mlir_options , artifact_options , false );
237304 } else {
238- try printUsage ();
305+ // Default: full compilation
306+ try runMlirEmitAdvancedWithYul (allocator , file_path , mlir_options , artifact_options , false );
239307 }
240308}
241309
@@ -244,38 +312,45 @@ fn printUsage() !void {
244312 var stdout_writer = std .fs .File .stdout ().writer (& stdout_buffer );
245313 const stdout = & stdout_writer .interface ;
246314 try stdout .print ("Ora Compiler v0.1 - Asuka\n " , .{});
247- try stdout .print ("Usage: ora [options] <command> <file>\n " , .{});
248- try stdout .print ("\n General Options:\n " , .{});
249- try stdout .print (" -o, --output-dir <dir> - Specify output directory for generated files\n " , .{});
250- try stdout .print (" --no-cst - Disable CST building (enabled by default)\n " , .{});
251- try stdout .print ("\n Artifact Saving Options:\n " , .{});
252- try stdout .print (" --save-tokens - Save tokens from lexical analysis\n " , .{});
253- try stdout .print (" --save-ast - Save AST from syntax analysis\n " , .{});
254- try stdout .print (" --save-mlir - Save MLIR from generation\n " , .{});
255- try stdout .print (" --save-yul - Save Yul from lowering\n " , .{});
256- try stdout .print (" --save-bytecode - Save EVM bytecode\n " , .{});
257- try stdout .print (" --save-all - Save all artifacts\n " , .{});
315+ try stdout .print ("Usage: ora [options] <file.ora>\n " , .{});
316+ try stdout .print ("\n Compilation Control:\n " , .{});
317+ try stdout .print (" (default) - Compile to EVM bytecode\n " , .{});
318+ try stdout .print (" --emit-tokens - Stop after lexical analysis (emit tokens)\n " , .{});
319+ try stdout .print (" --emit-ast - Stop after parsing (emit AST)\n " , .{});
320+ try stdout .print (" --emit-mlir - Stop after MLIR generation\n " , .{});
321+ try stdout .print (" --emit-yul - Stop after Yul lowering\n " , .{});
322+ try stdout .print (" --emit-bytecode - Generate EVM bytecode (default)\n " , .{});
323+ try stdout .print ("\n Output Options:\n " , .{});
324+ try stdout .print (" -o <file> - Write output to <file> (e.g., -o out.hex, -o out.mlir)\n " , .{});
325+ try stdout .print (" -o <dir>/ - Write artifacts to <dir>/ (e.g., -o build/)\n " , .{});
326+ try stdout .print (" Default: ./<basename>_artifacts/ or current dir\n " , .{});
327+ try stdout .print ("\n Optimization Options:\n " , .{});
328+ try stdout .print (" -O0, -Onone - No optimization (default)\n " , .{});
329+ try stdout .print (" -O1, -Obasic - Basic optimizations\n " , .{});
330+ try stdout .print (" -O2, -Oaggressive - Aggressive optimizations\n " , .{});
258331 try stdout .print ("\n MLIR Options:\n " , .{});
259- try stdout .print (" --emit- mlir - Generate MLIR output in addition to normal compilation \n " , .{});
260- try stdout .print (" --mlir-verify - Run MLIR verification passes \n " , .{});
261- try stdout .print (" --mlir-passes <str> - Custom MLIR pass pipeline (e.g., 'canonicalize,cse') \n " , .{});
262- try stdout .print (" --mlir-opt <level> - Optimization level: none, basic, aggressive \n " , .{});
263- try stdout .print (" --mlir-timing - Enable pass timing statistics \n " , .{});
264- try stdout .print (" --mlir-print-ir - Print IR before and after passes \n " , .{});
265- try stdout .print (" --mlir-pipeline - Use comprehensive MLIR optimization pipeline \n " , .{});
266- try stdout .print ("\n Commands: \n " , .{});
267- try stdout .print (" lex <file> - Tokenize a .ora file \n " , .{});
268- try stdout .print (" parse <file> - Parse a .ora file to AST \n " , .{});
269- try stdout .print (" ast <file> - Generate AST and save to JSON file \n " , .{});
270- try stdout .print (" compile <file> - Full frontend pipeline (lex -> parse -> [mlir] )\n " , .{});
271- try stdout .print (" mlir <file> - Run front-end and emit MLIR with advanced options \n " , .{});
332+ try stdout .print (" -- mlir-verify - Run MLIR verification passes \n " , .{});
333+ try stdout .print (" --mlir-passes <passes> - Custom MLIR pass pipeline (comma-separated) \n " , .{});
334+ try stdout .print (" --mlir-timing - Enable pass timing statistics \n " , .{});
335+ try stdout .print (" --mlir-print-ir - Print IR before and after passes \n " , .{});
336+ try stdout .print (" --mlir-pipeline - Use comprehensive MLIR optimization pipeline \n " , .{});
337+ try stdout .print ("\n Development/Debug Options: \n " , .{});
338+ try stdout .print (" --save-all - Save all intermediate artifacts \n " , .{});
339+ try stdout .print (" --verbose - Verbose output (show each compilation stage) \n " , .{});
340+ try stdout .print ("\n Legacy Commands (for step-by-step debugging): \n " , .{});
341+ try stdout .print (" ora lex <file> - Only tokenize (legacy: use --emit-tokens) \n " , .{});
342+ try stdout .print (" ora parse <file> - Only parse (legacy: use --emit-ast) \n " , .{});
343+ try stdout .print (" ora ast <file> - Generate AST JSON (legacy )\n " , .{});
344+ try stdout .print (" ora compile <file> - Full compilation (legacy: just use 'ora <file>') \n " , .{});
272345 try stdout .print ("\n Examples:\n " , .{});
273- try stdout .print (" ora -o build ast example.ora\n " , .{});
274- try stdout .print (" ora --emit-mlir compile example.ora\n " , .{});
275- try stdout .print (" ora --save-all compile example.ora\n " , .{});
276- try stdout .print (" ora --save-tokens --save-ast lex example.ora\n " , .{});
277- try stdout .print (" ora --mlir-opt aggressive --mlir-verify mlir example.ora\n " , .{});
278- try stdout .print (" ora --mlir-passes 'canonicalize,cse,sccp' --mlir-timing mlir example.ora\n " , .{});
346+ try stdout .print (" ora contract.ora # Compile to bytecode → contract_artifacts/\n " , .{});
347+ try stdout .print (" ora contract.ora -o build/ # Compile to bytecode → build/\n " , .{});
348+ try stdout .print (" ora contract.ora -o contract.hex # Compile to specific file\n " , .{});
349+ try stdout .print (" ora --emit-ast contract.ora # Stop at AST → contract_artifacts/ast.json\n " , .{});
350+ try stdout .print (" ora --emit-mlir -O2 contract.ora # Generate optimized MLIR\n " , .{});
351+ try stdout .print (" ora --emit-yul -o out.yul contract.ora # Compile to Yul\n " , .{});
352+ try stdout .print (" ora --save-all contract.ora # Save all stages (tokens, AST, MLIR, Yul, bytecode)\n " , .{});
353+ try stdout .print (" ora --mlir-verify --mlir-timing -O2 contract.ora # Compile with verification and timing\n " , .{});
279354 try stdout .flush ();
280355}
281356
@@ -493,7 +568,7 @@ fn saveBytecode(allocator: std.mem.Allocator, file_path: []const u8, bytecode: [
493568}
494569
495570/// Run parser on file and display AST
496- fn runParser (allocator : std.mem.Allocator , file_path : []const u8 , enable_cst : bool , artifact_options : ArtifactOptions ) ! void {
571+ fn runParser (allocator : std.mem.Allocator , file_path : []const u8 , artifact_options : ArtifactOptions ) ! void {
497572 var stdout_buffer : [1024 ]u8 = undefined ;
498573 var stdout_writer = std .fs .File .stdout ().writer (& stdout_buffer );
499574 const stdout = & stdout_writer .interface ;
@@ -525,13 +600,6 @@ fn runParser(allocator: std.mem.Allocator, file_path: []const u8, enable_cst: bo
525600 defer arena .deinit ();
526601 var parser = lib .Parser .init (tokens , & arena );
527602 parser .setFileId (1 );
528- var cst_builder_storage : lib.cst.CstBuilder = undefined ;
529- var cst_builder_ptr : ? * lib.cst.CstBuilder = null ;
530- if (enable_cst ) {
531- cst_builder_storage = lib .cst .CstBuilder .init (allocator );
532- cst_builder_ptr = & cst_builder_storage ;
533- parser .withCst (cst_builder_ptr .? );
534- }
535603 const ast_nodes = parser .parse () catch | err | {
536604 try stdout .print ("Parser error: {s}\n " , .{@errorName (err )});
537605 return ;
@@ -551,17 +619,11 @@ fn runParser(allocator: std.mem.Allocator, file_path: []const u8, enable_cst: bo
551619 try saveAST (allocator , file_path , ast_nodes , artifact_options );
552620 }
553621
554- if (enable_cst ) {
555- if (cst_builder_ptr ) | builder | {
556- const cst_root = try builder .buildRoot (tokens );
557- _ = cst_root ; // TODO: optional dump in future flag
558- builder .deinit ();
559- }
560- }
622+ try stdout .flush ();
561623}
562624
563625/// Run full compilation pipeline with optional MLIR support
564- fn runFullCompilation (allocator : std.mem.Allocator , file_path : []const u8 , enable_cst : bool , mlir_options : MlirOptions , artifact_options : ArtifactOptions ) ! void {
626+ fn runFullCompilation (allocator : std.mem.Allocator , file_path : []const u8 , mlir_options : MlirOptions , artifact_options : ArtifactOptions ) ! void {
565627 var stdout_buffer : [1024 ]u8 = undefined ;
566628 var stdout_writer = std .fs .File .stdout ().writer (& stdout_buffer );
567629 const stdout = & stdout_writer .interface ;
@@ -603,13 +665,6 @@ fn runFullCompilation(allocator: std.mem.Allocator, file_path: []const u8, enabl
603665 defer arena .deinit ();
604666 var parser = lib .Parser .init (tokens , & arena );
605667 parser .setFileId (1 );
606- var cst_builder_storage : lib.cst.CstBuilder = undefined ;
607- var cst_builder_ptr : ? * lib.cst.CstBuilder = null ;
608- if (enable_cst ) {
609- cst_builder_storage = lib .cst .CstBuilder .init (allocator );
610- cst_builder_ptr = & cst_builder_storage ;
611- parser .withCst (cst_builder_ptr .? );
612- }
613668 const ast_nodes = parser .parse () catch | err | {
614669 try stdout .print ("Parser failed: {s}\n " , .{@errorName (err )});
615670 return ;
@@ -631,13 +686,6 @@ fn runFullCompilation(allocator: std.mem.Allocator, file_path: []const u8, enabl
631686 }
632687
633688 try stdout .print ("============================================================\n " , .{});
634- if (enable_cst ) {
635- if (cst_builder_ptr ) | builder | {
636- const cst_root = try builder .buildRoot (tokens );
637- _ = cst_root ; // TODO: optional dump in future flag
638- builder .deinit ();
639- }
640- }
641689
642690 // Phase 3: MLIR Generation (if requested)
643691 if (mlir_options .emit_mlir ) {
@@ -689,7 +737,7 @@ fn printAstSummary(writer: anytype, node: *lib.AstNode, indent: u32) !void {
689737}
690738
691739/// Generate AST and save to JSON file
692- fn runASTGeneration (allocator : std.mem.Allocator , file_path : []const u8 , output_dir : ? []const u8 , enable_cst : bool , artifact_options : ArtifactOptions ) ! void {
740+ fn runASTGeneration (allocator : std.mem.Allocator , file_path : []const u8 , output_dir : ? []const u8 , artifact_options : ArtifactOptions ) ! void {
693741 var stdout_buffer : [1024 ]u8 = undefined ;
694742 var stdout_writer = std .fs .File .stdout ().writer (& stdout_buffer );
695743 const stdout = & stdout_writer .interface ;
@@ -718,24 +766,10 @@ fn runASTGeneration(allocator: std.mem.Allocator, file_path: []const u8, output_
718766 defer arena .deinit ();
719767 var parser = lib .Parser .init (tokens , & arena );
720768 parser .setFileId (1 );
721- var cst_builder_storage : lib.cst.CstBuilder = undefined ;
722- var cst_builder_ptr : ? * lib.cst.CstBuilder = null ;
723- if (enable_cst ) {
724- cst_builder_storage = lib .cst .CstBuilder .init (allocator );
725- cst_builder_ptr = & cst_builder_storage ;
726- parser .withCst (cst_builder_ptr .? );
727- }
728769 const ast_nodes = parser .parse () catch | err | {
729770 try stdout .print ("Parser error: {s}\n " , .{@errorName (err )});
730771 return ;
731772 };
732- if (enable_cst ) {
733- if (cst_builder_ptr ) | builder | {
734- const cst_root = try builder .buildRoot (tokens );
735- _ = cst_root ; // CST not emitted here yet
736- builder .deinit ();
737- }
738- }
739773 // Note: AST nodes are allocated in arena, so they're automatically freed when arena is deinited
740774
741775 try stdout .print ("Generated {d} AST nodes\n " , .{ast_nodes .len });
0 commit comments