1 // SPDX-License-Identifier: LGPL-2.1-or-later
2 // See Notices.txt for copyright information
4 use proc_macro2::{Ident, Span, TokenStream};
5 use quote::{quote, ToTokens, TokenStreamExt};
8 braced, bracketed, parenthesized,
9 parse::{Parse, ParseStream},
11 punctuated::Punctuated,
12 Attribute, Error, ItemFn, LitStr, Token,
15 macro_rules! valid_enumerants_as_string {
16 ($enumerant:ident) => {
17 concat!("`", stringify!($enumerant), "`")
19 ($enumerant1:ident, $enumerant2:ident) => {
20 concat!("`", stringify!($enumerant1), "` and `", stringify!($enumerant2), "`")
22 ($($enumerant:ident),+) => {
23 valid_enumerants_as_string!((), ($($enumerant),+))
25 (($first_enumerant:ident, $($enumerant:ident,)+), ($last_enumerant:ident)) => {
28 stringify!($first_enumerant),
31 stringify!($enumerant),
34 stringify!($last_enumerant),
38 (($($enumerants:ident,)*), ($next_enumerant:ident, $($rest:ident),*)) => {
39 valid_enumerants_as_string!(($($enumerants,)* $next_enumerant,), ($($rest),*))
46 macro_rules! ident_enum {
48 #[parse_error_msg = $parse_error_msg:literal]
49 enum $enum_name:ident {
55 #[derive(Copy, Clone, Eq, PartialEq, Hash)]
56 enum $enum_name<T = Span> {
62 impl<T> fmt::Debug for $enum_name<T> {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 f.write_str(self.name())
68 impl<T> $enum_name<T> {
69 fn enumerant(&self) -> $enum_name<()> {
72 $enum_name::$enumerant(_) => $enum_name::$enumerant(()),
76 fn name(&self) -> &'static str {
79 $enum_name::$enumerant(_) => stringify!($enumerant),
86 fn into_ident(self) -> Ident {
89 $enum_name::$enumerant(span) => Ident::new(stringify!($enumerant), span),
95 impl ToTokens for $enum_name<Span> {
96 fn to_tokens(&self, tokens: &mut TokenStream) {
97 tokens.append(self.clone().into_ident());
101 impl Parse for $enum_name<Span> {
102 fn parse(input: ParseStream) -> syn::Result<Self> {
103 let id: Ident = input.parse()?;
105 if id == stringify!($enumerant) {
106 return Ok($enum_name::$enumerant(id.span()));
109 Err(Error::new_spanned(
113 ": valid values are: ",
114 valid_enumerants_as_string!($($enumerant),*)
123 #[parse_error_msg = "unknown instruction input"]
124 enum InstructionInput {
133 #[parse_error_msg = "unknown instruction output"]
134 enum InstructionOutput {
146 inputs: Punctuated<InstructionInput, Token!(,)>,
147 outputs: Punctuated<InstructionOutput, Token!(,)>,
148 instruction_name: LitStr,
151 impl Parse for Instruction {
152 fn parse(input: ParseStream) -> syn::Result<Self> {
153 input.parse::<Token!(#)>()?;
154 let enumerant_attr_tokens;
155 bracketed!(enumerant_attr_tokens in input);
156 let enumerant_name: Ident = enumerant_attr_tokens.parse()?;
157 if enumerant_name != "enumerant" {
158 return Err(Error::new_spanned(
160 "expected `#[enumerant = ...]` attribute",
163 enumerant_attr_tokens.parse::<Token!(=)>()?;
164 let enumerant: Ident = enumerant_attr_tokens.parse()?;
165 input.parse::<Token!(fn)>()?;
166 let fn_name: Ident = input.parse()?;
168 parenthesized!(inputs_tokens in input);
169 let inputs = inputs_tokens.parse_terminated(InstructionInput::parse)?;
170 input.parse::<Token!(->)>()?;
172 parenthesized!(outputs_tokens in input);
173 let outputs = outputs_tokens.parse_terminated(InstructionOutput::parse)?;
175 braced!(body_tokens in input);
176 let instruction_name: LitStr = body_tokens.parse()?;
188 fn map_input_registers(&self) -> syn::Result<Vec<TokenStream>> {
191 fn to_assembly_text(&self) -> syn::Result<String> {
192 let mut retval = String::new();
193 retval += "mfxer $1\n\
196 todo!("map_instr_asm_args!([$($args)*], [$($results)*], []),");
202 fn to_native_fn_tokens(&self) -> syn::Result<TokenStream> {
210 let assembly_text = self.to_assembly_text()?;
211 let mut handle_inputs = Vec::<TokenStream>::new();
212 unimplemented!("fill handle_inputs");
213 let mut handle_outputs = Vec::<TokenStream>::new();
215 "fill handle_outputs\
216 map_instr_results!(rt, xer, cr, retval, [$($results)*]);"
219 pub fn #fn_name(inputs: InstructionInput) -> InstructionResult {
220 #![allow(unused_variables, unused_assignments)]
221 let InstructionInput {
234 : "=&b"(rt), "=&b"(xer), "=&b"(cr)
235 : "b"(ra), "b"(rb), "b"(rc), "b"(0u64), "b"(!0x8000_0000u64)
238 let mut retval = InstructionOutput::default();
247 struct Instructions {
248 instructions: Vec<Instruction>,
252 fn to_tokens(&self) -> syn::Result<TokenStream> {
253 let mut fn_names = Vec::new();
254 let mut instr_enumerants = Vec::new();
255 let mut get_native_fn_match_cases = Vec::new();
256 let mut get_model_fn_match_cases = Vec::new();
257 let mut get_used_input_registers_match_cases = Vec::new();
258 let mut name_match_cases = Vec::new();
259 let mut enumerants = Vec::new();
260 let mut native_fn_tokens = Vec::new();
261 for instruction in &self.instructions {
269 fn_names.push(fn_name);
270 enumerants.push(enumerant);
271 instr_enumerants.push(quote! {
272 #[serde(rename = #instruction_name)]
275 get_native_fn_match_cases.push(quote! {
276 Self::#enumerant => native_instrs::#fn_name,
278 get_model_fn_match_cases.push(quote! {
279 Self::#enumerant => instr_models::#fn_name,
281 let mapped_input_registers = instruction.map_input_registers()?;
282 get_used_input_registers_match_cases.push(quote! {
283 Self::#enumerant => &[#(#mapped_input_registers),*],
285 name_match_cases.push(quote! {
286 Self::#enumerant => #instruction_name,
288 native_fn_tokens.push(instruction.to_native_fn_tokens()?);
291 #[cfg(feature = "python")]
292 macro_rules! wrap_all_instr_fns {
297 #(fn #fn_names(inputs: InstructionInput) -> InstructionOutput;)*
302 #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Serialize, Deserialize)]
304 #(#instr_enumerants)*
308 #[cfg(feature = "native_instrs")]
309 pub fn get_native_fn(self) -> fn(InstructionInput) -> InstructionOutput {
311 #(#get_native_fn_match_cases)*
314 pub fn get_model_fn(self) -> fn(InstructionInput) -> InstructionOutput {
316 #(#get_model_fn_match_cases)*
319 pub fn get_used_input_registers(self) -> &'static [InstructionInputRegister] {
321 #(#get_used_input_registers_match_cases)*
324 pub fn name(self) -> &'static str {
326 #(#name_match_cases)*
329 pub const VALUES: &'static [Self] = &[
330 #(Self::#enumerants,)*
334 #[cfg(feature = "native_instrs")]
335 pub mod native_instrs {
338 #(#native_fn_tokens)*
344 impl Parse for Instructions {
345 fn parse(input: ParseStream) -> syn::Result<Self> {
346 let mut instructions = Vec::new();
347 while !input.is_empty() {
348 instructions.push(input.parse()?);
350 Ok(Self { instructions })
355 pub fn instructions(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
356 let input = parse_macro_input!(input as Instructions);
357 match input.to_tokens() {
358 Ok(retval) => retval,
359 Err(err) => err.to_compile_error(),