Skip to main content

steel_parser/
parser.rs

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
42// TODO: Fix the visibility here
43pub static SYNTAX_OBJECT_ID: AtomicUsize = AtomicUsize::new(0);
44
45// thread_local! {
46//     pub static TL_SYNTAX_OBJECT_ID: Cell<u32> = Cell::new(0);
47// }
48
49#[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        // TODO: Revisit why we're using this here
59        // SyntaxObjectId(TL_SYNTAX_OBJECT_ID.with(|x| {
60        //     let value = x.get();
61        //     x.set(value + 1);
62        //     value
63        // }))
64    }
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/// A syntax object that can hold anything as the syntax
90/// In this case, we're using the token type emitted by logos
91///
92/// This should open the door to interning our strings to make
93/// parsing (and optimizations later) faster
94#[derive(Serialize, Deserialize)]
95pub struct RawSyntaxObject<T> {
96    pub ty: T,
97    pub span: Span,
98    pub syntax_object_id: SyntaxObjectId,
99    // TODO: @Matt
100    // This is a hack. More or less, we need a way to mark that
101    // this particular syntax object is "unresolved" - and thus
102    // should mangle its usage. This can also be done by using
103    // the syntax object ID separately, but there is enough
104    // space on the object itself that keeping it alongside the
105    // object seemed to make sense. What we're going to do is mark
106    // any unresolved references to variables found in macro expansion.
107    // So, for example, consider the following:
108    //
109    // (define bound-x (vector 10 20 30 40))
110    //
111    // (define-syntax lexical-capture
112    //   (syntax-rules ()
113    //     [(_) (list bound-x)]))
114    //
115    // (let ([bound-x 'inner]) (lexical-capture))
116    //
117    // The define syntax is expanded without the context of knowing
118    // the globals, and as a result isn't aware that bound-x should
119    // refer to the local. However, we can expand and see that both
120    // `list` and `bound-x` don't refer to anything in the patterns,
121    // and so as a result, should be marked as "unresolved". Since
122    // they are unresolved, we can conclude that either they're
123    // global variables, or a free identifier.
124    //
125    // Then, when handling shadowed local variables, when we come across
126    // a local variable that we'd like to mangle, if its unresolved, we
127    // just leave it alone, and otherwise we should treat all locals as
128    // variables to be mangled.
129    //
130    // Then, once we're done with all macro expansion, all variables themselves
131    // should be "resolved" since either they refer to an individual variable,
132    // or nothing at all.
133    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
158// Implementing hash here just on the token type - we dont want the span included
159// For determining the hash here
160impl<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            // source: None,
181            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            // source: None,
192            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
291// #[derive(Debug)]
292pub 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    // Inside of a quote. Expressions should be parsed without being coerced into a typed variant of the AST
310    Quote(usize),
311    // Shortened version of a quote
312    QuoteTick(usize),
313    // Inside of an unquote - expressions should actually be parsed as usual
314    Unquote(usize),
315    // Shortened version of unquote
316    UnquoteTick(usize),
317    // Treat this like a normal quote
318    Quasiquote(usize),
319    // Shortened version of quasiquote
320    QuasiquoteTick(usize),
321    // expressions should parsed as normal
322    UnquoteSplicing(usize),
323    // Shorted version of Unquote Splicing
324    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    // Attach comments!
404    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        // println!("Inside construct quote vec with: {:?}", val);
440
441        let q = {
442            let rc_val = TokenType::Quote;
443            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
444            // let val = ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)));
445            // // self.intern.insert("quote".to_string(), rc_val);
446            // val
447        };
448
449        thin_vec![q, val]
450    }
451
452    // Reader macro for #'
453    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    // Reader macro for #'
463    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    // Reader macro for `
491    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    // Reader macro for ,
501    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(*UNQUOTE);
513            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    // Reader macro for ,@
520    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    // Reader macro for ,@
530    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        // println!("INCREMENTING");
541        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        // println!("DECREMENTING");
548        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        // Can we reuse this?
572        // TODO: I think we have to shove this into the parser state.
573        // Alongside the current frame and anything else.
574        //
575        // That way, we can just keep it around if we hit an EOF and
576        // we're in incremental mode, where we can keep feeding data
577        // in and it can continue to produce parsed values.
578        let mut stack: Vec<Frame> = Vec::new();
579
580        // self.stack.clear();
581
582        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        // println!("READING FROM TOKENS");
594        // self.quasiquote_depth = 0;
595
596        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                    // println!("Found a comment!");
638                    // Internal comments, we're gonna skip for now
639                }
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                    // quote_count += 1;
694                    // self.quote_stack.push(current_frame.exprs.len());
695                    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                    // println!("Entering context: Quote Tick in read from tokens");
704
705                    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                            // if self.quasiquote_depth == 0 {
715                            self.construct_quote(x, token.span)
716                            // } else {
717                            // self.construct_fake_quote(x, token.span)
718                            // }
719                        });
720                    // self.quote_stack.pop();
721                    self.shorthand_quote_stack.pop();
722
723                    self.quote_context = last_context;
724
725                    // println!(
726                    //     "Exiting Context: {:?} in read from tokens",
727                    //     self.context.pop()
728                    // );
729
730                    // self.context.pop();
731
732                    let popped_value = self.context.pop();
733
734                    if let Some(popped) = popped_value {
735                        // dbg!(&popped);
736                        debug_assert!(matches!(popped, ParsingContext::QuoteTick(_)))
737                    }
738
739                    current_frame.push(quote_inner?)?;
740                }
741                TokenType::Unquote => {
742                    // println!("Entering context: Unquote");
743
744                    // This could underflow and panic - if its negative then we have a problem. Maybe just use an isize and let it underflow?
745                    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                            // dbg!(self.quasiquote_depth);
757                            // dbg!(self.quote_context);
758                            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                    // println!("Exiting Context: {:?}", self.context.pop());
773                    current_frame.push(quote_inner?)?;
774                }
775                TokenType::QuasiQuote => {
776                    // println!("Entering context: Quasiquote");
777
778                    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                    // self.context.pop();
792                    // println!(
793                    //     ">>>>>>>>>>>>>>>>>>> Exiting Context: {:?}",
794                    //     self.context.pop()
795                    // );
796
797                    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                    // println!("Entering context: UnquoteSplicing");
809
810                    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                    // self.context.pop();
830
831                    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                    // println!("Exiting Context: {:?}", self.context.pop());
840                    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                    // This is the match that we'll want to move inside the below stack.pop() match statement
857                    // As we close the current context, we check what our current state is -
858
859                    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                                // self.increment_quasiquote_context_if_not_in_quote_context();
875                                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                                // println!("Exiting unquote");
881                            }
882                            Some(ident) if *ident == *QUASIQUOTE => {
883                                self.decrement_quasiquote_context_if_not_in_quote_context();
884
885                                // println!("Exiting quasiquote");
886                            }
887                            Some(ident) if *ident == *UNQUOTE_SPLICING => {
888                                // self.increment_quasiquote_context_if_not_in_quote_context();
889
890                                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                                // println!("Exiting unquote");
896                            }
897                            _ => {}
898                        }
899
900                        match self.context.last().copied() {
901                            // TODO: Change this -> This should really be just Some(ParsingContext::Quote)
902                            // If we have _anything_ then we should check if we need to parse it differently. If we're at the last_quote_index,
903                            // then we can pop it off inside there.
904                            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                                        // println!("Converting to list");
932                                        // println!("Context here: {:?}", self.context);
933                                        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                                        // println!("Converting to quote inside quote tick");
949                                        prev_frame
950                                            .push(self.maybe_lower_frame(current_frame, close)?)?;
951                                    }
952                                    _ => {
953                                        // if let Some(ParsingContext::QuasiquoteTick(_)) =
954                                        //     self.context.last()
955                                        // {
956                                        //     self.decrement_quasiquote_context_if_not_in_quote_context();
957                                        // }
958
959                                        // println!("Converting to list inside quote tick");
960                                        prev_frame.push(current_frame.into_expr(close)?)?
961                                    }
962                                }
963                            }
964
965                            // If we're in the short hand reader world, just ignore popping off the stack
966                            // but still treat it as a normal expression
967                            Some(ParsingContext::UnquoteTick(_))
968                            | Some(ParsingContext::UnquoteSplicingTick(_)) => {
969                                // self.quasiquote_depth += 1;
970
971                                // self.increment_quasiquote_context_if_not_in_quote_context();
972
973                                // println!(
974                                //     "UQ/UQS: Stack length: {:?}, last_quote_index: {:?}",
975                                //     stack.len(),
976                                //     last_quote_index
977                                // );
978
979                                // if stack.len() <= *last_quote_index {
980                                //     // println!("Exiting Context: {:?}", self.context.pop());
981                                //     self.context.pop();
982                                // }
983
984                                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                                // self.quasiquote_depth += 1;
990
991                                // self.increment_quasiquote_context_if_not_in_quote_context();
992
993                                // println!(
994                                //     "UQ/UQS: Stack length: {:?}, last_quote_index: {:?}",
995                                //     stack.len(),
996                                //     last_quote_index
997                                // );
998
999                                if stack.len() <= last_quote_index {
1000                                    // println!("{} - {}", stack.len(), last_quote_index);
1001                                    // println!("Exiting Context: {:?}", self.context.pop());
1002                                    self.context.pop();
1003                                }
1004
1005                                prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?;
1006                            }
1007
1008                            // Else case, just go ahead and assume it is a normal frame
1009                            _ => prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?,
1010                        }
1011
1012                        // Reinitialize current frame here
1013                        current_frame = prev_frame;
1014                    } else {
1015                        // println!("Else case: {:?}", current_frame.exprs);
1016                        // println!("Context: {:?}", self.context);
1017
1018                        // dbg!(&self.quote_stack);
1019                        // dbg!(&self.context);
1020                        // dbg!(&self.shorthand_quote_stack);
1021                        match self.context.last() {
1022                            Some(ParsingContext::QuoteTick(_))
1023                            | Some(ParsingContext::QuasiquoteTick(_)) => {
1024                                // | Some(ParsingContext::Quote(d)) && d > 0 => {
1025
1026                                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                                // dbg!(self.quasiquote_depth);
1040                                // println!("=> {}", List::new(current_frame.exprs.clone()));
1041                                // println!("----------------------------------------");
1042
1043                                if self.quasiquote_depth > 0 {
1044                                    // TODO/HACK - @Matt
1045                                    // If we're in a define syntax situation, go ahead and just return a normal one
1046                                    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                                    // println!("Should still be quoted here");
1056
1057                                    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(current_frame.exprs.len());
1069                        self.quote_stack.push(stack.len());
1070                    }
1071
1072                    // dbg!(&self.context);
1073
1074                    // Mark what context we're inside with the context stack:
1075                    // This only works when its the first argument - check the function call in open paren?
1076                    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                                // self.context.push(ParsingContext::Quote(stack.len()))
1086                            }
1087                            TokenType::Identifier(ident) if *ident == *UNQUOTE => {
1088                                // println!("Entering unquote");
1089
1090                                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                                // println!("Entering quasiquote");
1095
1096                                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                        // println!("Context on application: {:?}", self.context);
1108                    }
1109
1110                    // println!("{}", token);
1111
1112                    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
1137// TODO: Hack in the doc comment extraction for macros too since
1138// those can be special cased
1139fn 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            // Just emit a single @doc line for the define-syntax,
1150            // and we'll handle the macro itself separately.
1151            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        // Just emit a single @doc line for the define-syntax,
1166        // and we'll handle the macro itself separately.
1167        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 we hit another comment, clear it
1229                        if doc_line.starts_with("@doc") {
1230                            // println!("Clearing buffer");
1231
1232                            self.comment_buffer.clear();
1233                            continue;
1234                        }
1235
1236                        // println!("Collecting line: {}", doc_line);
1237
1238                        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                // Just turn this into `syntax`
1253                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                    // See if this does the job
1303                    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.quote_context = true;
1312
1313                    // println!("Entering Context: Quote Tick");
1314                    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                        // dbg!(&popped);
1330                        debug_assert!(matches!(popped, ParsingContext::QuoteTick(_)))
1331                    }
1332
1333                    self.quote_context = last;
1334
1335                    // println!("Exiting context: {:?}", self.context.pop());
1336                    // println!("Result: {:?}", value);
1337
1338                    // println!("{}", List::new(value.clone().unwrap()));
1339
1340                    maybe_return!(match value {
1341                        Ok(v) => {
1342                            // Ok(ExprKind::List(List::new(v)))
1343
1344                            self.maybe_lower(v)
1345                        }
1346                        Err(e) => Err(e),
1347                    });
1348                }
1349
1350                TokenType::Unquote => {
1351                    // println!("Entering Context: Unquote");
1352                    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                            // dbg!(&self.quasiquote_depth);
1364                            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                    // println!("Exiting context: {:?}", self.context.pop());
1379
1380                    maybe_return!(value);
1381                }
1382
1383                TokenType::UnquoteSplice => {
1384                    // println!("Entering Context: Unquotesplicing");
1385                    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                    // println!("Exiting context: {:?}", self.context.pop());
1412
1413                    maybe_return!(value);
1414                }
1415                // Make this also handle quasisyntax
1416                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        // We're done consuming input
1469        None
1470    }
1471}
1472
1473impl<'a> Iterator for Parser<'a> {
1474    type Item = Result<ExprKind>;
1475
1476    // TODO -> put the
1477    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                // Reset the comment collection until next @doc statement
1495                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
1515// Lower the syntax rules down from the list representation
1516pub 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
1563// Lower define-syntax down from the list representation
1564pub fn lower_macro_and_require_definitions(expr: ExprKind) -> Result<ExprKind> {
1565    let as_list = expr.list();
1566
1567    // If this qualifies as
1568    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    // TODO: Here, we should lower syntax-case itself
1612    // to a defmacro, so that things seem to work out correctly.
1613
1614    // HACK:
1615    // If we get here, we can convert the define-syntax back into an identifier
1616    // so that other macro expansion can occur on it.
1617    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                    // println!("Found quote: {:?}", value);
1639                    self.quote_depth += 1;
1640                }
1641
1642                // Visit the children first, on the way back up, assign into the
1643                // correct AST node
1644                // value.args = value
1645                //     .args
1646                //     .into_iter()
1647                //     .map(|x| self.lower(x))
1648                //     .collect::<Result<_>>()?;
1649
1650                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                                // TODO: Deprecate
1714                                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            // Ok(ExprKind::Begin(ast::Begin::new(
1837            //     b.exprs
1838            //         .into_iter()
1839            //         .map(|x| self.lower(x))
1840            //         .collect::<Result<_>>()?,
1841            //     b.location,
1842            // ))),
1843            ExprKind::Return(r) => {
1844                self.lower(&mut r.expr)?;
1845                Ok(())
1846            }
1847            // Ok(ExprKind::Return(Box::new(ast::Return::new(
1848            //     self.lower(r.expr)?,
1849            //     r.location,
1850            // )))),
1851            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            // Ok(ExprKind::Set(Box::new(ast::Set::new(
1861            //     self.lower(s.variable)?,
1862            //     self.lower(s.expr)?,
1863            //     s.location,
1864            // )))),
1865            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
1877// TODO: Lower the rest of the AST post expansion, such that
1878pub 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::TokenType::*;
2000    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 (quote (lambda y z)) '(x y z)))")
2167        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)");
2262        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                        // This _should_ be cleared, but it seems it is not!
3234                        // debug_assert!(self.is_empty());
3235                        // self.clear();
3236
3237                        // for frame in &self {
3238                        //     for expr in &frame.exprs {
3239                        //         println!("dropping: {}", expr);
3240                        //     }
3241                        // }
3242
3243                        // dbg!(&self);
3244                        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>);