brain/
parser.rs

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    //Range(Option<usize>, Option<usize>),
82    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    // Ensures that we reach EOF after all the statements
103    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            // must start with a non-digit
255            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        // We need to take until \ so that the unescaping can work
294        // We also need to take until " so that we don't go past the string boundary
295        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}