sbpf_assembler/preprocessor/
mod.rs1pub mod expand;
2pub mod include;
3pub mod macro_def;
4pub mod source_map;
5
6use {
7 crate::errors::CompileError,
8 source_map::{FileRegistry, SourceMap, SourceOrigin},
9 std::path::PathBuf,
10};
11
12#[derive(Debug, Clone)]
14pub(crate) struct SourceLine {
15 pub text: String,
16 pub origin: SourceOrigin,
17}
18
19pub trait FileResolver {
22 fn resolve(&self, path: &str, relative_to: &str) -> Result<String, std::io::Error>;
25}
26
27#[derive(Debug, Clone)]
29pub struct FsFileResolver {
30 pub include_paths: Vec<PathBuf>,
32}
33
34impl FsFileResolver {
35 pub fn new() -> Self {
36 Self {
37 include_paths: Vec::new(),
38 }
39 }
40
41 pub fn with_include_paths(include_paths: Vec<PathBuf>) -> Self {
42 Self { include_paths }
43 }
44}
45
46impl Default for FsFileResolver {
47 fn default() -> Self {
48 Self::new()
49 }
50}
51
52impl FileResolver for FsFileResolver {
53 fn resolve(&self, path: &str, relative_to: &str) -> Result<String, std::io::Error> {
54 let base_dir = std::path::Path::new(relative_to)
56 .parent()
57 .unwrap_or(std::path::Path::new("."));
58 let candidate = base_dir.join(path);
59 if candidate.exists() {
60 return std::fs::read_to_string(&candidate);
61 }
62
63 for include_dir in &self.include_paths {
65 let candidate = include_dir.join(path);
66 if candidate.exists() {
67 return std::fs::read_to_string(&candidate);
68 }
69 }
70
71 Err(std::io::Error::new(
72 std::io::ErrorKind::NotFound,
73 format!("file not found: {}", path),
74 ))
75 }
76}
77
78#[derive(Debug, Clone, Default)]
80pub struct MockFileResolver {
81 files: std::collections::HashMap<String, String>,
82}
83
84impl MockFileResolver {
85 pub fn new() -> Self {
86 Self::default()
87 }
88
89 pub fn add_file(&mut self, path: &str, content: &str) -> &mut Self {
90 self.files.insert(path.to_string(), content.to_string());
91 self
92 }
93}
94
95impl FileResolver for MockFileResolver {
96 fn resolve(&self, path: &str, _relative_to: &str) -> Result<String, std::io::Error> {
97 self.files.get(path).cloned().ok_or_else(|| {
98 std::io::Error::new(
99 std::io::ErrorKind::NotFound,
100 format!("file not found: {}", path),
101 )
102 })
103 }
104}
105
106pub struct PreprocessResult {
108 pub expanded_source: String,
109 pub source_map: SourceMap,
110}
111
112#[derive(Debug)]
114pub struct PreprocessorError {
115 pub error: CompileError,
116 pub origin: Option<SourceOrigin>,
117}
118
119pub struct PreprocessFailure {
122 pub errors: Vec<PreprocessorError>,
123 pub file_registry: FileRegistry,
124}
125
126pub fn preprocess(
133 source: &str,
134 source_path: &str,
135 resolver: Option<&dyn FileResolver>,
136) -> Result<PreprocessResult, PreprocessFailure> {
137 let mut registry = FileRegistry::new();
138
139 let lines = match include::resolve_includes(source, source_path, resolver, &mut registry) {
141 Ok(lines) => lines,
142 Err(errors) => {
143 return Err(PreprocessFailure {
144 errors: errors
145 .into_iter()
146 .map(|e| PreprocessorError {
147 error: e,
148 origin: None,
149 })
150 .collect(),
151 file_registry: registry,
152 });
153 }
154 };
155
156 let (expanded_lines, errors) = match expand::expand_macros(lines) {
158 Ok(result) => result,
159 Err(errors) => {
160 return Err(PreprocessFailure {
161 errors: errors
162 .into_iter()
163 .map(|e| PreprocessorError {
164 error: e.error,
165 origin: e.origin,
166 })
167 .collect(),
168 file_registry: registry,
169 });
170 }
171 };
172
173 if !errors.is_empty() {
174 return Err(PreprocessFailure {
175 errors: errors
176 .into_iter()
177 .map(|e| PreprocessorError {
178 error: e.error,
179 origin: e.origin,
180 })
181 .collect(),
182 file_registry: registry,
183 });
184 }
185
186 let mut expanded_source = String::new();
188 let mut line_origins = Vec::with_capacity(expanded_lines.len());
189
190 for line in &expanded_lines {
191 expanded_source.push_str(&line.text);
192 expanded_source.push('\n');
193 line_origins.push(line.origin.clone());
194 }
195
196 let source_map = SourceMap::new(registry, line_origins);
197
198 Ok(PreprocessResult {
199 expanded_source,
200 source_map,
201 })
202}