@@ -29,62 +29,58 @@ pub fn main() !void {
2929 return ;
3030 }
3131
32- const command = args [1 ];
33-
34- if (std .mem .eql (u8 , command , "lex" )) {
35- if (args .len < 3 ) {
36- try printUsage ();
37- return ;
38- }
39- try runLexer (allocator , args [2 ]);
40- } else if (std .mem .eql (u8 , command , "parse" )) {
41- if (args .len < 3 ) {
42- try printUsage ();
43- return ;
44- }
45- try runParser (allocator , args [2 ]);
46- } else if (std .mem .eql (u8 , command , "analyze" )) {
47- if (args .len < 3 ) {
48- try printUsage ();
49- return ;
50- }
51- try runSemanticAnalysis (allocator , args [2 ]);
52- } else if (std .mem .eql (u8 , command , "ir" )) {
53- if (args .len < 3 ) {
54- try printUsage ();
55- return ;
56- }
57- try runIRGeneration (allocator , args [2 ]);
58- } else if (std .mem .eql (u8 , command , "compile" )) {
59- if (args .len < 3 ) {
60- try printUsage ();
61- return ;
62- }
63- try runFullCompilation (allocator , args [2 ]);
64- } else if (std .mem .eql (u8 , command , "ast" )) {
65- if (args .len < 3 ) {
66- try printUsage ();
67- return ;
68- }
69- try runASTGeneration (allocator , args [2 ]);
70- } else if (std .mem .eql (u8 , command , "hir" )) {
71- if (args .len < 3 ) {
72- try printUsage ();
73- return ;
74- }
75- try runHIRGeneration (allocator , args [2 ]);
76- } else if (std .mem .eql (u8 , command , "yul" )) {
77- if (args .len < 3 ) {
78- try printUsage ();
79- return ;
80- }
81- try runYulGeneration (allocator , args [2 ]);
82- } else if (std .mem .eql (u8 , command , "bytecode" )) {
83- if (args .len < 3 ) {
32+ // Parse arguments to find output directory option
33+ var output_dir : ? []const u8 = null ;
34+ var command : ? []const u8 = null ;
35+ var input_file : ? []const u8 = null ;
36+ var i : usize = 1 ;
37+
38+ while (i < args .len ) {
39+ if (std .mem .eql (u8 , args [i ], "-o" ) or std .mem .eql (u8 , args [i ], "--output-dir" )) {
40+ if (i + 1 >= args .len ) {
41+ try printUsage ();
42+ return ;
43+ }
44+ output_dir = args [i + 1 ];
45+ i += 2 ;
46+ } else if (command == null ) {
47+ command = args [i ];
48+ i += 1 ;
49+ } else if (input_file == null ) {
50+ input_file = args [i ];
51+ i += 1 ;
52+ } else {
8453 try printUsage ();
8554 return ;
8655 }
87- try runBytecodeGeneration (allocator , args [2 ]);
56+ }
57+
58+ if (command == null or input_file == null ) {
59+ try printUsage ();
60+ return ;
61+ }
62+
63+ const cmd = command .? ;
64+ const file_path = input_file .? ;
65+
66+ if (std .mem .eql (u8 , cmd , "lex" )) {
67+ try runLexer (allocator , file_path );
68+ } else if (std .mem .eql (u8 , cmd , "parse" )) {
69+ try runParser (allocator , file_path );
70+ } else if (std .mem .eql (u8 , cmd , "analyze" )) {
71+ try runSemanticAnalysis (allocator , file_path );
72+ } else if (std .mem .eql (u8 , cmd , "ir" )) {
73+ try runIRGeneration (allocator , file_path );
74+ } else if (std .mem .eql (u8 , cmd , "compile" )) {
75+ try runFullCompilation (allocator , file_path );
76+ } else if (std .mem .eql (u8 , cmd , "ast" )) {
77+ try runASTGeneration (allocator , file_path , output_dir );
78+ } else if (std .mem .eql (u8 , cmd , "hir" )) {
79+ try runHIRGeneration (allocator , file_path , output_dir );
80+ } else if (std .mem .eql (u8 , cmd , "yul" )) {
81+ try runYulGeneration (allocator , file_path , output_dir );
82+ } else if (std .mem .eql (u8 , cmd , "bytecode" )) {
83+ try runBytecodeGeneration (allocator , file_path , output_dir );
8884 } else {
8985 try printUsage ();
9086 }
@@ -93,7 +89,9 @@ pub fn main() !void {
9389fn printUsage () ! void {
9490 const stdout = std .io .getStdOut ().writer ();
9591 try stdout .print ("Ora DSL Compiler v0.1\n " , .{});
96- try stdout .print ("Usage: ora <command> <file>\n " , .{});
92+ try stdout .print ("Usage: ora [options] <command> <file>\n " , .{});
93+ try stdout .print ("\n Options:\n " , .{});
94+ try stdout .print (" -o, --output-dir <dir> - Specify output directory for generated files\n " , .{});
9795 try stdout .print ("\n Commands:\n " , .{});
9896 try stdout .print (" lex <file> - Tokenize a .ora file\n " , .{});
9997 try stdout .print (" parse <file> - Parse a .ora file to AST\n " , .{});
@@ -104,6 +102,8 @@ fn printUsage() !void {
104102 try stdout .print (" hir <file> - Generate HIR and save to JSON file\n " , .{});
105103 try stdout .print (" yul <file> - Generate Yul code from HIR\n " , .{});
106104 try stdout .print (" bytecode <file> - Generate EVM bytecode from HIR\n " , .{});
105+ try stdout .print ("\n Example:\n " , .{});
106+ try stdout .print (" ora -o build ast example.ora\n " , .{});
107107}
108108
109109/// Run lexer on file and display tokens
@@ -517,7 +517,7 @@ fn printAstSummary(writer: anytype, node: *lib.AstNode, indent: u32) !void {
517517}
518518
519519/// Generate AST and save to JSON file
520- fn runASTGeneration (allocator : std.mem.Allocator , file_path : []const u8 ) ! void {
520+ fn runASTGeneration (allocator : std.mem.Allocator , file_path : []const u8 , output_dir : ? [] const u8 ) ! void {
521521 const stdout = std .io .getStdOut ().writer ();
522522
523523 // Read source file
@@ -550,7 +550,21 @@ fn runASTGeneration(allocator: std.mem.Allocator, file_path: []const u8) !void {
550550 try stdout .print ("Generated {} AST nodes\n " , .{ast_nodes .len });
551551
552552 // Generate output filename
553- const output_file = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { std .fs .path .stem (file_path ), ".ast.json" });
553+ const output_file = if (output_dir ) | dir | blk : {
554+ // Create output directory if it doesn't exist
555+ std .fs .cwd ().makeDir (dir ) catch | err | switch (err ) {
556+ error .PathAlreadyExists = > {},
557+ else = > return err ,
558+ };
559+
560+ const basename = std .fs .path .stem (file_path );
561+ const filename = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".ast.json" });
562+ defer allocator .free (filename );
563+ break :blk try std .fs .path .join (allocator , &[_ ][]const u8 { dir , filename });
564+ } else blk : {
565+ const basename = std .fs .path .stem (file_path );
566+ break :blk try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".ast.json" });
567+ };
554568 defer allocator .free (output_file );
555569
556570 // Save AST to JSON file
@@ -570,7 +584,7 @@ fn runASTGeneration(allocator: std.mem.Allocator, file_path: []const u8) !void {
570584}
571585
572586/// Generate HIR and save to JSON file
573- fn runHIRGeneration (allocator : std.mem.Allocator , file_path : []const u8 ) ! void {
587+ fn runHIRGeneration (allocator : std.mem.Allocator , file_path : []const u8 , output_dir : ? [] const u8 ) ! void {
574588 const stdout = std .io .getStdOut ().writer ();
575589
576590 // Read source file
@@ -627,7 +641,21 @@ fn runHIRGeneration(allocator: std.mem.Allocator, file_path: []const u8) !void {
627641 try stdout .print (" {} contracts converted to HIR\n " , .{hir_program .contracts .len });
628642
629643 // Generate output filename
630- const output_file = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { std .fs .path .stem (file_path ), ".hir.json" });
644+ const output_file = if (output_dir ) | dir | blk : {
645+ // Create output directory if it doesn't exist
646+ std .fs .cwd ().makeDir (dir ) catch | err | switch (err ) {
647+ error .PathAlreadyExists = > {},
648+ else = > return err ,
649+ };
650+
651+ const basename = std .fs .path .stem (file_path );
652+ const filename = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".hir.json" });
653+ defer allocator .free (filename );
654+ break :blk try std .fs .path .join (allocator , &[_ ][]const u8 { dir , filename });
655+ } else blk : {
656+ const basename = std .fs .path .stem (file_path );
657+ break :blk try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".hir.json" });
658+ };
631659 defer allocator .free (output_file );
632660
633661 // Save HIR to JSON file
@@ -647,7 +675,7 @@ fn runHIRGeneration(allocator: std.mem.Allocator, file_path: []const u8) !void {
647675}
648676
649677/// Generate Yul code from HIR
650- fn runYulGeneration (allocator : std.mem.Allocator , file_path : []const u8 ) ! void {
678+ fn runYulGeneration (allocator : std.mem.Allocator , file_path : []const u8 , output_dir : ? [] const u8 ) ! void {
651679 const stdout = std .io .getStdOut ().writer ();
652680
653681 // Read source file
@@ -703,7 +731,21 @@ fn runYulGeneration(allocator: std.mem.Allocator, file_path: []const u8) !void {
703731 try stdout .print ("{s}\n " , .{yul_code });
704732
705733 // Save to file
706- const output_file = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { std .fs .path .stem (file_path ), ".yul" });
734+ const output_file = if (output_dir ) | dir | blk : {
735+ // Create output directory if it doesn't exist
736+ std .fs .cwd ().makeDir (dir ) catch | err | switch (err ) {
737+ error .PathAlreadyExists = > {},
738+ else = > return err ,
739+ };
740+
741+ const basename = std .fs .path .stem (file_path );
742+ const filename = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".yul" });
743+ defer allocator .free (filename );
744+ break :blk try std .fs .path .join (allocator , &[_ ][]const u8 { dir , filename });
745+ } else blk : {
746+ const basename = std .fs .path .stem (file_path );
747+ break :blk try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".yul" });
748+ };
707749 defer allocator .free (output_file );
708750
709751 const file = std .fs .cwd ().createFile (output_file , .{}) catch | err | {
@@ -717,7 +759,7 @@ fn runYulGeneration(allocator: std.mem.Allocator, file_path: []const u8) !void {
717759}
718760
719761/// Generate EVM bytecode from HIR
720- fn runBytecodeGeneration (allocator : std.mem.Allocator , file_path : []const u8 ) ! void {
762+ fn runBytecodeGeneration (allocator : std.mem.Allocator , file_path : []const u8 , output_dir : ? [] const u8 ) ! void {
721763 const stdout = std .io .getStdOut ().writer ();
722764
723765 // Read source file
@@ -781,7 +823,21 @@ fn runBytecodeGeneration(allocator: std.mem.Allocator, file_path: []const u8) !v
781823 try stdout .print ("Bytecode: {s}\n " , .{bytecode });
782824
783825 // Save to file
784- const output_file = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { std .fs .path .stem (file_path ), ".bin" });
826+ const output_file = if (output_dir ) | dir | blk : {
827+ // Create output directory if it doesn't exist
828+ std .fs .cwd ().makeDir (dir ) catch | err | switch (err ) {
829+ error .PathAlreadyExists = > {},
830+ else = > return err ,
831+ };
832+
833+ const basename = std .fs .path .stem (file_path );
834+ const filename = try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".bin" });
835+ defer allocator .free (filename );
836+ break :blk try std .fs .path .join (allocator , &[_ ][]const u8 { dir , filename });
837+ } else blk : {
838+ const basename = std .fs .path .stem (file_path );
839+ break :blk try std .mem .concat (allocator , u8 , &[_ ][]const u8 { basename , ".bin" });
840+ };
785841 defer allocator .free (output_file );
786842
787843 const file = std .fs .cwd ().createFile (output_file , .{}) catch | err | {
0 commit comments