Skip to main content

Assembler

Struct Assembler 

Source
pub struct Assembler {
Show 18 fields pub rom: Rom, pub opcodes: Opcodes, pub symbols: HashMap<String, Symbol>, pub symbol_order: Vec<String>, pub macros: HashMap<String, Macro>, pub current_label: Option<String>, pub references: Vec<Reference>, pub device_map: HashMap<String, Device>, pub line_number: usize, pub position_in_line: usize, pub effective_length: usize, pub lambda_counter: usize, pub lambda_stack: Vec<usize>, pub last_top_label: Option<String>, pub macro_expansion_stack: Vec<String>, pub drif_mode: bool, pub after_unreferenced_sublabel: bool, pub verbose: u8,
}
Expand description

TAL assembler

Fields§

§rom: Rom§opcodes: Opcodes§symbols: HashMap<String, Symbol>§symbol_order: Vec<String>§macros: HashMap<String, Macro>§current_label: Option<String>§references: Vec<Reference>§device_map: HashMap<String, Device>§line_number: usize§position_in_line: usize§effective_length: usize§lambda_counter: usize§lambda_stack: Vec<usize>§last_top_label: Option<String>§macro_expansion_stack: Vec<String>§drif_mode: bool§after_unreferenced_sublabel: bool§verbose: u8

Implementations§

Source§

impl Assembler

Source

pub fn generate_symbol_file(&self) -> Vec<u8>

Generate symbol file content in binary format Format: [address:u16][name:null-terminated string] repeating

Examples found in repository?
examples/batch_assembler.rs (line 43)
31fn assemble_file_with_symbols(
32    path: &Path,
33) -> Result<(std::path::PathBuf, std::path::PathBuf, usize), AssemblerError> {
34    let source = std::fs::read_to_string(path)?;
35    let mut assembler = Assembler::new();
36    let canonical = std::fs::canonicalize(path)
37        .map(|p| p.to_string_lossy().to_string())
38        .unwrap_or_else(|_| path.to_string_lossy().to_string());
39    let rom = assembler.assemble(&source, Some(canonical))?;
40    let rom_path = path.with_extension("rom");
41    let sym_path = path.with_extension("sym");
42    std::fs::write(&rom_path, &rom)?;
43    let sym_txt = assembler.generate_symbol_file();
44    std::fs::write(&sym_path, sym_txt)?;
45    Ok((rom_path, sym_path, rom.len()))
46}
More examples
Hide additional examples
examples/comprehensive_demo.rs (line 66)
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}
examples/debug_assemble.rs (line 43)
12fn main() -> Result<(), AssemblerError> {
13    let args: Vec<String> = env::args().collect();
14    if args.len() != 2 {
15        eprintln!("Usage: {} <file.tal>", args[0]);
16        std::process::exit(1);
17    }
18    let tal_path = &args[1];
19    let source = fs::read_to_string(tal_path).map_err(|e| serr(tal_path, &format!("read: {e}")))?;
20
21    println!("== Source: {} ==", tal_path);
22    for (i, line) in source.lines().enumerate() {
23        println!("{:4}: {}", i + 1, line);
24    }
25
26    // 1. Internal assembler (non-fatal on error now)
27    let mut internal_rom: Option<Vec<u8>> = None;
28    let mut internal_err: Option<String> = None;
29    let internal_out_path = format!("{tal_path}.uxntal.rom");
30
31    let mut asm = Assembler::new();
32    match asm.assemble(&source, Some(tal_path.to_string())) {
33        Ok(bytes) => {
34            fs::write(&internal_out_path, &bytes).ok();
35            println!(
36                "\n[uxntal] OK -> {} ({} bytes)",
37                internal_out_path,
38                bytes.len()
39            );
40            internal_rom = Some(bytes);
41            // Emit symbol file from the same assembler instance.
42            let sym_path = format!("{}.sym", &internal_out_path);
43            let sym_bytes = asm.generate_symbol_file();
44            let _ = fs::write(&sym_path, &sym_bytes);
45            if have_uxncli() && Path::new("uxndis.rom").exists() {
46                dump_disassembly(&internal_out_path);
47            }
48        }
49        Err(e) => {
50            println!("\n[uxntal] FAIL: {e}");
51            internal_err = Some(format!("{e}"));
52        }
53    }
54
55    // 2. External backends (always attempted)
56    println!("\nRunning external backends...");
57    let uxna = run_uxnasm(tal_path);
58    let drif = run_drifblim(tal_path); // optional
59    if have_uxncli() && Path::new("uxndis.rom").exists() {
60        if internal_rom.is_some() {
61            dump_disassembly(&internal_out_path);
62        }
63        for r in [&uxna, &drif] {
64            if r.ok {
65                if let Some(ref rp) = r.rom_path {
66                    dump_disassembly(rp);
67                }
68            }
69        }
70    }
71
72    // 3. Summary
73    println!("\n== Backend Summary ==");
74    println!(
75        "  {:<9} {:<5} {:>8}  output/summary",
76        "backend", "stat", "bytes"
77    );
78    if let Some(ref rom) = internal_rom {
79        println!(
80            "  {:<9} {:<5} {:>8}  {}",
81            "uxntal",
82            "OK",
83            rom.len(),
84            internal_out_path
85        );
86    } else {
87        // Show last 3 non-empty lines of internal error (previously only last 1)
88        let summary = internal_err
89            .as_ref()
90            .map(|e| last_n_lines(e, 3))
91            .unwrap_or_else(|| "-".into());
92        println!("  {:<9} {:<5} {:>8}  {}", "uxntal", "FAIL", 0, summary);
93    }
94    for r in [&uxna, &drif] {
95        let summary = if r.ok {
96            r.rom_path.as_deref().unwrap_or("-").to_string()
97        } else {
98            let combined = if !r.stderr.trim().is_empty() {
99                r.stderr.trim().to_string()
100            } else {
101                r.stdout.trim().to_string()
102            };
103            if combined.is_empty() {
104                r.error.as_deref().unwrap_or("-").to_string()
105            } else {
106                last_n_lines(&combined, 3)
107            }
108        };
109        println!(
110            "  {:<9} {:<5} {:>8}  {}",
111            r.name,
112            if r.ok { "OK" } else { "FAIL" },
113            r.bytes.len(),
114            summary
115        );
116    }
117
118    // 4. Detailed output (stdout/stderr trimmed)
119    for r in [&uxna, &drif] {
120        println!("\n== {} ==", r.name);
121        if r.ok {
122            println!(
123                "{}: OK, {} bytes{}",
124                r.name,
125                r.bytes.len(),
126                r.rom_path
127                    .as_ref()
128                    .map(|p| format!(", rom={}", p))
129                    .unwrap_or_default()
130            );
131        } else {
132            println!("{}: FAIL: {}", r.name, r.error.as_deref().unwrap_or("-"));
133        }
134        if !r.stdout.trim().is_empty() {
135            println!("-- stdout --");
136            if r.name == "uxnasm" {
137                println!("{}", tail_block(&r.stdout, 4000));
138            } else {
139                println!("{}", trim_block(&r.stdout, 4000));
140            }
141        }
142        if !r.stderr.trim().is_empty() {
143            println!("-- stderr --");
144            if r.name == "uxnasm" {
145                println!("{}", tail_block(&r.stderr, 4000));
146            } else {
147                println!("{}", trim_block(&r.stderr, 4000));
148            }
149        }
150    }
151
152    // 5. Diffs (only if internal succeeded and external ok)
153    if let Some(ref int_rom) = internal_rom {
154        println!("\n== Byte Diffs vs uxntal ==");
155        for r in [&uxna, &drif] {
156            if r.ok {
157                print!("uxntal vs {:<9}: ", r.name);
158                if let Some(d) = first_byte_diff(int_rom, &r.bytes) {
159                    println!(
160                        "first diff at 0x{:04X}: {:02X} != {:02X}",
161                        d.index, d.a, d.b
162                    );
163                } else {
164                    println!("identical");
165                }
166            } else {
167                println!("uxntal vs {:<9}: skipped ({} failed)", r.name, r.name);
168            }
169        }
170
171        // Optional disassembly diff (needs uxndis.rom & uxncli)
172        if have_uxncli() && Path::new("uxndis.rom").exists() {
173            println!("\n== Disassembly Diffs (first differing line) ==");
174            if dis_ok(&internal_out_path) {
175                let uxntal_dis = disassemble(&internal_out_path).unwrap_or_default();
176                // Print the internal ROM path for clarity
177                println!("(disassemble) backend=uxntal rom={}", internal_out_path);
178                for r in [&uxna, &drif] {
179                    if r.ok {
180                        if let Some(ref rp) = r.rom_path {
181                            if dis_ok(rp) {
182                                // NOTE: This is where each external backend (including 'drifblim') is disassembled.
183                                // The next call to disassemble(rp) produces the B side of the diff.
184                                println!("(disassemble) backend={} rom={}", r.name, rp);
185                                match disassemble(rp) {
186                                    Some(other_dis) => {
187                                        match first_line_diff(&uxntal_dis, &other_dis) {
188                                            Some((ln, a, b)) => {
189                                                println!(
190                                                    "uxntal vs {:<9} line {}:\n  uxntal: {}\n  {:<9}: {}",
191                                                    r.name, ln, a, r.name, b
192                                                );
193                                            }
194                                            None => println!("uxntal vs {:<9} identical", r.name),
195                                        }
196                                    }
197                                    None => {
198                                        println!("uxntal vs {:<9} disassembly unavailable (empty output)", r.name);
199                                    }
200                                }
201                            } else {
202                                println!("uxntal vs {:<9} disassembly unavailable", r.name);
203                            }
204                        }
205                    }
206                }
207            } else {
208                println!("(uxntal disassembly unavailable, skipping)");
209            }
210        } else {
211            println!("\n(disassembly skipped: need uxndis.rom + uxncli)");
212        }
213    } else {
214        println!("\nSkipping diffs (internal uxntal failed).");
215    }
216
217    // 6. Explicit note if user expected relative $label support (internal failure hint)
218    if internal_err
219        .as_ref()
220        .map(|e| e.contains("Skip directive requires hex value"))
221        .unwrap_or(false)
222    {
223        println!("\nNOTE: Internal assembler currently rejects $label (relative padding) which uxnasm accepts.");
224    }
225
226    Ok(())
227}
Source

pub fn generate_symbol_file_binary(&self) -> Vec<u8>

Generate symbol file content in binary format Format: [address:u16][name:null-terminated string] repeating

Examples found in repository?
examples/comprehensive_demo.rs (line 73)
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}
Source

pub fn generate_symbol_file_txt(&self) -> String

Generate symbol file content in textual format (address and name per line)

Source

pub fn new() -> Self

Create a new assembler instance

Examples found in repository?
examples/test_blank.rs (line 9)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing blank.tal specifically...");
5
6    let content = std::fs::read_to_string("../tal/blank.tal")?;
7
8    // Assemble
9    let mut assembler = Assembler::new();
10    let rom = assembler.assemble(&content, Some("test_blank.rs".to_owned()))?;
11
12    println!("Assembly successful! ROM size: {} bytes", rom.len());
13
14    Ok(())
15}
More examples
Hide additional examples
examples/test_include.rs (line 10)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing include functionality...");
5
6    let content = std::fs::read_to_string("../tal/test_include.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_include.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}
examples/batch_assembler.rs (line 21)
19fn assemble_file(file_path: &str) -> Result<usize, AssemblerError> {
20    let source = std::fs::read_to_string(file_path)?;
21    let mut assembler = Assembler::new();
22    // Always use the canonical path for error context
23    let path = std::fs::canonicalize(file_path)
24        .map(|p| p.to_string_lossy().to_string())
25        .unwrap_or_else(|_| file_path.to_string());
26    let rom = assembler.assemble(&source, Some(path))?;
27    Ok(rom.len())
28}
29
30// Assemble a TAL file and write symbol file, returning ROM and symbol file paths and size
31fn assemble_file_with_symbols(
32    path: &Path,
33) -> Result<(std::path::PathBuf, std::path::PathBuf, usize), AssemblerError> {
34    let source = std::fs::read_to_string(path)?;
35    let mut assembler = Assembler::new();
36    let canonical = std::fs::canonicalize(path)
37        .map(|p| p.to_string_lossy().to_string())
38        .unwrap_or_else(|_| path.to_string_lossy().to_string());
39    let rom = assembler.assemble(&source, Some(canonical))?;
40    let rom_path = path.with_extension("rom");
41    let sym_path = path.with_extension("sym");
42    std::fs::write(&rom_path, &rom)?;
43    let sym_txt = assembler.generate_symbol_file();
44    std::fs::write(&sym_path, sym_txt)?;
45    Ok((rom_path, sym_path, rom.len()))
46}
47
48// Assemble a TAL file and write ROM, returning ROM path and size
49fn assemble_file_auto(path: &Path) -> Result<(std::path::PathBuf, usize), AssemblerError> {
50    let source = std::fs::read_to_string(path)?;
51    let mut assembler = Assembler::new();
52    let canonical = std::fs::canonicalize(path)
53        .map(|p| p.to_string_lossy().to_string())
54        .unwrap_or_else(|_| path.to_string_lossy().to_string());
55    let rom = assembler.assemble(&source, Some(canonical))?;
56    let rom_path = path.with_extension("rom");
57    std::fs::write(&rom_path, &rom)?;
58    Ok((rom_path, rom.len()))
59}
examples/test_macro_call.rs (line 10)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing macro call functionality...");
5
6    let content = std::fs::read_to_string("../tal/test_macro_call.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_macro_call.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}
examples/test_fixes.rs (line 10)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing fixes for device access and comments...");
5
6    let content = std::fs::read_to_string("../tal/test_fixes.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_fixes.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}
examples/test_hyphen.rs (line 10)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing hyphen identifiers and raw address refs...");
5
6    let content = std::fs::read_to_string("../tal/test_hyphen.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_hyphen.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}
Source

pub fn with_drif_mode(drif_mode: bool) -> Self

Source

pub fn with_verbose(verbose: u8) -> Self

Source

pub fn with_drif_mode_verbose(drif_mode: bool, verbose: u8) -> Self

Source

pub fn assemble( &mut self, source: &str, path: Option<String>, ) -> Result<Vec<u8>>

Assemble TAL source code into a ROM

Examples found in repository?
examples/test_blank.rs (line 10)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing blank.tal specifically...");
5
6    let content = std::fs::read_to_string("../tal/blank.tal")?;
7
8    // Assemble
9    let mut assembler = Assembler::new();
10    let rom = assembler.assemble(&content, Some("test_blank.rs".to_owned()))?;
11
12    println!("Assembly successful! ROM size: {} bytes", rom.len());
13
14    Ok(())
15}
More examples
Hide additional examples
examples/test_include.rs (line 11)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing include functionality...");
5
6    let content = std::fs::read_to_string("../tal/test_include.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_include.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}
examples/batch_assembler.rs (line 26)
19fn assemble_file(file_path: &str) -> Result<usize, AssemblerError> {
20    let source = std::fs::read_to_string(file_path)?;
21    let mut assembler = Assembler::new();
22    // Always use the canonical path for error context
23    let path = std::fs::canonicalize(file_path)
24        .map(|p| p.to_string_lossy().to_string())
25        .unwrap_or_else(|_| file_path.to_string());
26    let rom = assembler.assemble(&source, Some(path))?;
27    Ok(rom.len())
28}
29
30// Assemble a TAL file and write symbol file, returning ROM and symbol file paths and size
31fn assemble_file_with_symbols(
32    path: &Path,
33) -> Result<(std::path::PathBuf, std::path::PathBuf, usize), AssemblerError> {
34    let source = std::fs::read_to_string(path)?;
35    let mut assembler = Assembler::new();
36    let canonical = std::fs::canonicalize(path)
37        .map(|p| p.to_string_lossy().to_string())
38        .unwrap_or_else(|_| path.to_string_lossy().to_string());
39    let rom = assembler.assemble(&source, Some(canonical))?;
40    let rom_path = path.with_extension("rom");
41    let sym_path = path.with_extension("sym");
42    std::fs::write(&rom_path, &rom)?;
43    let sym_txt = assembler.generate_symbol_file();
44    std::fs::write(&sym_path, sym_txt)?;
45    Ok((rom_path, sym_path, rom.len()))
46}
47
48// Assemble a TAL file and write ROM, returning ROM path and size
49fn assemble_file_auto(path: &Path) -> Result<(std::path::PathBuf, usize), AssemblerError> {
50    let source = std::fs::read_to_string(path)?;
51    let mut assembler = Assembler::new();
52    let canonical = std::fs::canonicalize(path)
53        .map(|p| p.to_string_lossy().to_string())
54        .unwrap_or_else(|_| path.to_string_lossy().to_string());
55    let rom = assembler.assemble(&source, Some(canonical))?;
56    let rom_path = path.with_extension("rom");
57    std::fs::write(&rom_path, &rom)?;
58    Ok((rom_path, rom.len()))
59}
examples/test_macro_call.rs (line 11)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing macro call functionality...");
5
6    let content = std::fs::read_to_string("../tal/test_macro_call.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_macro_call.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}
examples/test_fixes.rs (line 11)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing fixes for device access and comments...");
5
6    let content = std::fs::read_to_string("../tal/test_fixes.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_fixes.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}
examples/test_hyphen.rs (line 11)
3fn main() -> Result<(), Box<dyn std::error::Error>> {
4    println!("Testing hyphen identifiers and raw address refs...");
5
6    let content = std::fs::read_to_string("../tal/test_hyphen.tal")?;
7    println!("Source content:\n{}", content);
8
9    // Assemble
10    let mut assembler = Assembler::new();
11    let rom = assembler.assemble(&content, Some("test_hyphen.rs".to_owned()))?;
12
13    println!("Assembly successful! ROM size: {} bytes", rom.len());
14
15    Ok(())
16}

Trait Implementations§

Source§

impl Default for Assembler

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more