1use std::iter::Peekable;
18
19use crate::ast::{Op, Pattern, Refrain};
20use crate::error::{RefrainError, Result};
21
22#[derive(Debug, Clone, PartialEq)]
23enum Sexp {
24 Atom(String),
25 List(Vec<Sexp>),
26}
27
28pub fn parse(src: &str) -> Result<Refrain> {
29 let tokens = tokenize(src);
30 let mut iter = tokens.into_iter().peekable();
31 let s = parse_sexp(&mut iter)?;
32 if iter.next().is_some() {
33 return Err(RefrainError::Parse(
34 "trailing tokens after top-level form".into(),
35 ));
36 }
37 sexp_to_refrain(&s)
38}
39
40fn tokenize(src: &str) -> Vec<String> {
41 let mut tokens = Vec::new();
42 let mut cur = String::new();
43 let mut in_comment = false;
44 for ch in src.chars() {
45 if in_comment {
46 if ch == '\n' {
47 in_comment = false;
48 }
49 continue;
50 }
51 if ch == ';' {
52 flush(&mut cur, &mut tokens);
53 in_comment = true;
54 continue;
55 }
56 if ch.is_whitespace() {
57 flush(&mut cur, &mut tokens);
58 continue;
59 }
60 if ch == '(' || ch == ')' {
61 flush(&mut cur, &mut tokens);
62 tokens.push(ch.to_string());
63 continue;
64 }
65 cur.push(ch);
66 }
67 flush(&mut cur, &mut tokens);
68 tokens
69}
70
71fn flush(cur: &mut String, out: &mut Vec<String>) {
72 if !cur.is_empty() {
73 out.push(std::mem::take(cur));
74 }
75}
76
77fn parse_sexp<I: Iterator<Item = String>>(iter: &mut Peekable<I>) -> Result<Sexp> {
78 let tok = iter
79 .next()
80 .ok_or_else(|| RefrainError::Parse("unexpected EOF".into()))?;
81 if tok == "(" {
82 let mut items = Vec::new();
83 loop {
84 let peek = iter
85 .peek()
86 .ok_or_else(|| RefrainError::Parse("unclosed list".into()))?;
87 if peek == ")" {
88 iter.next();
89 return Ok(Sexp::List(items));
90 }
91 items.push(parse_sexp(iter)?);
92 }
93 } else if tok == ")" {
94 Err(RefrainError::Parse("unexpected `)` at top".into()))
95 } else {
96 Ok(Sexp::Atom(tok))
97 }
98}
99
100fn sexp_to_refrain(s: &Sexp) -> Result<Refrain> {
101 let items = expect_list(s, "refrain form")?;
102 if items.len() < 2 {
103 return Err(RefrainError::Parse(
104 "refrain form requires `refrain` head and a name".into(),
105 ));
106 }
107 let head = expect_atom(&items[0], "refrain head")?;
108 if head != "refrain" {
109 return Err(RefrainError::Parse(format!(
110 "expected `refrain`, got `{}`",
111 head
112 )));
113 }
114 let name = expect_atom(&items[1], "refrain name")?.to_string();
115 let mut r = Refrain::new(name);
116 for stage in &items[2..] {
117 let stage_items = expect_list(stage, "stage form")?;
118 if stage_items.is_empty() {
119 return Err(RefrainError::Parse("empty stage form".into()));
120 }
121 let kind = expect_atom(&stage_items[0], "stage kind")?;
122 let body = sexp_to_pattern_body(&stage_items[1..])?;
123 match kind {
124 "territorialize" => r.territorialize = Some(body),
125 "deterritorialize" => r.deterritorialize = Some(body),
126 "reterritorialize" => r.reterritorialize = Some(body),
127 other => {
128 return Err(RefrainError::Parse(format!("unknown stage `{}`", other)));
129 }
130 }
131 }
132 Ok(r)
133}
134
135fn sexp_to_pattern_body(items: &[Sexp]) -> Result<Pattern> {
136 match items.len() {
137 0 => Err(RefrainError::Parse("empty stage body".into())),
138 1 => sexp_to_pattern(&items[0]),
139 _ => {
140 let mut pats = Vec::with_capacity(items.len());
141 for i in items {
142 pats.push(sexp_to_pattern(i)?);
143 }
144 Ok(Pattern::Seq(pats))
145 }
146 }
147}
148
149fn sexp_to_pattern(s: &Sexp) -> Result<Pattern> {
150 match s {
151 Sexp::Atom(a) => Ok(Pattern::Op(Op::Sym(a.clone()))),
152 Sexp::List(xs) => {
153 if xs.is_empty() {
154 return Err(RefrainError::Parse("empty pattern list".into()));
155 }
156 let head = expect_atom(&xs[0], "op head")?;
157 match head {
158 "note" => {
159 if xs.len() != 3 {
160 return Err(RefrainError::Parse("note expects (note PITCH DUR)".into()));
161 }
162 let pitch = expect_atom(&xs[1], "note pitch")?.to_string();
163 let dur = expect_atom(&xs[2], "note dur")?.to_string();
164 Ok(Pattern::Op(Op::Note { pitch, dur }))
165 }
166 "loop" => {
167 if xs.len() != 3 {
168 return Err(RefrainError::Parse("loop expects (loop COUNT BODY)".into()));
169 }
170 let count_atom = expect_atom(&xs[1], "loop count")?;
171 let count: u32 = count_atom.parse().map_err(|_| {
172 RefrainError::Parse(format!("loop count `{}` not u32", count_atom))
173 })?;
174 let body = Box::new(sexp_to_pattern(&xs[2])?);
175 Ok(Pattern::Op(Op::Loop { count, body }))
176 }
177 "dy/dx" => {
178 if xs.len() != 3 {
179 return Err(RefrainError::Parse("dy/dx expects (dy/dx X T)".into()));
180 }
181 let x = expect_atom(&xs[1], "dy/dx x")?.to_string();
182 let t = expect_atom(&xs[2], "dy/dx t")?.to_string();
183 Ok(Pattern::Op(Op::Diff { x, t }))
184 }
185 "quotient" => {
186 let mut rels = Vec::new();
187 for s in &xs[1..] {
188 rels.push(expect_atom(s, "quotient rel")?.to_string());
189 }
190 Ok(Pattern::Op(Op::Quotient { rels }))
191 }
192 _ => {
193 let head_owned = head.to_string();
194 let mut args = Vec::with_capacity(xs.len() - 1);
195 for s in &xs[1..] {
196 args.push(sexp_to_pattern(s)?);
197 }
198 Ok(Pattern::Op(Op::Call {
199 head: head_owned,
200 args,
201 }))
202 }
203 }
204 }
205 }
206}
207
208fn expect_list<'a>(s: &'a Sexp, what: &str) -> Result<&'a [Sexp]> {
209 match s {
210 Sexp::List(xs) => Ok(xs),
211 Sexp::Atom(_) => Err(RefrainError::Parse(format!("expected list ({})", what))),
212 }
213}
214
215fn expect_atom<'a>(s: &'a Sexp, what: &str) -> Result<&'a str> {
216 match s {
217 Sexp::Atom(a) => Ok(a.as_str()),
218 Sexp::List(_) => Err(RefrainError::Parse(format!("expected atom ({})", what))),
219 }
220}