1use alloc::{borrow::Cow, rc::Rc};
2use core::result;
3use core::sync::atomic::{AtomicU32, AtomicUsize, Ordering};
4use std::path::PathBuf;
5
6use serde::{Deserialize, Serialize};
7
8use crate::{
9 ast::{
10 self, parse_begin, parse_define, parse_if, parse_lambda, parse_let, parse_new_let,
11 parse_require, parse_set, parse_single_argument, Atom, ExprKind, List, Macro, PatternPair,
12 SyntaxRules, Vector, BEGIN, DEFINE, IF, LAMBDA, LAMBDA_FN, LAMBDA_SYMBOL, LET, PLAIN_LET,
13 QUASIQUOTE, QUASISYNTAX, QUOTE, RAW_UNQUOTE, RAW_UNQUOTE_SPLICING, RAW_UNSYNTAX,
14 RAW_UNSYNTAX_SPLICING, REQUIRE, RETURN, SET, SYNTAX_QUOTE, UNQUOTE, UNQUOTE_SPLICING,
15 },
16 interner::InternedString,
17 lexer::{OwnedTokenStream, ToOwnedString, TokenError, TokenStream},
18 span::Span,
19 tokens::{Paren, ParenMod, Token, TokenLike, TokenType},
20};
21
22use thin_vec::{thin_vec, ThinVec};
23
24static SOURCE_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
25
26#[derive(
27 Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
28)]
29#[repr(C)]
30pub struct SourceId(pub u32);
31
32impl SourceId {
33 pub const fn none() -> Option<Self> {
34 None
35 }
36
37 pub fn fresh() -> Self {
38 SourceId(SOURCE_ID_COUNTER.fetch_add(1, Ordering::Relaxed))
39 }
40}
41
42pub static SYNTAX_OBJECT_ID: AtomicUsize = AtomicUsize::new(0);
44
45#[derive(
50 Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
51)]
52pub struct SyntaxObjectId(pub u32);
53
54impl SyntaxObjectId {
55 #[inline]
56 pub fn fresh() -> Self {
57 SyntaxObjectId(SYNTAX_OBJECT_ID.fetch_add(1, Ordering::Relaxed) as _)
58 }
65}
66
67impl From<SyntaxObjectId> for u32 {
68 fn from(value: SyntaxObjectId) -> Self {
69 value.0
70 }
71}
72
73impl core::fmt::Display for SyntaxObjectId {
74 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
75 write!(f, "{self:?}")
76 }
77}
78
79#[derive(
80 Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
81)]
82pub struct ListId(usize);
83
84#[derive(
85 Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
86)]
87pub struct FunctionId(usize);
88
89#[derive(Serialize, Deserialize)]
95pub struct RawSyntaxObject<T> {
96 pub ty: T,
97 pub span: Span,
98 pub syntax_object_id: SyntaxObjectId,
99 pub unresolved: bool,
134 pub introduced_via_macro: bool,
135}
136
137impl<T: Clone> Clone for RawSyntaxObject<T> {
138 fn clone(&self) -> Self {
139 Self {
140 ty: self.ty.clone(),
141 span: self.span,
142 syntax_object_id: SyntaxObjectId::fresh(),
143 unresolved: self.unresolved,
144 introduced_via_macro: self.introduced_via_macro,
145 }
146 }
147}
148
149impl<T: core::fmt::Debug> core::fmt::Debug for RawSyntaxObject<T> {
150 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
151 f.debug_struct("RawSyntaxObject")
152 .field("ty", &self.ty)
153 .field("span", &self.span)
154 .finish()
155 }
156}
157
158impl<T: core::hash::Hash> core::hash::Hash for RawSyntaxObject<T> {
161 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
162 self.ty.hash(state);
163 self.span.hash(state);
164 }
165}
166
167pub type SyntaxObject = RawSyntaxObject<TokenType<InternedString>>;
168
169impl PartialEq for SyntaxObject {
170 fn eq(&self, other: &Self) -> bool {
171 self.ty == other.ty
172 }
173}
174
175impl SyntaxObject {
176 pub fn new(ty: TokenType<InternedString>, span: Span) -> Self {
177 SyntaxObject {
178 ty,
179 span,
180 syntax_object_id: SyntaxObjectId::fresh(),
182 unresolved: false,
183 introduced_via_macro: false,
184 }
185 }
186
187 pub fn default(ty: TokenType<InternedString>) -> Self {
188 SyntaxObject {
189 ty,
190 span: Span::new(0, 0, SourceId::none()),
191 syntax_object_id: SyntaxObjectId::fresh(),
193 unresolved: false,
194 introduced_via_macro: false,
195 }
196 }
197
198 pub fn set_span(&mut self, span: Span) {
199 self.span = span
200 }
201
202 pub fn from_token_with_source(
203 val: &Token<'_, InternedString>,
204 _source: &Option<Rc<PathBuf>>,
205 ) -> Self {
206 SyntaxObject {
207 ty: val.ty.clone(),
208 span: val.span,
209 syntax_object_id: SyntaxObjectId::fresh(),
210 unresolved: false,
211 introduced_via_macro: false,
212 }
213 }
214}
215
216impl From<&Token<'_, InternedString>> for SyntaxObject {
217 fn from(val: &Token<'_, InternedString>) -> SyntaxObject {
218 SyntaxObject::new(val.ty.clone(), val.span)
219 }
220}
221
222#[derive(Clone, Debug, PartialEq)]
223pub enum ParseError {
224 MismatchedParen(Paren, Span, Option<Rc<PathBuf>>),
225 UnexpectedEOF(Span, Option<Rc<PathBuf>>),
226 UnexpectedChar(char, Span, Option<Rc<PathBuf>>),
227 SyntaxError(String, Span, Option<Rc<PathBuf>>),
228 ArityMismatch(String, Span, Option<Rc<PathBuf>>),
229}
230
231impl From<TokenLike<'_, TokenError>> for ParseError {
232 fn from(value: TokenLike<'_, TokenError>) -> Self {
233 match value.ty {
234 TokenError::IncompleteString
235 | TokenError::IncompleteIdentifier
236 | TokenError::IncompleteComment => ParseError::UnexpectedEOF(value.span, None),
237 _ => ParseError::SyntaxError(format!("{}", value.ty), value.span, None),
238 }
239 }
240}
241
242impl core::fmt::Display for ParseError {
243 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
244 match self {
245 ParseError::MismatchedParen(paren, _, _) => {
246 write!(f, "Mismatched parenthesis, expected \"{}\"", paren.close())
247 }
248 ParseError::UnexpectedEOF(..) => write!(f, "Unexpected EOF"),
249 ParseError::UnexpectedChar(l, _, _) => {
250 write!(f, "Unexpected character: {:?}", l)
251 }
252 ParseError::SyntaxError(l, _, _) => write!(f, "Syntax Error: {}", l),
253 ParseError::ArityMismatch(l, _, _) => write!(f, "Arity mismatch: {}", l),
254 }
255 }
256}
257
258impl std::error::Error for ParseError {}
259
260impl ParseError {
261 pub fn span(&self) -> Span {
262 match self {
263 ParseError::MismatchedParen(_, s, _) => *s,
264 ParseError::UnexpectedEOF(s, _) => *s,
265 ParseError::UnexpectedChar(_, s, _) => *s,
266 ParseError::SyntaxError(_, s, _) => *s,
267 ParseError::ArityMismatch(_, s, _) => *s,
268 }
269 }
270
271 pub fn set_source(self, source: Option<Rc<PathBuf>>) -> Self {
272 use ParseError::*;
273 match self {
274 ParseError::MismatchedParen(l, s, _) => MismatchedParen(l, s, source),
275 ParseError::UnexpectedEOF(s, _) => UnexpectedEOF(s, source),
276 ParseError::UnexpectedChar(l, s, _) => UnexpectedChar(l, s, source),
277 ParseError::SyntaxError(l, s, _) => SyntaxError(l, s, source),
278 ParseError::ArityMismatch(l, s, _) => ArityMismatch(l, s, source),
279 }
280 }
281}
282
283pub struct InternString;
284
285impl ToOwnedString<InternedString> for InternString {
286 fn own(&self, s: Cow<str>) -> InternedString {
287 (&*s).into()
288 }
289}
290
291pub struct Parser<'a> {
293 tokenizer: OwnedTokenStream<'a>,
294 quote_stack: Vec<usize>,
295 quasiquote_depth: isize,
296 quote_context: bool,
297 shorthand_quote_stack: Vec<usize>,
298 source_name: Option<Rc<PathBuf>>,
299 context: Vec<ParsingContext>,
300 comment_buffer: Vec<&'a str>,
301 collecting_comments: bool,
302 keep_lists: bool,
303
304 queued: Option<ExprKind>,
305}
306
307#[derive(Debug, Copy, Clone, PartialEq)]
308enum ParsingContext {
309 Quote(usize),
311 QuoteTick(usize),
313 Unquote(usize),
315 UnquoteTick(usize),
317 Quasiquote(usize),
319 QuasiquoteTick(usize),
321 UnquoteSplicing(usize),
323 UnquoteSplicingTick(usize),
325}
326
327impl<'a> Parser<'a> {
328 pub fn parse(expr: &str) -> Result<Vec<ExprKind>> {
329 Parser::new(expr, SourceId::none()).collect()
330 }
331
332 pub fn parse_without_lowering(expr: &str) -> Result<Vec<ExprKind>> {
333 Parser::new(expr, SourceId::none())
334 .without_lowering()
335 .collect()
336 }
337
338 pub fn offset(&self) -> usize {
339 self.tokenizer.offset()
340 }
341}
342
343pub type Result<T> = result::Result<T, ParseError>;
344
345impl<'a> Parser<'a> {
346 pub fn new(input: &'a str, source_id: Option<SourceId>) -> Self {
347 Parser {
348 tokenizer: TokenStream::new(input, false, source_id).into_owned(),
349 quote_stack: Vec::new(),
350 quasiquote_depth: 0,
351 quote_context: false,
352 shorthand_quote_stack: Vec::new(),
353 source_name: None,
354 context: Vec::new(),
355 comment_buffer: Vec::new(),
356 collecting_comments: false,
357 keep_lists: false,
358 queued: None,
359 }
360 }
361
362 pub fn without_lowering(mut self) -> Self {
363 self.keep_lists = true;
364 self
365 }
366
367 pub fn new_flat(input: &'a str, source_id: Option<SourceId>) -> Self {
368 Parser {
369 tokenizer: TokenStream::new(input, false, source_id).into_owned(),
370 quote_stack: Vec::new(),
371 quasiquote_depth: 0,
372 quote_context: false,
373 shorthand_quote_stack: Vec::new(),
374 source_name: None,
375 context: Vec::new(),
376 comment_buffer: Vec::new(),
377 collecting_comments: false,
378 keep_lists: true,
379 queued: None,
380 }
381 }
382
383 pub fn new_from_source(
384 input: &'a str,
385 source_name: PathBuf,
386 source_id: Option<SourceId>,
387 ) -> Self {
388 Parser {
389 tokenizer: TokenStream::new(input, false, source_id).into_owned(),
390 quote_stack: Vec::new(),
391 quasiquote_depth: 0,
392 quote_context: false,
393 shorthand_quote_stack: Vec::new(),
394 source_name: Some(Rc::from(source_name)),
395 context: Vec::new(),
396 comment_buffer: Vec::new(),
397 collecting_comments: false,
398 keep_lists: false,
399 queued: None,
400 }
401 }
402
403 pub fn doc_comment_parser(input: &'a str, source_id: Option<SourceId>) -> Self {
405 Parser {
406 tokenizer: TokenStream::new(input, false, source_id).into_owned(),
407 quote_stack: Vec::new(),
408 quasiquote_depth: 0,
409 quote_context: false,
410 shorthand_quote_stack: Vec::new(),
411 source_name: None,
412 context: Vec::new(),
413 comment_buffer: Vec::new(),
414 collecting_comments: false,
415 keep_lists: false,
416 queued: None,
417 }
418 }
419
420 fn construct_quote(&mut self, val: ExprKind, span: Span) -> ExprKind {
421 ExprKind::Quote(Box::new(ast::Quote::new(
422 val,
423 SyntaxObject::new(TokenType::Quote, span),
424 )))
425 }
426
427 fn _expand_reader_macro(
428 &mut self,
429 token: TokenType<InternedString>,
430 val: ExprKind,
431 span: Span,
432 ) -> ExprKind {
433 let q = ExprKind::Atom(Atom::new(SyntaxObject::new(token, span)));
434
435 ExprKind::List(List::new(thin_vec![q, val]))
436 }
437
438 fn construct_quote_vec(&mut self, val: ExprKind, span: Span) -> ThinVec<ExprKind> {
439 let q = {
442 let rc_val = TokenType::Quote;
443 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
444 };
448
449 thin_vec![q, val]
450 }
451
452 fn construct_syntax(&mut self, val: ExprKind, span: Span) -> ExprKind {
454 let q = {
455 let rc_val = TokenType::Identifier(*SYNTAX_QUOTE);
456 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
457 };
458
459 ExprKind::List(List::new(thin_vec![q, val]))
460 }
461
462 fn construct_quasiquote_syntax(&mut self, val: ExprKind, span: Span) -> ExprKind {
464 let q = {
465 let rc_val = TokenType::Identifier(*QUASISYNTAX);
466 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
467 };
468
469 ExprKind::List(List::new(thin_vec![q, val]))
470 }
471
472 fn construct_quasiunquote_syntax(&mut self, val: ExprKind, span: Span) -> ExprKind {
473 let q = {
474 let rc_val = TokenType::Identifier(*RAW_UNSYNTAX);
475 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
476 };
477
478 ExprKind::List(List::new(thin_vec![q, val]))
479 }
480
481 fn construct_quasiunquote_syntax_splicing(&mut self, val: ExprKind, span: Span) -> ExprKind {
482 let q = {
483 let rc_val = TokenType::Identifier(*RAW_UNSYNTAX_SPLICING);
484 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
485 };
486
487 ExprKind::List(List::new(thin_vec![q, val]))
488 }
489
490 fn construct_quasiquote(&mut self, val: ExprKind, span: Span) -> ExprKind {
492 let q = {
493 let rc_val = TokenType::Identifier(*QUASIQUOTE);
494 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
495 };
496
497 ExprKind::List(List::new(thin_vec![q, val]))
498 }
499
500 fn construct_unquote(&mut self, val: ExprKind, span: Span) -> ExprKind {
502 let q = {
503 let rc_val = TokenType::Identifier(*UNQUOTE);
504 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
505 };
506
507 ExprKind::List(List::new(thin_vec![q, val]))
508 }
509
510 fn construct_raw_unquote(&mut self, val: ExprKind, span: Span) -> ExprKind {
511 let q = {
512 let rc_val = TokenType::Identifier(*RAW_UNQUOTE);
514 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
515 };
516
517 ExprKind::List(List::new(thin_vec![q, val]))
518 }
519 fn construct_unquote_splicing(&mut self, val: ExprKind, span: Span) -> ExprKind {
521 let q = {
522 let rc_val = TokenType::Identifier(*UNQUOTE_SPLICING);
523 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
524 };
525
526 ExprKind::List(List::new(thin_vec![q, val]))
527 }
528
529 fn construct_raw_unquote_splicing(&mut self, val: ExprKind, span: Span) -> ExprKind {
531 let q = {
532 let rc_val = TokenType::Identifier(*RAW_UNQUOTE_SPLICING);
533 ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
534 };
535
536 ExprKind::List(List::new(thin_vec![q, val]))
537 }
538
539 fn increment_quasiquote_context_if_not_in_quote_context(&mut self) {
540 if !self.quote_context {
542 self.quasiquote_depth += 1;
543 }
544 }
545
546 fn decrement_quasiquote_context_if_not_in_quote_context(&mut self) {
547 if !self.quote_context {
549 self.quasiquote_depth -= 1;
550 }
551 }
552
553 fn maybe_lower(&self, exprs: ThinVec<ExprKind>) -> Result<ExprKind> {
554 if self.keep_lists {
555 Ok(ExprKind::List(List::new(exprs)))
556 } else {
557 ExprKind::try_from(exprs)
558 }
559 }
560
561 fn maybe_lower_frame(&self, frame: Frame, close: Span) -> Result<ExprKind> {
562 frame.build_expr(close, |exprs| self.maybe_lower(exprs))
563 }
564
565 fn read_from_tokens(
566 &mut self,
567 (open, paren, paren_mod): (Span, Paren, Option<ParenMod>),
568 ) -> Result<ExprKind> {
569 let mut last = open;
570
571 let mut stack: Vec<Frame> = Vec::new();
579
580 let mut current_frame = Frame {
583 open,
584 paren,
585 paren_mod,
586 exprs: ThinVec::new(),
587 dot: None,
588 comment: 0,
589 };
590
591 self.quote_stack = Vec::new();
592
593 while let Some(token) = self.next_token() {
597 let token = token?;
598 last = token.span;
599
600 match token.ty {
601 TokenType::Dot => {
602 if current_frame.dot.is_some() {
603 return Err(ParseError::SyntaxError(
604 "improper lists can only have a single dot".into(),
605 token.span,
606 None,
607 ));
608 } else if current_frame.exprs.is_empty() {
609 return Err(ParseError::SyntaxError(
610 "improper lists must have a car element before the dot".into(),
611 token.span,
612 None,
613 ));
614 } else if current_frame.paren_mod.is_some() {
615 let paren_mod = current_frame.paren_mod.unwrap();
616 let object = match paren_mod {
617 ParenMod::Vector => "vector",
618 ParenMod::Bytes => "bytevector",
619 };
620
621 return Err(ParseError::SyntaxError(
622 format!("{object} literals cannot contain dots"),
623 token.span,
624 None,
625 ));
626 } else if current_frame.comment > 0 {
627 return Err(ParseError::SyntaxError(
628 "commented-out datum cannot start with a dot".into(),
629 token.span,
630 None,
631 ));
632 } else {
633 current_frame.dot = Some((current_frame.exprs.len() as _, token.span));
634 }
635 }
636 TokenType::Comment => {
637 }
640 TokenType::DatumComment => {
641 current_frame.comment += 1;
642 }
643
644 TokenType::QuoteSyntax => {
645 let quote_inner = self
646 .next()
647 .unwrap_or(Err(ParseError::UnexpectedEOF(
648 token.span,
649 self.source_name.clone(),
650 )))
651 .map(|x| self.construct_syntax(x, token.span))?;
652
653 current_frame.push(quote_inner)?
654 }
655
656 TokenType::QuasiQuoteSyntax => {
657 let quote_inner = self
658 .next()
659 .unwrap_or(Err(ParseError::UnexpectedEOF(
660 token.span,
661 self.source_name.clone(),
662 )))
663 .map(|x| self.construct_quasiquote_syntax(x, token.span))?;
664
665 current_frame.push(quote_inner)?
666 }
667
668 TokenType::UnquoteSyntax => {
669 let quote_inner = self
670 .next()
671 .unwrap_or(Err(ParseError::UnexpectedEOF(
672 token.span,
673 self.source_name.clone(),
674 )))
675 .map(|x| self.construct_quasiunquote_syntax(x, token.span))?;
676
677 current_frame.push(quote_inner)?
678 }
679
680 TokenType::UnquoteSpliceSyntax => {
681 let quote_inner = self
682 .next()
683 .unwrap_or(Err(ParseError::UnexpectedEOF(
684 token.span,
685 self.source_name.clone(),
686 )))
687 .map(|x| self.construct_quasiunquote_syntax_splicing(x, token.span))?;
688
689 current_frame.push(quote_inner)?
690 }
691
692 TokenType::QuoteTick => {
693 self.shorthand_quote_stack.push(stack.len());
696
697 let last_context = self.quote_context;
698
699 if self.quasiquote_depth == 0 {
700 self.quote_context = true;
701 }
702
703 self.context.push(ParsingContext::QuoteTick(stack.len()));
706
707 let quote_inner = self
708 .next()
709 .unwrap_or(Err(ParseError::UnexpectedEOF(
710 token.span,
711 self.source_name.clone(),
712 )))
713 .map(|x| {
714 self.construct_quote(x, token.span)
716 });
720 self.shorthand_quote_stack.pop();
722
723 self.quote_context = last_context;
724
725 let popped_value = self.context.pop();
733
734 if let Some(popped) = popped_value {
735 debug_assert!(matches!(popped, ParsingContext::QuoteTick(_)))
737 }
738
739 current_frame.push(quote_inner?)?;
740 }
741 TokenType::Unquote => {
742 self.decrement_quasiquote_context_if_not_in_quote_context();
746
747 self.context.push(ParsingContext::UnquoteTick(stack.len()));
748
749 let quote_inner = self
750 .next()
751 .unwrap_or(Err(ParseError::UnexpectedEOF(
752 token.span,
753 self.source_name.clone(),
754 )))
755 .map(|x| {
756 if self.quasiquote_depth == 0 && !self.quote_context {
759 self.construct_raw_unquote(x, token.span)
760 } else {
761 self.construct_unquote(x, token.span)
762 }
763 });
764
765 let popped_value = self.context.pop();
766
767 self.increment_quasiquote_context_if_not_in_quote_context();
768
769 if let Some(popped) = popped_value {
770 debug_assert!(matches!(popped, ParsingContext::UnquoteTick(_)))
771 }
772 current_frame.push(quote_inner?)?;
774 }
775 TokenType::QuasiQuote => {
776 self.increment_quasiquote_context_if_not_in_quote_context();
779
780 self.context
781 .push(ParsingContext::QuasiquoteTick(stack.len()));
782
783 let quote_inner = self
784 .next()
785 .unwrap_or(Err(ParseError::UnexpectedEOF(
786 token.span,
787 self.source_name.clone(),
788 )))
789 .map(|x| self.construct_quasiquote(x, token.span));
790
791 let popped_value = self.context.pop();
798
799 self.decrement_quasiquote_context_if_not_in_quote_context();
800
801 if let Some(popped) = popped_value {
802 debug_assert!(matches!(popped, ParsingContext::QuasiquoteTick(_)))
803 }
804
805 current_frame.push(quote_inner?)?;
806 }
807 TokenType::UnquoteSplice => {
808 self.decrement_quasiquote_context_if_not_in_quote_context();
811
812 self.context
813 .push(ParsingContext::UnquoteSplicingTick(stack.len()));
814
815 let quote_inner = self
816 .next()
817 .unwrap_or(Err(ParseError::UnexpectedEOF(
818 token.span,
819 self.source_name.clone(),
820 )))
821 .map(|x| {
822 if self.quasiquote_depth == 0 && !self.quote_context {
823 self.construct_raw_unquote_splicing(x, token.span)
824 } else {
825 self.construct_unquote_splicing(x, token.span)
826 }
827 });
828
829 let popped_value = self.context.pop();
832
833 self.increment_quasiquote_context_if_not_in_quote_context();
834
835 if let Some(popped) = popped_value {
836 debug_assert!(matches!(popped, ParsingContext::UnquoteSplicingTick(_)))
837 }
838
839 current_frame.push(quote_inner?)?;
841 }
842 TokenType::OpenParen(paren, paren_mod) => {
843 stack.push(current_frame);
844
845 current_frame = Frame {
846 open: token.span,
847 paren_mod,
848 exprs: ThinVec::with_capacity(4),
849 dot: None,
850 paren,
851 comment: 0,
852 };
853 }
854 TokenType::CloseParen(paren) => {
855 let close = token.span;
856 if paren != current_frame.paren {
860 return Err(ParseError::MismatchedParen(
861 current_frame.paren,
862 token.span,
863 self.source_name.clone(),
864 ));
865 }
866
867 if let Some(mut prev_frame) = stack.pop() {
868 match prev_frame
869 .exprs
870 .first_mut()
871 .and_then(|x| x.atom_identifier_mut())
872 {
873 Some(ident) if *ident == *UNQUOTE => {
874 if self.quasiquote_depth == 0 && !self.quote_context {
876 *ident = *RAW_UNQUOTE;
877 }
878 self.increment_quasiquote_context_if_not_in_quote_context();
879
880 }
882 Some(ident) if *ident == *QUASIQUOTE => {
883 self.decrement_quasiquote_context_if_not_in_quote_context();
884
885 }
887 Some(ident) if *ident == *UNQUOTE_SPLICING => {
888 if self.quasiquote_depth == 0 && !self.quote_context {
891 *ident = *RAW_UNQUOTE_SPLICING;
892 }
893 self.increment_quasiquote_context_if_not_in_quote_context();
894
895 }
897 _ => {}
898 }
899
900 match self.context.last().copied() {
901 Some(ParsingContext::Quote(last_quote_index))
905 | Some(ParsingContext::Quasiquote(last_quote_index)) => {
906 if stack.len() <= last_quote_index {
907 self.context.pop();
908 }
909
910 match current_frame.exprs.first() {
911 Some(ExprKind::Atom(Atom {
912 syn:
913 SyntaxObject {
914 ty: TokenType::Quote,
915 ..
916 },
917 })) => match self.context.last() {
918 Some(
919 ParsingContext::Quasiquote(_)
920 | ParsingContext::QuasiquoteTick(_)
921 | ParsingContext::Quote(_)
922 | ParsingContext::QuoteTick(_),
923 ) => prev_frame.push(current_frame.into_expr(close)?)?,
924 _ => {
925 prev_frame.push(
926 self.maybe_lower_frame(current_frame, close)?,
927 )?;
928 }
929 },
930 _ => {
931 prev_frame.push(current_frame.into_expr(close)?)?
934 }
935 }
936 }
937
938 Some(ParsingContext::QuoteTick(_))
939 | Some(ParsingContext::QuasiquoteTick(_)) => {
940 match current_frame.exprs.first() {
941 Some(ExprKind::Atom(Atom {
942 syn:
943 SyntaxObject {
944 ty: TokenType::Quote,
945 ..
946 },
947 })) => {
948 prev_frame
950 .push(self.maybe_lower_frame(current_frame, close)?)?;
951 }
952 _ => {
953 prev_frame.push(current_frame.into_expr(close)?)?
961 }
962 }
963 }
964
965 Some(ParsingContext::UnquoteTick(_))
968 | Some(ParsingContext::UnquoteSplicingTick(_)) => {
969 prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?;
985 }
986
987 Some(ParsingContext::Unquote(last_quote_index))
988 | Some(ParsingContext::UnquoteSplicing(last_quote_index)) => {
989 if stack.len() <= last_quote_index {
1000 self.context.pop();
1003 }
1004
1005 prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?;
1006 }
1007
1008 _ => prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?,
1010 }
1011
1012 current_frame = prev_frame;
1014 } else {
1015 match self.context.last() {
1022 Some(ParsingContext::QuoteTick(_))
1023 | Some(ParsingContext::QuasiquoteTick(_)) => {
1024 return current_frame.into_expr(close);
1027 }
1028 Some(ParsingContext::Quote(x)) if *x > 0 => {
1029 self.context.pop();
1030
1031 return current_frame.into_expr(close);
1032 }
1033 Some(ParsingContext::Quote(0)) => {
1034 self.context.pop();
1035
1036 return self.maybe_lower_frame(current_frame, close);
1037 }
1038 _ => {
1039 if self.quasiquote_depth > 0 {
1044 if current_frame
1047 .exprs
1048 .first()
1049 .map(|x| x.define_syntax_ident())
1050 .unwrap_or_default()
1051 {
1052 return self.maybe_lower_frame(current_frame, close);
1053 }
1054
1055 return current_frame.into_expr(close);
1058 }
1059
1060 return self.maybe_lower_frame(current_frame, close);
1061 }
1062 }
1063 }
1064 }
1065
1066 _ => {
1067 if let TokenType::Quote = &token.ty {
1068 self.quote_stack.push(stack.len());
1070 }
1071
1072 if current_frame.exprs.is_empty() {
1077 match &token.ty {
1078 TokenType::Quote => {
1079 if self.context == [ParsingContext::QuoteTick(0)] {
1080 self.context.push(ParsingContext::Quote(1))
1081 } else {
1082 self.context.push(ParsingContext::Quote(stack.len()))
1083 }
1084
1085 }
1087 TokenType::Identifier(ident) if *ident == *UNQUOTE => {
1088 self.context.push(ParsingContext::Unquote(stack.len()));
1091 self.decrement_quasiquote_context_if_not_in_quote_context();
1092 }
1093 TokenType::Identifier(ident) if *ident == *QUASIQUOTE => {
1094 self.context.push(ParsingContext::Quasiquote(stack.len()));
1097 self.increment_quasiquote_context_if_not_in_quote_context();
1098 }
1099 TokenType::Identifier(ident) if *ident == *UNQUOTE_SPLICING => {
1100 self.context
1101 .push(ParsingContext::UnquoteSplicing(stack.len()));
1102 self.decrement_quasiquote_context_if_not_in_quote_context();
1103 }
1104 _ => {}
1105 }
1106
1107 }
1109
1110 let atom = Atom::new(SyntaxObject::from_token_with_source(
1113 &token,
1114 &self.source_name.clone(),
1115 ));
1116
1117 current_frame.push(ExprKind::Atom(atom))?
1118 }
1119 }
1120 }
1121
1122 Err(ParseError::UnexpectedEOF(last, self.source_name.clone()))
1123 }
1124
1125 fn next_token(&mut self) -> Option<Result<Token<'a, InternedString>>> {
1126 let res = self.tokenizer.next()?;
1127
1128 Some(res.map_err(|err| ParseError::from(err).set_source(self.source_name.clone())))
1129 }
1130}
1131
1132enum DocResult {
1133 Single(ExprKind),
1134 Double(ExprKind, ExprKind),
1135}
1136
1137fn wrap_in_doc_function(expr: ExprKind, comment: String) -> DocResult {
1140 if let ExprKind::List(l) = &expr {
1141 if let Some(ExprKind::Atom(Atom {
1142 syn:
1143 RawSyntaxObject {
1144 ty: TokenType::DefineSyntax,
1145 ..
1146 },
1147 })) = l.first()
1148 {
1149 if let Some(ident) = l.second_ident() {
1152 let doc = ExprKind::List(List::new(thin_vec![
1153 ExprKind::ident("@doc"),
1154 ExprKind::string_lit(comment),
1155 ExprKind::ident("#%macro"),
1156 ExprKind::ident(ident.resolve()),
1157 ]));
1158
1159 return DocResult::Double(doc, expr);
1160 }
1161 }
1162 }
1163
1164 if let ExprKind::Macro(m) = &expr {
1165 if let Some(ident) = m.name.atom_identifier().copied() {
1168 let doc = ExprKind::List(List::new(thin_vec![
1169 ExprKind::ident("@doc"),
1170 ExprKind::string_lit(comment),
1171 ExprKind::ident("#%macro"),
1172 ExprKind::ident(ident.resolve()),
1173 ]));
1174
1175 return DocResult::Double(doc, expr);
1176 }
1177 }
1178
1179 DocResult::Single(ExprKind::List(List::new(thin_vec![
1180 ExprKind::ident("@doc"),
1181 ExprKind::string_lit(comment),
1182 expr,
1183 ])))
1184}
1185
1186impl<'a> Parser<'a> {
1187 fn get_next_and_maybe_wrap_in_doc(&mut self) -> Option<Result<ExprKind>> {
1188 let mut datum_comments = thin_vec![];
1189
1190 macro_rules! maybe_return {
1191 ($value:expr) => {{
1192 let value = $value;
1193
1194 if value.is_ok() {
1195 if datum_comments.len() > 0 {
1196 let _ = datum_comments.pop();
1197
1198 continue;
1199 }
1200 }
1201
1202 return Some(value);
1203 }};
1204 }
1205
1206 while let Some(res) = self.next_token() {
1207 let res = match res {
1208 Ok(res) => res,
1209 Err(err) => {
1210 return Some(Err(err));
1211 }
1212 };
1213
1214 match res.ty {
1215 TokenType::Comment => {
1216 if self.comment_buffer.is_empty()
1217 && !self.collecting_comments
1218 && res.source().trim_start_matches(';').starts_with("@doc")
1219 {
1220 self.collecting_comments = true;
1221
1222 continue;
1223 }
1224
1225 if self.collecting_comments {
1226 let doc_line = res.source().trim_start_matches(';');
1227
1228 if doc_line.starts_with("@doc") {
1230 self.comment_buffer.clear();
1233 continue;
1234 }
1235
1236 let line = doc_line
1239 .strip_prefix(" ")
1240 .unwrap_or(doc_line)
1241 .trim_end_matches(['\n', '\r']);
1242 self.comment_buffer.push(line);
1243 }
1244
1245 continue;
1246 }
1247
1248 TokenType::DatumComment => {
1249 datum_comments.push(res.span);
1250 }
1251
1252 TokenType::QuoteSyntax => {
1254 let value = self
1255 .next()
1256 .unwrap_or(Err(ParseError::UnexpectedEOF(
1257 res.span,
1258 self.source_name.clone(),
1259 )))
1260 .map(|x| self.construct_syntax(x, res.span));
1261
1262 maybe_return![value];
1263 }
1264
1265 TokenType::QuasiQuoteSyntax => {
1266 let value = self
1267 .next()
1268 .unwrap_or(Err(ParseError::UnexpectedEOF(
1269 res.span,
1270 self.source_name.clone(),
1271 )))
1272 .map(|x| self.construct_quasiquote_syntax(x, res.span));
1273
1274 maybe_return![value];
1275 }
1276
1277 TokenType::UnquoteSyntax => {
1278 let quote_inner = self
1279 .next()
1280 .unwrap_or(Err(ParseError::UnexpectedEOF(
1281 res.span,
1282 self.source_name.clone(),
1283 )))
1284 .map(|x| self.construct_quasiunquote_syntax(x, res.span));
1285
1286 maybe_return!(quote_inner);
1287 }
1288
1289 TokenType::UnquoteSpliceSyntax => {
1290 let quote_inner = self
1291 .next()
1292 .unwrap_or(Err(ParseError::UnexpectedEOF(
1293 res.span,
1294 self.source_name.clone(),
1295 )))
1296 .map(|x| self.construct_quasiunquote_syntax_splicing(x, res.span));
1297
1298 maybe_return!(quote_inner);
1299 }
1300
1301 TokenType::QuoteTick => {
1302 self.shorthand_quote_stack.push(0);
1304
1305 let last = self.quote_context;
1306
1307 if self.quasiquote_depth == 0 {
1308 self.quote_context = true;
1309 }
1310
1311 self.context.push(ParsingContext::QuoteTick(0));
1315
1316 let value = self
1317 .next()
1318 .unwrap_or(Err(ParseError::UnexpectedEOF(
1319 res.span,
1320 self.source_name.clone(),
1321 )))
1322 .map(|x| self.construct_quote_vec(x, res.span));
1323
1324 self.shorthand_quote_stack.pop();
1325
1326 let popped_value = self.context.pop();
1327
1328 if let Some(popped) = popped_value {
1329 debug_assert!(matches!(popped, ParsingContext::QuoteTick(_)))
1331 }
1332
1333 self.quote_context = last;
1334
1335 maybe_return!(match value {
1341 Ok(v) => {
1342 self.maybe_lower(v)
1345 }
1346 Err(e) => Err(e),
1347 });
1348 }
1349
1350 TokenType::Unquote => {
1351 self.context.push(ParsingContext::UnquoteTick(0));
1353
1354 self.decrement_quasiquote_context_if_not_in_quote_context();
1355
1356 let value = self
1357 .next()
1358 .unwrap_or(Err(ParseError::UnexpectedEOF(
1359 res.span,
1360 self.source_name.clone(),
1361 )))
1362 .map(|x| {
1363 if self.quasiquote_depth == 0 && !self.quote_context {
1365 self.construct_raw_unquote(x, res.span)
1366 } else {
1367 self.construct_unquote(x, res.span)
1368 }
1369 });
1370
1371 let popped_value = self.context.pop();
1372
1373 self.increment_quasiquote_context_if_not_in_quote_context();
1374
1375 if let Some(popped) = popped_value {
1376 debug_assert!(matches!(popped, ParsingContext::UnquoteTick(_)))
1377 }
1378 maybe_return!(value);
1381 }
1382
1383 TokenType::UnquoteSplice => {
1384 self.context.push(ParsingContext::UnquoteSplicingTick(0));
1386
1387 self.decrement_quasiquote_context_if_not_in_quote_context();
1388
1389 let value = self
1390 .next()
1391 .unwrap_or(Err(ParseError::UnexpectedEOF(
1392 res.span,
1393 self.source_name.clone(),
1394 )))
1395 .map(|x| {
1396 if self.quasiquote_depth == 0 && !self.quote_context {
1397 self.construct_raw_unquote_splicing(x, res.span)
1398 } else {
1399 self.construct_unquote_splicing(x, res.span)
1400 }
1401 });
1402
1403 let popped_value = self.context.pop();
1404
1405 self.increment_quasiquote_context_if_not_in_quote_context();
1406
1407 if let Some(popped) = popped_value {
1408 debug_assert!(matches!(popped, ParsingContext::UnquoteSplicingTick(_)))
1409 }
1410
1411 maybe_return!(value);
1414 }
1415 TokenType::QuasiQuote => {
1417 self.context.push(ParsingContext::QuasiquoteTick(0));
1418
1419 self.increment_quasiquote_context_if_not_in_quote_context();
1420
1421 let value = self
1422 .next()
1423 .unwrap_or(Err(ParseError::UnexpectedEOF(
1424 res.span,
1425 self.source_name.clone(),
1426 )))
1427 .map(|x| self.construct_quasiquote(x, res.span));
1428
1429 let popped_value = self.context.pop();
1430
1431 if let Some(popped) = popped_value {
1432 debug_assert!(matches!(popped, ParsingContext::QuasiquoteTick(_)))
1433 }
1434
1435 self.decrement_quasiquote_context_if_not_in_quote_context();
1436
1437 maybe_return![value];
1438 }
1439
1440 TokenType::OpenParen(paren, paren_mod) => {
1441 let value = self
1442 .read_from_tokens((res.span, paren, paren_mod))
1443 .map_err(|err| err.set_source(self.source_name.clone()));
1444
1445 maybe_return![value];
1446 }
1447 TokenType::CloseParen(paren) => {
1448 maybe_return!(Err(ParseError::UnexpectedChar(
1449 paren.close(),
1450 res.span,
1451 self.source_name.clone(),
1452 )))
1453 }
1454 _ => {
1455 maybe_return![Ok(ExprKind::Atom(Atom::new(SyntaxObject::from(&res))))];
1456 }
1457 };
1458 }
1459
1460 if !datum_comments.is_empty() {
1461 return Some(Err(ParseError::SyntaxError(
1462 "unfinished commented-out expression".into(),
1463 datum_comments.pop().unwrap(),
1464 None,
1465 )));
1466 }
1467
1468 None
1470 }
1471}
1472
1473impl<'a> Iterator for Parser<'a> {
1474 type Item = Result<ExprKind>;
1475
1476 fn next(&mut self) -> Option<Self::Item> {
1478 if let Some(next) = self.queued.take() {
1479 return Some(Ok(next));
1480 }
1481
1482 if self.quote_stack.is_empty()
1483 && self.shorthand_quote_stack.is_empty()
1484 && self.context.is_empty()
1485 {
1486 self.quasiquote_depth = 0;
1487 self.comment_buffer.clear();
1488 }
1489
1490 self.get_next_and_maybe_wrap_in_doc().map(|res| {
1491 if self.comment_buffer.is_empty() || !self.context.is_empty() {
1492 res
1493 } else {
1494 self.collecting_comments = false;
1496 res.map(|x| {
1497 let result = wrap_in_doc_function(
1498 x,
1499 self.comment_buffer.drain(..).collect::<Vec<_>>().join("\n"),
1500 );
1501
1502 match result {
1503 DocResult::Single(expr_kind) => expr_kind,
1504 DocResult::Double(expr_kind, expr_kind1) => {
1505 self.queued = Some(expr_kind1);
1506 expr_kind
1507 }
1508 }
1509 })
1510 }
1511 })
1512 }
1513}
1514
1515pub fn lower_syntax_rules(expr: ExprKind) -> Result<SyntaxRules> {
1517 let mut value_iter = expr.into_list().into_iter();
1518 let syn = value_iter
1519 .next()
1520 .unwrap()
1521 .into_atom_syntax_object()
1522 .unwrap();
1523
1524 let syntax_vec = if let Some(ExprKind::List(l)) = value_iter.next() {
1525 l.args
1526 } else {
1527 return Err(ParseError::SyntaxError(
1528 "syntax-rules expects a list of new syntax forms used in the macro".to_string(),
1529 syn.span,
1530 None,
1531 ));
1532 };
1533
1534 let mut pairs = ThinVec::new();
1535 let rest: Vec<_> = value_iter.collect();
1536
1537 for pair in rest {
1538 if let ExprKind::List(l) = pair {
1539 if l.args.len() != 2 {
1540 return Err(ParseError::SyntaxError(
1541 "syntax-rules requires only one pattern to one body".to_string(),
1542 syn.span,
1543 None,
1544 ));
1545 }
1546
1547 let mut pair_iter = l.args.into_iter();
1548 let pair_object =
1549 PatternPair::new(pair_iter.next().unwrap(), pair_iter.next().unwrap())?;
1550 pairs.push(pair_object);
1551 } else {
1552 return Err(ParseError::SyntaxError(
1553 "syntax-rules requires pattern to expressions to be in a list".to_string(),
1554 syn.span,
1555 None,
1556 ));
1557 }
1558 }
1559
1560 Ok(SyntaxRules::new(syntax_vec, pairs, syn))
1561}
1562
1563pub fn lower_macro_and_require_definitions(expr: ExprKind) -> Result<ExprKind> {
1565 let as_list = expr.list();
1566
1567 if as_list.map(List::is_define_syntax).unwrap_or_default()
1569 && as_list
1570 .unwrap()
1571 .get(2)
1572 .and_then(ExprKind::list)
1573 .map(List::is_syntax_rules)
1574 .unwrap_or_default()
1575 {
1576 let mut value_iter = expr.into_list().into_iter();
1577
1578 let define_syntax = value_iter.next().unwrap();
1579
1580 let name = value_iter.next().unwrap();
1581 let syntax = lower_syntax_rules(value_iter.next().unwrap())?;
1582
1583 return Ok(ExprKind::Macro(Box::new(Macro::new(
1584 name,
1585 Box::new(syntax),
1586 define_syntax.into_atom_syntax_object().unwrap(),
1587 ))));
1588 }
1589
1590 if as_list.map(List::is_require).unwrap_or_default() {
1591 let mut raw = expr.into_list().args;
1592
1593 let syn = raw.remove(0).into_atom_syntax_object().unwrap();
1594
1595 if raw.is_empty() {
1596 return Err(ParseError::ArityMismatch(
1597 "require expects at least one identifier or string".to_string(),
1598 syn.span,
1599 None,
1600 ));
1601 }
1602
1603 return Ok(ExprKind::Require(Box::new(ast::Require::new(
1604 raw.into(),
1605 syn,
1606 ))));
1607 }
1608
1609 let mut expr = expr;
1610
1611 if let Some(first) = expr
1618 .list_mut()
1619 .and_then(|x| x.args.first_mut().and_then(|x| x.atom_syntax_object_mut()))
1620 {
1621 if first.ty == TokenType::DefineSyntax {
1622 first.ty = TokenType::Identifier("define-syntax".into());
1623 }
1624 }
1625
1626 Ok(expr)
1627}
1628
1629struct ASTLowerPass {
1630 quote_depth: usize,
1631}
1632
1633impl ASTLowerPass {
1634 fn lower(&mut self, expr: &mut ExprKind) -> Result<()> {
1635 match expr {
1636 ExprKind::List(ref mut value) => {
1637 if value.is_quote() {
1638 self.quote_depth += 1;
1640 }
1641
1642 for expr in value.args.iter_mut() {
1651 self.lower(expr)?;
1652 }
1653
1654 if value.is_quote() {
1655 self.quote_depth -= 1;
1656 }
1657
1658 if let Some(f) = value.args.first_mut().and_then(|x| {
1659 if let ExprKind::Atom(a) = x {
1660 if a.syn.ty == TokenType::DefineSyntax {
1661 a.syn.ty = TokenType::Identifier("define-syntax".into());
1662 }
1663
1664 Some(x.clone())
1665 } else {
1666 None
1667 }
1668 }) {
1669 match f {
1670 ExprKind::Atom(a) if self.quote_depth == 0 && value.is_quote() => {
1671 match &a.syn.ty {
1672 TokenType::Quote => {
1673 *expr = parse_single_argument(
1674 core::mem::take(&mut value.args).into_iter(),
1675 a.syn.clone(),
1676 "quote",
1677 |expr, syn| ast::Quote::new(expr, syn).into(),
1678 )?;
1679
1680 Ok(())
1681 }
1682 _ => unreachable!(),
1683 }
1684 }
1685 ExprKind::Atom(a) if self.quote_depth == 0 => {
1686 let value = core::mem::replace(value, List::new(thin_vec![]));
1687
1688 *expr = match &a.syn.ty {
1689 TokenType::If => {
1690 parse_if(value.args_proper(TokenType::If)?.into_iter(), a.syn)
1691 }
1692 TokenType::Identifier(expr) if *expr == *IF => {
1693 parse_if(value.args_proper(TokenType::If)?.into_iter(), a.syn)
1694 }
1695
1696 TokenType::Define => parse_define(
1697 value.args_proper(TokenType::Define)?.into_iter(),
1698 a.syn,
1699 ),
1700 TokenType::Identifier(expr) if *expr == *DEFINE => parse_define(
1701 value.args_proper(TokenType::Define)?.into_iter(),
1702 a.syn,
1703 ),
1704
1705 TokenType::Let => parse_let(
1706 value.args_proper(TokenType::Let)?.into_iter(),
1707 a.syn.clone(),
1708 ),
1709 TokenType::Identifier(expr) if *expr == *LET => {
1710 parse_let(value.args_proper(TokenType::Let)?.into_iter(), a.syn)
1711 }
1712
1713 TokenType::TestLet => parse_new_let(
1715 value.args_proper(TokenType::TestLet)?.into_iter(),
1716 a.syn,
1717 ),
1718 TokenType::Identifier(expr) if *expr == *PLAIN_LET => {
1719 parse_new_let(
1720 value.args_proper(TokenType::TestLet)?.into_iter(),
1721 a.syn,
1722 )
1723 }
1724
1725 TokenType::Quote => parse_single_argument(
1726 value.args_proper(TokenType::Quote)?.into_iter(),
1727 a.syn,
1728 "quote",
1729 |expr, syn| ast::Quote::new(expr, syn).into(),
1730 ),
1731 TokenType::Identifier(expr) if *expr == *QUOTE => {
1732 parse_single_argument(
1733 value.args_proper(TokenType::Quote)?.into_iter(),
1734 a.syn,
1735 "quote",
1736 |expr, syn| ast::Quote::new(expr, syn).into(),
1737 )
1738 }
1739
1740 TokenType::Return => parse_single_argument(
1741 value.args_proper(TokenType::Return)?.into_iter(),
1742 a.syn,
1743 "return!",
1744 |expr, syn| ast::Return::new(expr, syn).into(),
1745 ),
1746 TokenType::Identifier(expr) if *expr == *RETURN => {
1747 parse_single_argument(
1748 value.args_proper(TokenType::Return)?.into_iter(),
1749 a.syn,
1750 "return!",
1751 |expr, syn| ast::Return::new(expr, syn).into(),
1752 )
1753 }
1754
1755 TokenType::Require => {
1756 parse_require(&a, value.args_proper(TokenType::Require)?)
1757 }
1758 TokenType::Identifier(expr) if *expr == *REQUIRE => {
1759 parse_require(&a, value.args_proper(TokenType::Require)?)
1760 }
1761
1762 TokenType::Set => parse_set(&a, value.args_proper(TokenType::Set)?),
1763 TokenType::Identifier(expr) if *expr == *SET => {
1764 parse_set(&a, value.args_proper(TokenType::Set)?)
1765 }
1766
1767 TokenType::Begin => {
1768 parse_begin(a, value.args_proper(TokenType::Begin)?)
1769 }
1770 TokenType::Identifier(expr) if *expr == *BEGIN => {
1771 parse_begin(a, value.args_proper(TokenType::Begin)?)
1772 }
1773
1774 TokenType::Lambda => {
1775 parse_lambda(a, value.args_proper(TokenType::Lambda)?)
1776 }
1777 TokenType::Identifier(expr)
1778 if *expr == *LAMBDA
1779 || *expr == *LAMBDA_FN
1780 || *expr == *LAMBDA_SYMBOL =>
1781 {
1782 parse_lambda(a, value.args_proper(TokenType::Lambda)?)
1783 }
1784
1785 _ => Ok(ExprKind::List(value)),
1786 }?;
1787
1788 Ok(())
1789 }
1790 _ => Ok(()),
1791 }
1792 } else {
1793 Ok(())
1794 }
1795 }
1796 ExprKind::Atom(_) => Ok(()),
1797 ExprKind::If(iff) => {
1798 self.lower(&mut iff.test_expr)?;
1799 self.lower(&mut iff.then_expr)?;
1800 self.lower(&mut iff.else_expr)?;
1801 Ok(())
1802 }
1803 ExprKind::Let(l) => {
1804 for (left, right) in l.bindings.iter_mut() {
1805 self.lower(left)?;
1806 self.lower(right)?;
1807 }
1808
1809 self.lower(&mut l.body_expr)?;
1810
1811 Ok(())
1812 }
1813 ExprKind::Define(d) => {
1814 self.lower(&mut d.name)?;
1815 self.lower(&mut d.body)?;
1816
1817 Ok(())
1818 }
1819
1820 ExprKind::LambdaFunction(f) => {
1821 for arg in f.args.iter_mut() {
1822 self.lower(arg)?;
1823 }
1824
1825 self.lower(&mut f.body)?;
1826
1827 Ok(())
1828 }
1829 ExprKind::Begin(b) => {
1830 for expr in b.exprs.iter_mut() {
1831 self.lower(expr)?;
1832 }
1833
1834 Ok(())
1835 }
1836 ExprKind::Return(r) => {
1844 self.lower(&mut r.expr)?;
1845 Ok(())
1846 }
1847 ExprKind::Quote(_) => Ok(()),
1852 ExprKind::Macro(_) => Ok(()),
1853 ExprKind::SyntaxRules(_) => Ok(()),
1854 ExprKind::Set(s) => {
1855 self.lower(&mut s.variable)?;
1856 self.lower(&mut s.expr)?;
1857
1858 Ok(())
1859 }
1860 ExprKind::Require(_) => Ok(()),
1866 ExprKind::Vector(v) => {
1867 for arg in &mut v.args {
1868 self.lower(arg)?;
1869 }
1870
1871 Ok(())
1872 }
1873 }
1874 }
1875}
1876
1877pub fn lower_entire_ast(expr: &mut ExprKind) -> Result<()> {
1879 ASTLowerPass { quote_depth: 0 }.lower(expr)
1880}
1881
1882#[derive(Debug)]
1883struct Frame {
1884 open: Span,
1885 paren: Paren,
1886 paren_mod: Option<ParenMod>,
1887 exprs: ThinVec<ExprKind>,
1888 dot: Option<(u32, Span)>,
1889 comment: u8,
1890}
1891
1892impl Frame {
1893 fn into_expr(self, close: Span) -> Result<ExprKind> {
1894 self.build_expr(close, |exprs| Ok(List::new(exprs).into()))
1895 }
1896
1897 fn build_expr(
1898 self,
1899 close: Span,
1900 builder: impl FnOnce(ThinVec<ExprKind>) -> Result<ExprKind>,
1901 ) -> Result<ExprKind> {
1902 if self.comment > 0 {
1903 return Err(ParseError::SyntaxError(
1904 "invalid datum comment".into(),
1905 self.open,
1906 None,
1907 ));
1908 }
1909
1910 if let Some(paren_mod) = self.paren_mod {
1911 let bytes = matches!(paren_mod, ParenMod::Bytes);
1912
1913 return Ok(Vector {
1914 args: self.exprs,
1915 bytes,
1916 span: Span::merge(self.open, close),
1917 }
1918 .into());
1919 };
1920
1921 let improper = self.improper()?;
1922
1923 let mut expr = builder(self.exprs)?;
1924
1925 match &mut expr {
1926 ExprKind::List(list) => {
1927 list.location = Span::merge(self.open, close);
1928
1929 if improper {
1930 list.make_improper();
1931 }
1932 }
1933 _ if improper => todo!(),
1934 _ => {}
1935 };
1936
1937 Ok(expr)
1938 }
1939
1940 fn push(&mut self, expr: ExprKind) -> Result<()> {
1941 if let Some(idx) = self.dot.as_ref().map(|x| x.0) {
1942 debug_assert!(!self.exprs.is_empty());
1943
1944 if idx as usize != self.exprs.len() {
1945 debug_assert_eq!(idx + 1, self.exprs.len() as _);
1946
1947 return Err(ParseError::SyntaxError(
1948 "improper list must have a single cdr".to_owned(),
1949 expr.span(),
1950 None,
1951 ));
1952 }
1953 }
1954
1955 let valid_for_bytes = match (self.paren_mod, &expr) {
1956 (Some(ParenMod::Bytes), ExprKind::Atom(atom)) if atom.byte().is_some() => true,
1957 (Some(ParenMod::Bytes), _) => false,
1958 _ => true,
1959 };
1960
1961 if !valid_for_bytes {
1962 return Err(ParseError::SyntaxError(
1963 "bytevector literals can only contain integer literals in the 0-255 range".into(),
1964 expr.span(),
1965 None,
1966 ));
1967 }
1968
1969 if self.comment > 0 {
1970 self.comment -= 1;
1971
1972 return Ok(());
1973 }
1974
1975 self.exprs.push(expr);
1976
1977 Ok(())
1978 }
1979
1980 fn improper(&self) -> Result<bool> {
1981 match self.dot {
1982 Some((idx, _)) if idx + 1 == self.exprs.len() as _ => Ok(true),
1983 Some((idx, span)) => {
1984 debug_assert_eq!(idx, self.exprs.len() as _);
1985
1986 Err(ParseError::SyntaxError(
1987 "improper list must have a single cdr".into(),
1988 span,
1989 None,
1990 ))
1991 }
1992 None => Ok(false),
1993 }
1994 }
1995}
1996
1997#[cfg(test)]
1998mod parser_tests {
1999 use super::*;
2001 use crate::parser::ast::{Begin, Define, If, LambdaFunction, Quote, Return};
2002 use crate::tokens::{Paren, RealLiteral};
2003 use crate::visitors::Eraser;
2004 use crate::{parser::ast::ExprKind, tokens::IntLiteral};
2005
2006 fn atom(ident: &str) -> ExprKind {
2007 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::Identifier(
2008 ident.into(),
2009 ))))
2010 }
2011
2012 fn int(num: isize) -> ExprKind {
2013 ExprKind::Atom(Atom::new(SyntaxObject::default(
2014 IntLiteral::Small(num).into(),
2015 )))
2016 }
2017
2018 fn character(c: char) -> ExprKind {
2019 ExprKind::Atom(Atom::new(SyntaxObject::default(
2020 TokenType::CharacterLiteral(c),
2021 )))
2022 }
2023
2024 #[test]
2025 fn check_quote_parsing() {
2026 println!("{:?}", Parser::parse("'(a b 'c)"));
2027 }
2028
2029 fn parses(s: &str) {
2030 let a: Result<Vec<_>> = Parser::new(s, SourceId::none()).collect();
2031 a.unwrap();
2032 }
2033
2034 fn parse_err(s: &str) -> ParseError {
2035 let a: Result<Vec<_>> = Parser::new(s, SourceId::none()).collect();
2036 a.unwrap_err()
2037 }
2038
2039 fn assert_parse(s: &str, result: &[ExprKind]) {
2040 let a: Result<Vec<ExprKind>> = Parser::new(s, SourceId::none()).collect();
2041 let mut a = a.unwrap();
2042
2043 let mut eraser = Eraser;
2044
2045 eraser.visit_many(&mut a);
2046
2047 assert_eq!(a.as_slice(), result);
2048 }
2049
2050 fn assert_syntax_err(s: &str, expected: &str) {
2051 let a: Result<Vec<ExprKind>> = Parser::new(s, SourceId::none()).collect();
2052 let Err(ParseError::SyntaxError(err, _, _)) = a else {
2053 panic!("expected syntax error, got {a:?}");
2054 };
2055
2056 assert_eq!(err, expected);
2057 }
2058
2059 fn assert_parse_is_err(s: &str) {
2060 let a: Result<Vec<ExprKind>> = Parser::new(s, SourceId::none()).collect();
2061 assert!(a.is_err());
2062 }
2063
2064 #[test]
2065 fn check_resulting_parsing() {
2066 let expr = r#"`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)"#;
2067
2068 let a: Result<Vec<ExprKind>> = Parser::new(expr, SourceId::none()).collect();
2069 let a = a.unwrap();
2070
2071 println!("{}", a[0]);
2072 }
2073
2074 #[test]
2075 fn check_double_unquote_parsing() {
2076 let expr = r#"(let ([name1 'x] [name2 'y]) `(a `(b ,,name1 ,',name2 d) e))"#;
2077
2078 let a: Result<Vec<ExprKind>> = Parser::new(expr, SourceId::none()).collect();
2079 let a = a.unwrap();
2080
2081 println!("{}", a[0]);
2082 }
2083
2084 #[test]
2085 fn check_parser_with_doc_comments() {
2086 let expr = r#"
2087 ;;@doc
2088 ;; This is a fancy cool comment, that I want to attach to a top level definition!
2089 ;; This is the second line of the comment, I want this attached as well!
2090 ;; Macro for creating a new struct, in the form of:
2091 ;; `(struct <struct-name> (fields ...) options ...)`
2092 ;; The options can consist of the following:
2093 ;;
2094 ;; Single variable options (those which their presence indicates #true)
2095 ;; - #:mutable
2096 ;; - #:transparent
2097 ;;
2098 ;; Other options must be presented as key value pairs, and will get stored
2099 ;; in the struct instance. They will also be bound to the variable
2100 ;; ___<struct-name>-options___ in the same lexical environment where the
2101 ;; struct was defined. For example:
2102 ;;
2103 ;; (Applesauce (a b c) #:mutable #:transparent #:unrecognized-option 1234)
2104 ;;
2105 ;; Will result in the value `___Applesauce-options___` like so:
2106 ;; (hash #:mutable #true #:transparent #true #:unrecognized-option 1234)
2107 ;;
2108 ;; By default, structs are immutable, which means setter functions will not
2109 ;; be generated. Also by default, structs are not transparent, which means
2110 ;; printing them will result in an opaque struct that does not list the fields
2111 (define foo 12345)
2112 "#;
2113
2114 let parser = Parser::doc_comment_parser(expr, SourceId::none());
2115
2116 let result: Result<Vec<_>> = parser.collect();
2117
2118 println!("{:?}", result.unwrap());
2119 }
2120
2121 #[test]
2122 fn parses_make_struct() {
2123 parses("(define make-struct (lambda (struct-name fields) (map (lambda (field) (list (quote define) (concat-symbols struct-name field) (quote (lambda (this) (vector-ref this 0))))) fields)))")
2124 }
2125
2126 #[test]
2127 fn parses_quasiquote() {
2128 parses(r#"(quasiquote ((unquote x) xs ...)) "#);
2129 }
2130
2131 #[test]
2132 fn parse_syntax_rules() {
2133 parses(
2134 r#"
2135 (syntax-rules (unquote unquote-splicing)
2136 ((quasiquote ((unquote x) xs ...)) (cons x (quasiquote (xs ...))))
2137 ((quasiquote ((unquote-splicing x))) (append (list x) '()))
2138 ((quasiquote ((unquote-splicing x) xs ...)) (append x (quasiquote (xs ...))))
2139 ((quasiquote (unquote x)) x)
2140 ((quasiquote (x)) '(x))
2141 ((quasiquote (x xs ...)) (cons (quasiquote x) (quasiquote (xs ...))))
2142 ((quasiquote x) 'x))
2143 "#,
2144 );
2145 }
2146
2147 #[test]
2148 fn parse_define_syntax() {
2149 parses(
2150 r#"
2151 (define-syntax quasiquote
2152 (syntax-rules (unquote unquote-splicing)
2153 ((quasiquote ((unquote x) xs ...)) (cons x (quasiquote (xs ...))))
2154 ((quasiquote ((unquote-splicing x))) (append (list x) '()))
2155 ((quasiquote ((unquote-splicing x) xs ...)) (append x (quasiquote (xs ...))))
2156 ((quasiquote (unquote x)) x)
2157 ((quasiquote (x)) '(x))
2158 ((quasiquote (x xs ...)) (cons (quasiquote x) (quasiquote (xs ...))))
2159 ((quasiquote x) 'x)))
2160 "#,
2161 );
2162 }
2163
2164 #[test]
2165 fn parse_quote() {
2166 parses("(displayln (match '(lambda y z) '(x y z)))")
2168 }
2169
2170 #[test]
2171 fn parse_unicode() {
2172 assert_parse("#\\¡", &[character('¡')]);
2173 assert_parse("#\\u{b}", &[character('\u{b}')]);
2174 }
2175
2176 #[test]
2177 fn parse_more_unicode() {
2178 assert_parse("#\\u{a0}", &[character('\u{a0}')]);
2179 }
2180
2181 #[test]
2182 fn parse_strange_characters() {
2183 assert_parse("#\\^", &[character('^')]);
2184 }
2185
2186 #[test]
2187 fn parse_character_sequence() {
2188 assert_parse(
2189 "#\\¡ #\\SPACE #\\g",
2190 &[character('¡'), character(' '), character('g')],
2191 )
2192 }
2193
2194 #[test]
2195 fn parse_character_sequence_inside_if() {
2196 assert_parse(
2197 "(if #\\¡ #\\SPACE #\\g)",
2198 &[ExprKind::If(Box::new(If::new(
2199 character('¡'),
2200 character(' '),
2201 character('g'),
2202 SyntaxObject::default(TokenType::If),
2203 )))],
2204 )
2205 }
2206
2207 #[test]
2208 fn parse_close_paren_character() {
2209 assert_parse("#\\)", &[character(')')]);
2210 assert_parse("#\\]", &[character(']')])
2211 }
2212
2213 #[test]
2214 fn parse_open_paren_character() {
2215 assert_parse("#\\(", &[character('(')])
2216 }
2217
2218 macro_rules! assert_matches {
2219 ($expr:expr, $pat:pat) => {{
2220 let value = $expr;
2221 match value {
2222 $pat => {}
2223 _ => panic!("{value:?} does not match"),
2224 }
2225 }};
2226 }
2227
2228 #[test]
2229 fn test_error() {
2230 assert_matches![parse_err("("), ParseError::UnexpectedEOF(..)];
2231 assert_matches![parse_err("(abc"), ParseError::UnexpectedEOF(..)];
2232 assert_matches![parse_err("(ab 1 2"), ParseError::UnexpectedEOF(..)];
2233 assert_matches![parse_err("((((ab 1 2) ("), ParseError::UnexpectedEOF(..)];
2234 assert_matches![parse_err("())"), ParseError::UnexpectedChar(')', ..)];
2235 assert_matches![parse_err("() (((("), ParseError::UnexpectedEOF(..)];
2236 assert_matches![parse_err("')"), ParseError::UnexpectedChar(')', ..)];
2237 assert_matches![parse_err("(')"), ParseError::UnexpectedChar(')', ..)];
2238 assert_matches![parse_err("('"), ParseError::UnexpectedEOF(..)];
2239 assert_matches![parse_err(r#""abc"#), ParseError::UnexpectedEOF(..)];
2240 assert_matches![
2241 parse_err("(]"),
2242 ParseError::MismatchedParen(Paren::Round, _, None)
2243 ];
2244 }
2245
2246 #[test]
2247 fn quote_multiple_args_should_err() {
2248 assert_parse_is_err("(quote a b c)");
2249 }
2250
2251 #[test]
2252 fn test_let_should_err() {
2253 assert_parse_is_err("(let)");
2254 assert_parse_is_err("(let (a) 10)");
2255 }
2256
2257 #[test]
2258 fn test_if_should_err() {
2259 assert_parse_is_err("(if)");
2260 assert_parse_is_err("(if 1)");
2261 assert_parse_is_err("(if 1 2 3 4)");
2263 }
2264
2265 #[test]
2266 fn test_define_should_err() {
2267 assert_parse_is_err("(define)");
2268 assert_parse_is_err("(define blagh)");
2269 assert_parse_is_err("(define test 1 2)");
2270 assert_parse_is_err("(define () test");
2271 }
2272
2273 #[test]
2274 fn test_lambda_should_err() {
2275 assert_parse_is_err("(lambda)");
2276 assert_parse_is_err("(lambda (x))");
2277 }
2278
2279 #[test]
2280 fn test_empty() {
2281 assert_parse("", &[]);
2282 assert_parse("()", &[ExprKind::List(List::new(thin_vec![]))]);
2283 }
2284
2285 #[test]
2286 fn test_empty_quote_inside_if() {
2287 assert_parse(
2288 "(if #\\¡ (quote ()) #\\g)",
2289 &[ExprKind::If(Box::new(If::new(
2290 character('¡'),
2291 ExprKind::Quote(
2292 Quote::new(
2293 List::new(thin_vec![]).into(),
2294 SyntaxObject::default(TokenType::Quote),
2295 )
2296 .into(),
2297 ),
2298 character('g'),
2299 SyntaxObject::default(TokenType::If),
2300 )))],
2301 )
2302 }
2303
2304 #[test]
2305 fn test_empty_quote() {
2306 assert_parse(
2307 "'()",
2308 &[ExprKind::Quote(
2309 Quote::new(
2310 List::new(thin_vec![]).into(),
2311 SyntaxObject::default(TokenType::Quote),
2312 )
2313 .into(),
2314 )],
2315 )
2316 }
2317
2318 #[test]
2319 fn test_empty_quote_nested() {
2320 assert_parse(
2321 "(list '())",
2322 &[ExprKind::List(List::new(thin_vec![
2323 atom("list"),
2324 ExprKind::Quote(
2325 Quote::new(
2326 List::new(thin_vec![]).into(),
2327 SyntaxObject::default(TokenType::Quote),
2328 )
2329 .into(),
2330 ),
2331 ]))],
2332 )
2333 }
2334
2335 #[test]
2336 fn test_multi_parse_simple() {
2337 assert_parse("a b +", &[atom("a"), atom("b"), atom("+")]);
2338 }
2339
2340 #[test]
2341 fn test_multi_parse_complicated() {
2342 assert_parse(
2343 "a b (funcall 1 (+ 2 3.5))",
2344 &[
2345 atom("a"),
2346 atom("b"),
2347 ExprKind::List(List::new(thin_vec![
2348 atom("funcall"),
2349 int(1),
2350 ExprKind::List(List::new(thin_vec![
2351 atom("+"),
2352 int(2),
2353 ExprKind::Atom(Atom::new(SyntaxObject::default(
2354 RealLiteral::Float((3.5).into()).into(),
2355 ))),
2356 ])),
2357 ])),
2358 ],
2359 )
2360 }
2361 #[test]
2362 fn test_parse_simple() {
2363 assert_parse(
2364 "(+ 1 2 3) (- 4 3)",
2365 &[
2366 ExprKind::List(List::new(thin_vec![atom("+"), int(1), int(2), int(3)])),
2367 ExprKind::List(List::new(thin_vec![atom("-"), int(4), int(3)])),
2368 ],
2369 );
2370 }
2371
2372 #[test]
2373 fn test_parse_nested() {
2374 assert_parse(
2375 "(+ 1 (foo (bar 2 3)))",
2376 &[ExprKind::List(List::new(thin_vec![
2377 atom("+"),
2378 int(1),
2379 ExprKind::List(List::new(thin_vec![
2380 atom("foo"),
2381 ExprKind::List(List::new(thin_vec![atom("bar"), int(2), int(3)])),
2382 ])),
2383 ]))],
2384 );
2385 assert_parse(
2386 "(+ 1 (+ 2 3) (foo (bar 2 3)))",
2387 &[ExprKind::List(List::new(thin_vec![
2388 atom("+"),
2389 int(1),
2390 ExprKind::List(List::new(thin_vec![atom("+"), int(2), int(3)])),
2391 ExprKind::List(List::new(thin_vec![
2392 atom("foo"),
2393 ExprKind::List(List::new(thin_vec![atom("bar"), int(2), int(3)])),
2394 ])),
2395 ]))],
2396 );
2397 }
2398
2399 #[test]
2400 fn test_if() {
2401 assert_parse(
2402 "(+ 1 (if 2 3 4) (foo (+ (bar 1 1) 3) 5))",
2403 &[ExprKind::List(List::new(thin_vec![
2404 atom("+"),
2405 int(1),
2406 ExprKind::If(Box::new(If::new(
2407 int(2),
2408 int(3),
2409 int(4),
2410 SyntaxObject::default(TokenType::If),
2411 ))),
2412 ExprKind::List(List::new(thin_vec![
2413 atom("foo"),
2414 ExprKind::List(List::new(thin_vec![
2415 atom("+"),
2416 ExprKind::List(List::new(thin_vec![atom("bar"), int(1), int(1)])),
2417 int(3),
2418 ])),
2419 int(5),
2420 ])),
2421 ]))],
2422 );
2423 }
2424
2425 #[test]
2426 fn test_quote() {
2427 assert_parse(
2428 "(quote (if 1 2))",
2429 &[ExprKind::Quote(Box::new(Quote::new(
2430 ExprKind::List(List::new(thin_vec![
2431 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2432 int(1),
2433 int(2),
2434 ])),
2435 SyntaxObject::default(TokenType::Quote),
2436 )))],
2437 )
2438 }
2439
2440 #[test]
2441 fn test_quote_shorthand() {
2442 assert_parse(
2443 "'(if 1 2)",
2444 &[ExprKind::Quote(Box::new(Quote::new(
2445 ExprKind::List(List::new(thin_vec![
2446 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2447 int(1),
2448 int(2),
2449 ])),
2450 SyntaxObject::default(TokenType::Quote),
2451 )))],
2452 )
2453 }
2454
2455 #[test]
2456 fn test_quote_nested() {
2457 assert_parse(
2458 "(quote (if (if 1 2) 3))",
2459 &[ExprKind::Quote(Box::new(Quote::new(
2460 ExprKind::List(List::new(thin_vec![
2461 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2462 ExprKind::List(List::new(thin_vec![
2463 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2464 int(1),
2465 int(2),
2466 ])),
2467 int(3),
2468 ])),
2469 SyntaxObject::default(TokenType::Quote),
2470 )))],
2471 )
2472 }
2473
2474 #[test]
2475 fn test_quote_shorthand_nested() {
2476 assert_parse(
2477 "'(if (if 1 2) 3)",
2478 &[ExprKind::Quote(Box::new(Quote::new(
2479 ExprKind::List(List::new(thin_vec![
2480 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2481 ExprKind::List(List::new(thin_vec![
2482 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2483 int(1),
2484 int(2),
2485 ])),
2486 int(3),
2487 ])),
2488 SyntaxObject::default(TokenType::Quote),
2489 )))],
2490 )
2491 }
2492
2493 #[test]
2494 fn test_quote_shorthand_multiple_exprs() {
2495 assert_parse(
2496 "'(if (if 1 2) 3) (+ 1 (if 2 3 4) (foo (+ (bar 1 1) 3) 5))",
2497 &[
2498 ExprKind::Quote(Box::new(Quote::new(
2499 ExprKind::List(List::new(thin_vec![
2500 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2501 ExprKind::List(List::new(thin_vec![
2502 ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2503 int(1),
2504 int(2),
2505 ])),
2506 int(3),
2507 ])),
2508 SyntaxObject::default(TokenType::Quote),
2509 ))),
2510 ExprKind::List(List::new(thin_vec![
2511 atom("+"),
2512 int(1),
2513 ExprKind::If(Box::new(If::new(
2514 int(2),
2515 int(3),
2516 int(4),
2517 SyntaxObject::default(TokenType::If),
2518 ))),
2519 ExprKind::List(List::new(thin_vec![
2520 atom("foo"),
2521 ExprKind::List(List::new(thin_vec![
2522 atom("+"),
2523 ExprKind::List(List::new(thin_vec![atom("bar"), int(1), int(1)])),
2524 int(3),
2525 ])),
2526 int(5),
2527 ])),
2528 ])),
2529 ],
2530 )
2531 }
2532
2533 #[test]
2534 fn test_quote_inner() {
2535 assert_parse(
2536 "'(applesauce 'one)",
2537 &[ExprKind::Quote(Box::new(Quote::new(
2538 ExprKind::List(List::new(thin_vec![
2539 atom("applesauce"),
2540 ExprKind::Quote(Box::new(Quote::new(
2541 atom("one"),
2542 SyntaxObject::default(TokenType::Quote),
2543 ))),
2544 ])),
2545 SyntaxObject::default(TokenType::Quote),
2546 )))],
2547 )
2548 }
2549
2550 #[test]
2551 fn test_quote_inner_without_shorthand() {
2552 assert_parse(
2553 "(quote (applesauce 'one))",
2554 &[ExprKind::Quote(Box::new(Quote::new(
2555 ExprKind::List(List::new(thin_vec![
2556 atom("applesauce"),
2557 ExprKind::Quote(Box::new(Quote::new(
2558 atom("one"),
2559 SyntaxObject::default(TokenType::Quote),
2560 ))),
2561 ])),
2562 SyntaxObject::default(TokenType::Quote),
2563 )))],
2564 )
2565 }
2566
2567 #[test]
2568 fn test_quasiquote_shorthand() {
2569 assert_parse(
2570 "`(+ 1 2)",
2571 &[ExprKind::List(List::new(thin_vec![
2572 atom("quasiquote"),
2573 ExprKind::List(List::new(thin_vec![atom("+"), int(1), int(2)])),
2574 ]))],
2575 )
2576 }
2577
2578 #[test]
2579 fn test_quasiquote_normal() {
2580 assert_parse(
2581 "(quasiquote (+ 1 2))",
2582 &[ExprKind::List(List::new(thin_vec![
2583 atom("quasiquote"),
2584 ExprKind::List(List::new(thin_vec![atom("+"), int(1), int(2)])),
2585 ]))],
2586 )
2587 }
2588
2589 #[test]
2590 fn test_unquote_shorthand() {
2591 assert_parse(
2592 ",(+ 1 2)",
2593 &[ExprKind::List(List::new(thin_vec![
2594 atom("unquote"),
2595 ExprKind::List(List::new(thin_vec![atom("+"), int(1), int(2)])),
2596 ]))],
2597 )
2598 }
2599
2600 #[test]
2601 fn test_unquote_normal() {
2602 assert_parse(
2603 "(unquote (+ 1 2))",
2604 &[ExprKind::List(List::new(thin_vec![
2605 atom("unquote"),
2606 ExprKind::List(List::new(thin_vec![atom("+"), int(1), int(2)])),
2607 ]))],
2608 )
2609 }
2610
2611 #[test]
2612 fn test_unquote_splicing_shorthand() {
2613 assert_parse(
2614 ",@(+ 1 2)",
2615 &[ExprKind::List(List::new(thin_vec![
2616 atom("unquote-splicing"),
2617 ExprKind::List(List::new(thin_vec![atom("+"), int(1), int(2)])),
2618 ]))],
2619 )
2620 }
2621
2622 #[test]
2623 fn test_unquote_splicing_normal() {
2624 assert_parse(
2625 "(unquote-splicing (+ 1 2))",
2626 &[ExprKind::List(List::new(thin_vec![
2627 atom("unquote-splicing"),
2628 ExprKind::List(List::new(thin_vec![atom("+"), int(1), int(2)])),
2629 ]))],
2630 )
2631 }
2632
2633 #[test]
2634 fn test_define_simple() {
2635 assert_parse(
2636 "(define a 10)",
2637 &[ExprKind::Define(Box::new(Define::new(
2638 atom("a"),
2639 int(10),
2640 SyntaxObject::default(TokenType::Define),
2641 )))],
2642 )
2643 }
2644
2645 #[test]
2646 fn test_define_func_simple() {
2647 assert_parse(
2648 "(define (foo x) (+ x 10))",
2649 &[ExprKind::Define(Box::new(Define::new(
2650 atom("foo"),
2651 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2652 thin_vec![atom("x")],
2653 ExprKind::List(List::new(thin_vec![atom("+"), atom("x"), int(10)])),
2654 SyntaxObject::default(TokenType::Lambda),
2655 ))),
2656 SyntaxObject::default(TokenType::Define),
2657 )))],
2658 )
2659 }
2660
2661 #[test]
2662 fn test_define_func_multiple_args() {
2663 assert_parse(
2664 "(define (foo x y z) (+ x 10))",
2665 &[ExprKind::Define(Box::new(Define::new(
2666 atom("foo"),
2667 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2668 thin_vec![atom("x"), atom("y"), atom("z")],
2669 ExprKind::List(List::new(thin_vec![atom("+"), atom("x"), int(10)])),
2670 SyntaxObject::default(TokenType::Lambda),
2671 ))),
2672 SyntaxObject::default(TokenType::Define),
2673 )))],
2674 )
2675 }
2676
2677 #[test]
2678 fn test_define_func_multiple_args_multiple_body_exprs() {
2679 assert_parse(
2680 "(define (foo x y z) (+ x 10) (+ y 20) (+ z 30))",
2681 &[ExprKind::Define(Box::new(Define::new(
2682 atom("foo"),
2683 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2684 thin_vec![atom("x"), atom("y"), atom("z")],
2685 ExprKind::Begin(Box::new(Begin::new(
2686 vec![
2687 ExprKind::List(List::new(thin_vec![atom("+"), atom("x"), int(10)])),
2688 ExprKind::List(List::new(thin_vec![atom("+"), atom("y"), int(20)])),
2689 ExprKind::List(List::new(thin_vec![atom("+"), atom("z"), int(30)])),
2690 ],
2691 SyntaxObject::default(TokenType::Begin),
2692 ))),
2693 SyntaxObject::default(TokenType::Lambda),
2694 ))),
2695 SyntaxObject::default(TokenType::Define),
2696 )))],
2697 )
2698 }
2699
2700 #[test]
2701 fn test_recursive_function() {
2702 assert_parse(
2703 "(define (test) (define (foo) (bar)) (define (bar) (foo)))",
2704 &[ExprKind::Define(Box::new(Define::new(
2705 atom("test"),
2706 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2707 thin_vec![],
2708 ExprKind::Begin(Box::new(Begin::new(
2709 vec![
2710 ExprKind::Define(Box::new(Define::new(
2711 atom("foo"),
2712 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2713 thin_vec![],
2714 ExprKind::List(List::new(thin_vec![atom("bar")])),
2715 SyntaxObject::default(TokenType::Lambda),
2716 ))),
2717 SyntaxObject::default(TokenType::Define),
2718 ))),
2719 ExprKind::Define(Box::new(Define::new(
2720 atom("bar"),
2721 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2722 thin_vec![],
2723 ExprKind::List(List::new(thin_vec![atom("foo")])),
2724 SyntaxObject::default(TokenType::Lambda),
2725 ))),
2726 SyntaxObject::default(TokenType::Define),
2727 ))),
2728 ],
2729 SyntaxObject::default(TokenType::Begin),
2730 ))),
2731 SyntaxObject::default(TokenType::Lambda),
2732 ))),
2733 SyntaxObject::default(TokenType::Define),
2734 )))],
2735 )
2736 }
2737
2738 #[test]
2739 fn test_return_normal() {
2740 assert_parse(
2741 "(return! 10)",
2742 &[ExprKind::Return(Box::new(Return::new(
2743 int(10),
2744 SyntaxObject::default(TokenType::Return),
2745 )))],
2746 )
2747 }
2748
2749 #[test]
2750 fn test_begin() {
2751 assert_parse(
2752 "(begin 1 2 3)",
2753 &[ExprKind::Begin(Box::new(Begin::new(
2754 vec![int(1), int(2), int(3)],
2755 SyntaxObject::default(TokenType::Begin),
2756 )))],
2757 )
2758 }
2759
2760 #[test]
2761 fn test_lambda_function() {
2762 assert_parse(
2763 "(lambda (x) 10)",
2764 &[ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2765 thin_vec![atom("x")],
2766 int(10),
2767 SyntaxObject::default(TokenType::Lambda),
2768 )))],
2769 )
2770 }
2771
2772 #[test]
2773 fn test_lambda_function_with_rest() {
2774 assert_parse(
2775 "(lambda (x . y) 10)",
2776 &[ExprKind::LambdaFunction(Box::new(
2777 LambdaFunction::new_maybe_rest(
2778 thin_vec![atom("x"), atom("y")],
2779 int(10),
2780 SyntaxObject::default(TokenType::Lambda),
2781 true,
2782 ),
2783 ))],
2784 )
2785 }
2786
2787 #[test]
2788 fn test_lambda_function_with_rest_only() {
2789 assert_parse(
2790 "(lambda x 10)",
2791 &[ExprKind::LambdaFunction(Box::new(
2792 LambdaFunction::new_maybe_rest(
2793 thin_vec![atom("x")],
2794 int(10),
2795 SyntaxObject::default(TokenType::Lambda),
2796 true,
2797 ),
2798 ))],
2799 )
2800 }
2801
2802 #[test]
2803 fn test_lambda_matches_let() {
2804 assert_parse(
2805 "((lambda (a) (+ a 20)) 10)",
2806 &[ExprKind::List(List::new(thin_vec![
2807 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2808 thin_vec![atom("a")],
2809 ExprKind::List(List::new(thin_vec![atom("+"), atom("a"), int(20)])),
2810 SyntaxObject::default(TokenType::Lambda),
2811 ))),
2812 int(10),
2813 ]))],
2814 );
2815 }
2816
2817 #[test]
2818 fn test_let() {
2819 assert_parse(
2820 "(let ([a 10]) (+ a 20))",
2821 &[ExprKind::List(List::new(thin_vec![
2822 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2823 thin_vec![atom("a")],
2824 ExprKind::List(List::new(thin_vec![atom("+"), atom("a"), int(20)])),
2825 SyntaxObject::default(TokenType::Lambda),
2826 ))),
2827 int(10),
2828 ]))],
2829 )
2830 }
2831
2832 #[test]
2833 fn test_quote_with_inner_nested() {
2834 assert_parse(
2835 "'(#f '())",
2836 &[ExprKind::Quote(
2837 Quote::new(
2838 ExprKind::List(List::new(thin_vec![
2839 ExprKind::Atom(Atom::new(SyntaxObject::default(
2840 TokenType::BooleanLiteral(false),
2841 ))),
2842 ExprKind::Quote(
2843 Quote::new(
2844 List::new(thin_vec![]).into(),
2845 SyntaxObject::default(TokenType::Quote),
2846 )
2847 .into(),
2848 ),
2849 ])),
2850 SyntaxObject::default(TokenType::Quote),
2851 )
2852 .into(),
2853 )],
2854 )
2855 }
2856
2857 #[test]
2858 fn test_quote_with_inner_nested_sub_expr() {
2859 assert_parse(
2860 "(if (null? contents)
2861 '(#f '())
2862 (list (car contents) (cdr contents)))",
2863 &[ExprKind::If(Box::new(If::new(
2864 ExprKind::List(List::new(thin_vec![atom("null?"), atom("contents")])),
2865 ExprKind::Quote(
2866 Quote::new(
2867 ExprKind::List(List::new(thin_vec![
2868 ExprKind::Atom(Atom::new(SyntaxObject::default(
2869 TokenType::BooleanLiteral(false),
2870 ))),
2871 ExprKind::Quote(
2872 Quote::new(
2873 List::new(thin_vec![]).into(),
2874 SyntaxObject::default(TokenType::Quote),
2875 )
2876 .into(),
2877 ),
2878 ])),
2879 SyntaxObject::default(TokenType::Quote),
2880 )
2881 .into(),
2882 ),
2883 ExprKind::List(List::new(thin_vec![
2884 atom("list"),
2885 ExprKind::List(List::new(thin_vec![atom("car"), atom("contents")])),
2886 ExprKind::List(List::new(thin_vec![atom("cdr"), atom("contents")])),
2887 ])),
2888 SyntaxObject::default(TokenType::If),
2889 )))],
2890 );
2891 }
2892
2893 #[test]
2894 fn test_quote_normal_with_inner_nested_sub_expr() {
2895 assert_parse(
2896 "(if (null? contents)
2897 (quote (#f '()))
2898 (list (car contents) (cdr contents)))",
2899 &[ExprKind::If(Box::new(If::new(
2900 ExprKind::List(List::new(thin_vec![atom("null?"), atom("contents")])),
2901 ExprKind::Quote(
2902 Quote::new(
2903 ExprKind::List(List::new(thin_vec![
2904 ExprKind::Atom(Atom::new(SyntaxObject::default(
2905 TokenType::BooleanLiteral(false),
2906 ))),
2907 ExprKind::Quote(
2908 Quote::new(
2909 List::new(thin_vec![]).into(),
2910 SyntaxObject::default(TokenType::Quote),
2911 )
2912 .into(),
2913 ),
2914 ])),
2915 SyntaxObject::default(TokenType::Quote),
2916 )
2917 .into(),
2918 ),
2919 ExprKind::List(List::new(thin_vec![
2920 atom("list"),
2921 ExprKind::List(List::new(thin_vec![atom("car"), atom("contents")])),
2922 ExprKind::List(List::new(thin_vec![atom("cdr"), atom("contents")])),
2923 ])),
2924 SyntaxObject::default(TokenType::If),
2925 )))],
2926 );
2927 }
2928
2929 #[test]
2930 fn test_quote_with_inner_sub_expr_even_more_nested() {
2931 assert_parse(
2932 "(list
2933 (if (null? contents)
2934 '(#f '())
2935 (list (car contents) (cdr contents))))",
2936 &[ExprKind::List(List::new(thin_vec![
2937 atom("list"),
2938 ExprKind::If(Box::new(If::new(
2939 ExprKind::List(List::new(thin_vec![atom("null?"), atom("contents")])),
2940 ExprKind::Quote(
2941 Quote::new(
2942 ExprKind::List(List::new(thin_vec![
2943 ExprKind::Atom(Atom::new(SyntaxObject::default(
2944 TokenType::BooleanLiteral(false),
2945 ))),
2946 ExprKind::Quote(
2947 Quote::new(
2948 List::new(thin_vec![]).into(),
2949 SyntaxObject::default(TokenType::Quote),
2950 )
2951 .into(),
2952 ),
2953 ])),
2954 SyntaxObject::default(TokenType::Quote),
2955 )
2956 .into(),
2957 ),
2958 ExprKind::List(List::new(thin_vec![
2959 atom("list"),
2960 ExprKind::List(List::new(thin_vec![atom("car"), atom("contents")])),
2961 ExprKind::List(List::new(thin_vec![atom("cdr"), atom("contents")])),
2962 ])),
2963 SyntaxObject::default(TokenType::If),
2964 ))),
2965 ]))],
2966 );
2967 }
2968
2969 #[test]
2970 fn test_define_with_datum_syntax_name() {
2971 assert_parse(
2972 "(define (datum->syntax var) (car ret-value))",
2973 &[ExprKind::Define(Box::new(Define::new(
2974 ExprKind::List(List::new(thin_vec![atom("datum->syntax"), atom("var")])),
2975 ExprKind::List(List::new(thin_vec![atom("car"), atom("ret-value")])),
2976 SyntaxObject::default(TokenType::Define),
2977 )))],
2978 )
2979 }
2980
2981 #[test]
2982 fn test_define_with_datum_syntax_function_name() {
2983 assert_parse(
2984 "(define ((datum->syntax var) arg) 10)",
2985 &[ExprKind::Define(Box::new(Define::new(
2986 ExprKind::List(List::new(thin_vec![atom("datum->syntax"), atom("var")])),
2987 ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2988 thin_vec![atom("arg")],
2989 int(10),
2990 SyntaxObject::default(TokenType::Lambda),
2991 ))),
2992 SyntaxObject::default(TokenType::Define),
2993 )))],
2994 )
2995 }
2996
2997 #[test]
2998 fn test_parse_without_lowering_ast() {
2999 let a: Result<Vec<ExprKind>> =
3000 Parser::new_flat("(define (quote a) 10) (require foo bar)", SourceId::none())
3001 .map(|x| x.and_then(lower_macro_and_require_definitions))
3002 .collect();
3003
3004 let a = a.unwrap();
3005
3006 println!("{:#?}", a);
3007 }
3008
3009 #[test]
3010 fn test_delayed_lowering() {
3011 let a: Result<Vec<ExprKind>> = Parser::new_flat(
3012 r#"
3013 ;; (define foo (quote a)) (require foo bar)
3014
3015 ;; (define (foo) (if 10 20 30))
3016
3017 ;; (define (foo) (quote (define 10 20)))
3018
3019 ;; (define foo '())
3020
3021 (define-syntax
3022 with-handler
3023 (syntax-rules
3024 ()
3025 ((with-handler handler expr)
3026 (reset
3027 (call-with-exception-handler
3028 (λ (err)
3029 (begin (handler err) (shift k (k void))))
3030 (λ ()
3031 expr))))
3032 ((with-handler handler expr ...)
3033 (reset
3034 (call-with-exception-handler
3035 (λ (err)
3036 (begin (handler err) (shift k (k void))))
3037 (λ ()
3038 (begin expr ...)))))))
3039
3040
3041
3042 "#,
3043 SourceId::none(),
3044 )
3045 .map(|x| x.and_then(lower_macro_and_require_definitions))
3046 .map(|x| {
3047 x.and_then(|mut expr| {
3048 lower_entire_ast(&mut expr)?;
3049 Ok(expr)
3050 })
3051 })
3052 .collect();
3053
3054 let a = a.unwrap();
3055
3056 println!("{:#?}", a);
3057 }
3058
3059 #[test]
3060 fn test_improper_list() {
3061 let mut pair = List::new(thin_vec![atom("x"), atom("y")]);
3062 pair.make_improper();
3063
3064 assert_parse("(x . y)", &[ExprKind::List(pair)]);
3065
3066 assert_parse(
3067 "(x . (y . ()))",
3068 &[ExprKind::List(List::new(thin_vec![atom("x"), atom("y")]))],
3069 )
3070 }
3071
3072 #[test]
3073 fn test_improper_list_failures() {
3074 assert_syntax_err(
3075 "(. a)",
3076 "improper lists must have a car element before the dot",
3077 );
3078 assert_syntax_err("(a .)", "improper list must have a single cdr");
3079 assert_syntax_err("(a . b . )", "improper lists can only have a single dot");
3080 assert_syntax_err("(a . b . c)", "improper lists can only have a single dot");
3081 assert_syntax_err("(a . b c)", "improper list must have a single cdr");
3082 assert_syntax_err("(a . b (c))", "improper list must have a single cdr");
3083 }
3084
3085 #[test]
3086 fn test_vectors() {
3087 assert_parse(
3088 "#(a b)",
3089 &[ExprKind::Vector(Vector {
3090 args: thin_vec![atom("a"), atom("b")],
3091 bytes: false,
3092 span: Span::default(),
3093 })],
3094 );
3095
3096 assert_parse(
3097 "#u8(1 3)",
3098 &[ExprKind::Vector(Vector {
3099 args: thin_vec![int(1), int(3)],
3100 bytes: true,
3101 span: Span::default(),
3102 })],
3103 );
3104 }
3105
3106 #[test]
3107 fn test_malformed_vectors() {
3108 assert_syntax_err(
3109 "#u8(#\\a)",
3110 "bytevector literals can only contain integer literals in the 0-255 range",
3111 );
3112
3113 assert_syntax_err(
3114 "#u8(())",
3115 "bytevector literals can only contain integer literals in the 0-255 range",
3116 );
3117
3118 assert_syntax_err("#u8(1 . 2)", "bytevector literals cannot contain dots");
3119
3120 assert_syntax_err("#(1 . 2)", "vector literals cannot contain dots");
3121 }
3122
3123 #[test]
3124 fn test_datum_comments() {
3125 assert_parse("#; 1 2", &[int(2)]);
3126
3127 assert_parse("#; #; #false (2) 3", &[int(3)]);
3128
3129 assert_parse("#; ,@foo 4", &[int(4)]);
3130
3131 assert_parse(
3132 "(1 #; #(a b c) 2)",
3133 &[ExprKind::List(List::new(thin_vec![int(1), int(2)]))],
3134 )
3135 }
3136
3137 #[test]
3138 fn test_invalid_datum_comments() {
3139 assert_syntax_err("( 1 #; )", "invalid datum comment");
3140
3141 assert_syntax_err(
3142 "( 1 2 #; . b)",
3143 "commented-out datum cannot start with a dot",
3144 );
3145 }
3146}
3147
3148use core::cell::RefCell;
3149use core::default::Default;
3150use core::ops::{Deref, DerefMut};
3151
3152pub trait Recyclable {
3153 fn put(self);
3154 fn get() -> Self;
3155 fn get_with_capacity(capacity: usize) -> Self;
3156}
3157
3158pub struct Recycle<T: Recyclable + Default> {
3159 t: T,
3160}
3161
3162impl<T: Recyclable + Default> Default for Recycle<T> {
3163 fn default() -> Self {
3164 Self::new()
3165 }
3166}
3167
3168impl<T: Recyclable + Default> Recycle<T> {
3169 pub fn new() -> Self {
3170 Recycle { t: T::get() }
3171 }
3172
3173 pub fn new_with_capacity(capacity: usize) -> Self {
3174 Recycle {
3175 t: T::get_with_capacity(capacity),
3176 }
3177 }
3178}
3179
3180impl<T: Recyclable + Default> Drop for Recycle<T> {
3181 fn drop(&mut self) {
3182 T::put(core::mem::take(&mut self.t))
3183 }
3184}
3185
3186impl<T: Recyclable + Default> Deref for Recycle<T> {
3187 type Target = T;
3188
3189 fn deref(&self) -> &T {
3190 &self.t
3191 }
3192}
3193
3194impl<T: Recyclable + Default + 'static> DerefMut for Recycle<T> {
3195 fn deref_mut(&mut self) -> &mut T {
3196 &mut self.t
3197 }
3198}
3199
3200impl<T: Recyclable + Clone + Default> Clone for Recycle<T> {
3201 fn clone(&self) -> Self {
3202 Recycle { t: self.t.clone() }
3203 }
3204}
3205
3206impl<T: Recyclable + core::fmt::Debug + Default> core::fmt::Debug for Recycle<T> {
3207 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
3208 f.debug_struct("Recycle").field("t", &self.t).finish()
3209 }
3210}
3211
3212impl<T: Recyclable + core::hash::Hash + Default> core::hash::Hash for Recycle<T> {
3213 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
3214 self.t.hash(state);
3215 }
3216}
3217
3218macro_rules! impl_recyclable {
3219 ($tl:ident, $t:ty) => {
3220 impl_recyclable!($tl, $t, Default::default(), Self::with_capacity);
3221 };
3222 ($tl:ident, $t:ty, $constructor:expr, $constructor_capacity:expr) => {
3223 thread_local! {
3224 static $tl: RefCell<Vec<$t>> = RefCell::new(Vec::new())
3225 }
3226
3227 impl Recyclable for $t {
3228 fn put(mut self) {
3229 let _ = $tl.try_with(|p| {
3230 let p = p.try_borrow_mut();
3231
3232 if let Ok(mut p) = p {
3233 self.clear();
3245
3246 p.push(self);
3247 }
3248 });
3249 }
3250
3251 fn get() -> Self {
3252 $tl.with(|p| {
3253 let mut p = p.borrow_mut();
3254 p.pop()
3255 })
3256 .unwrap_or($constructor)
3257 }
3258
3259 fn get_with_capacity(capacity: usize) -> Self {
3260 $tl.with(|p| {
3261 let mut p = p.borrow_mut();
3262 p.pop()
3263 })
3264 .unwrap_or(($constructor_capacity)(capacity))
3265 }
3266 }
3267 };
3268}
3269
3270impl_recyclable!(TL_V_STEELVAL, Vec<Frame>);