read_quotes/
read_quotes.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
use clojure_reader::edn::{self, Edn};

// Recursively traverse the Edn struct.
// To keep this example short, this only handles lists and literals.
fn wrap_quote(edn: Edn<'_>) -> Edn<'_> {
  match edn {
    Edn::Symbol(s) => s.strip_prefix('\'').map_or(Edn::Symbol(s), |stripped| {
      Edn::List(vec![Edn::Symbol("quote"), Edn::Symbol(stripped)])
    }),
    Edn::List(mut edn) => {
      edn.reverse();
      let mut list = vec![];

      while let Some(e) = edn.pop() {
        if e == Edn::Symbol("'") {
          list.push(Edn::List(vec![Edn::Symbol("quote"), wrap_quote(edn.pop().unwrap())]));
        } else {
          list.push(wrap_quote(e));
        }
      }

      return Edn::List(list);
    }
    _ => edn,
  }
}

// Use `read` to handle the leading ' symbol.
fn quotify(s: &str) -> Edn<'_> {
  let (edn, rest) = edn::read(s).unwrap();

  let edn = if edn == Edn::Symbol("'") {
    Edn::List(vec![Edn::Symbol("quote"), edn::read_string(rest).unwrap()])
  } else {
    edn
  };

  let edn = wrap_quote(edn);
  edn
}

fn main() {
  let quoted = quotify("'(foo (bar '(a 'b)))");
  assert_eq!(format!("{quoted}"), "(quote (foo (bar (quote (a (quote b))))))");

  let quoted = quotify("(foo '(a))");
  assert_eq!(format!("{quoted}"), "(foo (quote (a)))");

  let quoted = quotify("'(foo the 'bar)");
  assert_eq!(format!("{quoted}"), "(quote (foo the (quote bar)))");

  let quoted = quotify("(foo the 'bar)");
  assert_eq!(format!("{quoted}"), "(foo the (quote bar))");

  let quoted = quotify("(foo the bar)");
  assert_eq!(format!("{quoted}"), "(foo the bar)");
}

#[test]
fn run() {
  main();
}