diff options
| -rw-r--r-- | crates/nasm/src/main.rs | 164 | ||||
| -rw-r--r-- | lib/xixanta/fuzz/fuzz_targets/fuzz_target_assembler.rs | 3 | ||||
| -rw-r--r-- | lib/xixanta/fuzz/fuzz_targets/fuzz_target_parser.rs | 2 | ||||
| -rw-r--r-- | lib/xixanta/src/assembler.rs | 225 | ||||
| -rw-r--r-- | lib/xixanta/src/node.rs | 4 | ||||
| -rw-r--r-- | lib/xixanta/src/object.rs | 11 | ||||
| -rw-r--r-- | lib/xixanta/src/parser.rs | 242 |
7 files changed, 536 insertions, 115 deletions
diff --git a/crates/nasm/src/main.rs b/crates/nasm/src/main.rs index 9cc3049..cc516b6 100644 --- a/crates/nasm/src/main.rs +++ b/crates/nasm/src/main.rs @@ -1,8 +1,9 @@ use header::Header; -use std::fs::File; +use std::fs::{create_dir, File}; use std::io::{self, Write}; -use std::path::Path; -use xixanta::assembler::assemble; +use std::path::{Path, PathBuf}; +use xixanta::assembler::{assemble, MemoryResult}; +use xixanta::mapping::Mapping; use xixanta::SourceInfo; /// Version for this program. @@ -17,6 +18,8 @@ struct Args { stdout: bool, stats: bool, defines: Vec<(String, u8)>, + asan: bool, + info: bool, } // Print the help message and quit. @@ -24,6 +27,7 @@ fn print_help() { println!("Assembler for the 6502 microprocessor that targets the NES/Famicom.\n"); println!("usage: nasm [OPTIONS] <FILE>\n"); println!("Options:"); + println!(" -a, --asan\t\tEnable the Address Sanitizer."); println!(" -c, --config <FILE>\tLinker configuration to be used, whether an identifier or a file path."); println!(" -D <NAME>(=VALUE)\tDefine an 8-bit variable on the global scope (default: 1)"); println!(" -h, --help\t\tPrint this message."); @@ -31,6 +35,9 @@ fn print_help() { println!(" -s, --stats\t\tPrint the statistics on how segments have been filled."); println!(" --stdout\t\tPrint the output binary to the standard output."); println!(" -v, --version\t\tPrint the version of this program."); + println!( + " -w, --write-info\tWrite debug/analysis information into a special '.nasm' directory." + ); println!(" -Werror\t\tWarnings should be treated as errors."); std::process::exit(0); } @@ -77,6 +84,7 @@ fn parse_arguments() -> Args { while let Some(arg) = args.next() { match arg.as_str() { + "a" | "--asan" => res.asan = true, "-c" | "--config" => match res.config { Some(_) => die("only specify the '-C/--config' flag once".to_string()), None => match args.next() { @@ -106,6 +114,7 @@ fn parse_arguments() -> Args { } }, "-s" | "--stats" => res.stats = true, + "-w" | "--write-info" => res.info = true, "--stdout" => match res.out { Some(_) => die("you cannot mix '-o/--out' and '--stdout'".to_string()), None => { @@ -150,6 +159,106 @@ fn die(message: String) { std::process::exit(1); } +// Given a `source` object, find the first parent directory (including +// `source.directory`) which has a `.git` subdirectory. If none could be found, +// then `source.directory` is returned. +fn find_git_directory(source: &SourceInfo) -> PathBuf { + for dir in source.directory.ancestors() { + if dir.join(".git").exists() { + return dir.to_path_buf(); + } + } + source.directory.clone() +} + +// Get the path to the closest `.nasm` special directory and create it if it's +// not available on the expected base directory. +fn get_directory_from_source(source: &SourceInfo) -> PathBuf { + let dir = find_git_directory(source).join(".nasm"); + + if !dir.exists() { + if let Err(e) = create_dir(&dir) { + die(e.to_string()); + } + } + dir +} + +// Save the `memory` object into the `<source>/.nasm/memory.txt` file. +fn save_memory_stats(source: &SourceInfo, memory: &mut MemoryResult, has_working_ram: bool) { + let Ok(mut file) = File::create(get_directory_from_source(source).join("memory.txt")) else { + return die("could not write memory.txt file".to_string()); + }; + + let ranges = &mut memory.memory_ranges; + ranges.sort_by(|a, b| a.range.start.cmp(&b.range.start)); + + for mr in ranges { + if mr.range.start + 1 == mr.range.end { + if let Err(e) = writeln!(file, "{}: {}", mr.range_to_human(), mr.name) { + return die(format!("could not write memory.txt file: {e}")); + } + } else if let Err(e) = writeln!(file, "{}: {}", mr.range_to_human(), mr.name) { + return die(format!("could not write memory.txt file: {e}")); + } + } + + if let Err(e) = writeln!(file, "\n--- Summary (in bytes) ---") { + return die(format!("could not write memory.txt file: {e}")); + } + print_memory_summary(Box::new(file), memory, has_working_ram); +} + +// Print a memory summary message as given in `memory` to the `output` +// stream. The Working RAM will only be reported if `has_working_ram` is set to +// true. +fn print_memory_summary(mut output: Box<dyn Write>, memory: &MemoryResult, has_working_ram: bool) { + let perc = (memory.total_internal_ram * 100) as f64 / 2048.0; + + if let Err(e) = writeln!( + output, + "- Internal RAM: {}/2048 ({:.2}%)", + memory.total_internal_ram, perc + ) { + return die(format!("could not write memory summary: {e}")); + } + + if has_working_ram { + let perc = (memory.total_working_ram * 100) as f64 / 8192.0; + if let Err(e) = writeln!( + output, + "- Working RAM: {}/8192 ({:.2}%)", + memory.total_working_ram, perc + ) { + die(format!("could not write memory summary: {e}")) + } + } +} + +// Print to the `output` stream the statistics that can be gathered from the +// given `mappings`. +fn print_segments_stats(mut output: Box<dyn Write>, mappings: &[Mapping]) { + for mapping in mappings { + let perc = (mapping.offset * 100) as f64 / mapping.size as f64; + + if perc.fract().abs() < f64::EPSILON { + if let Err(e) = writeln!( + output, + "- {}: {}/{} ({:.0}%)", + mapping.name, mapping.offset, mapping.size, perc + ) { + return die(format!("could not write segments summary: {e}")); + } + } else if let Err(e) = writeln!( + output, + "- {}: {}/{} ({:.2}%)", + mapping.name, mapping.offset, mapping.size, perc + ) { + return die(format!("could not write segments summary: {e}")); + } + } +} + fn main() { let args = parse_arguments(); @@ -190,7 +299,8 @@ fn main() { input, args.config.unwrap_or("nrom".to_string()).as_str(), &args.defines, - source, + &source, + args.asan, ); // Print warnings and errors first, while also computing the amount of them @@ -208,6 +318,8 @@ fn main() { error_count += 1; } + let mut has_working_ram = false; + // Deliver the bundles unless the header is borked. if error_count == 0 { // Fetch the header first. @@ -229,6 +341,7 @@ fn main() { "requires Working RAM but the ROM header does not advertise it".to_string(), ); } + has_working_ram = header.has_persistent_memory; } Err(e) => { die(format!( @@ -246,26 +359,39 @@ fn main() { } } } - } - if args.stats { - println!("== Statistics ==\n"); - println!("=> Amount of space on each segment (in bytes):\n"); + // Print segment statistics. + if args.stats { + if args.info { + let Ok(file) = + File::create(get_directory_from_source(&source).join("segments.txt")) + else { + return die("could not write segments.txt file".to_string()); + }; + print_segments_stats(Box::new(file), &res.mappings); + } + + println!("== Statistics ==\n"); + println!("=> Amount of space on each segment (in bytes):\n"); - for mapping in res.mappings { - let perc = (mapping.offset * 100) as f64 / mapping.size as f64; + print_segments_stats(Box::new(io::stdout()), &res.mappings); + } - if perc.fract().abs() < f64::EPSILON { - println!( - "{}: {}/{} ({:.0}%)", - mapping.name, mapping.offset, mapping.size, perc - ); + // Print memory statistics. + if args.asan { + let mut memory = res.memory; + if args.info { + save_memory_stats(&source, &mut memory, has_working_ram); + } + + if !args.stats { + println!("== Statistics ==\n"); } else { - println!( - "{}: {}/{} ({:.2}%)", - mapping.name, mapping.offset, mapping.size, perc - ); + println!(); } + println!("=> Amount of memory used (in bytes):\n"); + + print_memory_summary(Box::new(io::stdout()), &memory, has_working_ram); } } diff --git a/lib/xixanta/fuzz/fuzz_targets/fuzz_target_assembler.rs b/lib/xixanta/fuzz/fuzz_targets/fuzz_target_assembler.rs index ff389a1..72077d9 100644 --- a/lib/xixanta/fuzz/fuzz_targets/fuzz_target_assembler.rs +++ b/lib/xixanta/fuzz/fuzz_targets/fuzz_target_assembler.rs @@ -4,5 +4,6 @@ use libfuzzer_sys::fuzz_target; use xixanta::assembler::assemble; fuzz_target!(|data: &[u8]| { - let _ = assemble(data, "empty", &[], xixanta::SourceInfo::default()); + let _ = assemble(data, "empty", &[], &xixanta::SourceInfo::default(), false); + let _ = assemble(data, "empty", &[], &xixanta::SourceInfo::default(), true); }); diff --git a/lib/xixanta/fuzz/fuzz_targets/fuzz_target_parser.rs b/lib/xixanta/fuzz/fuzz_targets/fuzz_target_parser.rs index da8a350..a68b9e2 100644 --- a/lib/xixanta/fuzz/fuzz_targets/fuzz_target_parser.rs +++ b/lib/xixanta/fuzz/fuzz_targets/fuzz_target_parser.rs @@ -4,5 +4,5 @@ use libfuzzer_sys::fuzz_target; fuzz_target!(|data: &[u8]| { let mut parser = xixanta::parser::Parser::default(); - let _ = parser.parse(data, xixanta::SourceInfo::default()); + let _ = parser.parse(data, &xixanta::SourceInfo::default()); }); diff --git a/lib/xixanta/src/assembler.rs b/lib/xixanta/src/assembler.rs index 5ab0e3d..37f9004 100644 --- a/lib/xixanta/src/assembler.rs +++ b/lib/xixanta/src/assembler.rs @@ -1,5 +1,5 @@ use crate::mapping::{get_mapping_configuration, Mapping}; -use crate::node::{ControlType, EchoKind, NodeType, OperationType, PNode, PString}; +use crate::node::{CommentType, ControlType, EchoKind, NodeType, OperationType, PNode, PString}; use crate::object::{Bundle, Context, Object, ObjectType}; use crate::opcodes::{AddressingMode, INSTRUCTIONS}; use crate::parser::Parser; @@ -10,6 +10,7 @@ use std::collections::HashMap; use std::fs::File; use std::io::{BufReader, Read}; use std::ops::Neg; +use std::ops::Range; /// The mode in which a literal is expressed. #[derive(Clone, PartialEq)] @@ -55,6 +56,40 @@ struct PendingNode { labels_seen: usize, } +/// Memory range that can be identified by a name. +#[derive(Clone, Debug)] +pub struct MemoryRange { + // The range in memory itself. + pub range: Range<usize>, + + // Name that can access this memory range. + pub name: String, +} + +impl MemoryRange { + /// Display the range in hexadecimal format and by taking into consideration + /// on whether it's really a range or a single value. + pub fn range_to_human(&self) -> String { + if self.range.start + 1 == self.range.end { + if self.range.start <= 0xFF { + return format!("${:02X}", self.range.start); + } + return format!("${:04X}", self.range.start); + } + + if self.range.start <= 0xFF { + return format!("${:02X}-${:02X}", self.range.start, self.range.end - 1); + } + format!("${:04X}-${:04X}", self.range.start, self.range.end - 1) + } +} + +impl std::fmt::Display for MemoryRange { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "'{}' ({})", self.name, self.range_to_human()) + } +} + struct Assembler<'a> { context: Context, literal_mode: Option<LiteralMode>, @@ -87,6 +122,32 @@ struct Assembler<'a> { // Whether the assembler has detected accesses to Working RAM or not // (0x6000-0x7FFF). accessing_working_ram: bool, + + // Whether the Address Sanitizer is enabled or not. + asan_enabled: bool, + + // Whether the next assignment should be ignored or not by the address + // sanitizer. + asan_next_ignore: bool, + + // The amount of bytes to reserve for the next variable assignment. + asan_next_reserve: u8, +} + +/// The result to be given at the end of `assembler::assemble` and +/// `assembler::assemble_with_mapping` functions. It includes everything a +/// caller might want to know about the resulting memory layout. +#[derive(Debug, Default)] +pub struct MemoryResult { + /// Memory ranges used by the source. + pub memory_ranges: Vec<MemoryRange>, + + /// Total Internal RAM being used by the source in bytes. + pub total_internal_ram: usize, + + /// Total Working RAM being used by the source in bytes. Ignore this field + /// if `accessing_working_ram` has been set to false in `Assembler`. + pub total_working_ram: usize, } /// All the information that a caller needs after calling either @@ -112,6 +173,10 @@ pub struct AssemblerResult { /// Whether the resulting ROM needs Working RAM to be available in order to /// work. Ignore this field if `errors` is not empty. pub accessing_working_ram: bool, + + /// The resaulting memory analysis from the address sanitizer. Ignore this + /// if you did not assemble the source with the address sanitizer enabled. + pub memory: MemoryResult, } /// Read the contents from the `reader` as a source file and produce a list of @@ -124,7 +189,8 @@ pub fn assemble( reader: impl Read, mapping: &str, defines: &[(String, u8)], - source: SourceInfo, + source: &SourceInfo, + asan: bool, ) -> AssemblerResult { let config = match get_mapping_configuration(mapping) { Ok(config) => config, @@ -135,16 +201,17 @@ pub fn assemble( global: true, line: 0, message: e, - source, + source: source.clone(), }], warnings: vec![], mappings: vec![], accessing_working_ram: false, + memory: MemoryResult::default(), }; } }; - assemble_with_mapping(reader, config, defines, source) + assemble_with_mapping(reader, config, defines, source, asan) } /// Read the contents from the `reader` as a source file and produce a list of @@ -157,9 +224,12 @@ pub fn assemble_with_mapping( reader: impl Read, mapping: Vec<Mapping>, defines: &[(String, u8)], - source: SourceInfo, + source: &SourceInfo, + asan: bool, ) -> AssemblerResult { let mut asm = Assembler::new(mapping); + let mut memory = MemoryResult::default(); + asm.asan_enabled = asan; // First of all, parse the input so we get a list of nodes we can work // with. @@ -171,6 +241,7 @@ pub fn assemble_with_mapping( warnings: asm.warnings, mappings: asm.mappings, accessing_working_ram: asm.accessing_working_ram, + memory, }; } @@ -187,6 +258,7 @@ pub fn assemble_with_mapping( warnings: vec![], mappings: asm.mappings, accessing_working_ram: asm.accessing_working_ram, + memory, }; } } @@ -200,6 +272,7 @@ pub fn assemble_with_mapping( warnings: asm.warnings, mappings: asm.mappings, accessing_working_ram: asm.accessing_working_ram, + memory, }; } @@ -214,6 +287,7 @@ pub fn assemble_with_mapping( warnings: asm.warnings, mappings: asm.mappings, accessing_working_ram: asm.accessing_working_ram, + memory, }; } @@ -226,9 +300,23 @@ pub fn assemble_with_mapping( warnings: asm.warnings, mappings: asm.mappings, accessing_working_ram: asm.accessing_working_ram, + memory, }; } + if asm.asan_enabled { + if let Err(errors) = asm.asan(&mut memory) { + return AssemblerResult { + bundles: vec![], + errors, + warnings: asm.warnings, + mappings: asm.mappings, + accessing_working_ram: asm.accessing_working_ram, + memory, + }; + } + } + // All set, fill the vector of bundles to be returned. match asm.fill() { Ok(bundles) => AssemblerResult { @@ -237,6 +325,7 @@ pub fn assemble_with_mapping( warnings: asm.warnings, mappings: asm.mappings, accessing_working_ram: asm.accessing_working_ram, + memory, }, Err(errors) => AssemblerResult { bundles: vec![], @@ -244,6 +333,7 @@ pub fn assemble_with_mapping( warnings: asm.warnings, mappings: asm.mappings, accessing_working_ram: asm.accessing_working_ram, + memory, }, } } @@ -266,6 +356,9 @@ impl<'a> Assembler<'a> { warnings: vec![], sources: vec![], accessing_working_ram: false, + asan_enabled: false, + asan_next_ignore: false, + asan_next_reserve: 1, } } @@ -292,6 +385,8 @@ impl<'a> Assembler<'a> { mapping: self.current_mapping, segment: self.current_segment, object_type: ObjectType::Value, + asan_ignore: false, + asan_reserve: 1, }; if let Err(err) = self.context.set_variable(&var_name, &var_value, false) { @@ -338,6 +433,12 @@ impl<'a> Assembler<'a> { let mut errors = Vec::new(); for node in nodes { + // Remove asan:ignore if the current node is not to be an assignment. + if self.asan_next_ignore && !matches!(&node.node_type, NodeType::Assignment) { + self.asan_next_ignore = false; + self.asan_next_reserve = 1; + } + match &node.node_type { // At this stage we only define the label into the current // context so it's known. The actual value cannot be computed @@ -362,6 +463,12 @@ impl<'a> Assembler<'a> { errors.push(err); } } + NodeType::Comment(CommentType::AsanReserve(size)) => { + self.asan_next_reserve = *size; + } + NodeType::Comment(CommentType::AsanIgnore) => { + self.asan_next_ignore = true; + } NodeType::Assignment => { if self.macros_seen > 0 || self.repeats_seen > 0 { errors.push(Error { @@ -374,6 +481,7 @@ impl<'a> Assembler<'a> { continue; } self.literal_mode = None; + match self.evaluate_node(node.left.as_ref().unwrap()) { Ok(value) => { if let Err(err) = self.context.set_variable( @@ -384,6 +492,8 @@ impl<'a> Assembler<'a> { mapping: self.current_mapping, segment: self.current_segment, object_type: ObjectType::Value, + asan_ignore: self.asan_next_ignore, + asan_reserve: self.asan_next_reserve, }, false, ) { @@ -394,6 +504,8 @@ impl<'a> Assembler<'a> { source: self.source_for(node), }); } + self.asan_next_ignore = false; + self.asan_next_reserve = 1; } Err(e) => errors.push(e), } @@ -550,6 +662,8 @@ impl<'a> Assembler<'a> { mapping: self.current_mapping, segment: self.current_segment, object_type: ObjectType::Address, + asan_ignore: false, + asan_reserve: 1, }; if !node.value.is_empty() { @@ -718,6 +832,77 @@ impl<'a> Assembler<'a> { } } + fn asan(&mut self, memory: &mut MemoryResult) -> Result<(), Vec<Error>> { + let mut errors = vec![]; + + for (_context, map) in self.context.map.iter() { + for (name, bundle) in map { + // Ignore this bundle if the user explicitely told us to do so. + if bundle.asan_ignore { + continue; + } + + // Evaluate if the given object conflicts with an existing + // range. + if name.starts_with("zp_") || name.starts_with("m_") || name.starts_with("wr_") { + let val = bundle.bundle.value() as usize; + let range = MemoryRange { + range: (val..val + bundle.asan_reserve as usize), + name: name.clone(), + }; + + for existing in &memory.memory_ranges { + if (range.range.start >= existing.range.start + && range.range.start < existing.range.end) + || (range.range.end > existing.range.start + && range.range.end < existing.range.end) + { + errors.push(Error { + line: 0, + global: true, + message: format!("The variable {range} conflicts with {existing}",), + source: self.sources[0].clone(), + }); + } + } + memory.memory_ranges.push(range); + } + + // Increase the counters for memory usage on either RAM slot and + // check for bounds. + if name.starts_with("zp_") || name.starts_with("m_") { + memory.total_internal_ram += bundle.asan_reserve as usize; + + if memory.total_internal_ram > 0x800 { + errors.push(Error { + line: 0, + global: true, + message: "out of internal RAM".to_string(), + source: self.sources[0].clone(), + }); + } + } else if name.starts_with("wr_") { + memory.total_working_ram += bundle.asan_reserve as usize; + + if memory.total_working_ram > 0x2000 { + errors.push(Error { + line: 0, + global: true, + message: "out of working RAM".to_string(), + source: self.sources[0].clone(), + }); + } + } + } + } + + if errors.is_empty() { + Ok(()) + } else { + Err(errors) + } + } + fn fill(&mut self) -> Result<Vec<Bundle>, Vec<Error>> { let mut errors = vec![]; @@ -844,6 +1029,8 @@ impl<'a> Assembler<'a> { mapping: self.current_mapping, segment: self.current_segment, object_type: ObjectType::Value, + asan_ignore: false, + asan_reserve: 1, }; // Note that we overwrite the variable value from previous @@ -1641,7 +1828,9 @@ impl<'a> Assembler<'a> { node: None, mapping: self.current_mapping, segment: self.current_segment, + asan_ignore: false, object_type: ObjectType::Value, + asan_reserve: 1, }, true, ) { @@ -2385,7 +2574,13 @@ mod tests { // the assembler will freak out. let real_line = minimal_header().to_string() + line; - assemble_with_mapping(real_line.as_bytes(), empty(), &[], SourceInfo::default()) + assemble_with_mapping( + real_line.as_bytes(), + empty(), + &[], + &SourceInfo::default(), + false, + ) } // Like `just_assemble` but it only returns bundles passed the header. @@ -4202,7 +4397,8 @@ lda #Variable .as_bytes(), one_two().to_vec(), &[], - SourceInfo::default(), + &SourceInfo::default(), + false, ); assert_eq!(res.bundles.len(), 0x11); @@ -4244,7 +4440,8 @@ lda #Variable .as_bytes(), one_two().to_vec(), &[], - SourceInfo::default(), + &SourceInfo::default(), + false, ); let bundles = &res.bundles[0x11..]; @@ -4318,7 +4515,8 @@ lda #Variable .as_bytes(), one_two().to_vec(), &[], - SourceInfo::default(), + &SourceInfo::default(), + false, ); let bundles = &res.bundles[0x12..]; // Ignoring HEADER + first two ONE @@ -4366,7 +4564,8 @@ lda #Variable .as_bytes(), one_two().to_vec(), &[], - SourceInfo::default(), + &SourceInfo::default(), + false, ); let bundles = &res.bundles[0x11..]; // Ignoring HEADER + first nop @@ -4421,7 +4620,8 @@ lda #Variable .as_bytes(), one_two().to_vec(), &[], - SourceInfo::default(), + &SourceInfo::default(), + false, ); let bundles = &res.bundles[0x10..]; @@ -4448,7 +4648,8 @@ lda #Variable .as_bytes(), one_two().to_vec(), &[], - SourceInfo::default(), + &SourceInfo::default(), + false, ); assert_eq!( diff --git a/lib/xixanta/src/node.rs b/lib/xixanta/src/node.rs index 4281c4a..7cfc107 100644 --- a/lib/xixanta/src/node.rs +++ b/lib/xixanta/src/node.rs @@ -252,7 +252,7 @@ pub enum OperationType { #[derive(Debug, Clone, PartialEq)] pub enum CommentType { AsanReserve(u8), - AsanWeak, + AsanIgnore, } /// The PNode type. @@ -349,7 +349,7 @@ impl fmt::Display for NodeType { }, NodeType::Comment(ct) => match ct { CommentType::AsanReserve(_) => write!(f, ";; asan:reserve"), - CommentType::AsanWeak => write!(f, ";; asan:weak"), + CommentType::AsanIgnore => write!(f, ";; asan:ignore"), }, } } diff --git a/lib/xixanta/src/object.rs b/lib/xixanta/src/object.rs index 373d06c..920a4f8 100644 --- a/lib/xixanta/src/object.rs +++ b/lib/xixanta/src/object.rs @@ -101,7 +101,8 @@ impl Bundle { } /// The type of object being referenced, which is either a value as-is, or an -/// address that needs to be interpreted when fetching it. +/// address that needs to be interpreted when fetching it; or a reference to a +/// value (i.e. something the address sanitizer can ignore). #[derive(Debug, Clone)] pub enum ObjectType { Address, @@ -132,6 +133,12 @@ pub struct Object { /// The type for this object. pub object_type: ObjectType, + + /// Whether the address sanitizer should ignore this object or not. + pub asan_ignore: bool, + + /// Amount of bytes reserved for this object on the address sanitizer. + pub asan_reserve: u8, } impl Object { @@ -143,6 +150,8 @@ impl Object { mapping, segment, object_type, + asan_ignore: false, + asan_reserve: 1, } } } diff --git a/lib/xixanta/src/parser.rs b/lib/xixanta/src/parser.rs index c40e0d1..a0d19d0 100644 --- a/lib/xixanta/src/parser.rs +++ b/lib/xixanta/src/parser.rs @@ -80,15 +80,15 @@ impl Parser { /// Parse the input from the given `reader`. You can then access the results /// from the `nodes` field. Otherwise, a vector of Error's might be /// returned. - pub fn parse(&mut self, reader: impl Read, source: SourceInfo) -> Result<(), Vec<Error>> { + pub fn parse(&mut self, reader: impl Read, source: &SourceInfo) -> Result<(), Vec<Error>> { let mut errors = Vec::new(); // Push the sources for the parsing session (note that this list might // be initialized by the caller already). The `current_source` is simply // the one we push upon initialization. self.sources.push(SourceInfo { - directory: path::absolute(&source.directory).unwrap_or(source.directory), - name: source.name, + directory: path::absolute(&source.directory).unwrap_or(source.directory.clone()), + name: source.name.clone(), }); self.current_source = self.sources.len() - 1; @@ -227,9 +227,9 @@ impl Parser { source: self.current_source, }); } - "asan:weak" => { + "asan:ignore" => { self.nodes.last_mut().unwrap().push(PNode { - node_type: NodeType::Comment(CommentType::AsanWeak), + node_type: NodeType::Comment(CommentType::AsanIgnore), value: PString { value: cmd, line: self.line, @@ -948,7 +948,7 @@ impl Parser { }; parser.parse( file, - SourceInfo { + &SourceInfo { directory: parent.to_path_buf(), name: path.file_name().unwrap().to_str().unwrap().to_string(), }, @@ -1735,7 +1735,9 @@ mod tests { use crate::node::ControlType; fn assert_one_valid(parser: &mut Parser, line: &str) { - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); assert!(parser.nodes.len() == 1); } @@ -1753,7 +1755,7 @@ mod tests { #[test] fn empty_line() { let mut parser = Parser::default(); - assert!(parser.parse("".as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser.parse("".as_bytes(), &SourceInfo::default()).is_ok()); assert_eq!(parser.nodes.last().unwrap().len(), 0); } @@ -1761,7 +1763,7 @@ mod tests { fn spaced_line() { let mut parser = Parser::default(); assert!(parser - .parse(" ".as_bytes(), SourceInfo::default()) + .parse(" ".as_bytes(), &SourceInfo::default()) .is_ok()); assert_eq!(parser.nodes.last().unwrap().len(), 0); } @@ -1770,7 +1772,9 @@ mod tests { fn just_a_comment_line() { for line in vec![";; This is a comment", " ;; Comment"].into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); assert_eq!(parser.nodes.last().unwrap().len(), 0); } } @@ -1780,7 +1784,7 @@ mod tests { #[test] fn anonymous_label() { let mut parser = Parser::default(); - assert!(parser.parse(":".as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser.parse(":".as_bytes(), &SourceInfo::default()).is_ok()); let mut nodes = parser.nodes.last().unwrap(); assert_eq!(nodes.len(), 1); @@ -1790,7 +1794,7 @@ mod tests { parser = Parser::default(); assert!(parser - .parse(" :".as_bytes(), SourceInfo::default()) + .parse(" :".as_bytes(), &SourceInfo::default()) .is_ok()); nodes = parser.nodes.last().unwrap(); @@ -1804,7 +1808,7 @@ mod tests { fn named_label() { let mut parser = Parser::default(); assert!(parser - .parse("label:".as_bytes(), SourceInfo::default()) + .parse("label:".as_bytes(), &SourceInfo::default()) .is_ok()); let mut nodes = parser.nodes.last().unwrap(); @@ -1815,7 +1819,7 @@ mod tests { parser = Parser::default(); assert!(parser - .parse(" label:".as_bytes(), SourceInfo::default()) + .parse(" label:".as_bytes(), &SourceInfo::default()) .is_ok()); nodes = parser.nodes.last().unwrap(); @@ -1830,7 +1834,9 @@ mod tests { let line = "label: dex"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); assert_eq!(nodes.len(), 2); @@ -1849,7 +1855,9 @@ mod tests { let line = ".L1: dex"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); assert_eq!(nodes.len(), 2); @@ -1876,7 +1884,9 @@ mod tests { .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); @@ -1896,7 +1906,9 @@ mod tests { fn parse_compound_literal() { let line = "lda #$20"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); @@ -1924,7 +1936,9 @@ mod tests { fn parse_variable_in_literal() { let line = "lda #Variable"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); @@ -1946,7 +1960,9 @@ mod tests { fn parse_paren_expression() { let line = "ldx #(Variable)"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let instr = parser.nodes.last().unwrap().last().unwrap(); assert_eq!(instr.node_type, NodeType::Instruction); @@ -1972,7 +1988,7 @@ mod tests { for line in vec!["lda #", "lda #%", "lda $"].into_iter() { let mut parser = Parser::default(); let err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!(err.first().unwrap().message, "invalid identifier"); @@ -1981,7 +1997,7 @@ mod tests { for line in vec!["lda $ 2", "lda #% 2", "lda # 2"].into_iter() { let mut parser = Parser::default(); let err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( @@ -2002,7 +2018,7 @@ mod tests { { let mut parser = Parser::default(); let err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!(err.first().unwrap().message, "bad literal syntax"); @@ -2014,7 +2030,9 @@ mod tests { let mut parser = Parser::default(); let line = ".asciiz \"=a: b, c; d\" ; Comment"; - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let stmt = parser.nodes.last().unwrap().last().unwrap(); let inner = stmt.args.as_ref().unwrap().first().unwrap(); @@ -2032,7 +2050,7 @@ mod tests { let line = ".asciiz \"à\""; let err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( @@ -2055,7 +2073,9 @@ mod tests { .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "dex"); @@ -2141,7 +2161,9 @@ mod tests { .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "inc"); @@ -2168,7 +2190,9 @@ mod tests { .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -2193,7 +2217,9 @@ mod tests { .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -2211,7 +2237,7 @@ mod tests { let mut parser = Parser::default(); let err = parser - .parse("lda (Variable, x), y".as_bytes(), SourceInfo::default()) + .parse("lda (Variable, x), y".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!(err.first().unwrap().message, "bad indirect addressing"); } @@ -2220,7 +2246,9 @@ mod tests { fn indirect_addressing_y() { for line in vec!["lda ($20), y"].into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -2239,7 +2267,9 @@ mod tests { fn variable_in_instruction() { let line = "lda Variable, x"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -2258,7 +2288,9 @@ mod tests { fn variable_literal_in_instruction() { let line = "lda #Variable, x"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -2278,7 +2310,9 @@ mod tests { for var in vec!["Scope::Variable", "Scope::Inner::Variable"].into_iter() { let line = format!("lda #{var}"); let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line.as_str(), "lda"); @@ -2299,7 +2333,7 @@ mod tests { let mut parser = Parser::default(); let err = parser - .parse("adc #One:Variable".as_bytes(), SourceInfo::default()) + .parse("adc #One:Variable".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2312,7 +2346,7 @@ mod tests { let mut parser = Parser::default(); let err = parser - .parse("lda = $10".as_bytes(), SourceInfo::default()) + .parse("lda = $10".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2325,7 +2359,9 @@ mod tests { for label in vec![":+", ":++", ":+++ ", ":++++", ":-", ":--", ":---", ":----"].into_iter() { let line = format!("jmp {label}"); let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line.as_str(), "jmp"); @@ -2347,7 +2383,7 @@ mod tests { let mut line = "jmp :+++++"; let mut err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2356,7 +2392,7 @@ mod tests { line = "jmp :+-"; err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2365,7 +2401,7 @@ mod tests { line = "jmp :-+-"; err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2374,7 +2410,7 @@ mod tests { line = "jmp Identifier:++"; err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2389,7 +2425,7 @@ mod tests { let mut parser = Parser::default(); let mut err = parser - .parse("abc = $10".as_bytes(), SourceInfo::default()) + .parse("abc = $10".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2398,7 +2434,7 @@ mod tests { parser = Parser::default(); err = parser - .parse(".var = 1".as_bytes(), SourceInfo::default()) + .parse(".var = 1".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -2407,19 +2443,19 @@ mod tests { parser = Parser::default(); err = parser - .parse("var =".as_bytes(), SourceInfo::default()) + .parse("var =".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!(err.first().unwrap().message, "incomplete assignment"); parser = Parser::default(); err = parser - .parse("var = ".as_bytes(), SourceInfo::default()) + .parse("var = ".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!(err.first().unwrap().message, "incomplete assignment"); parser = Parser::default(); err = parser - .parse("var = ; Comment".as_bytes(), SourceInfo::default()) + .parse("var = ; Comment".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!(err.first().unwrap().message, "incomplete assignment"); } @@ -2430,7 +2466,9 @@ mod tests { fn constant_expression_test() { let line = "ldx #(4 * NUM_SPRITES)"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "ldx"); @@ -2455,7 +2493,9 @@ mod tests { fn nested_expression_test() { let line = "lda #$80 >> ((BCD_BITS - 1) & 3)"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let instr = parser.nodes.last().unwrap().last().unwrap(); assert_node(instr, NodeType::Instruction, line, "lda"); @@ -2493,7 +2533,9 @@ mod tests { fn parens_to_desambiguate() { let line = ".byte ($01 << 4) | ($01 << 2) | ($01 << 1)"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Control(ControlType::Byte), line, ".byte"); @@ -2533,7 +2575,9 @@ mod tests { fn parens_to_desambiguate2() { let line = ".byte ($01 << 4) | ($01 << 2) | ($01 << 1), $02"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Control(ControlType::Byte), line, ".byte"); @@ -2556,7 +2600,9 @@ mod tests { fn unary_operator_test() { let line = "ldx #<NUM_SPRITES"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "ldx"); @@ -2583,7 +2629,9 @@ mod tests { fn parse_control_no_args() { for line in vec![".byte", " .byte", " label: .byte ; Comment"].into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Control(ControlType::Byte), line, ".byte"); @@ -2605,7 +2653,9 @@ mod tests { .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node( @@ -2635,7 +2685,9 @@ mod tests { .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Control(ControlType::Byte), line, ".byte"); @@ -2653,7 +2705,9 @@ mod tests { fn parse_byte_with_character_literals() { let line = ".byte 'N', 'E', 'S', $1A"; let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let args = parser .nodes @@ -2705,7 +2759,9 @@ mod tests { let real = String::from(line) + "\n.endscope"; let mut parser = Parser::default(); - assert!(parser.parse(real.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(real.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); let node = &nodes[nodes.len() - 2]; @@ -2739,7 +2795,9 @@ mod tests { let real = String::from(line) + "\n.endmacro"; let mut parser = Parser::default(); - assert!(parser.parse(real.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(real.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); let node = &nodes[nodes.len() - 2]; @@ -2776,7 +2834,9 @@ mod tests { let real = String::from(line) + "\n.endmacro"; let mut parser = Parser::default(); - assert!(parser.parse(real.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(real.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); let node = &nodes[nodes.len() - 2]; @@ -2802,7 +2862,7 @@ mod tests { fn parse_control_unclosed() { let mut parser = Parser::default(); let err = parser - .parse(".macro MACRO".as_bytes(), SourceInfo::default()) + .parse(".macro MACRO".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( @@ -2815,7 +2875,7 @@ mod tests { fn parse_control_too_many_closes() { let mut parser = Parser::default(); let err = parser - .parse(".endmacro".as_bytes(), SourceInfo::default()) + .parse(".endmacro".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( @@ -2832,7 +2892,7 @@ mod tests { .endmacro"#; let mut parser = Parser::default(); let err = parser - .parse(code.as_bytes(), SourceInfo::default()) + .parse(code.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( @@ -2852,7 +2912,9 @@ nop inc $20 .endmacro"#; let mut parser = Parser::default(); - assert!(parser.parse(code.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(code.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); assert_eq!(nodes.len(), 2); // .macro and .endmacro @@ -2886,7 +2948,7 @@ inc $20 for line in vec![".hibyte", ".hibyte($20, $22)"].into_iter() { let mut parser = Parser::default(); let err = parser - .parse(line.as_bytes(), SourceInfo::default()) + .parse(line.as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( @@ -2900,7 +2962,9 @@ inc $20 fn parse_control_in_instructions() { for line in vec!["lda #.hibyte($2010)", " label: lda #.hibyte $2010 "].into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -2937,7 +3001,9 @@ inc $20 .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -2981,7 +3047,9 @@ inc $20 .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Instruction, line, "lda"); @@ -3026,7 +3094,9 @@ inc $20 .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Assignment, line, "lala"); @@ -3058,7 +3128,7 @@ inc $20 fn parse_repeat_control() { let mut parser = Parser::default(); let err = parser - .parse(".repeat\n.endrepeat".as_bytes(), SourceInfo::default()) + .parse(".repeat\n.endrepeat".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!( err.first().unwrap().message, @@ -3069,7 +3139,7 @@ inc $20 let err = parser .parse( ".repeat 1, 2, 3\n.endrepeat".as_bytes(), - SourceInfo::default(), + &SourceInfo::default(), ) .unwrap_err(); assert_eq!( @@ -3082,7 +3152,9 @@ inc $20 parser = Parser::default(); let mut line = ".repeat 2\n.endrepeat"; - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let mut control = parser.nodes.last().unwrap().first().unwrap(); assert_node( control, @@ -3108,7 +3180,9 @@ inc $20 parser = Parser::default(); line = ".repeat 2, I\n.endrepeat"; - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); control = parser.nodes.last().unwrap().first().unwrap(); assert_node( control, @@ -3135,13 +3209,13 @@ inc $20 fn parse_unknown_control() { let mut parser = Parser::default(); let err = parser - .parse(".".as_bytes(), SourceInfo::default()) + .parse(".".as_bytes(), &SourceInfo::default()) .unwrap_err(); assert_eq!(err.first().unwrap().message, "empty identifier"); parser = Parser::default(); assert!(parser - .parse(".whatever".as_bytes(), SourceInfo::default()) + .parse(".whatever".as_bytes(), &SourceInfo::default()) .is_ok()); } @@ -3157,7 +3231,9 @@ inc $20 .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Call, line, "MACRO_CALL"); @@ -3179,7 +3255,9 @@ inc $20 .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Call, line, "MACRO_CALL"); @@ -3200,7 +3278,9 @@ inc $20 .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Call, line, "MACRO_CALL"); @@ -3224,7 +3304,9 @@ inc $20 .into_iter() { let mut parser = Parser::default(); - assert!(parser.parse(line.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(line.as_bytes(), &SourceInfo::default()) + .is_ok()); let node = parser.nodes.last().unwrap().last().unwrap(); assert_node(node, NodeType::Call, line, "MACRO_CALL"); @@ -3246,7 +3328,9 @@ VAR = $00 VAR2 = $02 ;; asan:reserve $03 "#; let mut parser = Parser::default(); - assert!(parser.parse(code.as_bytes(), SourceInfo::default()).is_ok()); + assert!(parser + .parse(code.as_bytes(), &SourceInfo::default()) + .is_ok()); let nodes = parser.nodes(); assert_eq!(nodes.len(), 4); @@ -3280,7 +3364,7 @@ VAR2 = $02 ;; asan:reserve $03 "#; let mut parser = Parser::default(); - let res = parser.parse(code.as_bytes(), SourceInfo::default()); + let res = parser.parse(code.as_bytes(), &SourceInfo::default()); assert!(res.is_err()); |
