Created
December 18, 2024 18:16
-
-
Save jinschoi/8eb84a95bd136e4f7119456bb0fc572a to your computer and use it in GitHub Desktop.
Rust proc macro for Advent of Code 2024 day 17
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
use proc_macro::TokenStream; | |
use std::fs; | |
use syn::{parse_macro_input, LitStr}; | |
fn combo(opr: u8) -> String { | |
match opr { | |
0..=3 => opr.to_string(), | |
4 => "a".to_string(), | |
5 => "b".to_string(), | |
6 => "c".to_string(), | |
_ => unreachable!(), | |
} | |
} | |
#[proc_macro] | |
pub fn comp(input: TokenStream) -> TokenStream { | |
let filename = parse_macro_input!(input as LitStr); | |
let filename_str = filename.value(); | |
let s = match fs::read_to_string(&filename_str) { | |
Ok(contents) => contents, | |
Err(e) => { | |
return syn::Error::new( | |
filename.span(), | |
format!("Failed to read file {}: {}", filename_str, e), | |
) | |
.to_compile_error() | |
.into() | |
} | |
}; | |
let mut res = | |
"fn comp(mut a: usize, mut b: usize, mut c: usize) -> Vec<u8> {\nlet mut res = vec![];\n" | |
.to_string(); | |
let prog = s | |
.lines() | |
.take(5) | |
.last() | |
.unwrap() | |
.split_once(": ") | |
.unwrap() | |
.1 | |
.split(',') | |
.map(|s| s.parse::<u8>().unwrap()) | |
.collect::<Vec<_>>(); | |
// Find any jnz arguments | |
let jump_inds = prog | |
.chunks_exact(2) | |
.filter_map(|c| { | |
if c[0] == 3 { | |
Some(c[1] as usize / 2) | |
} else { | |
None | |
} | |
}) | |
.collect::<Vec<_>>(); | |
for (i, chunk) in prog.chunks_exact(2).enumerate() { | |
let (opc, opr) = (chunk[0], chunk[1]); | |
if jump_inds.contains(&i) { | |
res.push_str("loop {\n"); | |
} | |
match opc { | |
0 => res.push_str(&format!("a /= (1 << {} as usize);\n", combo(opr))), | |
1 => res.push_str(&format!("b ^= {};\n", opr)), | |
2 => res.push_str(&format!("b = {} & 0x7;\n", combo(opr))), | |
3 => res.push_str("if a == 0 { break; }\n}\n"), | |
4 => res.push_str("b ^= c;\n"), | |
5 => res.push_str(&format!("res.push(({} & 0x7) as u8);\n", combo(opr))), | |
6 => res.push_str(&format!("b = a / (1 << {} as usize);\n", combo(opr))), | |
7 => res.push_str(&format!("c = a / (1 << {} as usize);\n", combo(opr))), | |
_ => unreachable!(), | |
} | |
} | |
res.push_str("res\n}\n"); | |
res.parse().unwrap() | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment