1use std::str::{self, FromStr};
2
3use nom::{is_alphabetic, is_digit, digit, Err};
4
5const STRING_BOUNDARY: &'static str = "\"";
6const STATEMENT_TERMINATOR: &'static str = ";";
7const ASSIGNMENT_OPERATOR: &'static str = "=";
8const LINE_COMMENT: &'static str = "//";
9
10const START_BLOCK_COMMENT: &'static str = "/*";
11const END_BLOCK_COMMENT: &'static str = "*/";
12const BEGIN_SLICE: &'static str = "[";
13const END_SLICE: &'static str = "]";
14const BEGIN_BLOCK: &'static str = "{";
15const END_BLOCK: &'static str = "}";
16
17const OUTPUT_KEYWORD: &'static str = "out";
18const INPUT_KEYWORD: &'static str = "in";
19const WHILE_KEYWORD: &'static str = "while";
20
21#[derive(Debug, PartialEq, Clone)]
22pub struct Program(Vec<Statement>);
23
24impl IntoIterator for Program {
25 type Item = Statement;
26 type IntoIter = ::std::vec::IntoIter<Statement>;
27
28 fn into_iter(self) -> Self::IntoIter {
29 self.0.into_iter()
30 }
31}
32
33impl FromStr for Program {
34 type Err = Err<String>;
35 fn from_str(input: &str) -> Result<Self, Self::Err> {
36 parse_all_statements(input.as_bytes()).to_result().map(|statements| {
37 Program(statements)
38 }).map_err(|e| match e {
39 Err::Code(kind) => {
40 println!("Code({:?})", kind);
41 unimplemented!();
42 },
43 Err::Node(kind, _) => {
44 println!("Node({:?}, ..)", kind);
45 unimplemented!();
46 },
47 Err::Position(kind, input) => {
48 println!("Position({:?}, {:?})", kind, str::from_utf8(input));
49 Err::Position(kind, str::from_utf8(input).unwrap().to_string())
50 },
51 Err::NodePosition(kind, input, _) => {
52 println!("NodePosition({:?}, {:?}, ..)", kind, str::from_utf8(input));
53 unimplemented!();
54 }
55 })
56 }
57}
58
59#[derive(Debug, PartialEq, Clone)]
60pub enum Statement {
61 Comment(String),
62 Output(Vec<Expression>),
63 Input {
64 name: String,
65 slice: Option<Slice>,
66 },
67 Declaration {
68 name: String,
69 slice: Option<Slice>,
70 expr: Expression,
71 },
72 WhileLoop {
73 condition: WhileCondition,
74 body: Vec<Statement>,
75 }
76}
77
78#[derive(Debug, PartialEq, Clone, Copy)]
79pub enum Slice {
80 SingleValue(usize),
81 Unspecified,
83}
84
85#[derive(Debug, PartialEq, Clone)]
86pub enum WhileCondition {
87 Input {
88 name: String,
89 slice: Option<Slice>,
90 },
91 Expression(Expression),
92}
93
94#[derive(Debug, PartialEq, Clone)]
95pub enum Expression {
96 StringLiteral(String),
97 Identifier(String),
98}
99
100named!(parse_all_statements< Vec<Statement> >, complete!(do_parse!(
101 statements: many0!(statement) >>
102 eof!() >>
104 (statements)
105)));
106
107named!(statement<Statement>, ws!(alt!(
108 comment => {|content: &str| Statement::Comment(content.to_owned())} |
109 outputs => {|exprs: Vec<Expression>| Statement::Output(exprs)} |
110 input => {|(name, slice): (String, Option<Slice>)| {
111 Statement::Input {name: name, slice: slice}
112 }} |
113 declaration => {|(name, slice, expr): (String, Option<Slice>, Expression)| {
114 Statement::Declaration {name: name, slice: slice, expr: expr}
115 }} |
116 while_loop => {|(cond, body): (WhileCondition, Vec<Statement>)| {
117 Statement::WhileLoop {condition: cond, body: body}
118 }}
119)));
120
121named!(comment<&str>, alt!(line_comment | block_comment));
122
123named!(line_comment<&str>,
124 map_res!(
125 do_parse!(
126 tag!(LINE_COMMENT) >>
127 content: take_until_and_consume!("\n") >>
128 (content)
129 ),
130 |s: &'a [u8]| str::from_utf8(s)
131 )
132);
133
134named!(block_comment<&str>,
135 map_res!(
136 delimited!(
137 tag!(START_BLOCK_COMMENT),
138 take_until!(END_BLOCK_COMMENT),
139 tag!(END_BLOCK_COMMENT)
140 ),
141 |s: &'a [u8]| str::from_utf8(s)
142 )
143);
144
145named!(outputs< Vec<Expression> >,
146 ws!(do_parse!(
147 tag!(OUTPUT_KEYWORD) >>
148 expr: many1!(expression) >>
149 tag!(STATEMENT_TERMINATOR) >>
150 (expr)
151 ))
152);
153
154named!(input<(String, Option<Slice>)>,
155 ws!(do_parse!(
156 tag!(INPUT_KEYWORD) >>
157 declaration: type_declaration >>
158 tag!(STATEMENT_TERMINATOR) >>
159 (declaration.0, declaration.1)
160 ))
161);
162
163named!(declaration<(String, Option<Slice>, Expression)>,
164 ws!(do_parse!(
165 declaration: type_declaration >>
166 tag!(ASSIGNMENT_OPERATOR) >>
167 expr: expression >>
168 tag!(STATEMENT_TERMINATOR) >>
169 (declaration.0, declaration.1, expr)
170 ))
171);
172
173named!(while_loop<(WhileCondition, Vec<Statement>)>,
174 ws!(do_parse!(
175 tag!(WHILE_KEYWORD) >>
176 cond: while_condition >>
177 statements: block_statements >>
178 (cond, statements)
179 ))
180);
181
182named!(while_condition<WhileCondition>,
183 alt_complete!(
184 map!(ws!(do_parse!(
185 tag!(INPUT_KEYWORD) >>
186 declaration: type_declaration >>
187 (declaration.0, declaration.1)
188 )), |(name, slice): (String, Option<Slice>)| WhileCondition::Input {name: name, slice: slice}) |
189 map!(expression, |expr: Expression| WhileCondition::Expression(expr))
190 )
191);
192
193named!(block_statements< Vec<Statement> >,
194 ws!(do_parse!(
195 tag!(BEGIN_BLOCK) >>
196 statements: many0!(statement) >>
197 tag!(END_BLOCK) >>
198 (statements)
199 ))
200);
201
202named!(type_declaration<(String, Option<Slice>)>,
203 do_parse!(
204 declaration: identifier_slice >>
205 (declaration.0, declaration.1)
206 )
207);
208
209named!(identifier_slice<(String, Option<Slice>)>,
210 ws!(do_parse!(
211 name: identifier >>
212 slice: opt!(slice_variants) >>
213 (name, slice)
214 ))
215);
216
217named!(slice_variants<Slice>,
218 alt_complete!(
219 do_parse!(
220 tag!(BEGIN_SLICE) >>
221 tag!(END_SLICE) >>
222 (Slice::Unspecified)
223 ) |
224 delimited!(
225 tag!(BEGIN_SLICE),
226 slice_single_value,
227 tag!(END_SLICE)
228 )
229 )
230);
231
232named!(slice_single_value<Slice>,
233 map!(ws!(index_value), |value: usize| Slice::SingleValue(value))
234);
235
236named!(index_value<usize>,
237 map_res!(digit_s, |n: &str| n.parse())
238);
239
240named!(digit_s<&str>,
241 map_res!(digit, |n: &'a [u8]| str::from_utf8(n))
242);
243
244named!(expression<Expression>,
245 ws!(alt!(
246 expr_string_literal => {|text: String| Expression::StringLiteral(text)} |
247 identifier => {|ident: String| Expression::Identifier(ident)}
248 ))
249);
250
251named!(identifier<String>,
252 map_res!(
253 do_parse!(
254 start: take_while!(is_identifier_start) >>
256 rest: take_while!(is_identifier_char) >>
257 (start, rest)
258 ),
259 |(start, rest): (&[u8], &[u8])| {
260 str::from_utf8(start).and_then(|start| {
261 str::from_utf8(rest).map(|rest| {
262 format!("{}{}", start, rest)
263 })
264 })
265 }
266 )
267);
268
269named!(expr_string_literal<String>,
270 map_res!(
271 delimited!(
272 tag!(STRING_BOUNDARY),
273 string_text,
274 tag!(STRING_BOUNDARY)
275 ),
276 |s: Vec<u8>| String::from_utf8(s)
277 )
278);
279
280named!(string_text<Vec<u8>>,
281 fold_many0!(
282 unescaped_string_text,
283 Vec::new(),
284 |mut acc: Vec<u8>, bytes: &[u8]| {
285 acc.extend(bytes);
286 acc
287 }
288 )
289);
290
291named!(unescaped_string_text<&[u8]>,
292 alt!(
293 take_until_either!("\\\"") |
296 tag!("\\\\") => {|_| &b"\\"[..]} |
297 tag!("\\\"") => {|_| &b"\""[..]} |
298 tag!("\\\'") => {|_| &b"\'"[..]} |
299 tag!("\\n") => {|_| &b"\n"[..]} |
300 tag!("\\r") => {|_| &b"\r"[..]} |
301 tag!("\\t") => {|_| &b"\t"[..]} |
302 tag!("\\0") => {|_| &b"\0"[..]}
303 )
304);
305
306fn is_identifier_start(c: u8) -> bool {
307 is_alphabetic(c) || c == '_' as u8
308}
309
310fn is_identifier_char(c: u8) -> bool {
311 is_identifier_start(c) || is_digit(c)
312}