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(
134 source: &str,
135 source_path: &str,
136 resolver: Option<&dyn FileResolver>,
137) -> Result<PreprocessResult, PreprocessFailure> {
138 let mut registry = FileRegistry::new();
139
140 let lines = match include::resolve_includes(source, source_path, resolver, &mut registry) {
142 Ok(lines) => lines,
143 Err(errors) => {
144 return Err(PreprocessFailure {
145 errors: errors
146 .into_iter()
147 .map(|e| PreprocessorError {
148 error: e,
149 origin: None,
150 })
151 .collect(),
152 file_registry: registry,
153 });
154 }
155 };
156
157 let (expanded_lines, errors) = match expand::expand_macros(lines) {
159 Ok(result) => result,
160 Err(errors) => {
161 return Err(PreprocessFailure {
162 errors: errors
163 .into_iter()
164 .map(|e| PreprocessorError {
165 error: e.error,
166 origin: e.origin,
167 })
168 .collect(),
169 file_registry: registry,
170 });
171 }
172 };
173
174 if !errors.is_empty() {
175 return Err(PreprocessFailure {
176 errors: errors
177 .into_iter()
178 .map(|e| PreprocessorError {
179 error: e.error,
180 origin: e.origin,
181 })
182 .collect(),
183 file_registry: registry,
184 });
185 }
186
187 let mut expanded_source = String::new();
189 let mut line_origins = Vec::with_capacity(expanded_lines.len());
190
191 for line in &expanded_lines {
192 expanded_source.push_str(&line.text);
193 expanded_source.push('\n');
194 line_origins.push(line.origin.clone());
195 }
196
197 let source_map = SourceMap::new(registry, line_origins);
198
199 Ok(PreprocessResult {
200 expanded_source,
201 source_map,
202 })
203}