|
1 | | -use std::collections::BTreeMap; |
| 1 | +use std::collections::{BTreeMap, BTreeSet}; |
2 | 2 | use std::env; |
3 | 3 | use std::fs; |
4 | 4 | use std::path::{Path, PathBuf}; |
@@ -138,27 +138,57 @@ fn write_core_package_index() -> Result<(), String> { |
138 | 138 |
|
139 | 139 | fn write_reg_vm_runtime_intrinsics() -> Result<(), String> { |
140 | 140 | println!("cargo:rerun-if-changed=src/reg_vm.rs"); |
| 141 | + println!("cargo:rerun-if-changed=src/runtime_abi.rs"); |
141 | 142 |
|
142 | 143 | let manifest_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").expect("manifest dir")); |
143 | 144 | let source_path = manifest_dir.join("src/reg_vm.rs"); |
144 | 145 | let source = fs::read_to_string(&source_path) |
145 | 146 | .map_err(|error| format!("failed to read {}: {error}", source_path.display()))?; |
146 | | - let signatures = collect_reg_vm_runtime_intrinsics(&source)?; |
147 | | - let generated = format!( |
| 147 | + let resolver_signatures = collect_reg_vm_resolver_signatures(&source)?; |
| 148 | + let runtime_abi_path = manifest_dir.join("src/runtime_abi.rs"); |
| 149 | + let runtime_abi_source = fs::read_to_string(&runtime_abi_path) |
| 150 | + .map_err(|error| format!("failed to read {}: {error}", runtime_abi_path.display()))?; |
| 151 | + let runtime_abi_signatures = collect_runtime_abi_signatures(&runtime_abi_source); |
| 152 | + let signatures = resolver_signatures |
| 153 | + .iter() |
| 154 | + .filter(|signature| runtime_abi_signatures.contains(*signature)) |
| 155 | + .cloned() |
| 156 | + .collect::<Vec<_>>(); |
| 157 | + let special_forms = resolver_signatures |
| 158 | + .into_iter() |
| 159 | + .filter(|signature| !runtime_abi_signatures.contains(signature)) |
| 160 | + .collect::<Vec<_>>(); |
| 161 | + let generated_runtime = format!( |
148 | 162 | "&[\n{}\n]\n", |
149 | 163 | signatures |
150 | 164 | .iter() |
151 | 165 | .map(|signature| format!(" {signature:?},")) |
152 | 166 | .collect::<Vec<_>>() |
153 | 167 | .join("\n") |
154 | 168 | ); |
| 169 | + let generated_special_forms = format!( |
| 170 | + "&[\n{}\n]\n", |
| 171 | + special_forms |
| 172 | + .iter() |
| 173 | + .map(|signature| format!(" {signature:?},")) |
| 174 | + .collect::<Vec<_>>() |
| 175 | + .join("\n") |
| 176 | + ); |
155 | 177 | let out_dir = PathBuf::from(env::var("OUT_DIR").expect("out dir")); |
156 | | - fs::write(out_dir.join("rss-reg-vm-runtime-intrinsics.rs"), generated) |
157 | | - .map_err(|error| format!("reg VM runtime intrinsic index should be written: {error}"))?; |
| 178 | + fs::write( |
| 179 | + out_dir.join("rss-reg-vm-runtime-intrinsics.rs"), |
| 180 | + generated_runtime, |
| 181 | + ) |
| 182 | + .map_err(|error| format!("reg VM runtime intrinsic index should be written: {error}"))?; |
| 183 | + fs::write( |
| 184 | + out_dir.join("rss-reg-vm-special-forms.rs"), |
| 185 | + generated_special_forms, |
| 186 | + ) |
| 187 | + .map_err(|error| format!("reg VM special form index should be written: {error}"))?; |
158 | 188 | Ok(()) |
159 | 189 | } |
160 | 190 |
|
161 | | -fn collect_reg_vm_runtime_intrinsics(source: &str) -> Result<Vec<String>, String> { |
| 191 | +fn collect_reg_vm_resolver_signatures(source: &str) -> Result<Vec<String>, String> { |
162 | 192 | let start_marker = "let intrinsic = match (namespace_root, name_root) {"; |
163 | 193 | let start = source |
164 | 194 | .find(start_marker) |
@@ -205,6 +235,40 @@ fn collect_reg_vm_runtime_intrinsics(source: &str) -> Result<Vec<String>, String |
205 | 235 | Ok(signatures.into_keys().collect()) |
206 | 236 | } |
207 | 237 |
|
| 238 | +fn collect_runtime_abi_signatures(source: &str) -> BTreeSet<String> { |
| 239 | + let mut signatures = BTreeSet::new(); |
| 240 | + let mut index = 0; |
| 241 | + while let Some(relative) = source[index..].find("runtime_intrinsic") { |
| 242 | + index += relative + "runtime_intrinsic".len(); |
| 243 | + let bytes = source.as_bytes(); |
| 244 | + let mut cursor = index; |
| 245 | + if source[cursor..].starts_with("_with_handles") { |
| 246 | + cursor += "_with_handles".len(); |
| 247 | + } |
| 248 | + cursor = skip_ascii_whitespace(bytes, cursor); |
| 249 | + if bytes.get(cursor) != Some(&b'(') { |
| 250 | + continue; |
| 251 | + } |
| 252 | + cursor += 1; |
| 253 | + cursor = skip_ascii_whitespace(bytes, cursor); |
| 254 | + let Some((namespace, after_namespace)) = parse_quoted_ascii(source, cursor) else { |
| 255 | + continue; |
| 256 | + }; |
| 257 | + cursor = skip_ascii_whitespace(bytes, after_namespace); |
| 258 | + if bytes.get(cursor) != Some(&b',') { |
| 259 | + continue; |
| 260 | + } |
| 261 | + cursor += 1; |
| 262 | + cursor = skip_ascii_whitespace(bytes, cursor); |
| 263 | + let Some((name, after_name)) = parse_quoted_ascii(source, cursor) else { |
| 264 | + continue; |
| 265 | + }; |
| 266 | + signatures.insert(format!("{namespace}.{name}")); |
| 267 | + index = after_name; |
| 268 | + } |
| 269 | + signatures |
| 270 | +} |
| 271 | + |
208 | 272 | fn parse_quoted_ascii(source: &str, quote_index: usize) -> Option<(String, usize)> { |
209 | 273 | let bytes = source.as_bytes(); |
210 | 274 | if bytes.get(quote_index) != Some(&b'"') { |
|
0 commit comments