mrubyedge_cli/rbs_parser/
mod.rs

1extern crate nom;
2
3#[derive(Debug)]
4pub struct FuncDef {
5    pub name: String,
6    pub argstype: Vec<String>,
7    pub rettype: String,
8}
9
10impl FuncDef {
11    pub fn args_decl(&self) -> &str {
12        if self.argstype.len() == 0 {
13            return "";
14        }
15
16        let converted: Vec<String> = self
17            .argstype
18            .iter()
19            .enumerate()
20            .map(|(idx, arg)| match arg.as_str() {
21                "Integer" => format!("a{}: i32", idx),
22                "Float" => format!("a{}: f32", idx),
23                "bool" => format!("a{}: bool", idx),
24                "String" => format!("p{0}: *const u8, l{0}: usize", idx),
25                _ => {
26                    unimplemented!("unsupported arg type")
27                }
28            })
29            .collect();
30        converted.join(", ").leak()
31    }
32
33    pub fn args_let_vec(&self) -> &str {
34        if self.argstype.len() == 0 {
35            return "vec![]";
36        }
37
38        let converted: Vec<String> = self
39            .argstype
40            .iter()
41            .enumerate()
42            .map(|(idx, arg)| match arg.as_str() {
43                "Integer" => format!("std::rc::Rc::new(RObject::integer(a{} as i64))", idx),
44                "Float" => format!("std::rc::Rc::new(RObject::float(a{} as f64))", idx),
45                "bool" => format!("std::rc::Rc::new(RObject::boolean(a{}))", idx),
46                "String" => format!("std::rc::Rc::new(RObject::string(a{}.to_string()))", idx),
47                _ => {
48                    unimplemented!("unsupported arg type")
49                }
50            })
51            .collect();
52        format!("vec![{}]", converted.join(", ")).leak()
53    }
54
55    pub fn str_args_converter(&self) -> &str {
56        if self.argstype.len() == 0 {
57            return "";
58        }
59        let mut buf = String::new();
60
61        for (idx, arg) in self.argstype.iter().enumerate() {
62            match arg.as_str() {
63                "String" => {
64                    buf.push_str(&format!(
65                        "
66let a{0} = unsafe {{
67    let s = std::slice::from_raw_parts(p{0}, l{0} as usize);
68    std::str::from_utf8(s).expect(\"invalid utf8\")
69}};
70",
71                        idx
72                    ));
73                }
74                _ => {
75                    // skip
76                }
77            }
78        }
79
80        buf.leak()
81    }
82
83    pub fn rettype_decl(&self) -> &str {
84        match self.rettype.as_str() {
85            "void" => "-> ()",
86            "Integer" => "-> i32",
87            "Float" => "-> f32",
88            "bool" => "-> bool",
89            "String" => "-> *const u8",
90            "SharedMemory" => "-> *mut u8",
91            _ => {
92                unimplemented!("unsupported arg type")
93            }
94        }
95    }
96
97    pub fn handle_retval(&self) -> &str {
98        match self.rettype.as_str() {
99            "String" => {
100                let mut buf = String::new();
101                buf.push_str("let mut retval: String = retval.as_ref().try_into().unwrap();\n");
102                buf.push_str("retval.push('\0');\n");
103                buf.push_str(&format!(
104                    "unsafe {{ {} = retval.len() - 1; }}\n",
105                    self.size_helper_var_name()
106                ));
107                buf.push_str("retval.as_str().as_ptr()\n");
108                buf.leak()
109            }
110            _ => "retval.as_ref().try_into().unwrap()",
111        }
112    }
113
114    fn size_helper_var_name(&self) -> String {
115        format!("__{}_size", self.name)
116    }
117
118    pub fn exported_helper_var(&self) -> &str {
119        match self.rettype.as_str() {
120            "String" => format!(
121                "
122#[allow(non_upper_case_globals)]
123pub static mut {0}: usize = 0;
124#[no_mangle]
125pub unsafe fn __get{0}() -> u32 {{
126    return {0} as u32;
127}}
128",
129                &self.size_helper_var_name()
130            )
131            .leak(),
132            _ => "",
133        }
134    }
135
136    pub fn import_helper_var(&self) -> &str {
137        match self.rettype.as_str() {
138            "String" => format!(
139                "
140#[allow(non_upper_case_globals)]
141pub static mut {0}: usize = 0;
142#[no_mangle]
143pub unsafe fn __set{0}(s: u32) {{
144    {0} = s as usize;
145}}
146",
147                &self.size_helper_var_name()
148            )
149            .leak(),
150            _ => "",
151        }
152    }
153
154    // for function importer
155    pub fn imported_body(&self) -> &str {
156        let mut buf = String::new();
157        for (i, typ) in self.argstype.iter().enumerate() {
158            let tmp = match typ.as_str() {
159                "String" => {
160                    let mut buf = String::new();
161                    buf.push_str(&format!(
162                        "let a{0}: String = args[{0}].clone().as_ref().try_into().unwrap();\n",
163                        i
164                    ));
165                    buf.push_str(&format!("let p{0} = a{0}.as_str().as_ptr();\n", i));
166                    buf.push_str(&format!("let l{0} = a{0}.as_str().len();\n", i));
167                    buf
168                }
169                _ => format!(
170                    "let a{0} = args[{0}].clone().as_ref().try_into().unwrap();\n",
171                    i,
172                ),
173            };
174            buf.push_str(&tmp);
175        }
176        let call_arg = self
177            .argstype
178            .iter()
179            .enumerate()
180            .map(|(i, typ)| match typ.as_str() {
181                "String" => format!("p{0}, l{0}", i),
182                _ => format!("a{}", i),
183            })
184            .collect::<Vec<String>>()
185            .join(",");
186        buf.push_str(&format!(
187            "let r0 = unsafe {{ {}({}) }};\n",
188            &self.name, call_arg
189        ));
190
191        if self.rettype.as_str() == "String" {
192            buf.push_str(&format!(
193                "
194let s0: String;
195unsafe {{
196    if {0} == 0 {{
197        let mut buf = Vec::<u8>::new();
198        let mut off: usize = 0;
199        loop {{
200            let b = *(r0.add(off));
201            if b == 0 {{
202                break;
203            }} else {{
204                buf.push(b);
205            }}
206            if off >= 65536 {{
207                panic!(\"unterminated string detected\");
208            }}
209            off += 1;
210        }}
211        s0 = String::from_utf8_unchecked(buf);
212    }} else {{
213        let off = {0};
214	let s = std::slice::from_raw_parts(r0, off);
215	s0 = String::from_utf8_unchecked(s.to_vec());
216    }}
217}}
218",
219                self.size_helper_var_name()
220            ));
221        }
222
223        let ret_mruby_type = match self.rettype.as_str() {
224            "Integer" => "RObject::integer(r0 as i64)",
225            "Float" => "RObject::float(r0 as f64)",
226            "bool" => "RObject::boolean(r0)",
227            "String" => "RObject::string(s0)",
228            "void" => "RObject::nil()",
229            _ => unimplemented!("unsupported arg type"),
230        };
231        buf.push_str(&format!("Ok(Rc::new({}))\n", ret_mruby_type));
232        buf.leak()
233    }
234}
235
236use nom::branch::alt;
237use nom::branch::permutation;
238use nom::bytes::complete::tag;
239use nom::character::complete::*;
240// use nom::combinator::opt;
241use nom::IResult;
242use nom::error::VerboseError;
243use nom::error::context;
244use nom::multi::*;
245use nom::sequence::tuple;
246
247type Res<T, U> = IResult<T, U, VerboseError<T>>;
248
249fn def(input: &str) -> Res<&str, ()> {
250    context("def", tag("def"))(input).map(|(s, _)| (s, ()))
251}
252
253fn alpha_just_1(input: &str) -> Res<&str, char> {
254    satisfy(|c| c == '_' || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'))(input)
255}
256
257fn alphanumeric_just_1(input: &str) -> Res<&str, char> {
258    satisfy(|c| {
259        c == '_' || ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')
260    })(input)
261}
262
263fn symbol(input: &str) -> Res<&str, String> {
264    tuple((alpha_just_1, many0(alphanumeric_just_1)))(input).map(|(s, (head, tail))| {
265        let mut name: String = head.to_string();
266        for c in tail.iter() {
267            name += &c.to_string()
268        }
269        (s, name)
270    })
271}
272
273fn method(input: &str) -> Res<&str, String> {
274    tuple((symbol, char(':'), space0))(input).map(|(s, (sym, _, _))| (s, sym))
275}
276
277fn emptyarg(input: &str) -> Res<&str, Vec<String>> {
278    tuple((char('('), space0, char(')')))(input).map(|(s, _)| (s, vec![]))
279}
280
281fn contentarg(input: &str) -> Res<&str, Vec<String>> {
282    tuple((
283        char('('),
284        space0,
285        symbol,
286        space0,
287        many0(tuple((char(','), space0, symbol, space0))),
288        char(')'),
289    ))(input)
290    .map(|(s, (_, _, head, _, rest, _))| {
291        let mut syms: Vec<String> = rest.into_iter().map(|(_, _, val, _)| val).collect();
292        syms.insert(0, head);
293        (s, syms)
294    })
295}
296
297fn arg(input: &str) -> Res<&str, Vec<String>> {
298    alt((emptyarg, contentarg))(input)
299}
300
301fn ret(input: &str) -> Res<&str, String> {
302    tuple((tag("->"), space0, symbol))(input).map(|(s, (_, _, sym))| (s, sym))
303}
304
305fn fntype(input: &str) -> Res<&str, (Vec<String>, String)> {
306    tuple((arg, space0, ret))(input).map(|(s, (arg, _, ret))| (s, (arg, ret)))
307}
308
309pub fn fn_def(input: &str) -> Res<&str, FuncDef> {
310    tuple((def, space1, method, fntype))(input).map(|(s, (_, _, name, (argstype, rettype)))| {
311        (
312            s,
313            FuncDef {
314                name,
315                argstype,
316                rettype,
317            },
318        )
319    })
320}
321
322pub fn parse(input: &str) -> Res<&str, Vec<FuncDef>> {
323    tuple((
324        multispace0,
325        separated_list0(permutation((space0, many1(char('\n')), space0)), fn_def),
326    ))(input)
327    .map(|(s, (_, list))| (s, list))
328}