diff --git a/vasm/src/main.rs b/vasm/src/main.rs index 3b52ade..32ffe7c 100644 --- a/vasm/src/main.rs +++ b/vasm/src/main.rs @@ -1,7 +1,6 @@ use std::collections::BTreeMap; use std::fs::File; use std::io::Write; -use clap::lazy_static::lazy_static; use clap::Parser; use regex::Regex; use serde_json::json; diff --git a/vasm_core/src/lib.rs b/vasm_core/src/lib.rs index 825ada8..354b234 100644 --- a/vasm_core/src/lib.rs +++ b/vasm_core/src/lib.rs @@ -10,4 +10,5 @@ mod vasm_parser; mod vasm_preprocessor; pub use vasm_assembler::assemble_snippet; +pub use vasm_assembler::snippet_source_map; pub use vasm_assembler::assemble_file; diff --git a/vasm_core/src/vasm_assembler.rs b/vasm_core/src/vasm_assembler.rs index 2dba839..8e31679 100644 --- a/vasm_core/src/vasm_assembler.rs +++ b/vasm_core/src/vasm_assembler.rs @@ -182,6 +182,45 @@ pub fn assemble_snippet>( assemble_line_results(line_results).map(|(bytes, _)| { bytes }) } +/// Turn an iterable of strs into a map from instruction address to line number. This +/// supports macros but not `#include`, just like `assemble_snippet`. Zero-length lines +/// won't appear in the map. This is intended to be used for highlighting lines while +/// stepping through a snippet. Lines in the snippet are indexed from 1 and comment and +/// blank lines are handled correctly. +/// ``` +/// use std::collections::BTreeMap; +/// assert_eq!( +/// vasm_core::snippet_source_map(".org 0x400 \n push 5 \n add 7".lines().map(String::from)), +/// Ok(BTreeMap::from([(1024, 2), (1026, 3)])) +/// ) +/// ``` +pub fn snippet_source_map>(lines: T) -> Result, AssembleError> { + let line_results = linesource_for_snippet(lines); + + let lines = line_results.iter().map(|line| line.clone().unwrap()); + let lines: Vec = lines.into_iter().collect(); + let scope = solve_equs(&lines)?; + let line_lengths = measure_instructions(&lines, &scope); + let (line_addresses, _scope) = place_labels(&lines, scope, &line_lengths)?; + let mut line_for_addr = BTreeMap::new(); + for (i, line) in lines.iter().enumerate() { + line_for_addr.insert(line_addresses[&i], line.location.line_num); + } + Ok(line_for_addr) +} + +fn linesource_for_snippet>(lines: T) -> Vec> { + let line_results: Vec> = + LineSource::new("", lines, |_file| { + Err(AssembleError::IncludeError( + Location::default(), + "Including is not supported in assembling snippets".to_string(), + )) + }) + .collect(); + line_results +} + /// Assemble a file from the filesystem, opening other files as it includes them. pub fn assemble_file(filename: &str) -> Result<(Vec, Scope), AssembleError> { let lines = lines_from_file(filename)?;