aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTolmachev Igor <me@igorek.dev>2026-05-11 08:34:22 +0300
committerTolmachev Igor <me@igorek.dev>2026-05-11 08:34:22 +0300
commitabda8d00117072f7c03f57eaeca9cf44427078dc (patch)
treea7caf8c91932ce195398dbd63758a057720366a1
parent7163aaebc993591db1cb4d7ae2be31669a0cb9a7 (diff)
downloadcrisp-abda8d00117072f7c03f57eaeca9cf44427078dc.tar.gz
crisp-abda8d00117072f7c03f57eaeca9cf44427078dc.zip
Replace generic list AST with typed expression tree
Each form (fn, let, for, set, do, call) now has its own variant with named fields instead of being a plain list.
-rw-r--r--compiler/src/ast/error.rs11
-rw-r--r--compiler/src/ast/mod.rs2
-rw-r--r--compiler/src/ast/models.rs48
-rw-r--r--compiler/src/ast/parser.rs303
-rw-r--r--compiler/src/ast/tests.rs1298
-rw-r--r--compiler/src/span.rs4
6 files changed, 1510 insertions, 156 deletions
diff --git a/compiler/src/ast/error.rs b/compiler/src/ast/error.rs
index 38b3916..5598376 100644
--- a/compiler/src/ast/error.rs
+++ b/compiler/src/ast/error.rs
@@ -10,8 +10,10 @@ pub enum Error {
10 UnexpectedEscapeChar(char), 10 UnexpectedEscapeChar(char),
11 11
12 // Par 12 // Par
13 UnexpectedRightPar, 13 UnexpectedClosePar,
14 UnclosedLeftPar, 14 UnclosedPar,
15
16 UnexpectedToken,
15 17
16 UnexpectedEof, 18 UnexpectedEof,
17 19
@@ -26,8 +28,9 @@ impl fmt::Display for Error {
26 } 28 }
27 Error::UnclosedString(string) => write!(f, "unclosed string {string:?}"), 29 Error::UnclosedString(string) => write!(f, "unclosed string {string:?}"),
28 Error::UnexpectedEscapeChar(ch) => write!(f, "unexpected escape char {ch:?}"), 30 Error::UnexpectedEscapeChar(ch) => write!(f, "unexpected escape char {ch:?}"),
29 Error::UnexpectedRightPar => write!(f, "unexpected right par"), 31 Error::UnexpectedClosePar => write!(f, "unexpected `)`"),
30 Error::UnclosedLeftPar => write!(f, "unclosed left par"), 32 Error::UnclosedPar => write!(f, "unclosed `(`"),
33 Error::UnexpectedToken => write!(f, "unexpected token"),
31 Error::UnexpectedEof => write!(f, "unexpected eof"), 34 Error::UnexpectedEof => write!(f, "unexpected eof"),
32 Error::RecursionLimit => write!(f, "recursion limit"), 35 Error::RecursionLimit => write!(f, "recursion limit"),
33 } 36 }
diff --git a/compiler/src/ast/mod.rs b/compiler/src/ast/mod.rs
index 2a0be03..afd459e 100644
--- a/compiler/src/ast/mod.rs
+++ b/compiler/src/ast/mod.rs
@@ -3,7 +3,7 @@ mod models;
3mod parser; 3mod parser;
4 4
5pub use error::Error; 5pub use error::Error;
6pub use models::{Ast, Atom, Expr}; 6pub use models::{Ast, Atom, Expr, LetVar};
7pub use parser::Parser; 7pub use parser::Parser;
8 8
9#[cfg(test)] 9#[cfg(test)]
diff --git a/compiler/src/ast/models.rs b/compiler/src/ast/models.rs
index 2a8c5ae..64fec19 100644
--- a/compiler/src/ast/models.rs
+++ b/compiler/src/ast/models.rs
@@ -2,22 +2,56 @@ use std::rc::Rc;
2 2
3use crate::span::Spanned; 3use crate::span::Spanned;
4 4
5#[derive(Clone, Debug, PartialEq)] 5#[derive(Clone, Debug, PartialEq, Eq)]
6pub struct LetVar {
7 pub name: Spanned<Rc<str>>,
8 pub expr: Spanned<Expr>,
9}
10
11#[derive(Clone, Debug, PartialEq, Eq)]
6pub enum Atom { 12pub enum Atom {
7 Integer(i64), 13 Int(i64),
8 String(Rc<str>), 14 Str(Rc<str>),
9 Symbol(Rc<str>), 15 Sym(Rc<str>),
10 Bool(bool), 16 Bool(bool),
11 Nil, 17 Nil,
12} 18}
13 19
14#[derive(Clone, Debug, PartialEq)] 20#[derive(Clone, Debug, PartialEq, Eq)]
15pub enum Expr { 21pub enum Expr {
22 Fn {
23 name: Spanned<Rc<str>>,
24 args: Vec<Spanned<Rc<str>>>,
25 body: Vec<Spanned<Expr>>,
26 },
27 Const {
28 vars: Vec<Spanned<LetVar>>,
29 },
30 Let {
31 vars: Vec<Spanned<LetVar>>,
32 body: Vec<Spanned<Expr>>,
33 },
34 For {
35 loop_var: Spanned<Rc<str>>,
36 from: Spanned<Box<Expr>>,
37 to: Spanned<Box<Expr>>,
38 body: Vec<Spanned<Expr>>,
39 },
40 Set {
41 target_var: Spanned<Rc<str>>,
42 expr: Spanned<Box<Expr>>,
43 },
44 Do {
45 body: Vec<Spanned<Expr>>,
46 },
47 Call {
48 fn_name: Spanned<Rc<str>>,
49 args: Vec<Spanned<Expr>>,
50 },
16 Atom(Atom), 51 Atom(Atom),
17 List(Vec<Spanned<Expr>>),
18} 52}
19 53
20#[derive(Clone, Debug, PartialEq)] 54#[derive(Clone, Debug, PartialEq, Eq)]
21pub struct Ast(Vec<Spanned<Expr>>); 55pub struct Ast(Vec<Spanned<Expr>>);
22 56
23impl Ast { 57impl Ast {
diff --git a/compiler/src/ast/parser.rs b/compiler/src/ast/parser.rs
index 4b4f949..12a6f0d 100644
--- a/compiler/src/ast/parser.rs
+++ b/compiler/src/ast/parser.rs
@@ -1,7 +1,7 @@
1use std::iter::Peekable; 1use std::{iter::Peekable, rc::Rc};
2 2
3use crate::{ 3use crate::{
4 ast::{Ast, Atom, Error, Expr}, 4 ast::{Ast, Atom, Error, Expr, models::LetVar},
5 lex::Token, 5 lex::Token,
6 span::{Pos, Span, Spanned}, 6 span::{Pos, Span, Spanned},
7}; 7};
@@ -10,7 +10,7 @@ pub(super) const MAX_DEPTH: usize = 256; // TODO: make it a compile flag
10 10
11fn parse_number(number: &str) -> Result<Atom, Error> { 11fn parse_number(number: &str) -> Result<Atom, Error> {
12 match number.parse() { 12 match number.parse() {
13 Ok(ok) => Ok(Atom::Integer(ok)), 13 Ok(ok) => Ok(Atom::Int(ok)),
14 Err(err) => Err(Error::InvalidIntegerLiteral(number.into(), err)), 14 Err(err) => Err(Error::InvalidIntegerLiteral(number.into(), err)),
15 } 15 }
16} 16}
@@ -41,7 +41,7 @@ fn parse_string(string: &str) -> Result<Atom, Error> {
41 return Err(Error::UnclosedString(string.into())); 41 return Err(Error::UnclosedString(string.into()));
42 } 42 }
43 43
44 Ok(Atom::String(result.into())) 44 Ok(Atom::Str(result.into()))
45} 45}
46 46
47fn parse_symbol(symbol: &str) -> Atom { 47fn parse_symbol(symbol: &str) -> Atom {
@@ -49,7 +49,7 @@ fn parse_symbol(symbol: &str) -> Atom {
49 "true" => Atom::Bool(true), 49 "true" => Atom::Bool(true),
50 "false" => Atom::Bool(false), 50 "false" => Atom::Bool(false),
51 "nil" => Atom::Nil, 51 "nil" => Atom::Nil,
52 _ => Atom::Symbol(symbol.into()), 52 _ => Atom::Sym(symbol.into()),
53 } 53 }
54} 54}
55 55
@@ -78,50 +78,275 @@ where
78 self.tokens.peek().copied() 78 self.tokens.peek().copied()
79 } 79 }
80 80
81 fn consume(&mut self) -> Option<Spanned<Token<'a>>> { 81 fn peek_token(&mut self) -> Result<Spanned<Token<'a>>, Spanned<Error>> {
82 self.tokens 82 match self.peek() {
83 .next() 83 Some(token) => Ok(token),
84 .inspect(|s| self.last_token_span = s.span) 84 None => Err(Spanned::new(Error::UnexpectedEof, self.last_token_span)),
85 }
85 } 86 }
86 87
87 fn parse_expr(&mut self) -> Result<Spanned<Expr>, Spanned<Error>> { 88 fn consume(&mut self) -> Result<(), Spanned<Error>> {
88 let Spanned { inner: token, span } = match self.peek() { 89 match self.tokens.next() {
89 Some(token) => token, 90 Some(token) => {
90 None => return Err(Spanned::new(Error::UnexpectedEof, self.last_token_span)), 91 let (token, span) = token.into_parts();
92
93 if let Token::LeftPar = token {
94 self.depth = self.depth.saturating_add(1);
95 if self.depth > MAX_DEPTH {
96 return Err(Spanned::new(Error::RecursionLimit, span));
97 }
98 } else if let Token::RightPar = token {
99 self.depth = self.depth.saturating_sub(1);
100 }
101
102 self.last_token_span = span;
103 Ok(())
104 }
105 None => panic!("no tokens to consume"),
106 }
107 }
108
109 fn require_sym(&mut self, symbol: &str) -> Result<Span, Spanned<Error>> {
110 let (token, span) = self.peek_token()?.into_parts();
111 self.consume()?;
112 match token {
113 Token::Symbol(s) if s == symbol => Ok(span),
114 _ => Err(Spanned::new(Error::UnexpectedToken, span)),
115 }
116 }
117
118 fn require_left_par(&mut self) -> Result<Span, Spanned<Error>> {
119 let (token, span) = self.peek_token()?.into_parts();
120 self.consume()?;
121 match token {
122 Token::LeftPar => Ok(span),
123 _ => Err(Spanned::new(Error::UnexpectedToken, span)),
124 }
125 }
126
127 fn require_right_par(&mut self) -> Result<Span, Spanned<Error>> {
128 let (token, span) = self.peek_token()?.into_parts();
129 self.consume()?;
130 match token {
131 Token::RightPar => Ok(span),
132 _ => Err(Spanned::new(Error::UnexpectedToken, span)),
133 }
134 }
135
136 fn parse_sym(&mut self) -> Result<Spanned<&'a str>, Spanned<Error>> {
137 let (token, span) = self.peek_token()?.into_parts();
138 self.consume()?;
139 match token {
140 Token::Symbol(symbol) => Ok(Spanned::new(symbol, span)),
141 _ => Err(Spanned::new(Error::UnexpectedToken, span)),
142 }
143 }
144
145 fn parse_args(&mut self, open_span: Span) -> Result<Vec<Spanned<Rc<str>>>, Spanned<Error>> {
146 let mut args = Vec::new();
147 while let Some(token) = self.peek() {
148 let (token, span) = token.into_parts();
149
150 self.consume()?;
151 match token {
152 Token::Symbol(symbol) => args.push(Spanned::new(symbol.into(), span)),
153 Token::RightPar => return Ok(args),
154 _ => return Err(Spanned::new(Error::UnexpectedToken, span)),
155 }
156 }
157
158 Err(Spanned::new(Error::UnclosedPar, open_span))
159 }
160
161 fn parse_body(
162 &mut self,
163 open_span: Span,
164 non_empty: bool,
165 ) -> Result<Vec<Spanned<Expr>>, Spanned<Error>> {
166 let mut body = Vec::new();
167 if non_empty {
168 body.push(self.parse_expr()?);
169 }
170 while let Some(token) = self.peek() {
171 match token.inner {
172 Token::RightPar => {
173 self.consume()?;
174 return Ok(body);
175 }
176 _ => body.push(self.parse_expr()?),
177 }
178 }
179
180 Err(Spanned::new(Error::UnclosedPar, open_span))
181 }
182
183 fn parse_var(&mut self) -> Result<Spanned<LetVar>, Spanned<Error>> {
184 let open_span = self.require_left_par()?;
185 let name = self.parse_sym()?.map(Into::into);
186 let expr = self.parse_expr()?;
187 let close_span = self.require_right_par()?;
188
189 let let_var = LetVar { name, expr };
190 let span = Span::new(open_span.start, close_span.end);
191 Ok(Spanned::new(let_var, span))
192 }
193
194 fn parse_vars(&mut self, open_span: Span) -> Result<Vec<Spanned<LetVar>>, Spanned<Error>> {
195 let mut vars = Vec::new();
196 vars.push(self.parse_var()?);
197
198 while let Some(token) = self.peek() {
199 let (token, span) = token.into_parts();
200 match token {
201 Token::LeftPar => vars.push(self.parse_var()?),
202 Token::RightPar => {
203 self.consume()?;
204 return Ok(vars);
205 }
206 _ => return Err(Spanned::new(Error::UnexpectedToken, span)),
207 }
208 }
209
210 Err(Spanned::new(Error::UnclosedPar, open_span))
211 }
212
213 fn parse_fn(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
214 self.consume()?;
215
216 let name = self.parse_sym()?.map(Into::into);
217 let args_open_span = self.require_left_par()?;
218 let args = self.parse_args(args_open_span)?;
219
220 let body = self.parse_body(open_span, true)?;
221 let function = Expr::Fn { name, args, body };
222 let span = Span::new(open_span.start, self.last_token_span.end);
223
224 Ok(Spanned::new(function, span))
225 }
226
227 fn parse_const(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
228 self.consume()?;
229
230 let vars = self.parse_vars(open_span)?;
231 let constant = Expr::Const { vars };
232 let span = Span::new(open_span.start, self.last_token_span.end);
233 Ok(Spanned::new(constant, span))
234 }
235
236 fn parse_let(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
237 self.consume()?;
238
239 let vars_span = self.require_left_par()?;
240 let vars = self.parse_vars(vars_span)?;
241 let body = self.parse_body(open_span, true)?;
242 let let_vars = Expr::Let { vars, body };
243 let span = Span::new(open_span.start, self.last_token_span.end);
244 Ok(Spanned::new(let_vars, span))
245 }
246
247 fn parse_for(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
248 self.consume()?;
249
250 let loop_var = self.parse_sym()?.map(Into::into);
251 self.require_sym("from")?;
252 let from = self.parse_expr()?.map(Box::new);
253 self.require_sym("to")?;
254 let to = self.parse_expr()?.map(Box::new);
255 let body = self.parse_body(open_span, true)?;
256
257 let for_loop = Expr::For {
258 loop_var,
259 from,
260 to,
261 body,
91 }; 262 };
263 let span = Span::new(open_span.start, self.last_token_span.end);
264 Ok(Spanned::new(for_loop, span))
265 }
266
267 fn parse_set(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
268 self.consume()?;
269
270 let target_var = self.parse_sym()?.map(Into::into);
271 let expr = self.parse_expr()?.map(Box::new);
272 self.require_right_par()?;
273
274 let set = Expr::Set { target_var, expr };
275 let span = Span::new(open_span.start, self.last_token_span.end);
276 Ok(Spanned::new(set, span))
277 }
278
279 fn parse_do(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
280 self.consume()?;
281
282 let body = self.parse_body(open_span, true)?;
283
284 let do_body = Expr::Do { body };
285 let span = Span::new(open_span.start, self.last_token_span.end);
286 Ok(Spanned::new(do_body, span))
287 }
288
289 fn parse_call(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
290 let fn_name = self.parse_sym()?.map(Into::into);
291 let args = self.parse_body(open_span, false)?;
292
293 let call = Expr::Call { fn_name, args };
294 let span = Span::new(open_span.start, self.last_token_span.end);
295 Ok(Spanned::new(call, span))
296 }
297
298 fn parse_special_form(&mut self, open_span: Span) -> Result<Spanned<Expr>, Spanned<Error>> {
299 let (token, span) = self.peek_token()?.into_parts();
300
301 let symbol = match token {
302 Token::Symbol(symbol) => symbol,
303 Token::RightPar => {
304 self.consume()?;
305 let span = Span::new(open_span.start, span.end);
306 return Ok(Spanned::new(Expr::Atom(Atom::Nil), span));
307 }
308 _ => return Err(Spanned::new(Error::UnexpectedToken, span)),
309 };
310
311 match symbol {
312 "fn" => self.parse_fn(open_span),
313 "const" => self.parse_const(open_span),
314 "let" => self.parse_let(open_span),
315 "for" => self.parse_for(open_span),
316 "set" => self.parse_set(open_span),
317 "do" => self.parse_do(open_span),
318 _ => self.parse_call(open_span),
319 }
320 }
321
322 fn parse_expr(&mut self) -> Result<Spanned<Expr>, Spanned<Error>> {
323 let (token, span) = self.peek_token()?.into_parts();
92 324
93 let expr = match token { 325 let expr = match token {
94 Token::LeftPar => { 326 Token::LeftPar => {
95 self.consume(); 327 self.consume()?;
96 let list = self.parse_list(span)?; 328 self.parse_special_form(span)?
97 let expr = if !list.is_empty() {
98 Expr::List(list)
99 } else {
100 Expr::Atom(Atom::Nil)
101 };
102
103 Spanned::new(expr, Span::new(span.start, self.last_token_span.end))
104 } 329 }
105 Token::RightPar => { 330 Token::RightPar => {
106 self.consume(); 331 self.consume()?;
107 return Err(Spanned::new(Error::UnexpectedRightPar, span)); 332 return Err(Spanned::new(Error::UnexpectedClosePar, span));
108 } 333 }
109 Token::Number(number) => { 334 Token::Number(number) => {
110 self.consume(); 335 self.consume()?;
111 let atom = parse_number(number).map_err(|e| Spanned::new(e, span))?; 336 let atom = parse_number(number).map_err(|e| Spanned::new(e, span))?;
112 Spanned::new(Expr::Atom(atom), span) 337 Spanned::new(Expr::Atom(atom), span)
113 } 338 }
114 Token::String(string) => { 339 Token::String(string) => {
115 self.consume(); 340 self.consume()?;
116 let atom = parse_string(string).map_err(|e| Spanned::new(e, span))?; 341 let atom = parse_string(string).map_err(|e| Spanned::new(e, span))?;
117 Spanned::new(Expr::Atom(atom), span) 342 Spanned::new(Expr::Atom(atom), span)
118 } 343 }
119 Token::UnclosedString(string) => { 344 Token::UnclosedString(string) => {
120 self.consume(); 345 self.consume()?;
121 return Err(Spanned::new(Error::UnclosedString(string.into()), span)); 346 return Err(Spanned::new(Error::UnclosedString(string.into()), span));
122 } 347 }
123 Token::Symbol(symbol) => { 348 Token::Symbol(symbol) => {
124 self.consume(); 349 self.consume()?;
125 let atom = parse_symbol(symbol); 350 let atom = parse_symbol(symbol);
126 Spanned::new(Expr::Atom(atom), span) 351 Spanned::new(Expr::Atom(atom), span)
127 } 352 }
@@ -130,28 +355,6 @@ where
130 Ok(expr) 355 Ok(expr)
131 } 356 }
132 357
133 fn parse_list(&mut self, left_par_span: Span) -> Result<Vec<Spanned<Expr>>, Spanned<Error>> {
134 let mut list = Vec::new();
135
136 self.depth += 1;
137 if self.depth >= MAX_DEPTH {
138 return Err(Spanned::new(Error::RecursionLimit, self.last_token_span));
139 }
140
141 while let Some(Spanned { inner: token, .. }) = self.peek() {
142 match token {
143 Token::RightPar => {
144 self.consume();
145 return Ok(list);
146 }
147 _ => list.push(self.parse_expr()?),
148 }
149 }
150 self.depth -= 1;
151
152 Err(Spanned::new(Error::UnclosedLeftPar, left_par_span))
153 }
154
155 pub fn parse(mut self) -> Result<Ast, Spanned<Error>> { 358 pub fn parse(mut self) -> Result<Ast, Spanned<Error>> {
156 let mut ast = Vec::new(); 359 let mut ast = Vec::new();
157 360
diff --git a/compiler/src/ast/tests.rs b/compiler/src/ast/tests.rs
index 44789cb..5b2399f 100644
--- a/compiler/src/ast/tests.rs
+++ b/compiler/src/ast/tests.rs
@@ -1,7 +1,7 @@
1use std::{fmt::Debug, iter::repeat_n}; 1use std::fmt::Debug;
2 2
3use crate::{ 3use crate::{
4 ast::{Atom, Error, Expr, Parser, parser::MAX_DEPTH, tests::E::*}, 4 ast::{Atom, Error, Expr, LetVar, Parser, parser::MAX_DEPTH, tests::E::*},
5 lex::Token::{self, *}, 5 lex::Token::{self, *},
6 span::{Pos, Span, Spanned}, 6 span::{Pos, Span, Spanned},
7}; 7};
@@ -13,20 +13,62 @@ enum E {
13 Sym(&'static str), 13 Sym(&'static str),
14 Bool(bool), 14 Bool(bool),
15 Nil, 15 Nil,
16 List(Vec<E>), 16 Fn(&'static str, Vec<&'static str>, Vec<E>),
17 Const(Vec<(&'static str, E)>),
18 Let(Vec<(&'static str, E)>, Vec<E>),
19 For(&'static str, Box<E>, Box<E>, Vec<E>),
20 Set(&'static str, Box<E>),
21 Do(Vec<E>),
22 Call(&'static str, Vec<E>),
23}
24
25fn leak(s: &str) -> &'static str {
26 Box::leak(s.to_string().into_boxed_str())
27}
28
29fn convert_var(var: LetVar) -> (&'static str, E) {
30 (leak(&var.name.inner), var.expr.inner.into())
17} 31}
18 32
19impl From<Expr> for E { 33impl From<Expr> for E {
20 fn from(expr: Expr) -> Self { 34 fn from(expr: Expr) -> Self {
21 match expr { 35 match expr {
22 Expr::Atom(atom) => match atom { 36 Expr::Atom(atom) => match atom {
23 Atom::Integer(i) => Int(i), 37 Atom::Int(i) => Int(i),
24 Atom::String(s) => Str(Box::leak(s.into())), 38 Atom::Str(s) => Str(leak(&s)),
25 Atom::Symbol(s) => Sym(Box::leak(s.into())), 39 Atom::Sym(s) => Sym(leak(&s)),
26 Atom::Bool(b) => Bool(b), 40 Atom::Bool(b) => Bool(b),
27 Atom::Nil => Nil, 41 Atom::Nil => Nil,
28 }, 42 },
29 Expr::List(l) => List(l.into_iter().map(|e| e.inner.into()).collect()), 43 Expr::Fn { name, args, body } => Fn(
44 leak(&name.inner),
45 args.into_iter().map(|a| leak(&a.inner)).collect(),
46 body.into_iter().map(|e| e.inner.into()).collect(),
47 ),
48 Expr::Const { vars } => Const(vars.into_iter().map(|v| convert_var(v.inner)).collect()),
49 Expr::Let { vars, body } => Let(
50 vars.into_iter().map(|v| convert_var(v.inner)).collect(),
51 body.into_iter().map(|e| e.inner.into()).collect(),
52 ),
53 Expr::For {
54 loop_var,
55 from,
56 to,
57 body,
58 } => For(
59 leak(&loop_var.inner),
60 Box::new(E::from(*from.inner)),
61 Box::new(E::from(*to.inner)),
62 body.into_iter().map(|e| e.inner.into()).collect(),
63 ),
64 Expr::Set { target_var, expr } => {
65 Set(leak(&target_var.inner), Box::new(E::from(*expr.inner)))
66 }
67 Expr::Do { body } => Do(body.into_iter().map(|e| e.inner.into()).collect()),
68 Expr::Call { fn_name, args } => Call(
69 leak(&fn_name.inner),
70 args.into_iter().map(|e| e.inner.into()).collect(),
71 ),
30 } 72 }
31 } 73 }
32} 74}
@@ -142,72 +184,311 @@ fn test_string_escapes() {
142} 184}
143 185
144#[test] 186#[test]
145fn test_lists() { 187fn test_call() {
146 let cases = vec![ 188 let cases = vec![
147 // (1) 189 // (foo 1)
148 ( 190 (
149 vec![LeftPar, Number("1"), RightPar], 191 vec![LeftPar, Symbol("foo"), Number("1"), RightPar],
150 vec![List(vec![Int(1)])], 192 vec![Call("foo", vec![Int(1)])],
151 ), 193 ),
152 // (1 2 3) 194 // (+ 1 2 3)
153 ( 195 (
154 vec![LeftPar, Number("1"), Number("2"), Number("3"), RightPar], 196 vec![
155 vec![List(vec![Int(1), Int(2), Int(3)])], 197 LeftPar,
198 Symbol("+"),
199 Number("1"),
200 Number("2"),
201 Number("3"),
202 RightPar,
203 ],
204 vec![Call("+", vec![Int(1), Int(2), Int(3)])],
156 ), 205 ),
157 // (()) -> (nil) 206 // (foo (bar 1) baz)
158 ( 207 (
159 vec![LeftPar, LeftPar, RightPar, RightPar], 208 vec![
160 vec![List(vec![Nil])], 209 LeftPar,
210 Symbol("foo"),
211 LeftPar,
212 Symbol("bar"),
213 Number("1"),
214 RightPar,
215 Symbol("baz"),
216 RightPar,
217 ],
218 vec![Call("foo", vec![Call("bar", vec![Int(1)]), Sym("baz")])],
161 ), 219 ),
162 // (a (b c) d) 220 // (f "s" foo true nil)
163 ( 221 (
164 vec![ 222 vec![
165 LeftPar, 223 LeftPar,
166 Symbol("a"), 224 Symbol("f"),
225 String("s"),
226 Symbol("foo"),
227 Symbol("true"),
228 Symbol("nil"),
229 RightPar,
230 ],
231 vec![Call("f", vec![Str("s"), Sym("foo"), Bool(true), Nil])],
232 ),
233 ];
234 for (tokens, ast) in cases {
235 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
236 }
237}
238
239#[test]
240fn test_fn() {
241 let cases = vec![
242 // (fn foo () 1)
243 (
244 vec![
245 LeftPar,
246 Symbol("fn"),
247 Symbol("foo"),
167 LeftPar, 248 LeftPar,
168 Symbol("b"),
169 Symbol("c"),
170 RightPar, 249 RightPar,
171 Symbol("d"), 250 Number("1"),
172 RightPar, 251 RightPar,
173 ], 252 ],
174 vec![List(vec![ 253 vec![Fn("foo", vec![], vec![Int(1)])],
175 Sym("a"),
176 List(vec![Sym("b"), Sym("c")]),
177 Sym("d"),
178 ])],
179 ), 254 ),
180 // (define x 42) 255 // (fn add (x y) (+ x y))
181 ( 256 (
182 vec![ 257 vec![
183 LeftPar, 258 LeftPar,
184 Symbol("define"), 259 Symbol("fn"),
260 Symbol("add"),
261 LeftPar,
262 Symbol("x"),
263 Symbol("y"),
264 RightPar,
265 LeftPar,
266 Symbol("+"),
185 Symbol("x"), 267 Symbol("x"),
186 Number("42"), 268 Symbol("y"),
269 RightPar,
187 RightPar, 270 RightPar,
188 ], 271 ],
189 vec![List(vec![Sym("define"), Sym("x"), Int(42)])], 272 vec![Fn(
273 "add",
274 vec!["x", "y"],
275 vec![Call("+", vec![Sym("x"), Sym("y")])],
276 )],
190 ), 277 ),
191 // (1 2.5 "s" foo true nil) 278 // (fn id (x) x x)
192 ( 279 (
193 vec![ 280 vec![
194 LeftPar, 281 LeftPar,
282 Symbol("fn"),
283 Symbol("id"),
284 LeftPar,
285 Symbol("x"),
286 RightPar,
287 Symbol("x"),
288 Symbol("x"),
289 RightPar,
290 ],
291 vec![Fn("id", vec!["x"], vec![Sym("x"), Sym("x")])],
292 ),
293 ];
294 for (tokens, ast) in cases {
295 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
296 }
297}
298
299#[test]
300fn test_const() {
301 let cases = vec![
302 // (const (x 1))
303 (
304 vec![
305 LeftPar,
306 Symbol("const"),
307 LeftPar,
308 Symbol("x"),
195 Number("1"), 309 Number("1"),
196 Number("-1"), 310 RightPar,
197 String("s"), 311 RightPar,
198 Symbol("foo"), 312 ],
199 Symbol("true"), 313 vec![Const(vec![("x", Int(1))])],
200 Symbol("nil"), 314 ),
315 // (const (x 1) (y 2))
316 (
317 vec![
318 LeftPar,
319 Symbol("const"),
320 LeftPar,
321 Symbol("x"),
322 Number("1"),
323 RightPar,
324 LeftPar,
325 Symbol("y"),
326 Number("2"),
327 RightPar,
328 RightPar,
329 ],
330 vec![Const(vec![("x", Int(1)), ("y", Int(2))])],
331 ),
332 ];
333 for (tokens, ast) in cases {
334 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
335 }
336}
337
338#[test]
339fn test_let() {
340 let cases = vec![
341 // (let ((x 1)) x)
342 (
343 vec![
344 LeftPar,
345 Symbol("let"),
346 LeftPar,
347 LeftPar,
348 Symbol("x"),
349 Number("1"),
350 RightPar,
351 RightPar,
352 Symbol("x"),
353 RightPar,
354 ],
355 vec![Let(vec![("x", Int(1))], vec![Sym("x")])],
356 ),
357 // (let ((x 1) (y 2)) (+ x y))
358 (
359 vec![
360 LeftPar,
361 Symbol("let"),
362 LeftPar,
363 LeftPar,
364 Symbol("x"),
365 Number("1"),
366 RightPar,
367 LeftPar,
368 Symbol("y"),
369 Number("2"),
370 RightPar,
371 RightPar,
372 LeftPar,
373 Symbol("+"),
374 Symbol("x"),
375 Symbol("y"),
376 RightPar,
377 RightPar,
378 ],
379 vec![Let(
380 vec![("x", Int(1)), ("y", Int(2))],
381 vec![Call("+", vec![Sym("x"), Sym("y")])],
382 )],
383 ),
384 ];
385 for (tokens, ast) in cases {
386 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
387 }
388}
389
390#[test]
391fn test_for() {
392 let cases = vec![
393 // (for i from 0 to 10 i)
394 (
395 vec![
396 LeftPar,
397 Symbol("for"),
398 Symbol("i"),
399 Symbol("from"),
400 Number("0"),
401 Symbol("to"),
402 Number("10"),
403 Symbol("i"),
404 RightPar,
405 ],
406 vec![For(
407 "i",
408 Box::new(Int(0)),
409 Box::new(Int(10)),
410 vec![Sym("i")],
411 )],
412 ),
413 // (for i from 0 to 10 i (+ i 1))
414 (
415 vec![
416 LeftPar,
417 Symbol("for"),
418 Symbol("i"),
419 Symbol("from"),
420 Number("0"),
421 Symbol("to"),
422 Number("10"),
423 Symbol("i"),
424 LeftPar,
425 Symbol("+"),
426 Symbol("i"),
427 Number("1"),
428 RightPar,
429 RightPar,
430 ],
431 vec![For(
432 "i",
433 Box::new(Int(0)),
434 Box::new(Int(10)),
435 vec![Sym("i"), Call("+", vec![Sym("i"), Int(1)])],
436 )],
437 ),
438 ];
439 for (tokens, ast) in cases {
440 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
441 }
442}
443
444#[test]
445fn test_set() {
446 let cases = vec![
447 // (set x 5)
448 (
449 vec![LeftPar, Symbol("set"), Symbol("x"), Number("5"), RightPar],
450 vec![Set("x", Box::new(Int(5)))],
451 ),
452 // (set x (+ x 1))
453 (
454 vec![
455 LeftPar,
456 Symbol("set"),
457 Symbol("x"),
458 LeftPar,
459 Symbol("+"),
460 Symbol("x"),
461 Number("1"),
462 RightPar,
463 RightPar,
464 ],
465 vec![Set("x", Box::new(Call("+", vec![Sym("x"), Int(1)])))],
466 ),
467 ];
468 for (tokens, ast) in cases {
469 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
470 }
471}
472
473#[test]
474fn test_do() {
475 let cases = vec![
476 // (do 1)
477 (
478 vec![LeftPar, Symbol("do"), Number("1"), RightPar],
479 vec![Do(vec![Int(1)])],
480 ),
481 // (do 1 2 3)
482 (
483 vec![
484 LeftPar,
485 Symbol("do"),
486 Number("1"),
487 Number("2"),
488 Number("3"),
201 RightPar, 489 RightPar,
202 ], 490 ],
203 vec![List(vec![ 491 vec![Do(vec![Int(1), Int(2), Int(3)])],
204 Int(1),
205 Int(-1),
206 Str("s"),
207 Sym("foo"),
208 Bool(true),
209 Nil,
210 ])],
211 ), 492 ),
212 ]; 493 ];
213 for (tokens, ast) in cases { 494 for (tokens, ast) in cases {
@@ -226,12 +507,14 @@ fn test_top_level() {
226 vec![ 507 vec![
227 LeftPar, 508 LeftPar,
228 Symbol("a"), 509 Symbol("a"),
510 Number("1"),
229 RightPar, 511 RightPar,
230 LeftPar, 512 LeftPar,
231 Symbol("b"), 513 Symbol("b"),
514 Number("2"),
232 RightPar, 515 RightPar,
233 ], 516 ],
234 vec![List(vec![Sym("a")]), List(vec![Sym("b")])], 517 vec![Call("a", vec![Int(1)]), Call("b", vec![Int(2)])],
235 ), 518 ),
236 ]; 519 ];
237 for (tokens, expected) in cases { 520 for (tokens, expected) in cases {
@@ -244,32 +527,103 @@ fn parse_err(tokens: Vec<Token<'static>>) -> Error {
244} 527}
245 528
246#[test] 529#[test]
247fn test_unexpected_right_par() { 530fn test_unexpected_close_par() {
248 let cases = vec![ 531 let cases = vec![
532 // )
249 vec![RightPar], 533 vec![RightPar],
534 // 1 )
250 vec![Number("1"), RightPar], 535 vec![Number("1"), RightPar],
536 // (a) )
251 vec![LeftPar, Symbol("a"), RightPar, RightPar], 537 vec![LeftPar, Symbol("a"), RightPar, RightPar],
538 // (do)
539 vec![LeftPar, Symbol("do"), RightPar],
540 // (set x)
541 vec![LeftPar, Symbol("set"), Symbol("x"), RightPar],
542 // (let ((x 1)))
543 vec![
544 LeftPar,
545 Symbol("let"),
546 LeftPar,
547 LeftPar,
548 Symbol("x"),
549 Number("1"),
550 RightPar,
551 RightPar,
552 RightPar,
553 ],
252 ]; 554 ];
253 for tokens in cases { 555 for tokens in cases {
254 assert_eq!( 556 assert_eq!(
255 parse_err(tokens.clone()), 557 parse_err(tokens.clone()),
256 Error::UnexpectedRightPar, 558 Error::UnexpectedClosePar,
257 "input: {tokens:?}" 559 "input: {tokens:?}"
258 ); 560 );
259 } 561 }
260} 562}
261 563
262#[test] 564#[test]
263fn test_unclosed_left_par() { 565fn test_unclosed_par() {
264 let cases = vec![ 566 let cases = vec![
567 // (foo
568 vec![LeftPar, Symbol("foo")],
569 // (foo 1
570 vec![LeftPar, Symbol("foo"), Number("1")],
571 // (foo 1 2
572 vec![LeftPar, Symbol("foo"), Number("1"), Number("2")],
573 // (foo (bar 1)
574 vec![
575 LeftPar,
576 Symbol("foo"),
577 LeftPar,
578 Symbol("bar"),
579 Number("1"),
580 RightPar,
581 ],
582 ];
583 for tokens in cases {
584 assert_eq!(
585 parse_err(tokens.clone()),
586 Error::UnclosedPar,
587 "input: {tokens:?}"
588 );
589 }
590}
591
592#[test]
593fn test_unexpected_eof() {
594 let cases = vec![
595 // (
265 vec![LeftPar], 596 vec![LeftPar],
266 vec![LeftPar, Number("1")], 597 // (fn foo ()
267 vec![LeftPar, LeftPar, Symbol("a"), RightPar], 598 vec![LeftPar, Symbol("fn"), Symbol("foo"), LeftPar, RightPar],
268 ]; 599 ];
269 for tokens in cases { 600 for tokens in cases {
270 assert_eq!( 601 assert_eq!(
271 parse_err(tokens.clone()), 602 parse_err(tokens.clone()),
272 Error::UnclosedLeftPar, 603 Error::UnexpectedEof,
604 "input: {tokens:?}"
605 );
606 }
607}
608
609#[test]
610fn test_unexpected_token() {
611 let cases = vec![
612 // (1 2 3)
613 vec![LeftPar, Number("1"), Number("2"), Number("3"), RightPar],
614 // (())
615 vec![LeftPar, LeftPar, RightPar, RightPar],
616 // ("hello")
617 vec![LeftPar, String("hello"), RightPar],
618 // (for)
619 vec![LeftPar, Symbol("for"), RightPar],
620 // (fn)
621 vec![LeftPar, Symbol("fn"), RightPar],
622 ];
623 for tokens in cases {
624 assert_eq!(
625 parse_err(tokens.clone()),
626 Error::UnexpectedToken,
273 "input: {tokens:?}" 627 "input: {tokens:?}"
274 ); 628 );
275 } 629 }
@@ -329,18 +683,34 @@ fn test_unexpected_escape_char_propagates() {
329 ); 683 );
330} 684}
331 685
686fn run_with_large_stack(f: impl FnOnce() + Send + 'static) {
687 std::thread::Builder::new()
688 .stack_size(8 * 1024 * 1024)
689 .spawn(f)
690 .unwrap()
691 .join()
692 .unwrap();
693}
694
332#[test] 695#[test]
333fn test_recursion_limit() { 696fn test_recursion_limit() {
334 let mut tokens = Vec::with_capacity(MAX_DEPTH * 2); 697 run_with_large_stack(|| {
335 tokens.extend(repeat_n(LeftPar, MAX_DEPTH)); 698 let n = MAX_DEPTH + 1;
336 tokens.extend(repeat_n(RightPar, MAX_DEPTH)); 699 let mut tokens = Vec::with_capacity(n * 2 + 1 + n);
337 assert_eq!( 700 for _ in 0..n {
338 parse_err(tokens), 701 tokens.push(LeftPar);
339 Error::RecursionLimit, 702 tokens.push(Symbol("foo"));
340 "input: {} LeftPar then {} RightPar", 703 }
341 MAX_DEPTH, 704 tokens.push(Number("1"));
342 MAX_DEPTH, 705 for _ in 0..n {
343 ); 706 tokens.push(RightPar);
707 }
708 assert_eq!(
709 parse_err(tokens),
710 Error::RecursionLimit,
711 "input: {n} nested calls",
712 );
713 });
344} 714}
345 715
346fn p(line: usize, column: usize, offset: usize) -> Pos { 716fn p(line: usize, column: usize, offset: usize) -> Pos {
@@ -360,8 +730,6 @@ fn parse_sp(tokens: Vec<Spanned<Token<'static>>>) -> Vec<Spanned<Expr>> {
360 .parse() 730 .parse()
361 .unwrap() 731 .unwrap()
362 .into_inner() 732 .into_inner()
363 .into_iter()
364 .collect()
365} 733}
366 734
367fn parse_sp_err(tokens: Vec<Spanned<Token<'static>>>) -> Spanned<Error> { 735fn parse_sp_err(tokens: Vec<Spanned<Token<'static>>>) -> Spanned<Error> {
@@ -378,26 +746,33 @@ fn test_span_atom() {
378} 746}
379 747
380#[test] 748#[test]
381fn test_span_list_covers_parens() { 749fn test_span_call_covers_parens() {
382 // (foo) 750 // (foo 1)
383 let lp = sp((1, 0, 0), (1, 1, 1)); 751 let lp = sp((1, 0, 0), (1, 1, 1));
384 let foo = sp((1, 1, 1), (1, 4, 4)); 752 let foo = sp((1, 1, 1), (1, 4, 4));
385 let rp = sp((1, 4, 4), (1, 5, 5)); 753 let one = sp((1, 5, 5), (1, 6, 6));
386 let tokens = vec![tsp(LeftPar, lp), tsp(Symbol("foo"), foo), tsp(RightPar, rp)]; 754 let rp = sp((1, 6, 6), (1, 7, 7));
755 let tokens = vec![
756 tsp(LeftPar, lp),
757 tsp(Symbol("foo"), foo),
758 tsp(Number("1"), one),
759 tsp(RightPar, rp),
760 ];
387 let prog = parse_sp(tokens.clone()); 761 let prog = parse_sp(tokens.clone());
388 762
389 assert_eq!(prog[0].span, sp((1, 0, 0), (1, 5, 5)), "input: {tokens:?}"); 763 assert_eq!(prog[0].span, sp((1, 0, 0), (1, 7, 7)), "input: {tokens:?}");
390 764
391 if let Expr::List(items) = &prog[0].inner { 765 if let Expr::Call { fn_name, args } = &prog[0].inner {
392 assert_eq!(items[0].span, foo, "input: {tokens:?}"); 766 assert_eq!(fn_name.span, foo, "input: {tokens:?}");
767 assert_eq!(args[0].span, one, "input: {tokens:?}");
393 } else { 768 } else {
394 panic!("expected list, input: {tokens:?}"); 769 panic!("expected call, input: {tokens:?}");
395 } 770 }
396} 771}
397 772
398#[test] 773#[test]
399fn test_span_empty_list_covers_parens() { 774fn test_span_empty_list_covers_parens() {
400 // () -> Atom::Nil, span [0..2] 775 // ()
401 let lp = sp((1, 0, 0), (1, 1, 1)); 776 let lp = sp((1, 0, 0), (1, 1, 1));
402 let rp = sp((1, 1, 1), (1, 2, 2)); 777 let rp = sp((1, 1, 1), (1, 2, 2));
403 let tokens = vec![tsp(LeftPar, lp), tsp(RightPar, rp)]; 778 let tokens = vec![tsp(LeftPar, lp), tsp(RightPar, rp)];
@@ -408,12 +783,13 @@ fn test_span_empty_list_covers_parens() {
408} 783}
409 784
410#[test] 785#[test]
411fn test_error_span_unexpected_right_par() { 786fn test_error_span_unexpected_close_par() {
787 // )
412 let s = sp((1, 5, 5), (1, 6, 6)); 788 let s = sp((1, 5, 5), (1, 6, 6));
413 let tokens = vec![tsp(RightPar, s)]; 789 let tokens = vec![tsp(RightPar, s)];
414 let err = parse_sp_err(tokens.clone()); 790 let err = parse_sp_err(tokens.clone());
415 791
416 assert_eq!(err.inner, Error::UnexpectedRightPar, "input: {tokens:?}"); 792 assert_eq!(err.inner, Error::UnexpectedClosePar, "input: {tokens:?}");
417 assert_eq!(err.span, s, "input: {tokens:?}"); 793 assert_eq!(err.span, s, "input: {tokens:?}");
418} 794}
419 795
@@ -427,27 +803,68 @@ fn test_error_span_invalid_integer() {
427} 803}
428 804
429#[test] 805#[test]
430fn test_error_span_unclosed_left_par() { 806fn test_error_span_unclosed_par() {
807 // (foo 1
431 let lp = sp((1, 0, 0), (1, 1, 1)); 808 let lp = sp((1, 0, 0), (1, 1, 1));
432 let tokens = vec![tsp(LeftPar, lp)]; 809 let foo = sp((1, 1, 1), (1, 4, 4));
810 let one = sp((1, 5, 5), (1, 6, 6));
811 let tokens = vec![
812 tsp(LeftPar, lp),
813 tsp(Symbol("foo"), foo),
814 tsp(Number("1"), one),
815 ];
433 let err = parse_sp_err(tokens.clone()); 816 let err = parse_sp_err(tokens.clone());
434 817
435 assert_eq!(err.inner, Error::UnclosedLeftPar, "input: {tokens:?}"); 818 assert_eq!(err.inner, Error::UnclosedPar, "input: {tokens:?}");
436 assert_eq!(err.span, lp, "input: {tokens:?}"); 819 assert_eq!(err.span, lp, "input: {tokens:?}");
437} 820}
438 821
439#[test] 822#[test]
440fn test_error_span_unclosed_left_par_nested() { 823fn test_error_span_unclosed_par_nested() {
824 // (foo (bar 1
441 let outer = sp((1, 0, 0), (1, 1, 1)); 825 let outer = sp((1, 0, 0), (1, 1, 1));
442 let inner = sp((1, 2, 2), (1, 3, 3)); 826 let foo = sp((1, 1, 1), (1, 4, 4));
443 let tokens = vec![tsp(LeftPar, outer), tsp(LeftPar, inner)]; 827 let inner = sp((1, 5, 5), (1, 6, 6));
828 let bar = sp((1, 6, 6), (1, 9, 9));
829 let one = sp((1, 10, 10), (1, 11, 11));
830 let tokens = vec![
831 tsp(LeftPar, outer),
832 tsp(Symbol("foo"), foo),
833 tsp(LeftPar, inner),
834 tsp(Symbol("bar"), bar),
835 tsp(Number("1"), one),
836 ];
444 let err = parse_sp_err(tokens.clone()); 837 let err = parse_sp_err(tokens.clone());
445 838
446 assert_eq!(err.inner, Error::UnclosedLeftPar, "input: {tokens:?}"); 839 assert_eq!(err.inner, Error::UnclosedPar, "input: {tokens:?}");
447 assert_eq!(err.span, inner, "input: {tokens:?}"); 840 assert_eq!(err.span, inner, "input: {tokens:?}");
448} 841}
449 842
450#[test] 843#[test]
844fn test_error_span_unexpected_eof() {
845 // (
846 let lp = sp((1, 0, 0), (1, 1, 1));
847 let tokens = vec![tsp(LeftPar, lp)];
848 let err = parse_sp_err(tokens.clone());
849
850 assert_eq!(err.inner, Error::UnexpectedEof, "input: {tokens:?}");
851 assert_eq!(err.span, lp, "input: {tokens:?}");
852}
853
854#[test]
855fn test_error_span_unexpected_token() {
856 // (1)
857 let lp = sp((1, 0, 0), (1, 1, 1));
858 let one = sp((1, 1, 1), (1, 2, 2));
859 let rp = sp((1, 2, 2), (1, 3, 3));
860 let tokens = vec![tsp(LeftPar, lp), tsp(Number("1"), one), tsp(RightPar, rp)];
861 let err = parse_sp_err(tokens.clone());
862
863 assert_eq!(err.inner, Error::UnexpectedToken, "input: {tokens:?}");
864 assert_eq!(err.span, one, "input: {tokens:?}");
865}
866
867#[test]
451fn test_error_span_unclosed_string() { 868fn test_error_span_unclosed_string() {
452 let s = sp((1, 0, 0), (1, 7, 7)); 869 let s = sp((1, 0, 0), (1, 7, 7));
453 let tokens = vec![tsp(UnclosedString("oops"), s)]; 870 let tokens = vec![tsp(UnclosedString("oops"), s)];
@@ -477,16 +894,16 @@ fn test_error_span_unexpected_escape_char() {
477 894
478#[test] 895#[test]
479fn test_error_span_deep_nested() { 896fn test_error_span_deep_nested() {
480 // (a (b (c BAD))) 897 // (foo (bar (baz 99999999999999999999)))
481 let bad_span = sp((1, 9, 9), (1, 29, 29)); 898 let bad_span = sp((1, 9, 9), (1, 29, 29));
482 let any = sp((1, 0, 0), (1, 1, 1)); 899 let any = sp((1, 0, 0), (1, 1, 1));
483 let tokens = vec![ 900 let tokens = vec![
484 tsp(LeftPar, any), 901 tsp(LeftPar, any),
485 tsp(Symbol("a"), any), 902 tsp(Symbol("foo"), any),
486 tsp(LeftPar, any), 903 tsp(LeftPar, any),
487 tsp(Symbol("b"), any), 904 tsp(Symbol("bar"), any),
488 tsp(LeftPar, any), 905 tsp(LeftPar, any),
489 tsp(Symbol("c"), any), 906 tsp(Symbol("baz"), any),
490 tsp(Number("99999999999999999999"), bad_span), 907 tsp(Number("99999999999999999999"), bad_span),
491 tsp(RightPar, any), 908 tsp(RightPar, any),
492 tsp(RightPar, any), 909 tsp(RightPar, any),
@@ -504,14 +921,707 @@ fn test_error_span_deep_nested() {
504 921
505#[test] 922#[test]
506fn test_error_span_recursion_limit() { 923fn test_error_span_recursion_limit() {
507 let mut tokens = Vec::with_capacity(MAX_DEPTH); 924 run_with_large_stack(|| {
508 for i in 0..MAX_DEPTH { 925 let any = sp((0, 0, 0), (0, 0, 0));
509 let s = sp((1, i, i), (1, i + 1, i + 1)); 926 let mut tokens = Vec::with_capacity((MAX_DEPTH + 1) * 2);
510 tokens.push(tsp(LeftPar, s)); 927 for i in 0..=MAX_DEPTH {
928 let s = sp((1, i, i), (1, i + 1, i + 1));
929 tokens.push(tsp(LeftPar, s));
930 tokens.push(tsp(Symbol("foo"), any));
931 }
932 let trigger = sp((1, MAX_DEPTH, MAX_DEPTH), (1, MAX_DEPTH + 1, MAX_DEPTH + 1));
933 let err = parse_sp_err(tokens);
934
935 assert_eq!(err.inner, Error::RecursionLimit, "MAX_DEPTH={MAX_DEPTH}");
936 assert_eq!(err.span, trigger, "MAX_DEPTH={MAX_DEPTH}");
937 });
938}
939
940#[test]
941fn test_keyword_prefixed_symbols() {
942 let cases = vec![
943 (vec![Symbol("fn-foo")], vec![Sym("fn-foo")]),
944 (vec![Symbol("let1")], vec![Sym("let1")]),
945 (vec![Symbol("from-here")], vec![Sym("from-here")]),
946 (vec![Symbol("do!")], vec![Sym("do!")]),
947 (vec![Symbol("set?")], vec![Sym("set?")]),
948 (vec![Symbol("for-each")], vec![Sym("for-each")]),
949 (vec![Symbol("const-x")], vec![Sym("const-x")]),
950 // (fn-foo 1)
951 (
952 vec![LeftPar, Symbol("fn-foo"), Number("1"), RightPar],
953 vec![Call("fn-foo", vec![Int(1)])],
954 ),
955 // (set! x 1)
956 (
957 vec![LeftPar, Symbol("set!"), Symbol("x"), Number("1"), RightPar],
958 vec![Call("set!", vec![Sym("x"), Int(1)])],
959 ),
960 ];
961 for (tokens, ast) in cases {
962 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
963 }
964}
965
966#[test]
967fn test_long_symbol() {
968 let long: &'static str = leak(&"a".repeat(10_000));
969 let tokens = vec![Symbol(long)];
970 assert_eq!(parse(tokens), vec![Sym(long)]);
971}
972
973#[test]
974fn test_signed_zero() {
975 let cases = vec![
976 (vec![Number("+0")], vec![Int(0)]),
977 (vec![Number("-0")], vec![Int(0)]),
978 ];
979 for (tokens, ast) in cases {
980 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
981 }
982}
983
984#[test]
985fn test_double_backslash_in_string() {
986 let cases = vec![
987 (vec![String(r"\\")], vec![Str("\\")]),
988 (vec![String(r"a\\b")], vec![Str("a\\b")]),
989 (vec![String(r"\\\\")], vec![Str("\\\\")]),
990 ];
991 for (tokens, ast) in cases {
992 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
993 }
994}
995
996#[test]
997fn test_nil_as_value() {
998 let cases = vec![
999 // (foo () bar)
1000 (
1001 vec![
1002 LeftPar,
1003 Symbol("foo"),
1004 LeftPar,
1005 RightPar,
1006 Symbol("bar"),
1007 RightPar,
1008 ],
1009 vec![Call("foo", vec![Nil, Sym("bar")])],
1010 ),
1011 // (do () nil ())
1012 (
1013 vec![
1014 LeftPar,
1015 Symbol("do"),
1016 LeftPar,
1017 RightPar,
1018 Symbol("nil"),
1019 LeftPar,
1020 RightPar,
1021 RightPar,
1022 ],
1023 vec![Do(vec![Nil, Nil, Nil])],
1024 ),
1025 ];
1026 for (tokens, ast) in cases {
1027 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
1028 }
1029}
1030
1031#[test]
1032fn test_special_form_errors() {
1033 let cases = vec![
1034 // (fn foo)
1035 (
1036 vec![LeftPar, Symbol("fn"), Symbol("foo"), RightPar],
1037 Error::UnexpectedToken,
1038 ),
1039 // (fn foo bar)
1040 (
1041 vec![
1042 LeftPar,
1043 Symbol("fn"),
1044 Symbol("foo"),
1045 Symbol("bar"),
1046 RightPar,
1047 ],
1048 Error::UnexpectedToken,
1049 ),
1050 // (fn 1 2)
1051 (
1052 vec![LeftPar, Symbol("fn"), Number("1"), Number("2"), RightPar],
1053 Error::UnexpectedToken,
1054 ),
1055 // (fn foo (1) body)
1056 (
1057 vec![
1058 LeftPar,
1059 Symbol("fn"),
1060 Symbol("foo"),
1061 LeftPar,
1062 Number("1"),
1063 RightPar,
1064 Symbol("body"),
1065 RightPar,
1066 ],
1067 Error::UnexpectedToken,
1068 ),
1069 // (let)
1070 (
1071 vec![LeftPar, Symbol("let"), RightPar],
1072 Error::UnexpectedToken,
1073 ),
1074 // (let () body)
1075 (
1076 vec![
1077 LeftPar,
1078 Symbol("let"),
1079 LeftPar,
1080 RightPar,
1081 Symbol("body"),
1082 RightPar,
1083 ],
1084 Error::UnexpectedToken,
1085 ),
1086 // (for i)
1087 (
1088 vec![LeftPar, Symbol("for"), Symbol("i"), RightPar],
1089 Error::UnexpectedToken,
1090 ),
1091 // (for i from 0)
1092 (
1093 vec![
1094 LeftPar,
1095 Symbol("for"),
1096 Symbol("i"),
1097 Symbol("from"),
1098 Number("0"),
1099 RightPar,
1100 ],
1101 Error::UnexpectedToken,
1102 ),
1103 // (for i from 0 to)
1104 (
1105 vec![
1106 LeftPar,
1107 Symbol("for"),
1108 Symbol("i"),
1109 Symbol("from"),
1110 Number("0"),
1111 Symbol("to"),
1112 RightPar,
1113 ],
1114 Error::UnexpectedClosePar,
1115 ),
1116 // (for i wrong 0 to 10 body)
1117 (
1118 vec![
1119 LeftPar,
1120 Symbol("for"),
1121 Symbol("i"),
1122 Symbol("wrong"),
1123 Number("0"),
1124 Symbol("to"),
1125 Number("10"),
1126 Symbol("body"),
1127 RightPar,
1128 ],
1129 Error::UnexpectedToken,
1130 ),
1131 // (set x y z)
1132 (
1133 vec![
1134 LeftPar,
1135 Symbol("set"),
1136 Symbol("x"),
1137 Symbol("y"),
1138 Symbol("z"),
1139 RightPar,
1140 ],
1141 Error::UnexpectedToken,
1142 ),
1143 // (const)
1144 (
1145 vec![LeftPar, Symbol("const"), RightPar],
1146 Error::UnexpectedToken,
1147 ),
1148 // (const ())
1149 (
1150 vec![LeftPar, Symbol("const"), LeftPar, RightPar, RightPar],
1151 Error::UnexpectedToken,
1152 ),
1153 ];
1154 for (tokens, expected) in cases {
1155 assert_eq!(parse_err(tokens.clone()), expected, "input: {tokens:?}");
1156 }
1157}
1158
1159#[test]
1160fn test_stops_at_first_error() {
1161 let cases = vec![
1162 // ) ) )
1163 (
1164 vec![RightPar, RightPar, RightPar],
1165 Error::UnexpectedClosePar,
1166 ),
1167 // 1 ) 2
1168 (
1169 vec![Number("1"), RightPar, Number("2")],
1170 Error::UnexpectedClosePar,
1171 ),
1172 ];
1173 for (tokens, expected) in cases {
1174 assert_eq!(parse_err(tokens.clone()), expected, "input: {tokens:?}");
1175 }
1176 // 99999999999999999999 )
1177 let tokens = vec![Number("99999999999999999999"), RightPar];
1178 let err = parse_err(tokens.clone());
1179 assert!(
1180 matches!(err, Error::InvalidIntegerLiteral(..)),
1181 "input: {tokens:?}, got: {err:?}",
1182 );
1183}
1184
1185#[test]
1186fn test_nested_special_forms() {
1187 let cases = vec![
1188 // (do (do 1))
1189 (
1190 vec![
1191 LeftPar,
1192 Symbol("do"),
1193 LeftPar,
1194 Symbol("do"),
1195 Number("1"),
1196 RightPar,
1197 RightPar,
1198 ],
1199 vec![Do(vec![Do(vec![Int(1)])])],
1200 ),
1201 // (fn outer () (fn inner () 1))
1202 (
1203 vec![
1204 LeftPar,
1205 Symbol("fn"),
1206 Symbol("outer"),
1207 LeftPar,
1208 RightPar,
1209 LeftPar,
1210 Symbol("fn"),
1211 Symbol("inner"),
1212 LeftPar,
1213 RightPar,
1214 Number("1"),
1215 RightPar,
1216 RightPar,
1217 ],
1218 vec![Fn("outer", vec![], vec![Fn("inner", vec![], vec![Int(1)])])],
1219 ),
1220 // (let ((x (let ((y 1)) y))) x)
1221 (
1222 vec![
1223 LeftPar,
1224 Symbol("let"),
1225 LeftPar,
1226 LeftPar,
1227 Symbol("x"),
1228 LeftPar,
1229 Symbol("let"),
1230 LeftPar,
1231 LeftPar,
1232 Symbol("y"),
1233 Number("1"),
1234 RightPar,
1235 RightPar,
1236 Symbol("y"),
1237 RightPar,
1238 RightPar,
1239 RightPar,
1240 Symbol("x"),
1241 RightPar,
1242 ],
1243 vec![Let(
1244 vec![("x", Let(vec![("y", Int(1))], vec![Sym("y")]))],
1245 vec![Sym("x")],
1246 )],
1247 ),
1248 // (for i from 0 to (+ 1 2) (set sum (+ sum i)))
1249 (
1250 vec![
1251 LeftPar,
1252 Symbol("for"),
1253 Symbol("i"),
1254 Symbol("from"),
1255 Number("0"),
1256 Symbol("to"),
1257 LeftPar,
1258 Symbol("+"),
1259 Number("1"),
1260 Number("2"),
1261 RightPar,
1262 LeftPar,
1263 Symbol("set"),
1264 Symbol("sum"),
1265 LeftPar,
1266 Symbol("+"),
1267 Symbol("sum"),
1268 Symbol("i"),
1269 RightPar,
1270 RightPar,
1271 RightPar,
1272 ],
1273 vec![For(
1274 "i",
1275 Box::new(Int(0)),
1276 Box::new(Call("+", vec![Int(1), Int(2)])),
1277 vec![Set("sum", Box::new(Call("+", vec![Sym("sum"), Sym("i")])))],
1278 )],
1279 ),
1280 // (let ((x 1)) x (+ x 1))
1281 (
1282 vec![
1283 LeftPar,
1284 Symbol("let"),
1285 LeftPar,
1286 LeftPar,
1287 Symbol("x"),
1288 Number("1"),
1289 RightPar,
1290 RightPar,
1291 Symbol("x"),
1292 LeftPar,
1293 Symbol("+"),
1294 Symbol("x"),
1295 Number("1"),
1296 RightPar,
1297 RightPar,
1298 ],
1299 vec![Let(
1300 vec![("x", Int(1))],
1301 vec![Sym("x"), Call("+", vec![Sym("x"), Int(1)])],
1302 )],
1303 ),
1304 ];
1305 for (tokens, ast) in cases {
1306 assert_eq!(parse(tokens.clone()), ast, "input: {tokens:?}");
1307 }
1308}
1309
1310#[test]
1311fn test_smoke_program() {
1312 // (const (x 1))
1313 // (fn add (a b) (+ a b))
1314 // (let ((y 2)) (add x y))
1315 let tokens = vec![
1316 LeftPar,
1317 Symbol("const"),
1318 LeftPar,
1319 Symbol("x"),
1320 Number("1"),
1321 RightPar,
1322 RightPar,
1323 LeftPar,
1324 Symbol("fn"),
1325 Symbol("add"),
1326 LeftPar,
1327 Symbol("a"),
1328 Symbol("b"),
1329 RightPar,
1330 LeftPar,
1331 Symbol("+"),
1332 Symbol("a"),
1333 Symbol("b"),
1334 RightPar,
1335 RightPar,
1336 LeftPar,
1337 Symbol("let"),
1338 LeftPar,
1339 LeftPar,
1340 Symbol("y"),
1341 Number("2"),
1342 RightPar,
1343 RightPar,
1344 LeftPar,
1345 Symbol("add"),
1346 Symbol("x"),
1347 Symbol("y"),
1348 RightPar,
1349 RightPar,
1350 ];
1351 let expected = vec![
1352 Const(vec![("x", Int(1))]),
1353 Fn(
1354 "add",
1355 vec!["a", "b"],
1356 vec![Call("+", vec![Sym("a"), Sym("b")])],
1357 ),
1358 Let(
1359 vec![("y", Int(2))],
1360 vec![Call("add", vec![Sym("x"), Sym("y")])],
1361 ),
1362 ];
1363 assert_eq!(parse(tokens), expected);
1364}
1365
1366#[test]
1367fn test_recursion_limit_via_do() {
1368 run_with_large_stack(|| {
1369 let n = MAX_DEPTH + 1;
1370 let mut tokens = Vec::with_capacity(n * 2 + 1 + n);
1371 for _ in 0..n {
1372 tokens.push(LeftPar);
1373 tokens.push(Symbol("do"));
1374 }
1375 tokens.push(Number("1"));
1376 for _ in 0..n {
1377 tokens.push(RightPar);
1378 }
1379 assert_eq!(parse_err(tokens), Error::RecursionLimit);
1380 });
1381}
1382
1383#[test]
1384fn test_span_fn() {
1385 // (fn id (x) x)
1386 let lp = sp((1, 0, 0), (1, 1, 1));
1387 let kw = sp((1, 1, 1), (1, 3, 3));
1388 let name = sp((1, 4, 4), (1, 6, 6));
1389 let lp_args = sp((1, 7, 7), (1, 8, 8));
1390 let arg = sp((1, 8, 8), (1, 9, 9));
1391 let rp_args = sp((1, 9, 9), (1, 10, 10));
1392 let body_x = sp((1, 11, 11), (1, 12, 12));
1393 let rp = sp((1, 12, 12), (1, 13, 13));
1394
1395 let tokens = vec![
1396 tsp(LeftPar, lp),
1397 tsp(Symbol("fn"), kw),
1398 tsp(Symbol("id"), name),
1399 tsp(LeftPar, lp_args),
1400 tsp(Symbol("x"), arg),
1401 tsp(RightPar, rp_args),
1402 tsp(Symbol("x"), body_x),
1403 tsp(RightPar, rp),
1404 ];
1405 let prog = parse_sp(tokens.clone());
1406
1407 assert_eq!(
1408 prog[0].span,
1409 sp((1, 0, 0), (1, 13, 13)),
1410 "input: {tokens:?}"
1411 );
1412 if let Expr::Fn {
1413 name: n,
1414 args,
1415 body,
1416 } = &prog[0].inner
1417 {
1418 assert_eq!(n.span, name, "input: {tokens:?}");
1419 assert_eq!(args[0].span, arg, "input: {tokens:?}");
1420 assert_eq!(body[0].span, body_x, "input: {tokens:?}");
1421 } else {
1422 panic!("expected Fn, input: {tokens:?}");
1423 }
1424}
1425
1426#[test]
1427fn test_span_let() {
1428 // (let ((x 1)) x)
1429 let lp = sp((1, 0, 0), (1, 1, 1));
1430 let kw = sp((1, 1, 1), (1, 4, 4));
1431 let lp_vars = sp((1, 5, 5), (1, 6, 6));
1432 let lp_var = sp((1, 6, 6), (1, 7, 7));
1433 let x_name = sp((1, 7, 7), (1, 8, 8));
1434 let one = sp((1, 9, 9), (1, 10, 10));
1435 let rp_var = sp((1, 10, 10), (1, 11, 11));
1436 let rp_vars = sp((1, 11, 11), (1, 12, 12));
1437 let body_x = sp((1, 13, 13), (1, 14, 14));
1438 let rp = sp((1, 14, 14), (1, 15, 15));
1439
1440 let tokens = vec![
1441 tsp(LeftPar, lp),
1442 tsp(Symbol("let"), kw),
1443 tsp(LeftPar, lp_vars),
1444 tsp(LeftPar, lp_var),
1445 tsp(Symbol("x"), x_name),
1446 tsp(Number("1"), one),
1447 tsp(RightPar, rp_var),
1448 tsp(RightPar, rp_vars),
1449 tsp(Symbol("x"), body_x),
1450 tsp(RightPar, rp),
1451 ];
1452 let prog = parse_sp(tokens.clone());
1453
1454 assert_eq!(
1455 prog[0].span,
1456 sp((1, 0, 0), (1, 15, 15)),
1457 "input: {tokens:?}"
1458 );
1459 if let Expr::Let { vars, body } = &prog[0].inner {
1460 assert_eq!(
1461 vars[0].span,
1462 sp((1, 6, 6), (1, 11, 11)),
1463 "input: {tokens:?}"
1464 );
1465 assert_eq!(vars[0].inner.name.span, x_name, "input: {tokens:?}");
1466 assert_eq!(vars[0].inner.expr.span, one, "input: {tokens:?}");
1467 assert_eq!(body[0].span, body_x, "input: {tokens:?}");
1468 } else {
1469 panic!("expected Let, input: {tokens:?}");
1470 }
1471}
1472
1473#[test]
1474fn test_span_for() {
1475 // (for i from 0 to 10 i)
1476 let lp = sp((1, 0, 0), (1, 1, 1));
1477 let kw = sp((1, 1, 1), (1, 4, 4));
1478 let i = sp((1, 5, 5), (1, 6, 6));
1479 let from = sp((1, 7, 7), (1, 11, 11));
1480 let zero = sp((1, 12, 12), (1, 13, 13));
1481 let to = sp((1, 14, 14), (1, 16, 16));
1482 let ten = sp((1, 17, 17), (1, 19, 19));
1483 let body_i = sp((1, 20, 20), (1, 21, 21));
1484 let rp = sp((1, 21, 21), (1, 22, 22));
1485
1486 let tokens = vec![
1487 tsp(LeftPar, lp),
1488 tsp(Symbol("for"), kw),
1489 tsp(Symbol("i"), i),
1490 tsp(Symbol("from"), from),
1491 tsp(Number("0"), zero),
1492 tsp(Symbol("to"), to),
1493 tsp(Number("10"), ten),
1494 tsp(Symbol("i"), body_i),
1495 tsp(RightPar, rp),
1496 ];
1497 let prog = parse_sp(tokens.clone());
1498
1499 assert_eq!(
1500 prog[0].span,
1501 sp((1, 0, 0), (1, 22, 22)),
1502 "input: {tokens:?}"
1503 );
1504 if let Expr::For {
1505 loop_var,
1506 from: f,
1507 to: t,
1508 body,
1509 } = &prog[0].inner
1510 {
1511 assert_eq!(loop_var.span, i, "input: {tokens:?}");
1512 assert_eq!(f.span, zero, "input: {tokens:?}");
1513 assert_eq!(t.span, ten, "input: {tokens:?}");
1514 assert_eq!(body[0].span, body_i, "input: {tokens:?}");
1515 } else {
1516 panic!("expected For, input: {tokens:?}");
1517 }
1518}
1519
1520#[test]
1521fn test_span_set() {
1522 // (set x 5)
1523 let lp = sp((1, 0, 0), (1, 1, 1));
1524 let kw = sp((1, 1, 1), (1, 4, 4));
1525 let x = sp((1, 5, 5), (1, 6, 6));
1526 let five = sp((1, 7, 7), (1, 8, 8));
1527 let rp = sp((1, 8, 8), (1, 9, 9));
1528
1529 let tokens = vec![
1530 tsp(LeftPar, lp),
1531 tsp(Symbol("set"), kw),
1532 tsp(Symbol("x"), x),
1533 tsp(Number("5"), five),
1534 tsp(RightPar, rp),
1535 ];
1536 let prog = parse_sp(tokens.clone());
1537
1538 assert_eq!(prog[0].span, sp((1, 0, 0), (1, 9, 9)), "input: {tokens:?}");
1539 if let Expr::Set { target_var, expr } = &prog[0].inner {
1540 assert_eq!(target_var.span, x, "input: {tokens:?}");
1541 assert_eq!(expr.span, five, "input: {tokens:?}");
1542 } else {
1543 panic!("expected Set, input: {tokens:?}");
1544 }
1545}
1546
1547#[test]
1548fn test_span_do() {
1549 // (do 1 2)
1550 let lp = sp((1, 0, 0), (1, 1, 1));
1551 let kw = sp((1, 1, 1), (1, 3, 3));
1552 let one = sp((1, 4, 4), (1, 5, 5));
1553 let two = sp((1, 6, 6), (1, 7, 7));
1554 let rp = sp((1, 7, 7), (1, 8, 8));
1555
1556 let tokens = vec![
1557 tsp(LeftPar, lp),
1558 tsp(Symbol("do"), kw),
1559 tsp(Number("1"), one),
1560 tsp(Number("2"), two),
1561 tsp(RightPar, rp),
1562 ];
1563 let prog = parse_sp(tokens.clone());
1564
1565 assert_eq!(prog[0].span, sp((1, 0, 0), (1, 8, 8)), "input: {tokens:?}");
1566 if let Expr::Do { body } = &prog[0].inner {
1567 assert_eq!(body[0].span, one, "input: {tokens:?}");
1568 assert_eq!(body[1].span, two, "input: {tokens:?}");
1569 } else {
1570 panic!("expected Do, input: {tokens:?}");
511 } 1571 }
512 let trigger = sp((1, MAX_DEPTH - 1, MAX_DEPTH - 1), (1, MAX_DEPTH, MAX_DEPTH)); 1572}
513 let err = parse_sp_err(tokens);
514 1573
515 assert_eq!(err.inner, Error::RecursionLimit, "MAX_DEPTH={MAX_DEPTH}"); 1574#[test]
516 assert_eq!(err.span, trigger, "MAX_DEPTH={MAX_DEPTH}"); 1575fn test_span_const() {
1576 // (const (x 1) (y 2))
1577 let lp = sp((1, 0, 0), (1, 1, 1));
1578 let kw = sp((1, 1, 1), (1, 6, 6));
1579 let lp_x = sp((1, 7, 7), (1, 8, 8));
1580 let x_name = sp((1, 8, 8), (1, 9, 9));
1581 let one = sp((1, 10, 10), (1, 11, 11));
1582 let rp_x = sp((1, 11, 11), (1, 12, 12));
1583 let lp_y = sp((1, 13, 13), (1, 14, 14));
1584 let y_name = sp((1, 14, 14), (1, 15, 15));
1585 let two = sp((1, 16, 16), (1, 17, 17));
1586 let rp_y = sp((1, 17, 17), (1, 18, 18));
1587 let rp = sp((1, 18, 18), (1, 19, 19));
1588
1589 let tokens = vec![
1590 tsp(LeftPar, lp),
1591 tsp(Symbol("const"), kw),
1592 tsp(LeftPar, lp_x),
1593 tsp(Symbol("x"), x_name),
1594 tsp(Number("1"), one),
1595 tsp(RightPar, rp_x),
1596 tsp(LeftPar, lp_y),
1597 tsp(Symbol("y"), y_name),
1598 tsp(Number("2"), two),
1599 tsp(RightPar, rp_y),
1600 tsp(RightPar, rp),
1601 ];
1602 let prog = parse_sp(tokens.clone());
1603
1604 assert_eq!(
1605 prog[0].span,
1606 sp((1, 0, 0), (1, 19, 19)),
1607 "input: {tokens:?}"
1608 );
1609 if let Expr::Const { vars } = &prog[0].inner {
1610 assert_eq!(
1611 vars[0].span,
1612 sp((1, 7, 7), (1, 12, 12)),
1613 "input: {tokens:?}"
1614 );
1615 assert_eq!(vars[0].inner.name.span, x_name, "input: {tokens:?}");
1616 assert_eq!(vars[0].inner.expr.span, one, "input: {tokens:?}");
1617 assert_eq!(
1618 vars[1].span,
1619 sp((1, 13, 13), (1, 18, 18)),
1620 "input: {tokens:?}"
1621 );
1622 assert_eq!(vars[1].inner.name.span, y_name, "input: {tokens:?}");
1623 assert_eq!(vars[1].inner.expr.span, two, "input: {tokens:?}");
1624 } else {
1625 panic!("expected Const, input: {tokens:?}");
1626 }
517} 1627}
diff --git a/compiler/src/span.rs b/compiler/src/span.rs
index 8686f4f..8b46b31 100644
--- a/compiler/src/span.rs
+++ b/compiler/src/span.rs
@@ -38,6 +38,10 @@ impl<T> Spanned<T> {
38 Self { inner, span } 38 Self { inner, span }
39 } 39 }
40 40
41 pub fn into_parts(self) -> (T, Span) {
42 (self.inner, self.span)
43 }
44
41 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U> { 45 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Spanned<U> {
42 let Self { inner, span } = self; 46 let Self { inner, span } = self;
43 Spanned { 47 Spanned {