1use crate::lisp::Lval;
2use nom::{
3 branch::alt,
4 character::complete::{char, multispace0, none_of, one_of},
5 combinator::{all_consuming, map},
6 error::{ErrorKind, ParseError},
7 multi::{many0, many1},
8 number::complete::double,
9 sequence::{delimited, preceded},
10 IResult,
11};
12
13#[derive(Debug, PartialEq)]
14pub enum SyntaxError<I> {
15 InvalidArguments,
16 InvalidSymbol,
17 Nom(I, ErrorKind),
18}
19
20impl<I> ParseError<I> for SyntaxError<I> {
21 fn from_error_kind(input: I, kind: ErrorKind) -> Self {
22 SyntaxError::Nom(input, kind)
23 }
24
25 fn append(_: I, _: ErrorKind, other: Self) -> Self {
26 other
27 }
28}
29
30fn parse_number(s: &str) -> IResult<&str, Lval, SyntaxError<&str>> {
31 map(preceded(multispace0, double), |n| Lval::Num(n))(s)
32}
33
34fn parse_symbol(s: &str) -> IResult<&str, Lval, SyntaxError<&str>> {
35 map(
36 preceded(
37 multispace0,
38 many1(map(
39 one_of(
40 "_+\\:-*/=<>|!&%abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890",
41 ),
42 |c| format!("{}", c),
43 )),
44 ),
45 |o| Lval::Sym(o.join("")),
46 )(s)
47}
48
49fn parse_string(s: &str) -> IResult<&str, Lval, SyntaxError<&str>> {
50 map(
51 delimited(
52 preceded(multispace0, char('"')),
53 many0(map(none_of("\""), |c| format!("{}", c))),
54 preceded(multispace0, char('"')),
55 ),
56 |o| Lval::Str(o.join("")),
57 )(s)
58}
59
60fn parse_sexpression(s: &str) -> IResult<&str, Lval, SyntaxError<&str>> {
61 delimited(
62 preceded(multispace0, char('(')),
63 map(many0(parse_expression), |e| Lval::Sexpr(e)),
64 preceded(multispace0, char(')')),
65 )(s)
66}
67
68fn parse_qexpression(s: &str) -> IResult<&str, Lval, SyntaxError<&str>> {
69 delimited(
70 preceded(multispace0, char('[')),
71 map(many0(parse_expression), |e| Lval::Qexpr(e)),
72 preceded(multispace0, char(']')),
73 )(s)
74}
75
76fn parse_expression(s: &str) -> IResult<&str, Lval, SyntaxError<&str>> {
77 alt((
78 parse_number,
79 parse_symbol,
80 parse_string,
81 parse_sexpression,
82 parse_qexpression,
83 ))(s)
84}
85
86pub fn parse(s: &str) -> IResult<&str, Lval, SyntaxError<&str>> {
87 all_consuming(delimited(
88 multispace0,
89 map(many0(parse_expression), |e| Lval::Sexpr(e)),
90 multispace0,
91 ))(s)
92}
93
94#[cfg(test)]
95mod test {
96 use super::*;
97
98 #[test]
99 fn it_parses_numbers() {
100 assert_eq!(parse_number("1"), Ok(("", Lval::Num(1.0_f64))));
101 assert_eq!(
102 parse_number("1.000001-1"),
103 Ok(("-1", Lval::Num(1.000001_f64)))
104 );
105 assert_eq!(parse_number("123E-02"), Ok(("", Lval::Num(1.23_f64))));
106 assert_eq!(parse_number("-12302"), Ok(("", Lval::Num(-12302_f64))));
107 assert_eq!(parse_number(" \t1"), Ok(("", Lval::Num(1_f64))));
108 }
109
110 #[test]
111 fn it_parses_all_symbols() {
112 assert_eq!(parse_symbol("+"), Ok(("", Lval::Sym(String::from("+")))));
113 assert_eq!(parse_symbol("\t-"), Ok(("", Lval::Sym(String::from("-")))));
114 assert_eq!(parse_symbol(" *"), Ok(("", Lval::Sym(String::from("*")))));
115 assert_eq!(parse_symbol("\n/"), Ok(("", Lval::Sym(String::from("/")))));
116 assert_eq!(
117 parse_symbol("orange"),
118 Ok(("", Lval::Sym(String::from("orange"))))
119 );
120 assert_eq!(
121 parse_symbol("tail"),
122 Ok(("", Lval::Sym(String::from("tail"))))
123 );
124 }
125
126 #[test]
127 fn it_parses_sexpr() {
128 assert_eq!(
129 parse_sexpression(
130 "(* 1
131 2 3)"
132 ),
133 Ok((
134 "",
135 Lval::Sexpr(vec!(
136 Lval::Sym(String::from("*")),
137 Lval::Num(1_f64),
138 Lval::Num(2_f64),
139 Lval::Num(3_f64),
140 ))
141 ))
142 );
143 }
144
145 #[test]
146 fn it_parses_qexpr() {
147 assert_eq!(
148 parse_qexpression(
149 "[* 1
150 2 3]"
151 ),
152 Ok((
153 "",
154 Lval::Qexpr(vec!(
155 Lval::Sym(String::from("*")),
156 Lval::Num(1_f64),
157 Lval::Num(2_f64),
158 Lval::Num(3_f64),
159 ))
160 ))
161 );
162 }
163
164 #[test]
165 fn it_parses_an_expression() {
166 assert_eq!(
167 parse_expression(
168 "(* 1
169 2 3)"
170 ),
171 Ok((
172 "",
173 Lval::Sexpr(vec!(
174 Lval::Sym(String::from("*")),
175 Lval::Num(1_f64),
176 Lval::Num(2_f64),
177 Lval::Num(3_f64),
178 ))
179 ))
180 );
181
182 assert_eq!(
183 parse_expression(
184 "(* 1
185 2 (* 1
186 2 3))"
187 ),
188 Ok((
189 "",
190 Lval::Sexpr(vec!(
191 Lval::Sym(String::from("*")),
192 Lval::Num(1_f64),
193 Lval::Num(2_f64),
194 Lval::Sexpr(vec!(
195 Lval::Sym(String::from("*")),
196 Lval::Num(1_f64),
197 Lval::Num(2_f64),
198 Lval::Num(3_f64),
199 )),
200 ))
201 ))
202 );
203
204 assert_eq!(
205 parse_expression(
206 "9 (* 1
207 2 (* 1
208 2 3))"
209 ),
210 Ok((
211 " (* 1\n 2 (* 1\n 2 3))",
212 Lval::Num(9_f64)
213 ))
214 );
215 assert_eq!(parse_expression("1"), Ok(("", Lval::Num(1_f64),)));
216 assert_eq!(
217 parse_expression("*"),
218 Ok(("", Lval::Sym(String::from("*"),)))
219 );
220 }
221
222 #[test]
223 fn it_parses_expressions() {
224 assert_eq!(
225 parse(
226 "* 9 (* 1
227 2 (* 1
228 2 3))"
229 ),
230 Ok((
231 "",
232 Lval::Sexpr(vec!(
233 Lval::Sym(String::from("*")),
234 Lval::Num(9_f64),
235 Lval::Sexpr(vec!(
236 Lval::Sym(String::from("*")),
237 Lval::Num(1_f64),
238 Lval::Num(2_f64),
239 Lval::Sexpr(vec!(
240 Lval::Sym(String::from("*")),
241 Lval::Num(1_f64),
242 Lval::Num(2_f64),
243 Lval::Num(3_f64),
244 )),
245 )),
246 ))
247 ))
248 );
249 assert_eq!(parse(""), Ok(("", Lval::Sexpr(vec![]))));
250 assert_eq!(
251 parse("()"),
252 Ok(("", Lval::Sexpr(vec![Lval::Sexpr(vec![])])))
253 );
254 assert_eq!(
255 parse("*"),
256 Ok(("", Lval::Sexpr(vec![Lval::Sym(String::from("*"))]),))
257 );
258 assert_eq!(parse("9"), Ok(("", Lval::Sexpr(vec![Lval::Num(9_f64)]),)));
259 assert_eq!(
260 parse("* 1 2 3"),
261 Ok((
262 "",
263 Lval::Sexpr(vec!(
264 Lval::Sym(String::from("*")),
265 Lval::Num(1_f64),
266 Lval::Num(2_f64),
267 Lval::Num(3_f64),
268 )),
269 ))
270 );
271 }
272}