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
12pub fn parse(s: &str) -> Sdc {
36 let mut parser = sdc_parser();
37 parser.parse(s).unwrap().0
38}
39
40pub 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#[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#[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
147impl 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
159struct 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
186struct 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#[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}