nuidl_lib/parser/
mod.rs

1use codespan::Span;
2use std::borrow::Cow;
3use std::fmt;
4use std::fmt::Debug;
5use std::fmt::Display;
6use std::ops::Deref;
7use thiserror::Error;
8use uuid::Uuid;
9
10#[derive(Debug, Clone)]
11pub struct File {
12    pub elements: Vec<Toplevel>,
13}
14
15impl File {
16    pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
17        for el in self.elements.iter() {
18            el.visit_type_idents(&mut f);
19        }
20    }
21}
22
23#[derive(Debug, Clone)]
24pub enum Toplevel {
25    Import(Vec<Sp<String>>),
26    Include(Vec<Sp<String>>),
27    Interface(Interface),
28    Typelib(Typelib),
29    Enum(Enum),
30    CppQuote(String),
31}
32
33impl Toplevel {
34    pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
35        match self {
36            Toplevel::Import(_) => {}
37            Toplevel::Include(_) => {}
38            Toplevel::Interface(el) => el.visit_type_idents(&mut f),
39            Toplevel::Typelib(_) => {}
40            Toplevel::Enum(_) => {}
41            Toplevel::CppQuote(_) => {}
42        }
43    }
44}
45
46#[derive(Debug, Clone)]
47pub struct Interface {
48    pub name: String,
49    pub attrs: Vec<ItfAttr>,
50    pub defn: Option<InterfaceDefn>,
51}
52
53#[derive(Debug, Clone)]
54pub struct InterfaceDefn {
55    pub base: Option<Sp<String>>,
56    pub elems: Vec<Function>,
57}
58
59impl Interface {
60    pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
61        let Some(InterfaceDefn { base, elems, .. }) = &self.defn else {
62            return;
63        };
64
65        if let Some(el) = base {
66            f(el);
67        }
68
69        for el in elems.iter() {
70            el.visit_type_idents(&mut f);
71        }
72    }
73
74    pub fn guid(&self) -> Option<Uuid> {
75        for a in self.attrs.iter() {
76            match a {
77                Attr::Uuid(id) => return Some(*id),
78                _ => {}
79            }
80        }
81
82        None
83    }
84}
85
86#[derive(Debug, Clone)]
87pub struct Enum {
88    pub name: String,
89}
90
91#[derive(Debug, Clone)]
92pub enum Attr {
93    Default,
94    Dual,
95    HelpString(String),
96    Local,
97    Object,
98    OleAutomation,
99    PointerDefault(PointerType),
100    Restricted,
101    Uuid(Uuid),
102    Version(u16, u16),
103}
104
105pub type ItfAttr = Attr;
106pub type TlbAttr = Attr;
107pub type ClassAttr = Attr;
108
109#[derive(Debug, Clone)]
110pub struct Typelib {
111    pub name: String,
112    pub attrs: Vec<TlbAttr>,
113    pub elems: Vec<TlbElem>,
114}
115
116#[derive(Debug, Clone)]
117pub enum TlbElem {
118    ImportLib(String),
119    Interface(Interface),
120    Class(Class),
121}
122
123#[derive(Debug, Clone)]
124pub struct Class {
125    pub name: String,
126    pub attrs: Vec<ClassAttr>,
127    pub elems: Vec<ClassElem>,
128}
129
130#[derive(Debug, Clone)]
131pub enum ClassElem {
132    Interface(Interface),
133}
134
135#[derive(Debug, Clone, Copy)]
136pub enum PointerType {
137    Unique,
138    Ref,
139    Ptr,
140}
141
142#[derive(Debug, Clone)]
143pub struct Function {
144    pub attrs: Vec<FnAttr>,
145    pub ret: Ctype,
146    pub name: String,
147    pub args: Vec<FnArg>,
148}
149
150impl Function {
151    pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
152        self.ret.visit_type_idents(&mut f);
153
154        for el in self.args.iter() {
155            el.visit_type_idents(&mut f);
156        }
157    }
158}
159
160#[derive(Debug, Clone)]
161pub enum FnAttr {
162    PointerType(PointerType),
163    PropGet,
164    PropPut,
165    PropPutRef,
166}
167
168#[derive(Debug, Clone)]
169pub struct FnArg {
170    pub attrs: Vec<Sp<ArgAttr>>,
171    pub name: Option<Sp<String>>,
172    pub ty: Sp<Ctype>,
173    pub arr: bool,
174}
175
176impl FnArg {
177    pub fn visit_type_idents<F: FnMut(&str)>(&self, f: F) {
178        self.ty.visit_type_idents(f);
179    }
180}
181
182#[derive(Debug, Clone)]
183pub enum ArgAttr {
184    In,
185    MaxIs(Vec<Option<Cexpr>>),
186    Out,
187    PointerType(PointerType),
188    Poly(String),
189    RetVal,
190    SizeIs(Vec<Option<Cexpr>>),
191}
192
193#[derive(Debug, Clone)]
194pub enum Cexpr {
195    Ident(String),
196    Deref(Box<Cexpr>),
197}
198
199#[derive(Debug, Clone, Eq, PartialEq)]
200pub struct Ctype {
201    pub typename: String,
202    pub is_const: bool,
203    pub indirection: Vec<Ptr>,
204}
205
206impl Ctype {
207    pub fn visit_type_idents<F: FnMut(&str)>(&self, mut f: F) {
208        f(&self.typename);
209    }
210
211    pub fn is_void(&self) -> bool {
212        &self.typename == "void" && self.indirection.is_empty()
213    }
214}
215
216#[derive(Debug, Clone, Copy, Eq, PartialEq)]
217pub struct Ptr {
218    pub is_const: bool,
219}
220
221#[derive(Debug, Clone)]
222pub struct Str<'a>(Vec<StrComponent<'a>>);
223
224#[derive(Debug, Clone)]
225pub enum StrComponent<'a> {
226    Literal(&'a str),
227    Esc(char),
228}
229
230impl<'a> StrComponent<'a> {
231    fn len(&self) -> usize {
232        match self {
233            StrComponent::Literal(v) => v.len(),
234            StrComponent::Esc(v) => v.len_utf8(),
235        }
236    }
237}
238
239impl<'a> Str<'a> {
240    pub fn from_str(s: &'a str) -> Result<Self, StrError> {
241        let mut state = Vec::new();
242        let mut iter = s.char_indices();
243
244        while let Some((pos, ch)) = iter.next() {
245            if ch == '\\' {
246                let (_, esc_type) = iter.next().ok_or(StrError::PartialEscape)?;
247
248                if esc_type == 'u' || esc_type == 'U' {
249                    let size = if esc_type == 'u' { 4 } else { 8 };
250                    let (from, _) = iter.next().ok_or(StrError::PartialEscape)?;
251
252                    for _ in 2..size {
253                        let _ = iter.next().ok_or(StrError::PartialEscape)?;
254                    }
255
256                    let (to, last) = iter.next().ok_or(StrError::PartialEscape)?;
257                    let to = to + last.len_utf8();
258                    let spec = &s[from..to];
259                    let num = u32::from_str_radix(s, 16)
260                        .map_err(|_| StrError::InvalidUnicode(from, spec.to_owned(), to))?;
261                    state.push(StrComponent::Esc(
262                        char::from_u32(num as u32).ok_or(StrError::InvalidUnicode(
263                            from,
264                            spec.to_owned(),
265                            to,
266                        ))?,
267                    ));
268                } else if esc_type == 'n' {
269                    state.push(StrComponent::Esc('\n'));
270                } else if esc_type == 'r' {
271                    state.push(StrComponent::Esc('\r'));
272                } else if esc_type == 't' {
273                    state.push(StrComponent::Esc('\t'));
274                } else if esc_type == '0' {
275                    state.push(StrComponent::Esc('\0'));
276                }
277            } else {
278                if let Some(StrComponent::Literal(ref mut lit)) = state.last_mut() {
279                    let diff = lit.as_ptr() as usize - s.as_ptr() as usize;
280                    *lit = &s[diff..diff + lit.len() + ch.len_utf8()];
281                } else {
282                    state.push(StrComponent::Literal(&s[pos..pos + ch.len_utf8()]));
283                }
284            }
285        }
286
287        Ok(Str(state))
288    }
289
290    fn to_string(&self) -> String {
291        let len = self.0.iter().map(|v| v.len()).sum();
292        let mut s = String::with_capacity(len);
293
294        for el in self.0.iter() {
295            match el {
296                StrComponent::Literal(v) => s.push_str(v.as_ref()),
297                StrComponent::Esc(v) => s.push(*v),
298            }
299        }
300
301        s
302    }
303
304    pub fn to_str(&self) -> Cow<str> {
305        match &*self.0 {
306            [] => Cow::Borrowed(""),
307            [StrComponent::Literal(s)] => Cow::Borrowed(s.as_ref()),
308            _ => Cow::Owned(self.to_string()),
309        }
310    }
311}
312
313impl<'a> Display for Str<'a> {
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        for el in self.0.iter() {
316            match el {
317                StrComponent::Literal(v) => write!(f, "{}", v)?,
318                StrComponent::Esc(v) => write!(f, "{}", v)?,
319            }
320        }
321
322        Ok(())
323    }
324}
325
326#[derive(Debug, Error)]
327pub enum StrError {
328    #[error("partial escape sequence")]
329    PartialEscape,
330    #[error("invalid unicode escape: {1}")]
331    InvalidUnicode(usize, String, usize),
332}
333
334#[derive(Copy, Clone, Debug, Eq, PartialEq)]
335pub struct Sp<T> {
336    inner: T,
337    span: Span,
338}
339
340impl<T> Deref for Sp<T> {
341    type Target = T;
342
343    fn deref(&self) -> &Self::Target {
344        &self.inner
345    }
346}
347
348impl<T, R> AsRef<R> for Sp<T>
349where
350    T: AsRef<R>,
351    R: ?Sized,
352{
353    fn as_ref(&self) -> &R {
354        self.inner.as_ref()
355    }
356}
357
358impl<T> Sp<T> {
359    pub fn new(inner: T, left: usize, right: usize) -> Self {
360        Self::new_from_span(inner, Span::new(left as u32, right as u32))
361    }
362
363    pub fn new_from_span(inner: T, span: Span) -> Self {
364        Self { inner, span }
365    }
366
367    pub fn inner(&self) -> &T {
368        &self.inner
369    }
370
371    pub fn into_inner(self) -> T {
372        self.inner
373    }
374
375    pub fn span(&self) -> Span {
376        self.span
377    }
378
379    pub fn map<F, R>(self, f: F) -> Sp<R>
380    where
381        F: FnOnce(T) -> R,
382    {
383        Sp {
384            inner: f(self.inner),
385            span: self.span,
386        }
387    }
388}