autd3capi_wrapper_generator/
parse.rs

1/*
2 * File: parse.rs
3 * Project: src
4 * Created Date: 25/05/2022
5 * Author: Shun Suzuki
6 * -----
7 * Last Modified: 18/07/2023
8 * Modified By: Shun Suzuki (suzuki@hapis.k.u-tokyo.ac.jp)
9 * -----
10 * Copyright (c) 2022 Shun Suzuki. All rights reserved.
11 *
12 */
13
14use std::{fs::File, io::Read, path::Path};
15
16use anyhow::Result;
17use syn::__private::ToTokens;
18
19use crate::types::{InOut, Type};
20
21#[derive(Debug, PartialEq, Eq, Hash)]
22pub struct Arg {
23    pub name: String,
24    pub ty: Type,
25    pub inout: InOut,
26    pub pointer: usize,
27}
28
29#[derive(Debug, PartialEq, Eq, Hash)]
30pub struct Function {
31    pub docs: Vec<String>,
32    pub name: String,
33    pub return_ty: Type,
34    pub args: Vec<Arg>,
35}
36
37#[derive(Debug, PartialEq, Eq, Hash)]
38pub struct Const {
39    pub name: String,
40    pub ty: Type,
41    pub value: String,
42}
43
44#[derive(Debug, PartialEq, Eq, Hash)]
45pub struct Enum {
46    pub name: String,
47    pub ty: Type,
48    pub values: Vec<(String, String)>,
49}
50
51#[derive(Debug, PartialEq, Eq, Hash)]
52pub struct Struct {
53    pub name: String,
54    pub fields: Vec<(Type, String)>,
55}
56
57pub fn parse_func<P>(header: P, use_single: bool) -> Result<Vec<Function>>
58where
59    P: AsRef<Path>,
60{
61    let mut file = File::open(header)?;
62    let mut contents = String::new();
63    file.read_to_string(&mut contents)?;
64
65    let syntax_tree = syn::parse_file(&contents)?;
66
67    Ok(syntax_tree
68        .items
69        .into_iter()
70        .filter_map(|item| match item {
71            syn::Item::Fn(item_fn) => {
72                let docs = item_fn
73                    .attrs
74                    .iter()
75                    .filter(|attr| attr.path().is_ident("doc"))
76                    .map(|attr| {
77                        attr.meta
78                            .require_name_value()
79                            .unwrap()
80                            .value
81                            .clone()
82                            .into_token_stream()
83                            .to_string()
84                            .trim()
85                            .to_string()
86                    })
87                    .collect();
88
89                let name = item_fn.sig.ident.to_string();
90                let return_ty = Type::parse_return(item_fn.sig.output, use_single);
91                let args = item_fn
92                    .sig
93                    .inputs
94                    .into_iter()
95                    .map(|i| Type::parse_arg(i, use_single))
96                    .collect::<Vec<_>>();
97
98                Some(Function {
99                    docs,
100                    name,
101                    return_ty,
102                    args,
103                })
104            }
105            _ => None,
106        })
107        .collect())
108}
109
110pub fn parse_const<P>(header: P, use_single: bool) -> Result<Vec<Const>>
111where
112    P: AsRef<Path>,
113{
114    let mut file = File::open(header)?;
115    let mut contents = String::new();
116    file.read_to_string(&mut contents)?;
117
118    let syntax_tree = syn::parse_file(&contents)?;
119
120    Ok(syntax_tree
121        .items
122        .into_iter()
123        .filter_map(|item| match item {
124            syn::Item::Const(item_const) => {
125                let name = item_const.ident.to_string();
126                let ty =
127                    Type::parse_str(&item_const.ty.into_token_stream().to_string(), use_single);
128                let mut value = item_const.expr.into_token_stream().to_string();
129                value.retain(|c| !c.is_whitespace());
130
131                Some(Const { name, ty, value })
132            }
133            _ => None,
134        })
135        .collect())
136}
137
138pub fn parse_enum<P>(header: P, use_single: bool) -> Result<Vec<Enum>>
139where
140    P: AsRef<Path>,
141{
142    let mut file = File::open(header)?;
143    let mut contents = String::new();
144    file.read_to_string(&mut contents)?;
145
146    let syntax_tree = syn::parse_file(&contents)?;
147
148    Ok(syntax_tree
149        .items
150        .into_iter()
151        .filter_map(|item| match item {
152            syn::Item::Enum(item_enum) => {
153                let name = item_enum.ident.to_string();
154                let ty = Type::parse_str(
155                    item_enum.attrs[0]
156                        .meta
157                        .require_list()
158                        .unwrap()
159                        .tokens
160                        .to_string()
161                        .as_str(),
162                    use_single,
163                );
164                let values = item_enum
165                    .variants
166                    .into_iter()
167                    .map(|v| {
168                        let name = v.ident.to_string();
169                        let value = v.discriminant.unwrap().1.into_token_stream().to_string();
170                        (name, value)
171                    })
172                    .collect();
173
174                Some(Enum { name, ty, values })
175            }
176            _ => None,
177        })
178        .collect())
179}
180
181pub fn parse_struct<P>(header: P, use_single: bool) -> Result<Vec<Struct>>
182where
183    P: AsRef<Path>,
184{
185    let mut file = File::open(header)?;
186    let mut contents = String::new();
187    file.read_to_string(&mut contents)?;
188
189    let syntax_tree = syn::parse_file(&contents)?;
190
191    Ok(syntax_tree
192        .items
193        .into_iter()
194        .filter_map(|item| match item {
195            syn::Item::Struct(item_struct) => match item_struct.vis {
196                syn::Visibility::Public(_) => {
197                    let name = item_struct.ident.to_string();
198                    let fields = item_struct
199                        .fields
200                        .iter()
201                        .filter(|f| f.ident.is_some())
202                        .map(|f| {
203                            (
204                                Type::parse_str(
205                                    f.ty.clone().into_token_stream().to_string().as_str(),
206                                    use_single,
207                                ),
208                                f.ident.as_ref().unwrap().to_string(),
209                            )
210                        })
211                        .collect();
212                    Some(Struct { name, fields })
213                }
214                _ => None,
215            },
216            _ => None,
217        })
218        .collect())
219}