cmacro/ast/
function_decl.rs

1use std::{
2  fmt::Debug,
3  ops::{RangeFrom, RangeTo},
4};
5
6use nom::{
7  branch::permutation,
8  combinator::opt,
9  multi::separated_list0,
10  sequence::{pair, tuple},
11  AsChar, Compare, FindSubstring, FindToken, IResult, InputIter, InputLength, InputTake, InputTakeAtPosition, Offset,
12  ParseTo, Slice,
13};
14use proc_macro2::TokenStream;
15use quote::{quote, TokenStreamExt};
16
17use super::{tokens::parenthesized, *};
18use crate::{CodegenContext, LocalContext, MacroArgType, ParseContext};
19
20/// A function declaration.
21///
22/// ```c
23/// #define FUNC_DECL void f(int a, int b, int c)
24/// ```
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub struct FunctionDecl {
27  ret_ty: Type,
28  name: Identifier,
29  args: Vec<(Type, Identifier)>,
30}
31
32impl FunctionDecl {
33  /// Parse a function declaration.
34  pub(crate) fn parse<'i, 'p, I, C>(tokens: &'i [I], ctx: &'p ParseContext<'_>) -> IResult<&'i [I], Self>
35  where
36    I: Debug
37      + InputTake
38      + InputLength
39      + InputIter<Item = C>
40      + InputTakeAtPosition<Item = C>
41      + Slice<RangeFrom<usize>>
42      + Slice<RangeTo<usize>>
43      + Compare<&'static str>
44      + FindSubstring<&'static str>
45      + ParseTo<f64>
46      + ParseTo<f32>
47      + Offset
48      + Clone,
49    C: AsChar + Copy,
50    &'static str: FindToken<<I as InputIter>::Item>,
51  {
52    let (tokens, ((_, ret_ty), name, args)) = tuple((
53      permutation((opt(token("static")), |tokens| Type::parse(tokens, ctx))),
54      |tokens| Identifier::parse(tokens, ctx),
55      parenthesized(separated_list0(
56        pair(meta, token(",")),
57        pair(|tokens| Type::parse(tokens, ctx), |tokens| Identifier::parse(tokens, ctx)),
58      )),
59    ))(tokens)?;
60
61    Ok((tokens, Self { ret_ty, name, args }))
62  }
63
64  pub(crate) fn finish<C>(&mut self, ctx: &mut LocalContext<'_, C>) -> Result<Option<Type>, crate::Error>
65  where
66    C: CodegenContext,
67  {
68    self.ret_ty.finish(ctx)?;
69    self.name.finish(ctx)?;
70
71    if let Identifier::Literal(id) = &self.name {
72      if id.macro_arg {
73        if let Some(arg_type) = ctx.arg_type_mut(id.as_str()) {
74          *arg_type = MacroArgType::Ident;
75        }
76      }
77    }
78
79    for (ty, arg) in self.args.iter_mut() {
80      ty.finish(ctx)?;
81      arg.finish(ctx)?;
82    }
83
84    // A declaration has no type.
85    Ok(Some(Type::BuiltIn(BuiltInType::Void)))
86  }
87
88  pub(crate) fn to_tokens<C: CodegenContext>(&self, ctx: &mut LocalContext<'_, C>, tokens: &mut TokenStream) {
89    let name = self.name.to_token_stream(ctx);
90    let args = self
91      .args
92      .iter()
93      .map(|(ty, arg)| {
94        let ty = ty.to_token_stream(ctx);
95        let arg = arg.to_token_stream(ctx);
96        quote! { #arg: #ty }
97      })
98      .collect::<Vec<_>>();
99    let ret_ty = self.ret_ty.to_token_stream(ctx);
100
101    tokens.append_all(quote! {
102      extern "C" {
103        pub fn #name(#(#args),*) -> #ret_ty;
104      }
105    })
106  }
107}