sdc_parser/
lib.rs

1pub mod object;
2pub mod sdc;
3pub mod util;
4
5use crate::sdc::{sdc, sdc_strict, Sdc};
6use combine::error::ParseResult;
7use combine::{Parser, Stream};
8use failure::{Backtrace, Context, Fail};
9use std::fmt::{self, Display};
10use std::marker::PhantomData;
11
12// -----------------------------------------------------------------------------
13
14/// Parse SDC string
15///
16/// This function always successes.
17/// Any line failed to parse ( include vendor extension ) is contained as `sdc::Command::Unknown`.
18///
19/// # Examples
20///
21/// ```
22/// use sdc_parser::{self, sdc};
23///
24/// let result = sdc_parser::parse("current_instance duv");
25///
26/// let expect = sdc::Sdc {
27///     commands: vec![sdc::Command::CurrentInstance(
28///         sdc::CurrentInstance {
29///             instance: Some(String::from("duv"))
30///         }
31///     )]
32/// };
33/// assert_eq!(expect, result);
34/// ```
35pub fn parse(s: &str) -> Sdc {
36    let mut parser = sdc_parser();
37    parser.parse(s).unwrap().0
38}
39
40/// Parse SDC string strictly
41///
42/// This function fails if the input is not valid SDC.
43///
44/// # Examples
45///
46/// ```
47/// use sdc_parser::{self, sdc};
48///
49/// let result = sdc_parser::parse_strict("current_instance duv").unwrap();
50///
51/// let expect = sdc::Sdc {
52///     commands: vec![sdc::Command::CurrentInstance(
53///         sdc::CurrentInstance {
54///             instance: Some(String::from("duv"))
55///         }
56///     )]
57/// };
58/// assert_eq!(expect, result);
59/// ```
60pub fn parse_strict(s: &str) -> Result<Sdc, Error> {
61    let mut parser = sdc_parser_strict();
62    let (ret, rest) = parser
63        .parse(s)
64        .map_err::<combine::error::StringStreamError, _>(Into::into)?;
65
66    if rest.is_empty() {
67        Ok(ret)
68    } else {
69        Err(Error {
70            inner: Context::new(ErrorKind::Interrupt(InterruptError {
71                parsed: ret,
72                rest: String::from(rest),
73            })),
74        })
75    }
76}
77
78// -----------------------------------------------------------------------------
79
80#[derive(Fail, Debug)]
81pub enum ErrorKind {
82    #[fail(display = "Parse failed {:?}", 0)]
83    Parse(ParseError),
84
85    #[fail(display = "Parse interruptted {:?}", 0)]
86    Interrupt(InterruptError),
87}
88
89#[derive(Debug)]
90pub struct ParseError {
91    pub message: String,
92}
93
94#[derive(Debug)]
95pub struct InterruptError {
96    pub parsed: Sdc,
97    pub rest: String,
98}
99
100// -----------------------------------------------------------------------------
101
102#[derive(Debug)]
103pub struct Error {
104    inner: Context<ErrorKind>,
105}
106
107impl Fail for Error {
108    fn cause(&self) -> Option<&Fail> {
109        self.inner.cause()
110    }
111
112    fn backtrace(&self) -> Option<&Backtrace> {
113        self.inner.backtrace()
114    }
115}
116
117impl Display for Error {
118    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
119        Display::fmt(&self.inner, f)
120    }
121}
122
123impl Error {
124    pub fn new(inner: Context<ErrorKind>) -> Error {
125        Error { inner }
126    }
127
128    pub fn kind(&self) -> &ErrorKind {
129        self.inner.get_context()
130    }
131}
132
133impl From<ErrorKind> for Error {
134    fn from(kind: ErrorKind) -> Error {
135        Error {
136            inner: Context::new(kind),
137        }
138    }
139}
140
141impl From<Context<ErrorKind>> for Error {
142    fn from(inner: Context<ErrorKind>) -> Error {
143        Error { inner }
144    }
145}
146
147// -----------------------------------------------------------------------------
148
149impl From<combine::error::StringStreamError> for Error {
150    fn from(error: combine::error::StringStreamError) -> Error {
151        let message = format!("{:?}", error);
152
153        Error {
154            inner: Context::new(ErrorKind::Parse(ParseError { message })),
155        }
156    }
157}
158
159// -----------------------------------------------------------------------------
160
161struct SdcParser<I>(PhantomData<fn(I) -> I>);
162
163impl<I> Parser for SdcParser<I>
164where
165    I: Stream<Item = char>,
166    I::Error: combine::error::ParseError<I::Item, I::Range, I::Position>,
167{
168    type Input = I;
169    type Output = Sdc;
170    type PartialState = ();
171    #[inline]
172    fn parse_stream(&mut self, input: &mut I) -> ParseResult<Self::Output, Self::Input> {
173        let mut parser = sdc();
174        parser.parse_stream(input)
175    }
176}
177
178fn sdc_parser<I>() -> SdcParser<I>
179where
180    I: Stream<Item = char>,
181    I::Error: combine::error::ParseError<I::Item, I::Range, I::Position>,
182{
183    SdcParser(PhantomData)
184}
185
186// -----------------------------------------------------------------------------
187
188struct SdcParserStrict<I>(PhantomData<fn(I) -> I>);
189
190impl<I> Parser for SdcParserStrict<I>
191where
192    I: Stream<Item = char>,
193    I::Error: combine::error::ParseError<I::Item, I::Range, I::Position>,
194{
195    type Input = I;
196    type Output = Sdc;
197    type PartialState = ();
198    #[inline]
199    fn parse_stream(&mut self, input: &mut I) -> ParseResult<Self::Output, Self::Input> {
200        let mut parser = sdc_strict();
201        parser.parse_stream(input)
202    }
203}
204
205fn sdc_parser_strict<I>() -> SdcParserStrict<I>
206where
207    I: Stream<Item = char>,
208    I::Error: combine::error::ParseError<I::Item, I::Range, I::Position>,
209{
210    SdcParserStrict(PhantomData)
211}
212
213// -----------------------------------------------------------------------------
214
215#[cfg(test)]
216mod test {
217    use super::*;
218    use combine::stream::state::State;
219    use std::fs::File;
220    use std::io::Read;
221    use walkdir::WalkDir;
222
223    #[test]
224    fn test_parse() {
225        let result = parse("current_instance duv");
226
227        let expect = Sdc {
228            commands: vec![sdc::Command::CurrentInstance(sdc::CurrentInstance {
229                instance: Some(String::from("duv")),
230            })],
231        };
232        assert_eq!(expect, result);
233    }
234
235    #[test]
236    fn test_by_testcase() {
237        for entry in WalkDir::new("./testcase") {
238            if let Ok(entry) = entry {
239                if entry.file_type().is_dir() {
240                    continue;
241                }
242                let file = entry.path();
243                let mut f = File::open(&file).unwrap();
244                let mut buf = String::new();
245                let _ = f.read_to_string(&mut buf);
246
247                let file = dbg!(file);
248
249                let mut parser = sdc_parser();
250                let ret = parser.parse(State::new(buf.as_str()));
251
252                assert!(ret.is_ok(), "Parse is failed at {:?}: {:?}", file, ret);
253                assert_eq!("", ret.unwrap().1.input, "Input is Remained at {:?}", file);
254            }
255        }
256    }
257}