Skip to main content

comprehensive_demo/
comprehensive_demo.rs

1use std::{fs, io::BufRead};
2use uxn_tal::{assemble_directory, assemble_file_with_symbols, Assembler};
3
4fn main() -> Result<(), Box<dyn std::error::Error>> {
5    println!("šŸ”Ø UXN TAL Assembler Demo");
6    println!("========================\n");
7
8    // Create some demo TAL files to show our assembler in action
9    create_demo_files()?;
10
11    // Demo 1: Single file assembly with symbols
12    println!("šŸ“ Demo 1: Single File Assembly");
13    let (rom_path, sym_path, size) = assemble_file_with_symbols("demo_hello.tal")?;
14    println!("āœ… Assembled {} bytes to {}", size, rom_path.display());
15    println!("šŸ“ Generated symbols to {}", sym_path.display());
16
17    let symbols = fs::read_to_string(&sym_path)?;
18    println!("Symbols:");
19    for line in symbols.lines() {
20        println!("  {:?}", line);
21    }
22    println!();
23
24    // Demo 2: Batch assembly
25    println!("šŸ“‚ Demo 2: Batch Assembly");
26    let results = assemble_directory(".", true)?;
27
28    for (tal_path, rom_path, sym_path, size) in &results {
29        if tal_path
30            .file_name()
31            .unwrap()
32            .to_string_lossy()
33            .starts_with("demo_")
34        {
35            println!(
36                "āœ… {} -> {} ({} bytes)",
37                tal_path.file_name().unwrap().to_string_lossy(),
38                rom_path.file_name().unwrap().to_string_lossy(),
39                size
40            );
41            if let Some(sym_path) = sym_path {
42                println!("  + {}", sym_path.file_name().unwrap().to_string_lossy());
43            }
44        }
45    }
46
47    // Demo 3: Show assembler flexibility
48    println!("\nšŸ”§ Demo 3: Manual Assembly");
49    let tal_code = r#"
50( Counter example with $ padding )
51|0100 @main
52    #00 
53    &loop
54        INC DUP 
55        #0a EQU ,end JCN
56        ,loop JMP
57    &end BRK
58    
59@data $1
60"#;
61
62    let mut assembler = Assembler::new();
63    let rom = assembler.assemble(tal_code, None)?;
64    println!("Generated {} bytes from inline TAL code", rom.len());
65
66    let symbols = assembler.generate_symbol_file();
67    println!("Extracted symbols:");
68    for line in symbols.lines() {
69        println!("  {:?}", line);
70    }
71
72    // Show binary symbol format too
73    let binary_symbols = assembler.generate_symbol_file_binary();
74    println!("Binary symbol data: {} bytes", binary_symbols.len());
75    // If you want to print lines, try converting to String (if valid UTF-8)
76    if let Ok(symbols_str) = String::from_utf8(binary_symbols.clone()) {
77        println!("Binary symbol lines:");
78        for line in symbols_str.lines() {
79            println!("  {}", line);
80        }
81    } else {
82        println!("Binary symbol data is not valid UTF-8, cannot print lines.");
83    }
84
85    // Clean up demo files
86    cleanup_demo_files()?;
87
88    println!("\nšŸŽ‰ Demo complete! The assembler supports:");
89    println!("  āœ… All UXN opcodes with mode flags (2, r, k)");
90    println!("  āœ… Hex literals (#12, #1234)");
91    println!("  āœ… Character literals ('A')");
92    println!("  āœ… Labels (@main) and sublabels (&loop)");
93    println!("  āœ… Label references (;main, ,loop)");
94    println!("  āœ… Padding directives (|0100) and skip bytes ($10)");
95    println!("  āœ… Symbol file generation (text and binary formats)");
96    println!("  āœ… Batch processing with ergonomic API");
97
98    Ok(())
99}
100
101fn create_demo_files() -> Result<(), Box<dyn std::error::Error>> {
102    let hello_tal = r#"
103( Hello World Example )
104|0100 @main
105    #48 #65 #6c #6c #6f #20 #57 #6f #72 #6c #64
106    BRK
107
108@data $10
109"#;
110
111    let counter_tal = r#"
112( Simple Counter with Skip )
113|0100 @main
114    #00 
115    &loop
116        INC DUP
117        #05 EQU 
118        ,done JCN
119        ,loop JMP
120    &done BRK
121
122@value $1
123@buffer $10
124"#;
125
126    let echo_tal = r#"
127( Echo example with character literals )
128|0100 @main
129    'H 'e 'l 'l 'o
130    BRK
131"#;
132
133    fs::write("demo_hello.tal", hello_tal)?;
134    fs::write("demo_counter.tal", counter_tal)?;
135    fs::write("demo_echo.tal", echo_tal)?;
136
137    Ok(())
138}
139
140fn cleanup_demo_files() -> Result<(), Box<dyn std::error::Error>> {
141    let patterns = ["demo_hello", "demo_counter", "demo_echo"];
142
143    for pattern in &patterns {
144        if let Ok(entries) = fs::read_dir(".") {
145            for entry in entries.flatten() {
146                let name = entry.file_name();
147                let name_str = name.to_string_lossy();
148                if name_str.starts_with(pattern) {
149                    let _ = fs::remove_file(entry.path());
150                }
151            }
152        }
153    }
154
155    Ok(())
156}