amethyst/
basic_parser.rs

1#![allow(dead_code)]
2use crate::syntax::{AutomatonType, Machine, MacroType, Program};
3use crate::syntax::{Move, State};
4use crate::syntax::{StateType, Transition};
5
6const ALLOWED_NAME_SYMBOLS: &str = "abcdefghijklmnopqrstuvwxyz0123456789_>";
7const ALLOWED_TAPE_SYMBOLS: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*[]-+=/?_:";
8
9/// Use string slices (`&str`) instead of `String` for more efficient parsing.
10enum Parser<'a, T> {
11    Parser(Box<dyn Fn(&'a str) -> Option<(&'a str, T)> + 'a>),
12}
13
14fn fmap<'a, A: 'a, B: 'a, F>(f: F, p: Parser<'a, A>) -> Parser<'a, B>
15where
16    F: Fn(A) -> B + 'a,
17{
18    match p {
19        Parser::Parser(parse) => Parser::Parser(Box::new(move |input| match parse(input) {
20            None => None,
21            Some((input2, x)) => Some((input2, f(x))),
22        })),
23    }
24}
25
26fn char_p<'a>(x: char) -> Parser<'a, char> {
27    Parser::Parser(Box::new(move |input: &'a str| {
28        let mut chars = input.char_indices();
29        match chars.next() {
30            Some((_, c)) if c == x => {
31                let next_index = c.len_utf8();
32                Some((&input[next_index..], c))
33            }
34            _ => None,
35        }
36    }))
37}
38fn pure<'a, T: Clone + 'a>(x: T) -> Parser<'a, T> {
39    Parser::Parser(Box::new(move |input| Some((input, x.clone()))))
40}
41
42fn ap<'a, A: 'a, B: 'a, F>(pf: Parser<'a, F>, pa: Parser<'a, A>) -> Parser<'a, B>
43where
44    F: Fn(A) -> B + 'a,
45{
46    Parser::Parser(Box::new(move |input| {
47        let Parser::Parser(ref pf_inner) = pf;
48        let Parser::Parser(ref pa_inner) = pa;
49        pf_inner(input).and_then(|(input1, f)| pa_inner(input1).map(|(input2, x)| (input2, f(x))))
50    }))
51}
52
53fn empty<'a, T: 'a>() -> Parser<'a, T> {
54    Parser::Parser(Box::new(|_| None))
55}
56
57fn or<'a, T: 'a>(p1: Parser<'a, T>, p2: Parser<'a, T>) -> Parser<'a, T> {
58    Parser::Parser(Box::new(move |input| {
59        let Parser::Parser(ref p1_inner) = p1;
60        let Parser::Parser(ref p2_inner) = p2;
61        p1_inner(input).or_else(|| p2_inner(input))
62    }))
63}
64
65fn string_p<'a>(s: &'a str) -> Parser<'a, String> {
66    s.chars().fold(pure(String::new()), |acc, c| {
67        let f = |s: &String, ch: char| {
68            let mut new_s = s.clone();
69            new_s.push(ch);
70            new_s
71        };
72        ap(
73            fmap(
74                move |s| {
75                    let s = s.clone();
76                    move |ch| f(&s, ch)
77                },
78                acc,
79            ),
80            char_p(c),
81        )
82    })
83}
84
85fn span_p<'a, F>(f: F) -> Parser<'a, String>
86where
87    F: Fn(char) -> bool + 'a,
88{
89    Parser::Parser(Box::new(move |input: &'a str| {
90        let token: String = input.chars().take_while(|&c| f(c)).collect();
91        let len = token.chars().map(|c| c.len_utf8()).sum();
92        if !token.is_empty() {
93            Some((&input[len..], token))
94        } else {
95            Some((input, String::new()))
96        }
97    }))
98}
99
100fn not_null<'a, T: 'a + Clone>(p: Parser<'a, Vec<T>>) -> Parser<'a, Vec<T>> {
101    Parser::Parser(Box::new(move |input| {
102        let Parser::Parser(ref inner) = p;
103        inner(input).and_then(|(input2, xs)| {
104            if xs.is_empty() {
105                None
106            } else {
107                Some((input2, xs))
108            }
109        })
110    }))
111}
112
113fn not_nulls<'a>(p: Parser<'a, String>) -> Parser<'a, String> {
114    Parser::Parser(Box::new(move |input| {
115        let Parser::Parser(ref inner) = p;
116        inner(input).and_then(|(input2, xs)| {
117            if xs.is_empty() {
118                None
119            } else {
120                Some((input2, xs))
121            }
122        })
123    }))
124}
125
126fn sep_by<'a, A: 'a, B: 'a>(sep: Parser<'a, A>, element: Parser<'a, B>) -> Parser<'a, Vec<B>> {
127    let rest = Parser::Parser(Box::new(move |input| {
128        let Parser::Parser(ref sep_inner) = sep;
129        let Parser::Parser(ref element_inner) = element;
130        let mut result = Vec::new();
131        let mut current_input = input;
132        if let Some((input2, first)) = element_inner(current_input) {
133            result.push(first);
134            current_input = input2;
135            while let Some((input3, _)) = sep_inner(current_input) {
136                if let Some((input4, next)) = element_inner(input3) {
137                    result.push(next);
138                    current_input = input4;
139                } else {
140                    break;
141                }
142            }
143            Some((current_input, result))
144        } else {
145            Some((input, Vec::new()))
146        }
147    }));
148    rest
149}
150
151fn ws<'a>() -> Parser<'a, String> {
152    span_p(|c| c == ' ' || c == '\n')
153}
154
155fn ws2<'a>() -> Parser<'a, String> {
156    fmap(
157        |chars: Vec<char>| chars.into_iter().collect::<String>(),
158        not_null(fmap(|s: String| s.chars().collect::<Vec<char>>(), ws())),
159    )
160}
161fn number_p<'a>() -> Parser<'a, i32> {
162    Parser::Parser(Box::new(move |input| {
163        let Parser::Parser(ref inner) = span_p(|c| "0123456789".contains(c));
164        inner(input).and_then(|(input2, s)| match s.parse::<i32>() {
165            Ok(num) => Some((input2, num)),
166            Err(_) => None,
167        })
168    }))
169}
170
171fn word_p<'a>() -> Parser<'a, String> {
172    span_p(|c| ALLOWED_NAME_SYMBOLS.contains(c))
173}
174
175fn tape_p<'a>() -> Parser<'a, String> {
176    span_p(|c| ALLOWED_TAPE_SYMBOLS.contains(c))
177}
178
179fn symbol_p<'a>() -> Parser<'a, char> {
180    ALLOWED_TAPE_SYMBOLS
181        .chars()
182        .fold(empty(), |acc, c| or(acc, char_p(c)))
183}
184
185fn move_p<'a>() -> Parser<'a, Move> {
186    or(
187        fmap(|_| Move::Left, char_p('L')),
188        or(
189            fmap(|_| Move::Right, char_p('R')),
190            fmap(|_| Move::Neutral, char_p('N')),
191        ),
192    )
193}
194fn transition_p<'a>() -> Parser<'a, Transition> {
195    fmap(
196        |(s, (t, (m, n)))| Transition {
197            read_symbol: s,
198            write_symbol: t,
199            move_symbol: m,
200            new_state: n,
201        },
202        ap(
203            ap(
204                ap(
205                    fmap(
206                        |s| move |t| move |m| move |n| (s, (t, (m, n))),
207                        ws().and_then(symbol_p())
208                            .and_keep(ws())
209                            .and_keep(char_p('/')),
210                    ),
211                    ws().and_then(symbol_p())
212                        .and_keep(ws())
213                        .and_keep(char_p(',')),
214                ),
215                ws().and_then(move_p())
216                    .and_keep(ws())
217                    .and_keep(string_p("->")),
218            ),
219            ws().and_then(word_p()).and_keep(ws()).and_keep(char_p(';')),
220        ),
221    )
222}
223
224fn some<'a, T: 'a + Clone>(p: Parser<'a, T>) -> Parser<'a, Vec<T>> {
225    not_null(many(p))
226}
227
228fn many<'a, T: 'a>(p: Parser<'a, T>) -> Parser<'a, Vec<T>> {
229    Parser::Parser(Box::new(move |mut input| {
230        let Parser::Parser(ref inner) = p;
231        let mut result = Vec::new();
232        while let Some((input2, x)) = inner(input) {
233            result.push(x);
234            input = input2;
235        }
236        Some((input, result))
237    }))
238}
239
240fn and_then<'a, A: 'a, B: 'a>(self_p: Parser<'a, A>, next: Parser<'a, B>) -> Parser<'a, B> {
241    Parser::Parser(Box::new(move |input| {
242        let Parser::Parser(ref self_inner) = self_p;
243        self_inner(input).and_then(|(input2, _)| {
244            let Parser::Parser(ref next_inner) = next;
245            next_inner(input2)
246        })
247    }))
248}
249
250fn and_keep<'a, A: 'a + Clone, B: 'a>(self_p: Parser<'a, A>, next: Parser<'a, B>) -> Parser<'a, A> {
251    Parser::Parser(Box::new(move |input| {
252        let Parser::Parser(ref self_inner) = self_p;
253        self_inner(input).and_then(|(input2, a)| {
254            let Parser::Parser(ref next_inner) = next;
255            next_inner(input2).map(|(input3, _)| (input3, a.clone()))
256        })
257    }))
258}
259
260trait ParserExt<'a, T: 'a> {
261    fn and_then<B: 'a>(self, next: Parser<'a, B>) -> Parser<'a, B>;
262    fn and_keep<B: 'a>(self, next: Parser<'a, B>) -> Parser<'a, T>
263    where
264        T: Clone;
265}
266impl<'a, T: 'a> ParserExt<'a, T> for Parser<'a, T> {
267    fn and_then<B: 'a>(self, next: Parser<'a, B>) -> Parser<'a, B> {
268        and_then(self, next)
269    }
270    fn and_keep<B: 'a>(self, next: Parser<'a, B>) -> Parser<'a, T>
271    where
272        T: Clone,
273    {
274        and_keep(self, next)
275    }
276}
277
278fn state_p<'a>() -> Parser<'a, StateType> {
279    // Helper to parse transitions block
280    let make_transitions_block_p = || {
281        char_p('{')
282            .and_then(ws())
283            .and_then(some(transition_p()))
284            .and_keep(ws())
285            .and_keep(char_p('}'))
286    };
287
288    // Reject state parser
289    let reject_p = string_p("reject")
290        .and_then(ws2())
291        .and_then(string_p("state"))
292        .and_then(ws2())
293        .and_then(not_nulls(word_p()))
294        .and_keep(ws())
295        .and_keep(char_p(';'));
296
297    // Accept state parser
298    let accept_p = string_p("accept")
299        .and_then(ws2())
300        .and_then(string_p("state"))
301        .and_then(ws2())
302        .and_then(not_nulls(word_p()))
303        .and_keep(ws())
304        .and_keep(char_p(';'));
305
306    // Initial state parser
307    let initial_p = string_p("initial")
308        .and_then(ws2())
309        .and_then(string_p("state"))
310        .and_then(ws2())
311        .and_then(not_nulls(word_p()))
312        .and_keep(ws());
313
314    let normal_p = string_p("state")
315        .and_then(ws())
316        .and_then(not_nulls(word_p()))
317        .and_keep(ws());
318
319    // Compose the parser
320    or(
321        or(
322            fmap(|name: String| StateType::Reject(name), reject_p),
323            fmap(|name: String| StateType::Accept(name), accept_p),
324        ),
325        or(
326            ap(
327                fmap(
328                    |name: String| {
329                        let name_clone = name.clone();
330                        move |transitions| {
331                            StateType::State(
332                                name_clone.clone(),
333                                State {
334                                    transitions: Box::new(transitions),
335                                    initial: true,
336                                },
337                            )
338                        }
339                    },
340                    initial_p,
341                ),
342                make_transitions_block_p(),
343            ),
344            ap(
345                fmap(
346                    |name: String| {
347                        let name_clone = name.clone();
348                        move |transitions| {
349                            StateType::State(
350                                name_clone.clone(),
351                                State {
352                                    transitions: Box::new(transitions),
353                                    initial: false,
354                                },
355                            )
356                        }
357                    },
358                    normal_p,
359                ),
360                make_transitions_block_p(),
361            ),
362        ),
363    )
364}
365
366fn complement_p<'a>() -> Parser<'a, MacroType> {
367    fmap(
368        |name| MacroType::Complement(name),
369        string_p("complement")
370            .and_then(ws())
371            .and_then(char_p('('))
372            .and_then(ws())
373            .and_then(not_nulls(word_p()))
374            .and_keep(ws())
375            .and_keep(char_p(')')),
376    )
377}
378
379fn sep_by_word_p<'a>() -> Parser<'a, Vec<String>> {
380    sep_by(
381        ws().and_then(char_p(',')).and_keep(ws()),
382        not_nulls(word_p()),
383    )
384}
385
386fn intersect_p<'a>() -> Parser<'a, MacroType> {
387    fmap(
388        |names| MacroType::Intersect(Box::new(names)),
389        string_p("intersect")
390            .and_then(ws())
391            .and_then(char_p('('))
392            .and_then(ws())
393            .and_then(not_null(sep_by_word_p()))
394            .and_keep(ws())
395            .and_keep(char_p(')')),
396    )
397}
398
399fn reunion_p<'a>() -> Parser<'a, MacroType> {
400    fmap(
401        |names| MacroType::Reunion(Box::new(names)),
402        string_p("reunion")
403            .and_then(ws())
404            .and_then(char_p('('))
405            .and_then(ws())
406            .and_then(not_null(sep_by_word_p()))
407            .and_keep(ws())
408            .and_keep(char_p(')')),
409    )
410}
411
412fn chain_p<'a>() -> Parser<'a, MacroType> {
413    fmap(
414        |names| MacroType::Chain(Box::new(names)),
415        string_p("chain")
416            .and_then(ws())
417            .and_then(char_p('('))
418            .and_then(ws())
419            .and_then(not_null(sep_by_word_p()))
420            .and_keep(ws())
421            .and_keep(char_p(')')),
422    )
423}
424
425fn repeat_p<'a>() -> Parser<'a, MacroType> {
426    fmap(
427        |(n, name)| MacroType::Repeat(n as u32, name),
428        ap(
429            fmap(
430                |n| move |name| (n, name),
431                string_p("repeat")
432                    .and_then(ws())
433                    .and_then(char_p('('))
434                    .and_then(ws())
435                    .and_then(number_p())
436                    .and_keep(ws()),
437            ),
438            char_p(',')
439                .and_then(ws())
440                .and_then(not_nulls(word_p()))
441                .and_keep(ws())
442                .and_keep(char_p(')')),
443        ),
444    )
445}
446
447fn move_mp<'a>() -> Parser<'a, MacroType> {
448    fmap(
449        |(mv, n)| MacroType::Move(mv, n as u32),
450        ap(
451            fmap(
452                |mv| move |n| (mv, n),
453                string_p("move")
454                    .and_then(ws())
455                    .and_then(char_p('('))
456                    .and_then(ws())
457                    .and_then(move_p())
458                    .and_keep(ws()),
459            ),
460            char_p(',')
461                .and_then(ws())
462                .and_then(number_p())
463                .and_keep(ws())
464                .and_keep(char_p(')')),
465        ),
466    )
467}
468
469fn override_p<'a>() -> Parser<'a, MacroType> {
470    fmap(
471        |((mv, n), sym)| MacroType::Override(mv, n as u32, sym),
472        ap(
473            ap(
474                fmap(
475                    |mv| move |n| move |sym| ((mv, n), sym),
476                    string_p("override")
477                        .and_then(ws())
478                        .and_then(char_p('('))
479                        .and_then(ws())
480                        .and_then(move_p())
481                        .and_keep(ws()),
482                ),
483                char_p(',')
484                    .and_then(ws())
485                    .and_then(number_p())
486                    .and_keep(ws())
487                    .and_keep(char_p(','))
488                    .and_keep(ws()),
489            ),
490            char_p('\'')
491                .and_then(symbol_p())
492                .and_keep(char_p('\''))
493                .and_keep(ws())
494                .and_keep(char_p(')')),
495        ),
496    )
497}
498
499fn place_p<'a>() -> Parser<'a, MacroType> {
500    fmap(
501        |tape| MacroType::Place(tape),
502        string_p("place")
503            .and_then(ws())
504            .and_then(char_p('('))
505            .and_then(ws())
506            .and_then(char_p('"'))
507            .and_then(tape_p())
508            .and_keep(char_p('"'))
509            .and_keep(ws())
510            .and_keep(char_p(')')),
511    )
512}
513
514fn shift_p<'a>() -> Parser<'a, MacroType> {
515    fmap(
516        |(mv, n)| MacroType::Shift(mv, n as u32),
517        ap(
518            fmap(
519                |mv| move |n| (mv, n),
520                string_p("shift")
521                    .and_then(ws())
522                    .and_then(char_p('('))
523                    .and_then(ws())
524                    .and_then(move_p())
525                    .and_keep(ws()),
526            ),
527            char_p(',')
528                .and_then(ws())
529                .and_then(number_p())
530                .and_keep(ws())
531                .and_keep(char_p(')')),
532        ),
533    )
534}
535
536fn macro_p<'a>() -> Parser<'a, AutomatonType> {
537    fmap(
538        |(name, macro_kw)| AutomatonType::Macro(name, macro_kw),
539        ap(
540            fmap(
541                |name: String| move |macro_kw| (name.clone(), macro_kw),
542                string_p("automaton")
543                    .and_then(ws2())
544                    .and_then(not_nulls(word_p()))
545                    .and_keep(ws())
546                    .and_keep(char_p('='))
547                    .and_keep(ws()),
548            ),
549            or(
550                complement_p(),
551                or(
552                    intersect_p(),
553                    or(
554                        reunion_p(),
555                        or(
556                            chain_p(),
557                            or(
558                                repeat_p(),
559                                or(move_mp(), or(override_p(), or(place_p(), shift_p()))),
560                            ),
561                        ),
562                    ),
563                ),
564            ),
565        )
566        .and_keep(ws())
567        .and_keep(char_p(';')),
568    )
569}
570
571fn pair_p<'a>() -> Parser<'a, (String, String)> {
572    ap(
573        fmap(|a: String| move |b: String| (a.clone(), b), word_p()),
574        ws2().and_then(word_p()),
575    )
576}
577
578fn machine_p<'a>() -> Parser<'a, AutomatonType> {
579    fmap(
580        |(name, (pairs, states))| {
581            AutomatonType::Machine(
582                name,
583                Machine {
584                    components: Box::new(pairs),
585                    states: Box::new(states),
586                },
587            )
588        },
589        ap(
590            ap(
591                fmap(
592                    |name: String| {
593                        // this is ugly, maybe there's a way around it?
594                        let name_clone = name.clone();
595                        move |pairs: Vec<(String, String)>| {
596                            let name_clone2 = name_clone.clone();
597                            let pairs_clone = pairs.clone();
598                            move |states| (name_clone2.clone(), (pairs_clone.clone(), states))
599                        }
600                    },
601                    string_p("automaton")
602                        .and_then(ws2())
603                        .and_then(not_nulls(word_p()))
604                        .and_keep(ws()),
605                ),
606                char_p('(')
607                    .and_then(sep_by(ws().and_then(char_p(',')).and_keep(ws()), pair_p()))
608                    .and_keep(char_p(')'))
609                    .and_keep(ws()),
610            ),
611            char_p('{')
612                .and_then(ws())
613                .and_then(some(state_p().and_keep(ws())))
614                .and_keep(char_p('}')),
615        ),
616    )
617}
618
619fn automata_p<'a>() -> Parser<'a, AutomatonType> {
620    or(macro_p(), machine_p())
621}
622
623fn program_p<'a>() -> Parser<'a, Program> {
624    fmap(
625        |automata| Program {
626            automata: Box::new(automata),
627        },
628        many(ws().and_then(automata_p()).and_keep(ws())),
629    )
630}
631
632pub fn parse_move(input: &str) -> Option<Move> {
633    let Parser::Parser(parse) = move_p();
634    match parse(input) {
635        None => None,
636        Some((_, move_symbol)) => Some(move_symbol),
637    }
638}
639
640pub fn parse_transition(input: &str) -> Option<Transition> {
641    let Parser::Parser(parse) = transition_p();
642    match parse(input) {
643        None => None,
644        Some((_, transition)) => Some(transition),
645    }
646}
647
648pub fn parse_state(input: &str) -> Option<StateType> {
649    let Parser::Parser(parse) = state_p();
650    match parse(input) {
651        None => None,
652        Some((_, state)) => Some(state),
653    }
654}
655
656pub fn parse_automaton(input: &str) -> Option<AutomatonType> {
657    let Parser::Parser(parse) = automata_p();
658    match parse(input) {
659        None => None,
660        Some((_, automaton)) => Some(automaton),
661    }
662}
663
664pub fn parse_program(input: &str) -> Option<Program> {
665    let Parser::Parser(parse) = program_p();
666    match parse(input) {
667        None => None,
668        Some((_, program)) => Some(program),
669    }
670}