1010// oo7 demo Run a built-in demo that produces traces
1111
1212use oo7_core:: ast:: * ;
13+ use oo7_core:: codegen_elixir;
1314use oo7_core:: eval:: Evaluator ;
1415use oo7_core:: parser;
1516use oo7_core:: typechecker;
@@ -21,6 +22,7 @@ fn main() {
2122 Some ( "parse" ) => cmd_parse ( & args) ,
2223 Some ( "check" ) => cmd_check ( & args) ,
2324 Some ( "typecheck" ) => cmd_typecheck ( & args) ,
25+ Some ( "compile" ) => cmd_compile ( & args) ,
2426 Some ( "eval" ) => cmd_eval ( & args) ,
2527 Some ( "demo" ) => run_demo ( ) ,
2628 Some ( "agent-parse" ) => cmd_agent_parse ( & args) ,
@@ -44,6 +46,7 @@ fn print_usage() {
4446 println ! ( " oo7 parse <file.007> Parse a .007 file and print AST as JSON" ) ;
4547 println ! ( " oo7 check <file.007> Validate syntax (no output on success)" ) ;
4648 println ! ( " oo7 typecheck <file.007> Type-check a .007 file (L1-3, L7)" ) ;
49+ println ! ( " oo7 compile <file.007> [--out DIR] Compile to Elixir/OTP project" ) ;
4750 println ! ( " oo7 eval <file.007> Parse and evaluate (parse-only for now)" ) ;
4851 println ! ( " oo7 demo Run built-in demo producing decision traces" ) ;
4952 println ! ( ) ;
@@ -142,6 +145,101 @@ fn cmd_typecheck(args: &[String]) {
142145 }
143146}
144147
148+ /// `oo7 compile <file.007> [--out DIR]` — compile to Elixir/OTP project.
149+ ///
150+ /// Parses the source file, runs the type checker (warnings only),
151+ /// then generates a complete Elixir/OTP project in the output directory.
152+ fn cmd_compile ( args : & [ String ] ) {
153+ let source = read_source_file ( args) ;
154+ let path = args. get ( 2 ) . unwrap ( ) ;
155+
156+ // Determine output directory
157+ let out_dir = if let Some ( pos) = args. iter ( ) . position ( |a| a == "--out" ) {
158+ args. get ( pos + 1 )
159+ . map ( |s| s. as_str ( ) )
160+ . unwrap_or ( "_build/elixir" )
161+ } else {
162+ "_build/elixir"
163+ } ;
164+
165+ // Determine project name from the source file stem
166+ let project_name = std:: path:: Path :: new ( path)
167+ . file_stem ( )
168+ . and_then ( |s| s. to_str ( ) )
169+ . unwrap_or ( "oo7_project" ) ;
170+
171+ // Parse
172+ let program = match parser:: parse_program ( & source) {
173+ Ok ( p) => p,
174+ Err ( e) => {
175+ eprintln ! ( "{}" , format_parse_error( path, & e) ) ;
176+ std:: process:: exit ( 1 ) ;
177+ }
178+ } ;
179+
180+ // Type-check (warnings only — do not fail)
181+ if let Err ( errors) = typechecker:: check_program ( & program) {
182+ for e in & errors {
183+ eprintln ! ( "Warning (typecheck): {}" , e. message) ;
184+ }
185+ }
186+
187+ // Generate Elixir
188+ let project = match codegen_elixir:: generate_elixir ( & program, project_name) {
189+ Ok ( p) => p,
190+ Err ( e) => {
191+ eprintln ! ( "Code generation error: {}" , e) ;
192+ std:: process:: exit ( 1 ) ;
193+ }
194+ } ;
195+
196+ // Write all files
197+ let base = std:: path:: Path :: new ( out_dir) ;
198+
199+ // mix.exs
200+ let mix_path = base. join ( "mix.exs" ) ;
201+ write_file ( & mix_path, & project. mix_exs ) ;
202+
203+ // config/config.exs
204+ let config_path = base. join ( "config" ) . join ( "config.exs" ) ;
205+ write_file ( & config_path, & project. config ) ;
206+
207+ // Source files
208+ for file in & project. files {
209+ let file_path = base. join ( & file. path ) ;
210+ write_file ( & file_path, & file. content ) ;
211+ }
212+
213+ // Summary
214+ println ! ( "007 Compiler — Elixir/OTP output" ) ;
215+ println ! ( " Source: {}" , path) ;
216+ println ! ( " Output: {}" , out_dir) ;
217+ println ! ( " Project: {}" , project_name) ;
218+ println ! ( " Files generated: {}" , project. files. len( ) + 2 ) ; // +2 for mix.exs + config
219+ for file in & project. files {
220+ println ! ( " {}" , file. path) ;
221+ }
222+ println ! ( " mix.exs" ) ;
223+ println ! ( " config/config.exs" ) ;
224+ println ! ( ) ;
225+ println ! ( "To build: cd {} && mix deps.get && mix compile" , out_dir) ;
226+ println ! ( "The telescope is on. We're looking." ) ;
227+ }
228+
229+ /// Write a file, creating parent directories as needed.
230+ fn write_file ( path : & std:: path:: Path , content : & str ) {
231+ if let Some ( parent) = path. parent ( ) {
232+ std:: fs:: create_dir_all ( parent) . unwrap_or_else ( |e| {
233+ eprintln ! ( "Error: could not create directory '{}': {}" , parent. display( ) , e) ;
234+ std:: process:: exit ( 1 ) ;
235+ } ) ;
236+ }
237+ std:: fs:: write ( path, content) . unwrap_or_else ( |e| {
238+ eprintln ! ( "Error: could not write '{}': {}" , path. display( ) , e) ;
239+ std:: process:: exit ( 1 ) ;
240+ } ) ;
241+ }
242+
145243/// `oo7 eval <file.007>` — parse and evaluate.
146244///
147245/// Currently this only parses and reports the structure, since the
0 commit comments