• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mattwparas / steel / 17772690385

16 Sep 2025 04:36PM UTC coverage: 43.331% (+0.04%) from 43.289%
17772690385

Pull #519

github

web-flow
Merge 98d4fd22c into 3c10433b9
Pull Request #519: fix a bunch more clippy lints

56 of 123 new or added lines in 30 files covered. (45.53%)

8 existing lines in 3 files now uncovered.

12416 of 28654 relevant lines covered (43.33%)

2985398.75 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

72.84
/crates/steel-parser/src/parser.rs
1
use std::{
2
    borrow::Cow,
3
    path::PathBuf,
4
    rc::Rc,
5
    result,
6
    sync::atomic::{AtomicUsize, Ordering},
7
};
8

9
use serde::{Deserialize, Serialize};
10

11
use crate::{
12
    ast::{
13
        self, parse_begin, parse_define, parse_if, parse_lambda, parse_let, parse_new_let,
14
        parse_require, parse_set, parse_single_argument, Atom, ExprKind, List, Macro, PatternPair,
15
        SyntaxRules, Vector, BEGIN, DEFINE, IF, LAMBDA, LAMBDA_FN, LAMBDA_SYMBOL, LET, PLAIN_LET,
16
        QUASIQUOTE, QUASISYNTAX, QUOTE, RAW_UNQUOTE, RAW_UNQUOTE_SPLICING, RAW_UNSYNTAX,
17
        RAW_UNSYNTAX_SPLICING, REQUIRE, RETURN, SET, SYNTAX_QUOTE, UNQUOTE, UNQUOTE_SPLICING,
18
    },
19
    interner::InternedString,
20
    lexer::{OwnedTokenStream, ToOwnedString, TokenError, TokenStream},
21
    span::Span,
22
    tokens::{Paren, ParenMod, Token, TokenLike, TokenType},
23
};
24

25
#[derive(
26
    Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
27
)]
28
#[repr(C)]
29
pub struct SourceId(pub u32);
30

31
impl SourceId {
32
    pub const fn none() -> Option<Self> {
760,815✔
33
        None
760,815✔
34
    }
35
}
36

37
// TODO: Fix the visibility here
38
pub static SYNTAX_OBJECT_ID: AtomicUsize = AtomicUsize::new(0);
39

40
// thread_local! {
41
//     pub static TL_SYNTAX_OBJECT_ID: Cell<u32> = Cell::new(0);
42
// }
43

44
#[derive(
45
    Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
46
)]
47
pub struct SyntaxObjectId(pub u32);
48

49
impl SyntaxObjectId {
50
    #[inline]
51
    pub fn fresh() -> Self {
54,718,761✔
52
        SyntaxObjectId(SYNTAX_OBJECT_ID.fetch_add(1, Ordering::Relaxed) as _)
164,156,283✔
53
        // TODO: Revisit why we're using this here
54
        // SyntaxObjectId(TL_SYNTAX_OBJECT_ID.with(|x| {
55
        //     let value = x.get();
56
        //     x.set(value + 1);
57
        //     value
58
        // }))
59
    }
60
}
61

62
impl From<SyntaxObjectId> for u32 {
63
    fn from(value: SyntaxObjectId) -> Self {
1,806,863✔
64
        value.0
1,806,863✔
65
    }
66
}
67

68
impl std::fmt::Display for SyntaxObjectId {
69
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
2✔
70
        write!(f, "{self:?}")
6✔
71
    }
72
}
73

74
#[derive(
75
    Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
76
)]
77
pub struct ListId(usize);
78

79
#[derive(
80
    Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default, Debug, Ord, PartialOrd,
81
)]
82
pub struct FunctionId(usize);
83

84
/// A syntax object that can hold anything as the syntax
85
/// In this case, we're using the token type emitted by logos
86
///
87
/// This should open the door to interning our strings to make
88
/// parsing (and optimizations later) faster
89
#[derive(Serialize, Deserialize)]
90
pub struct RawSyntaxObject<T> {
91
    pub ty: T,
92
    pub span: Span,
93
    pub syntax_object_id: SyntaxObjectId,
94
    // TODO: @Matt
95
    // This is a hack. More or less, we need a way to mark that
96
    // this particular syntax object is "unresolved" - and thus
97
    // should mangle its usage. This can also be done by using
98
    // the syntax object ID separately, but there is enough
99
    // space on the object itself that keeping it alongside the
100
    // object seemed to make sense. What we're going to do is mark
101
    // any unresolved references to variables found in macro expansion.
102
    // So, for example, consider the following:
103
    //
104
    // (define bound-x (vector 10 20 30 40))
105
    //
106
    // (define-syntax lexical-capture
107
    //   (syntax-rules ()
108
    //     [(_) (list bound-x)]))
109
    //
110
    // (let ([bound-x 'inner]) (lexical-capture))
111
    //
112
    // The define syntax is expanded without the context of knowing
113
    // the globals, and as a result isn't aware that bound-x should
114
    // refer to the local. However, we can expand and see that both
115
    // `list` and `bound-x` don't refer to anything in the patterns,
116
    // and so as a result, should be marked as "unresolved". Since
117
    // they are unresolved, we can conclude that either they're
118
    // global variables, or a free identifier.
119
    //
120
    // Then, when handling shadowed local variables, when we come across
121
    // a local variable that we'd like to mangle, if its unresolved, we
122
    // just leave it alone, and otherwise we should treat all locals as
123
    // variables to be mangled.
124
    //
125
    // Then, once we're done with all macro expansion, all variables themselves
126
    // should be "resolved" since either they refer to an individual variable,
127
    // or nothing at all.
128
    pub unresolved: bool,
129
    pub introduced_via_macro: bool,
130
}
131

132
impl<T: Clone> Clone for RawSyntaxObject<T> {
133
    fn clone(&self) -> Self {
276,299,128✔
134
        Self {
135
            ty: self.ty.clone(),
828,897,384✔
136
            span: self.span,
552,598,256✔
137
            syntax_object_id: SyntaxObjectId::fresh(),
552,598,256✔
138
            unresolved: self.unresolved,
276,299,128✔
139
            introduced_via_macro: self.introduced_via_macro,
276,299,128✔
140
        }
141
    }
142
}
143

144
impl<T: std::fmt::Debug> std::fmt::Debug for RawSyntaxObject<T> {
145
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84✔
146
        f.debug_struct("RawSyntaxObject")
336✔
147
            .field("ty", &self.ty)
252✔
148
            .field("span", &self.span)
168✔
149
            .finish()
150
    }
151
}
152

153
// Implementing hash here just on the token type - we dont want the span included
154
// For determining the hash here
155
impl<T: std::hash::Hash> std::hash::Hash for RawSyntaxObject<T> {
156
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
×
157
        self.ty.hash(state);
×
158
        self.span.hash(state);
×
159
    }
160
}
161

162
pub type SyntaxObject = RawSyntaxObject<TokenType<InternedString>>;
163

164
impl PartialEq for SyntaxObject {
165
    fn eq(&self, other: &Self) -> bool {
412✔
166
        self.ty == other.ty
412✔
167
    }
168
}
169

170
impl SyntaxObject {
171
    pub fn new(ty: TokenType<InternedString>, span: Span) -> Self {
250,911✔
172
        SyntaxObject {
173
            ty,
174
            span,
175
            // source: None,
176
            syntax_object_id: SyntaxObjectId::fresh(),
250,911✔
177
            unresolved: false,
178
            introduced_via_macro: false,
179
        }
180
    }
181

182
    pub fn default(ty: TokenType<InternedString>) -> Self {
760,982✔
183
        SyntaxObject {
184
            ty,
185
            span: Span::new(0, 0, SourceId::none()),
1,521,964✔
186
            // source: None,
187
            syntax_object_id: SyntaxObjectId::fresh(),
760,982✔
188
            unresolved: false,
189
            introduced_via_macro: false,
190
        }
191
    }
192

193
    pub fn set_span(&mut self, span: Span) {
1,344,950✔
194
        self.span = span
1,344,950✔
195
    }
196

197
    pub fn from_token_with_source(
6,670,837✔
198
        val: &Token<'_, InternedString>,
199
        _source: &Option<Rc<PathBuf>>,
200
    ) -> Self {
201
        SyntaxObject {
202
            ty: val.ty.clone(),
20,012,511✔
203
            span: val.span,
6,670,837✔
204
            syntax_object_id: SyntaxObjectId::fresh(),
6,670,837✔
205
            unresolved: false,
206
            introduced_via_macro: false,
207
        }
208
    }
209
}
210

211
impl From<&Token<'_, InternedString>> for SyntaxObject {
212
    fn from(val: &Token<'_, InternedString>) -> SyntaxObject {
60,123✔
213
        SyntaxObject::new(val.ty.clone(), val.span)
240,492✔
214
    }
215
}
216

217
#[derive(Clone, Debug, PartialEq)]
218
pub enum ParseError {
219
    MismatchedParen(Paren, Span, Option<Rc<PathBuf>>),
220
    UnexpectedEOF(Span, Option<Rc<PathBuf>>),
221
    UnexpectedChar(char, Span, Option<Rc<PathBuf>>),
222
    SyntaxError(String, Span, Option<Rc<PathBuf>>),
223
    ArityMismatch(String, Span, Option<Rc<PathBuf>>),
224
}
225

226
impl From<TokenLike<'_, TokenError>> for ParseError {
227
    fn from(value: TokenLike<'_, TokenError>) -> Self {
1✔
228
        match value.ty {
1✔
229
            TokenError::IncompleteString
230
            | TokenError::IncompleteIdentifier
231
            | TokenError::IncompleteComment => ParseError::UnexpectedEOF(value.span, None),
1✔
232
            _ => ParseError::SyntaxError(format!("{}", value.ty), value.span, None),
×
233
        }
234
    }
235
}
236

237
impl std::fmt::Display for ParseError {
238
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13✔
239
        match self {
13✔
240
            ParseError::MismatchedParen(paren, _, _) => {
×
241
                write!(
×
242
                    f,
×
243
                    "Parse: Mismatched parenthesis, expected \"{}\"",
244
                    paren.close()
×
245
                )
246
            }
247
            ParseError::UnexpectedEOF(..) => write!(f, "Parse: Unexpected EOF"),
×
248
            ParseError::UnexpectedChar(l, _, _) => {
1✔
249
                write!(f, "Parse: Unexpected character: {:?}", l)
3✔
250
            }
251
            ParseError::SyntaxError(l, _, _) => write!(f, "Parse: Syntax Error: {}", l),
40✔
252
            ParseError::ArityMismatch(l, _, _) => write!(f, "Parse: Arity mismatch: {}", l),
8✔
253
        }
254
    }
255
}
256

257
impl std::error::Error for ParseError {}
258

259
impl ParseError {
260
    pub fn span(&self) -> Span {
×
261
        match self {
×
262
            ParseError::MismatchedParen(_, s, _) => *s,
×
263
            ParseError::UnexpectedEOF(s, _) => *s,
×
264
            ParseError::UnexpectedChar(_, s, _) => *s,
×
265
            ParseError::SyntaxError(_, s, _) => *s,
×
266
            ParseError::ArityMismatch(_, s, _) => *s,
×
267
        }
268
    }
269

270
    pub fn set_source(self, source: Option<Rc<PathBuf>>) -> Self {
33✔
271
        use ParseError::*;
272
        match self {
33✔
273
            ParseError::MismatchedParen(l, s, _) => MismatchedParen(l, s, source),
1✔
274
            ParseError::UnexpectedEOF(s, _) => UnexpectedEOF(s, source),
16✔
275
            ParseError::UnexpectedChar(l, s, _) => UnexpectedChar(l, s, source),
4✔
276
            ParseError::SyntaxError(l, s, _) => SyntaxError(l, s, source),
92✔
277
            ParseError::ArityMismatch(l, s, _) => ArityMismatch(l, s, source),
×
278
        }
279
    }
280
}
281

282
pub struct InternString;
283

284
impl ToOwnedString<InternedString> for InternString {
285
    fn own(&self, s: Cow<str>) -> InternedString {
×
286
        (&*s).into()
×
287
    }
288
}
289

290
// #[derive(Debug)]
291
pub struct Parser<'a> {
292
    tokenizer: OwnedTokenStream<'a>,
293
    quote_stack: Vec<usize>,
294
    quasiquote_depth: isize,
295
    quote_context: bool,
296
    shorthand_quote_stack: Vec<usize>,
297
    source_name: Option<Rc<PathBuf>>,
298
    context: Vec<ParsingContext>,
299
    comment_buffer: Vec<&'a str>,
300
    collecting_comments: bool,
301
    keep_lists: bool,
302
}
303

304
#[derive(Debug, Copy, Clone, PartialEq)]
305
enum ParsingContext {
306
    // Inside of a quote. Expressions should be parsed without being coerced into a typed variant of the AST
307
    Quote(usize),
308
    // Shortened version of a quote
309
    QuoteTick(usize),
310
    // Inside of an unquote - expressions should actually be parsed as usual
311
    Unquote(usize),
312
    // Shortened version of unquote
313
    UnquoteTick(usize),
314
    // Treat this like a normal quote
315
    Quasiquote(usize),
316
    // Shortened version of quasiquote
317
    QuasiquoteTick(usize),
318
    // expressions should parsed as normal
319
    UnquoteSplicing(usize),
320
    // Shorted version of Unquote Splicing
321
    UnquoteSplicingTick(usize),
322
}
323

324
impl<'a> Parser<'a> {
325
    pub fn parse(expr: &str) -> Result<Vec<ExprKind>> {
38✔
326
        Parser::new(expr, SourceId::none()).collect()
152✔
327
    }
328

329
    pub fn parse_without_lowering(expr: &str) -> Result<Vec<ExprKind>> {
54✔
330
        Parser::new(expr, SourceId::none())
162✔
331
            .without_lowering()
332
            .collect()
333
    }
334

335
    pub fn offset(&self) -> usize {
12,550✔
336
        self.tokenizer.offset()
25,100✔
337
    }
338
}
339

340
pub type Result<T> = result::Result<T, ParseError>;
341

342
impl<'a> Parser<'a> {
343
    pub fn new(input: &'a str, source_id: Option<SourceId>) -> Self {
11,600✔
344
        Parser {
345
            tokenizer: TokenStream::new(input, false, source_id).into_owned(),
58,000✔
346
            quote_stack: Vec::new(),
23,200✔
347
            quasiquote_depth: 0,
348
            quote_context: false,
349
            shorthand_quote_stack: Vec::new(),
23,200✔
350
            source_name: None,
351
            context: Vec::new(),
11,600✔
352
            comment_buffer: Vec::new(),
11,600✔
353
            collecting_comments: false,
354
            keep_lists: false,
355
        }
356
    }
357

358
    pub fn without_lowering(mut self) -> Self {
54✔
359
        self.keep_lists = true;
54✔
360
        self
54✔
361
    }
362

363
    pub fn new_flat(input: &'a str, source_id: Option<SourceId>) -> Self {
15,052✔
364
        Parser {
365
            tokenizer: TokenStream::new(input, false, source_id).into_owned(),
75,260✔
366
            quote_stack: Vec::new(),
30,104✔
367
            quasiquote_depth: 0,
368
            quote_context: false,
369
            shorthand_quote_stack: Vec::new(),
30,104✔
370
            source_name: None,
371
            context: Vec::new(),
15,052✔
372
            comment_buffer: Vec::new(),
15,052✔
373
            collecting_comments: false,
374
            keep_lists: true,
375
        }
376
    }
377

378
    pub fn new_from_source(
1,615✔
379
        input: &'a str,
380
        source_name: PathBuf,
381
        source_id: Option<SourceId>,
382
    ) -> Self {
383
        Parser {
384
            tokenizer: TokenStream::new(input, false, source_id).into_owned(),
8,075✔
385
            quote_stack: Vec::new(),
3,230✔
386
            quasiquote_depth: 0,
387
            quote_context: false,
388
            shorthand_quote_stack: Vec::new(),
3,230✔
389
            source_name: Some(Rc::from(source_name)),
3,230✔
390
            context: Vec::new(),
1,615✔
391
            comment_buffer: Vec::new(),
1,615✔
392
            collecting_comments: false,
393
            keep_lists: false,
394
        }
395
    }
396

397
    // Attach comments!
398
    pub fn doc_comment_parser(input: &'a str, source_id: Option<SourceId>) -> Self {
1✔
399
        Parser {
400
            tokenizer: TokenStream::new(input, false, source_id).into_owned(),
5✔
401
            quote_stack: Vec::new(),
2✔
402
            quasiquote_depth: 0,
403
            quote_context: false,
404
            shorthand_quote_stack: Vec::new(),
2✔
405
            source_name: None,
406
            context: Vec::new(),
1✔
407
            comment_buffer: Vec::new(),
1✔
408
            collecting_comments: false,
409
            keep_lists: false,
410
        }
411
    }
412

413
    fn construct_quote(&mut self, val: ExprKind, span: Span) -> ExprKind {
84,562✔
414
        ExprKind::Quote(Box::new(ast::Quote::new(
253,686✔
415
            val,
169,124✔
416
            SyntaxObject::new(TokenType::Quote, span),
169,124✔
417
        )))
418
    }
419

420
    fn _expand_reader_macro(
×
421
        &mut self,
422
        token: TokenType<InternedString>,
423
        val: ExprKind,
424
        span: Span,
425
    ) -> ExprKind {
426
        let q = ExprKind::Atom(Atom::new(SyntaxObject::new(token, span)));
×
427

428
        ExprKind::List(List::new(vec![q, val]))
×
429
    }
430

431
    fn construct_quote_vec(&mut self, val: ExprKind, span: Span) -> Vec<ExprKind> {
15✔
432
        // println!("Inside construct quote vec with: {:?}", val);
433

434
        let q = {
15✔
435
            let rc_val = TokenType::Quote;
30✔
436
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
45✔
437
            // let val = ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)));
438
            // // self.intern.insert("quote".to_string(), rc_val);
439
            // val
440
        };
441

442
        vec![q, val]
45✔
443
    }
444

445
    // Reader macro for #'
446
    fn construct_syntax(&mut self, val: ExprKind, span: Span) -> ExprKind {
11✔
447
        let q = {
11✔
448
            let rc_val = TokenType::Identifier(*SYNTAX_QUOTE);
22✔
449
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
33✔
450
        };
451

452
        ExprKind::List(List::new(vec![q, val]))
33✔
453
    }
454

455
    // Reader macro for #'
456
    fn construct_quasiquote_syntax(&mut self, val: ExprKind, span: Span) -> ExprKind {
3✔
457
        let q = {
3✔
458
            let rc_val = TokenType::Identifier(*QUASISYNTAX);
6✔
459
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
9✔
460
        };
461

462
        ExprKind::List(List::new(vec![q, val]))
9✔
463
    }
464

465
    fn construct_quasiunquote_syntax(&mut self, val: ExprKind, span: Span) -> ExprKind {
2✔
466
        let q = {
2✔
467
            let rc_val = TokenType::Identifier(*RAW_UNSYNTAX);
4✔
468
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
6✔
469
        };
470

471
        ExprKind::List(List::new(vec![q, val]))
6✔
472
    }
473

474
    fn construct_quasiunquote_syntax_splicing(&mut self, val: ExprKind, span: Span) -> ExprKind {
1✔
475
        let q = {
1✔
476
            let rc_val = TokenType::Identifier(*RAW_UNSYNTAX_SPLICING);
2✔
477
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
3✔
478
        };
479

480
        ExprKind::List(List::new(vec![q, val]))
3✔
481
    }
482

483
    // Reader macro for `
484
    fn construct_quasiquote(&mut self, val: ExprKind, span: Span) -> ExprKind {
9,158✔
485
        let q = {
9,158✔
486
            let rc_val = TokenType::Identifier(*QUASIQUOTE);
18,316✔
487
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
27,474✔
488
        };
489

490
        ExprKind::List(List::new(vec![q, val]))
27,474✔
491
    }
492

493
    // Reader macro for ,
494
    fn construct_unquote(&mut self, val: ExprKind, span: Span) -> ExprKind {
35✔
495
        let q = {
35✔
496
            let rc_val = TokenType::Identifier(*UNQUOTE);
70✔
497
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
105✔
498
        };
499

500
        ExprKind::List(List::new(vec![q, val]))
105✔
501
    }
502

503
    fn construct_raw_unquote(&mut self, val: ExprKind, span: Span) -> ExprKind {
23,344✔
504
        let q = {
23,344✔
505
            // let rc_val = TokenType::Identifier(*UNQUOTE);
506
            let rc_val = TokenType::Identifier(*RAW_UNQUOTE);
46,688✔
507
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
70,032✔
508
        };
509

510
        ExprKind::List(List::new(vec![q, val]))
70,032✔
511
    }
512
    // Reader macro for ,@
513
    fn construct_unquote_splicing(&mut self, val: ExprKind, span: Span) -> ExprKind {
14✔
514
        let q = {
14✔
515
            let rc_val = TokenType::Identifier(*UNQUOTE_SPLICING);
28✔
516
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
42✔
517
        };
518

519
        ExprKind::List(List::new(vec![q, val]))
42✔
520
    }
521

522
    // Reader macro for ,@
523
    fn construct_raw_unquote_splicing(&mut self, val: ExprKind, span: Span) -> ExprKind {
2,850✔
524
        let q = {
2,850✔
525
            let rc_val = TokenType::Identifier(*RAW_UNQUOTE_SPLICING);
5,700✔
526
            ExprKind::Atom(Atom::new(SyntaxObject::new(rc_val, span)))
8,550✔
527
        };
528

529
        ExprKind::List(List::new(vec![q, val]))
8,550✔
530
    }
531

532
    fn increment_quasiquote_context_if_not_in_quote_context(&mut self) {
42,098✔
533
        // println!("INCREMENTING");
534
        if !self.quote_context {
84,166✔
535
            self.quasiquote_depth += 1;
42,068✔
536
        }
537
    }
538

539
    fn decrement_quasiquote_context_if_not_in_quote_context(&mut self) {
41,251✔
540
        // println!("DECREMENTING");
541
        if !self.quote_context {
82,472✔
542
            self.quasiquote_depth -= 1;
41,221✔
543
        }
544
    }
545

546
    fn maybe_lower(&self, exprs: Vec<ExprKind>) -> Result<ExprKind> {
2,107,622✔
547
        if self.keep_lists {
2,107,622✔
548
            Ok(ExprKind::List(List::new(exprs)))
2,106,337✔
549
        } else {
550
            ExprKind::try_from(exprs)
1,285✔
551
        }
552
    }
553

554
    fn maybe_lower_frame(&self, frame: Frame, close: Span) -> Result<ExprKind> {
2,107,919✔
555
        frame.build_expr(close, |exprs| self.maybe_lower(exprs))
12,646,578✔
556
    }
557

558
    fn read_from_tokens(
154,042✔
559
        &mut self,
560
        (open, paren, paren_mod): (Span, Paren, Option<ParenMod>),
561
    ) -> Result<ExprKind> {
562
        let mut last = open;
308,084✔
563

564
        // Can we reuse this?
565
        // TODO: I think we have to shove this into the parser state.
566
        // Alongside the current frame and anything else.
567
        //
568
        // That way, we can just keep it around if we hit an EOF and
569
        // we're in incremental mode, where we can keep feeding data
570
        // in and it can continue to produce parsed values.
571
        let mut stack: Vec<Frame> = Vec::new();
462,126✔
572

573
        // self.stack.clear();
574

575
        let mut current_frame = Frame {
576
            open,
577
            paren,
578
            paren_mod,
579
            exprs: Vec::new(),
154,042✔
580
            dot: None,
581
            comment: 0,
582
        };
583

584
        self.quote_stack = Vec::new();
308,084✔
585

586
        // println!("READING FROM TOKENS");
587
        // self.quasiquote_depth = 0;
588

589
        while let Some(token) = self.next_token() {
29,168,600✔
590
            let token = token?;
14,584,297✔
591
            last = token.span;
×
592

593
            match token.ty {
×
594
                TokenType::Dot => {
×
595
                    if current_frame.dot.is_some() {
11,518✔
596
                        return Err(ParseError::SyntaxError(
2✔
597
                            "improper lists can only have a single dot".into(),
6✔
598
                            token.span,
2✔
599
                            None,
2✔
600
                        ));
601
                    } else if current_frame.exprs.is_empty() {
5,757✔
602
                        return Err(ParseError::SyntaxError(
1✔
603
                            "improper lists must have a car element before the dot".into(),
3✔
604
                            token.span,
1✔
605
                            None,
1✔
606
                        ));
607
                    } else if current_frame.paren_mod.is_some() {
5,756✔
608
                        let paren_mod = current_frame.paren_mod.unwrap();
6✔
609
                        let object = match paren_mod {
4✔
610
                            ParenMod::Vector => "vector",
1✔
611
                            ParenMod::Bytes => "bytevector",
1✔
612
                        };
613

614
                        return Err(ParseError::SyntaxError(
2✔
615
                            format!("{object} literals cannot contain dots"),
6✔
616
                            token.span,
2✔
617
                            None,
2✔
618
                        ));
619
                    } else if current_frame.comment > 0 {
5,754✔
620
                        return Err(ParseError::SyntaxError(
1✔
621
                            "commented-out datum cannot start with a dot".into(),
3✔
622
                            token.span,
1✔
623
                            None,
1✔
624
                        ));
625
                    } else {
626
                        current_frame.dot = Some((current_frame.exprs.len() as _, token.span));
5,753✔
627
                    }
628
                }
629
                TokenType::Comment => {
110,736✔
630
                    // println!("Found a comment!");
631
                    // Internal comments, we're gonna skip for now
632
                }
633
                TokenType::DatumComment => {
3✔
634
                    current_frame.comment += 1;
3✔
635
                }
636

637
                TokenType::QuoteSyntax => {
×
638
                    let quote_inner = self
22✔
639
                        .next()
640
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
22✔
641
                            token.span,
22✔
642
                            self.source_name.clone(),
11✔
643
                        )))
644
                        .map(|x| self.construct_syntax(x, token.span))?;
55✔
645

646
                    current_frame.push(quote_inner)?
×
647
                }
648

649
                TokenType::QuasiQuoteSyntax => {
×
650
                    let quote_inner = self
6✔
651
                        .next()
652
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
6✔
653
                            token.span,
6✔
654
                            self.source_name.clone(),
3✔
655
                        )))
656
                        .map(|x| self.construct_quasiquote_syntax(x, token.span))?;
15✔
657

658
                    current_frame.push(quote_inner)?
×
659
                }
660

661
                TokenType::UnquoteSyntax => {
×
662
                    let quote_inner = self
4✔
663
                        .next()
664
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
4✔
665
                            token.span,
4✔
666
                            self.source_name.clone(),
2✔
667
                        )))
668
                        .map(|x| self.construct_quasiunquote_syntax(x, token.span))?;
10✔
669

670
                    current_frame.push(quote_inner)?
×
671
                }
672

673
                TokenType::UnquoteSpliceSyntax => {
×
674
                    let quote_inner = self
2✔
675
                        .next()
676
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
2✔
677
                            token.span,
2✔
678
                            self.source_name.clone(),
1✔
679
                        )))
680
                        .map(|x| self.construct_quasiunquote_syntax_splicing(x, token.span))?;
5✔
681

682
                    current_frame.push(quote_inner)?
×
683
                }
684

685
                TokenType::QuoteTick => {
×
686
                    // quote_count += 1;
687
                    // self.quote_stack.push(current_frame.exprs.len());
688
                    self.shorthand_quote_stack.push(stack.len());
338,256✔
689

690
                    let last_context = self.quote_context;
169,128✔
691

692
                    if self.quasiquote_depth == 0 {
167,096✔
693
                        self.quote_context = true;
82,532✔
694
                    }
695

696
                    // println!("Entering context: Quote Tick in read from tokens");
697

698
                    self.context.push(ParsingContext::QuoteTick(stack.len()));
253,692✔
699

700
                    let quote_inner = self
169,128✔
701
                        .next()
702
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
169,128✔
703
                            token.span,
169,128✔
704
                            self.source_name.clone(),
84,564✔
705
                        )))
706
                        .map(|x| {
169,126✔
707
                            // if self.quasiquote_depth == 0 {
708
                            self.construct_quote(x, token.span)
338,248✔
709
                            // } else {
710
                            // self.construct_fake_quote(x, token.span)
711
                            // }
712
                        });
713
                    // self.quote_stack.pop();
714
                    self.shorthand_quote_stack.pop();
169,128✔
715

716
                    self.quote_context = last_context;
84,564✔
717

718
                    // println!(
719
                    //     "Exiting Context: {:?} in read from tokens",
720
                    //     self.context.pop()
721
                    // );
722

723
                    // self.context.pop();
724

725
                    let popped_value = self.context.pop();
253,692✔
726

727
                    if let Some(popped) = popped_value {
169,128✔
728
                        // dbg!(&popped);
729
                        debug_assert!(matches!(popped, ParsingContext::QuoteTick(_)))
×
730
                    }
731

732
                    current_frame.push(quote_inner?)?;
169,128✔
733
                }
734
                TokenType::Unquote => {
×
735
                    // println!("Entering context: Unquote");
736

737
                    // This could underflow and panic - if its negative then we have a problem. Maybe just use an isize and let it underflow?
738
                    self.decrement_quasiquote_context_if_not_in_quote_context();
46,734✔
739

740
                    self.context.push(ParsingContext::UnquoteTick(stack.len()));
70,101✔
741

742
                    let quote_inner = self
46,734✔
743
                        .next()
744
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
46,734✔
745
                            token.span,
46,734✔
746
                            self.source_name.clone(),
23,367✔
747
                        )))
748
                        .map(|x| {
46,734✔
749
                            // dbg!(self.quasiquote_depth);
750
                            // dbg!(self.quote_context);
751
                            if self.quasiquote_depth == 0 && !self.quote_context {
46,715✔
752
                                self.construct_raw_unquote(x, token.span)
93,332✔
753
                            } else {
754
                                self.construct_unquote(x, token.span)
34✔
755
                            }
756
                        });
757

758
                    let popped_value = self.context.pop();
70,101✔
759

760
                    self.increment_quasiquote_context_if_not_in_quote_context();
46,734✔
761

762
                    if let Some(popped) = popped_value {
46,734✔
763
                        debug_assert!(matches!(popped, ParsingContext::UnquoteTick(_)))
×
764
                    }
765
                    // println!("Exiting Context: {:?}", self.context.pop());
766
                    current_frame.push(quote_inner?)?;
46,734✔
767
                }
768
                TokenType::QuasiQuote => {
×
769
                    // println!("Entering context: Quasiquote");
770

771
                    self.increment_quasiquote_context_if_not_in_quote_context();
18,312✔
772

773
                    self.context
9,156✔
774
                        .push(ParsingContext::QuasiquoteTick(stack.len()));
18,312✔
775

776
                    let quote_inner = self
18,312✔
777
                        .next()
778
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
18,312✔
779
                            token.span,
18,312✔
780
                            self.source_name.clone(),
9,156✔
781
                        )))
782
                        .map(|x| self.construct_quasiquote(x, token.span));
45,780✔
783

784
                    // self.context.pop();
785
                    // println!(
786
                    //     ">>>>>>>>>>>>>>>>>>> Exiting Context: {:?}",
787
                    //     self.context.pop()
788
                    // );
789

790
                    let popped_value = self.context.pop();
27,468✔
791

792
                    self.decrement_quasiquote_context_if_not_in_quote_context();
18,312✔
793

794
                    if let Some(popped) = popped_value {
18,312✔
795
                        debug_assert!(matches!(popped, ParsingContext::QuasiquoteTick(_)))
×
796
                    }
797

798
                    current_frame.push(quote_inner?)?;
18,312✔
799
                }
800
                TokenType::UnquoteSplice => {
×
801
                    // println!("Entering context: UnquoteSplicing");
802

803
                    self.decrement_quasiquote_context_if_not_in_quote_context();
5,724✔
804

805
                    self.context
2,862✔
806
                        .push(ParsingContext::UnquoteSplicingTick(stack.len()));
5,724✔
807

808
                    let quote_inner = self
5,724✔
809
                        .next()
810
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
5,724✔
811
                            token.span,
5,724✔
812
                            self.source_name.clone(),
2,862✔
813
                        )))
814
                        .map(|x| {
5,724✔
815
                            if self.quasiquote_depth == 0 && !self.quote_context {
5,718✔
816
                                self.construct_raw_unquote_splicing(x, token.span)
11,400✔
817
                            } else {
818
                                self.construct_unquote_splicing(x, token.span)
12✔
819
                            }
820
                        });
821

822
                    // self.context.pop();
823

824
                    let popped_value = self.context.pop();
8,586✔
825

826
                    self.increment_quasiquote_context_if_not_in_quote_context();
5,724✔
827

828
                    if let Some(popped) = popped_value {
5,724✔
829
                        debug_assert!(matches!(popped, ParsingContext::UnquoteSplicingTick(_)))
×
830
                    }
831

832
                    // println!("Exiting Context: {:?}", self.context.pop());
833
                    current_frame.push(quote_inner?)?;
5,724✔
834
                }
835
                TokenType::OpenParen(paren, paren_mod) => {
3,761,489✔
836
                    stack.push(current_frame);
×
837

838
                    current_frame = Frame {
×
839
                        open: token.span,
×
840
                        paren_mod,
×
841
                        exprs: Vec::with_capacity(4),
×
842
                        dot: None,
×
843
                        paren,
×
844
                        comment: 0,
×
845
                    };
846
                }
847
                TokenType::CloseParen(paren) => {
3,915,507✔
848
                    let close = token.span;
7,831,014✔
849
                    // This is the match that we'll want to move inside the below stack.pop() match statement
850
                    // As we close the current context, we check what our current state is -
851

852
                    if paren != current_frame.paren {
3,915,507✔
853
                        return Err(ParseError::MismatchedParen(
1✔
854
                            current_frame.paren,
2✔
855
                            token.span,
2✔
856
                            self.source_name.clone(),
1✔
857
                        ));
858
                    }
859

860
                    if let Some(mut prev_frame) = stack.pop() {
3,761,483✔
861
                        match prev_frame
×
862
                            .exprs
×
863
                            .first_mut()
×
864
                            .and_then(|x| x.atom_identifier_mut())
7,081,232✔
865
                        {
866
                            Some(ident) if *ident == *UNQUOTE => {
2,182,758✔
867
                                // self.increment_quasiquote_context_if_not_in_quote_context();
868
                                if self.quasiquote_depth == 0 && !self.quote_context {
10✔
869
                                    *ident = *RAW_UNQUOTE;
3✔
870
                                }
871
                                self.increment_quasiquote_context_if_not_in_quote_context();
8✔
872

873
                                // println!("Exiting unquote");
874
                            }
875
                            Some(ident) if *ident == *QUASIQUOTE => {
2,197,005✔
876
                                self.decrement_quasiquote_context_if_not_in_quote_context();
4,753✔
877

878
                                // println!("Exiting quasiquote");
879
                            }
880
                            Some(ident) if *ident == *UNQUOTE_SPLICING => {
2,177,995✔
881
                                // self.increment_quasiquote_context_if_not_in_quote_context();
882

883
                                if self.quasiquote_depth == 0 && !self.quote_context {
1✔
884
                                    *ident = *RAW_UNQUOTE_SPLICING;
×
885
                                }
886
                                self.increment_quasiquote_context_if_not_in_quote_context();
2✔
887

888
                                // println!("Exiting unquote");
889
                            }
890
                            _ => {}
3,756,725✔
891
                        }
892

893
                        match self.context.last().copied() {
×
894
                            // TODO: Change this -> This should really be just Some(ParsingContext::Quote)
895
                            // If we have _anything_ then we should check if we need to parse it differently. If we're at the last_quote_index,
896
                            // then we can pop it off inside there.
897
                            Some(ParsingContext::Quote(last_quote_index))
1,751,949✔
898
                            | Some(ParsingContext::Quasiquote(last_quote_index)) => {
7,770✔
899
                                if stack.len() <= last_quote_index {
1,810,174✔
900
                                    self.context.pop();
50,455✔
901
                                }
902

903
                                match current_frame.exprs.first() {
×
904
                                    Some(ExprKind::Atom(Atom {
×
905
                                        syn:
×
906
                                            SyntaxObject {
×
907
                                                ty: TokenType::Quote,
×
908
                                                ..
×
909
                                            },
910
                                    })) => match self.context.last() {
34,432✔
911
                                        Some(
×
912
                                            ParsingContext::Quasiquote(_)
×
913
                                            | ParsingContext::QuasiquoteTick(_)
×
914
                                            | ParsingContext::Quote(_)
×
915
                                            | ParsingContext::QuoteTick(_),
×
916
                                        ) => prev_frame.push(current_frame.into_expr(close)?)?,
2,750✔
917
                                        _ => {
×
918
                                            prev_frame.push(
66,114✔
919
                                                self.maybe_lower_frame(current_frame, close)?,
132,228✔
920
                                            )?;
921
                                        }
922
                                    },
923
                                    _ => {
×
924
                                        // println!("Converting to list");
925
                                        // println!("Context here: {:?}", self.context);
926
                                        prev_frame.push(current_frame.into_expr(close)?)?
8,626,435✔
927
                                    }
928
                                }
929
                            }
930

931
                            Some(ParsingContext::QuoteTick(_))
×
932
                            | Some(ParsingContext::QuasiquoteTick(_)) => {
×
933
                                match current_frame.exprs.first() {
59,104✔
934
                                    Some(ExprKind::Atom(Atom {
×
935
                                        syn:
×
936
                                            SyntaxObject {
×
937
                                                ty: TokenType::Quote,
×
938
                                                ..
×
939
                                            },
940
                                    })) => {
×
941
                                        // println!("Converting to quote inside quote tick");
942
                                        prev_frame
×
943
                                            .push(self.maybe_lower_frame(current_frame, close)?)?;
×
944
                                    }
945
                                    _ => {
×
946
                                        // if let Some(ParsingContext::QuasiquoteTick(_)) =
947
                                        //     self.context.last()
948
                                        // {
949
                                        //     self.decrement_quasiquote_context_if_not_in_quote_context();
950
                                        // }
951

952
                                        // println!("Converting to list inside quote tick");
953
                                        prev_frame.push(current_frame.into_expr(close)?)?
147,760✔
954
                                    }
955
                                }
956
                            }
957

958
                            // If we're in the short hand reader world, just ignore popping off the stack
959
                            // but still treat it as a normal expression
960
                            Some(ParsingContext::UnquoteTick(_))
×
961
                            | Some(ParsingContext::UnquoteSplicingTick(_)) => {
×
962
                                // self.quasiquote_depth += 1;
963

964
                                // self.increment_quasiquote_context_if_not_in_quote_context();
965

966
                                // println!(
967
                                //     "UQ/UQS: Stack length: {:?}, last_quote_index: {:?}",
968
                                //     stack.len(),
969
                                //     last_quote_index
970
                                // );
971

972
                                // if stack.len() <= *last_quote_index {
973
                                //     // println!("Exiting Context: {:?}", self.context.pop());
974
                                //     self.context.pop();
975
                                // }
976

977
                                prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?;
54,684✔
978
                            }
979

980
                            Some(ParsingContext::Unquote(last_quote_index))
659✔
981
                            | Some(ParsingContext::UnquoteSplicing(last_quote_index)) => {
438✔
982
                                // self.quasiquote_depth += 1;
983

984
                                // self.increment_quasiquote_context_if_not_in_quote_context();
985

986
                                // println!(
987
                                //     "UQ/UQS: Stack length: {:?}, last_quote_index: {:?}",
988
                                //     stack.len(),
989
                                //     last_quote_index
990
                                // );
991

992
                                if stack.len() <= last_quote_index {
2,194✔
993
                                    // println!("{} - {}", stack.len(), last_quote_index);
994
                                    // println!("Exiting Context: {:?}", self.context.pop());
995
                                    self.context.pop();
1,097✔
996
                                }
997

998
                                prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?;
1,097✔
999
                            }
1000

1001
                            // Else case, just go ahead and assume it is a normal frame
1002
                            _ => prev_frame.push(self.maybe_lower_frame(current_frame, close)?)?,
11,772,008✔
1003
                        }
1004

1005
                        // Reinitialize current frame here
1006
                        current_frame = prev_frame;
3,761,481✔
1007
                    } else {
1008
                        // println!("Else case: {:?}", current_frame.exprs);
1009
                        // println!("Context: {:?}", self.context);
1010

1011
                        // dbg!(&self.quote_stack);
1012
                        // dbg!(&self.context);
1013
                        // dbg!(&self.shorthand_quote_stack);
1014
                        match self.context.last() {
308,046✔
1015
                            Some(ParsingContext::QuoteTick(_))
×
1016
                            | Some(ParsingContext::QuasiquoteTick(_)) => {
×
1017
                                // | Some(ParsingContext::Quote(d)) && d > 0 => {
1018

1019
                                return current_frame.into_expr(close);
154,083✔
1020
                            }
1021
                            Some(ParsingContext::Quote(x)) if *x > 0 => {
5✔
1022
                                self.context.pop();
2✔
1023

1024
                                return current_frame.into_expr(close);
3✔
1025
                            }
1026
                            Some(ParsingContext::Quote(0)) => {
×
1027
                                self.context.pop();
1✔
1028

1029
                                return self.maybe_lower_frame(current_frame, close);
×
1030
                            }
1031
                            _ => {
×
1032
                                // dbg!(self.quasiquote_depth);
1033
                                // println!("=> {}", List::new(current_frame.exprs.clone()));
1034
                                // println!("----------------------------------------");
1035

1036
                                if self.quasiquote_depth > 0 {
102,660✔
1037
                                    // TODO/HACK - @Matt
1038
                                    // If we're in a define syntax situation, go ahead and just return a normal one
1039
                                    if current_frame
226✔
1040
                                        .exprs
226✔
1041
                                        .first()
1042
                                        .map(|x| x.define_syntax_ident())
678✔
1043
                                        .unwrap_or_default()
1044
                                    {
1045
                                        return self.maybe_lower_frame(current_frame, close);
860✔
1046
                                    }
1047

1048
                                    // println!("Should still be quoted here");
1049

NEW
1050
                                    return current_frame.into_expr(close);
×
1051
                                }
1052

1053
                                return self.maybe_lower_frame(current_frame, close);
×
1054
                            }
1055
                        }
1056
                    }
1057
                }
1058

1059
                _ => {
×
1060
                    if let TokenType::Quote = &token.ty {
6,714,602✔
1061
                        // self.quote_stack.push(current_frame.exprs.len());
1062
                        self.quote_stack.push(stack.len());
43,765✔
1063
                    }
1064

1065
                    // dbg!(&self.context);
1066

1067
                    // Mark what context we're inside with the context stack:
1068
                    // This only works when its the first argument - check the function call in open paren?
1069
                    if current_frame.exprs.is_empty() {
13,341,674✔
1070
                        match &token.ty {
3,092,409✔
1071
                            TokenType::Quote => {
×
1072
                                if self.context == [ParsingContext::QuoteTick(0)] {
43,765✔
1073
                                    self.context.push(ParsingContext::Quote(1))
3✔
1074
                                } else {
1075
                                    self.context.push(ParsingContext::Quote(stack.len()))
43,764✔
1076
                                }
1077

1078
                                // self.context.push(ParsingContext::Quote(stack.len()))
1079
                            }
1080
                            TokenType::Identifier(ident) if *ident == *UNQUOTE => {
6,200,838✔
1081
                                // println!("Entering unquote");
1082

1083
                                self.context.push(ParsingContext::Unquote(stack.len()));
2,636✔
1084
                                self.decrement_quasiquote_context_if_not_in_quote_context();
659✔
1085
                            }
1086
                            TokenType::Identifier(ident) if *ident == *QUASIQUOTE => {
3,112,485✔
1087
                                // println!("Entering quasiquote");
1088

1089
                                self.context.push(ParsingContext::Quasiquote(stack.len()));
26,768✔
1090
                                self.increment_quasiquote_context_if_not_in_quote_context();
6,692✔
1091
                            }
1092
                            TokenType::Identifier(ident) if *ident == *UNQUOTE_SPLICING => {
876✔
1093
                                self.context
876✔
1094
                                    .push(ParsingContext::UnquoteSplicing(stack.len()));
1,314✔
1095
                                self.decrement_quasiquote_context_if_not_in_quote_context();
438✔
1096
                            }
1097
                            _ => {}
3,586,676✔
1098
                        }
1099

1100
                        // println!("Context on application: {:?}", self.context);
1101
                    }
1102

1103
                    // println!("{}", token);
1104

1105
                    let atom = Atom::new(SyntaxObject::from_token_with_source(
20,012,511✔
1106
                        &token,
6,670,837✔
1107
                        &self.source_name.clone(),
6,670,837✔
1108
                    ));
1109

1110
                    current_frame.push(ExprKind::Atom(atom))?
20,012,513✔
1111
                }
1112
            }
1113
        }
1114

1115
        Err(ParseError::UnexpectedEOF(last, self.source_name.clone()))
12✔
1116
    }
1117

1118
    fn next_token(&mut self) -> Option<Result<Token<'a, InternedString>>> {
15,037,418✔
1119
        let res = self.tokenizer.next()?;
45,112,254✔
1120

1121
        Some(res.map_err(|err| ParseError::from(err).set_source(self.source_name.clone())))
5✔
1122
    }
1123
}
1124

1125
fn wrap_in_doc_function(expr: ExprKind, comment: String) -> ExprKind {
2,391✔
1126
    // println!("Found comment : {} for expr {}", comment, expr);
1127

1128
    ExprKind::List(List::new(vec![
7,173✔
1129
        ExprKind::ident("@doc"),
7,173✔
1130
        ExprKind::string_lit(comment),
4,782✔
1131
        expr,
2,391✔
1132
    ]))
1133
}
1134

1135
impl<'a> Parser<'a> {
1136
    fn get_next_and_maybe_wrap_in_doc(&mut self) -> Option<Result<ExprKind>> {
229,878✔
1137
        let mut datum_comments = vec![];
459,756✔
1138

1139
        macro_rules! maybe_return {
×
1140
            ($value:expr) => {{
×
1141
                let value = $value;
×
1142

1143
                if value.is_ok() {
×
1144
                    if datum_comments.len() > 0 {
×
1145
                        let _ = datum_comments.pop();
×
1146

1147
                        continue;
×
1148
                    }
1149
                }
1150

1151
                return Some(value);
×
1152
            }};
1153
        }
1154

1155
        while let Some(res) = self.next_token() {
890,550✔
1156
            let res = match res {
437,434✔
1157
                Ok(res) => res,
×
1158
                Err(err) => {
1✔
1159
                    return Some(Err(err));
1✔
1160
                }
1161
            };
1162

1163
            match res.ty {
×
1164
                TokenType::Comment => {
×
1165
                    if self.comment_buffer.is_empty()
446,458✔
1166
                        && !self.collecting_comments
210,367✔
1167
                        && res.source().trim_start_matches(';').starts_with("@doc")
415,952✔
1168
                    {
1169
                        self.collecting_comments = true;
2,391✔
1170

1171
                        continue;
2,391✔
1172
                    }
1173

1174
                    if self.collecting_comments {
×
1175
                        let doc_line = res.source().trim_start_matches(';');
45,759✔
1176

1177
                        // If we hit another comment, clear it
1178
                        if doc_line.starts_with("@doc") {
30,506✔
1179
                            // println!("Clearing buffer");
1180

1181
                            self.comment_buffer.clear();
×
1182
                            continue;
×
1183
                        }
1184

1185
                        // println!("Collecting line: {}", doc_line);
1186

1187
                        let line = doc_line
×
1188
                            .strip_prefix(" ")
1189
                            .unwrap_or(doc_line)
×
1190
                            .trim_end_matches(['\n', '\r']);
×
1191
                        self.comment_buffer.push(line);
×
1192
                    }
1193

1194
                    continue;
220,838✔
1195
                }
1196

1197
                TokenType::DatumComment => {
4✔
1198
                    datum_comments.push(res.span);
4✔
1199
                }
1200

1201
                // Just turn this into `syntax`
1202
                TokenType::QuoteSyntax => {
×
1203
                    let value = self
×
1204
                        .next()
1205
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
×
1206
                            res.span,
×
1207
                            self.source_name.clone(),
×
1208
                        )))
1209
                        .map(|x| self.construct_syntax(x, res.span));
×
1210

1211
                    maybe_return![value];
×
1212
                }
1213

1214
                TokenType::QuasiQuoteSyntax => {
×
1215
                    let value = self
×
1216
                        .next()
1217
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
×
1218
                            res.span,
×
1219
                            self.source_name.clone(),
×
1220
                        )))
1221
                        .map(|x| self.construct_quasiquote_syntax(x, res.span));
×
1222

1223
                    maybe_return![value];
×
1224
                }
1225

1226
                TokenType::UnquoteSyntax => {
×
1227
                    let quote_inner = self
×
1228
                        .next()
1229
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
×
1230
                            res.span,
×
1231
                            self.source_name.clone(),
×
1232
                        )))
1233
                        .map(|x| self.construct_quasiunquote_syntax(x, res.span));
×
1234

1235
                    maybe_return!(quote_inner);
×
1236
                }
1237

1238
                TokenType::UnquoteSpliceSyntax => {
×
1239
                    let quote_inner = self
×
1240
                        .next()
1241
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
×
1242
                            res.span,
×
1243
                            self.source_name.clone(),
×
1244
                        )))
1245
                        .map(|x| self.construct_quasiunquote_syntax_splicing(x, res.span));
×
1246

1247
                    maybe_return!(quote_inner);
×
1248
                }
1249

1250
                TokenType::QuoteTick => {
×
1251
                    // See if this does the job
1252
                    self.shorthand_quote_stack.push(0);
32✔
1253

1254
                    let last = self.quote_context;
32✔
1255

1256
                    if self.quasiquote_depth == 0 {
28✔
1257
                        self.quote_context = true;
12✔
1258
                    }
1259

1260
                    // self.quote_context = true;
1261

1262
                    // println!("Entering Context: Quote Tick");
1263
                    self.context.push(ParsingContext::QuoteTick(0));
48✔
1264

1265
                    let value = self
32✔
1266
                        .next()
1267
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
32✔
1268
                            res.span,
32✔
1269
                            self.source_name.clone(),
16✔
1270
                        )))
1271
                        .map(|x| self.construct_quote_vec(x, res.span));
76✔
1272

1273
                    self.shorthand_quote_stack.pop();
32✔
1274

1275
                    let popped_value = self.context.pop();
48✔
1276

1277
                    if let Some(popped) = popped_value {
32✔
1278
                        // dbg!(&popped);
1279
                        debug_assert!(matches!(popped, ParsingContext::QuoteTick(_)))
×
1280
                    }
1281

1282
                    self.quote_context = last;
16✔
1283

1284
                    // println!("Exiting context: {:?}", self.context.pop());
1285
                    // println!("Result: {:?}", value);
1286

1287
                    // println!("{}", List::new(value.clone().unwrap()));
1288

1289
                    maybe_return!(match value {
×
1290
                        Ok(v) => {
15✔
1291
                            // Ok(ExprKind::List(List::new(v)))
1292

1293
                            self.maybe_lower(v)
×
1294
                        }
1295
                        Err(e) => Err(e),
2✔
1296
                    });
1297
                }
1298

1299
                TokenType::Unquote => {
×
1300
                    // println!("Entering Context: Unquote");
1301
                    self.context.push(ParsingContext::UnquoteTick(0));
36✔
1302

1303
                    self.decrement_quasiquote_context_if_not_in_quote_context();
24✔
1304

1305
                    let value = self
24✔
1306
                        .next()
1307
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
24✔
1308
                            res.span,
24✔
1309
                            self.source_name.clone(),
12✔
1310
                        )))
1311
                        .map(|x| {
24✔
1312
                            // dbg!(&self.quasiquote_depth);
1313
                            if self.quasiquote_depth == 0 && !self.quote_context {
23✔
1314
                                self.construct_raw_unquote(x, res.span)
44✔
1315
                            } else {
1316
                                self.construct_unquote(x, res.span)
1✔
1317
                            }
1318
                        });
1319

1320
                    let popped_value = self.context.pop();
36✔
1321

1322
                    self.increment_quasiquote_context_if_not_in_quote_context();
24✔
1323

1324
                    if let Some(popped) = popped_value {
24✔
1325
                        debug_assert!(matches!(popped, ParsingContext::UnquoteTick(_)))
×
1326
                    }
1327
                    // println!("Exiting context: {:?}", self.context.pop());
1328

1329
                    maybe_return!(value);
12✔
1330
                }
1331

1332
                TokenType::UnquoteSplice => {
×
1333
                    // println!("Entering Context: Unquotesplicing");
1334
                    self.context.push(ParsingContext::UnquoteSplicingTick(0));
6✔
1335

1336
                    self.decrement_quasiquote_context_if_not_in_quote_context();
4✔
1337

1338
                    let value = self
4✔
1339
                        .next()
1340
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
4✔
1341
                            res.span,
4✔
1342
                            self.source_name.clone(),
2✔
1343
                        )))
1344
                        .map(|x| {
4✔
1345
                            if self.quasiquote_depth == 0 && !self.quote_context {
2✔
1346
                                self.construct_raw_unquote_splicing(x, res.span)
×
1347
                            } else {
1348
                                self.construct_unquote_splicing(x, res.span)
2✔
1349
                            }
1350
                        });
1351

1352
                    let popped_value = self.context.pop();
6✔
1353

1354
                    self.increment_quasiquote_context_if_not_in_quote_context();
4✔
1355

1356
                    if let Some(popped) = popped_value {
4✔
1357
                        debug_assert!(matches!(popped, ParsingContext::UnquoteSplicingTick(_)))
×
1358
                    }
1359

1360
                    // println!("Exiting context: {:?}", self.context.pop());
1361

1362
                    maybe_return!(value);
2✔
1363
                }
1364
                // Make this also handle quasisyntax
1365
                TokenType::QuasiQuote => {
×
1366
                    self.context.push(ParsingContext::QuasiquoteTick(0));
6✔
1367

1368
                    self.increment_quasiquote_context_if_not_in_quote_context();
4✔
1369

1370
                    let value = self
4✔
1371
                        .next()
1372
                        .unwrap_or(Err(ParseError::UnexpectedEOF(
4✔
1373
                            res.span,
4✔
1374
                            self.source_name.clone(),
2✔
1375
                        )))
1376
                        .map(|x| self.construct_quasiquote(x, res.span));
10✔
1377

1378
                    let popped_value = self.context.pop();
6✔
1379

1380
                    if let Some(popped) = popped_value {
4✔
1381
                        debug_assert!(matches!(popped, ParsingContext::QuasiquoteTick(_)))
×
1382
                    }
1383

1384
                    self.decrement_quasiquote_context_if_not_in_quote_context();
2✔
1385

1386
                    maybe_return![value];
×
1387
                }
1388

1389
                TokenType::OpenParen(paren, paren_mod) => {
308,084✔
1390
                    let value = self
308,084✔
1391
                        .read_from_tokens((res.span, paren, paren_mod))
462,126✔
1392
                        .map_err(|err| err.set_source(self.source_name.clone()));
154,170✔
1393

1394
                    maybe_return![value];
308,084✔
1395
                }
1396
                TokenType::CloseParen(paren) => {
4✔
1397
                    maybe_return!(Err(ParseError::UnexpectedChar(
8✔
1398
                        paren.close(),
12✔
1399
                        res.span,
8✔
1400
                        self.source_name.clone(),
4✔
1401
                    )))
1402
                }
1403
                _ => {
×
1404
                    maybe_return![Ok(ExprKind::Atom(Atom::new(SyntaxObject::from(&res))))];
180,369✔
1405
                }
1406
            };
1407
        }
1408

1409
        if !datum_comments.is_empty() {
15,680✔
1410
            return Some(Err(ParseError::SyntaxError(
×
1411
                "unfinished commented-out expression".into(),
×
1412
                datum_comments.pop().unwrap(),
×
1413
                None,
×
1414
            )));
1415
        }
1416

1417
        // We're done consuming input
1418
        None
15,680✔
1419
    }
1420
}
1421

1422
impl<'a> Iterator for Parser<'a> {
1423
    type Item = Result<ExprKind>;
1424

1425
    // TODO -> put the
1426
    fn next(&mut self) -> Option<Self::Item> {
229,878✔
1427
        if self.quote_stack.is_empty()
459,756✔
1428
            && self.shorthand_quote_stack.is_empty()
411,736✔
1429
            && self.context.is_empty()
271,328✔
1430
        {
1431
            self.quasiquote_depth = 0;
206,270✔
1432
            self.comment_buffer.clear();
103,135✔
1433
        }
1434

1435
        self.get_next_and_maybe_wrap_in_doc().map(|res| {
903,832✔
1436
            if self.comment_buffer.is_empty() || !self.context.is_empty() {
431,203✔
1437
                res
211,807✔
1438
            } else {
1439
                // Reset the comment collection until next @doc statement
1440
                self.collecting_comments = false;
2,391✔
1441
                res.map(|x| {
7,173✔
1442
                    // println!("Wrapping in doc: {}", x);
1443
                    let result = wrap_in_doc_function(
4,782✔
1444
                        x,
2,391✔
1445
                        self.comment_buffer.drain(..).collect::<Vec<_>>().join("\n"),
9,564✔
1446
                    );
1447

1448
                    result
2,391✔
1449
                })
1450
            }
1451
        })
1452
    }
1453
}
1454

1455
// Lower the syntax rules down from the list representation
1456
pub fn lower_syntax_rules(expr: ExprKind) -> Result<SyntaxRules> {
10,249✔
1457
    let mut value_iter = expr.into_list().into_iter();
40,996✔
1458
    let syn = value_iter
20,498✔
1459
        .next()
1460
        .unwrap()
1461
        .into_atom_syntax_object()
1462
        .unwrap();
1463

1464
    let syntax_vec = if let Some(ExprKind::List(l)) = value_iter.next() {
30,747✔
1465
        l.args
1466
    } else {
1467
        return Err(ParseError::SyntaxError(
×
1468
            "syntax-rules expects a list of new syntax forms used in the macro".to_string(),
×
1469
            syn.span,
×
1470
            None,
×
1471
        ));
1472
    };
1473

1474
    let mut pairs = Vec::new();
1475
    let rest: Vec<_> = value_iter.collect();
1476

1477
    for pair in rest {
79,958✔
1478
        if let ExprKind::List(l) = pair {
69,712✔
1479
            if l.args.len() != 2 {
1480
                return Err(ParseError::SyntaxError(
2✔
1481
                    "syntax-rules requires only one pattern to one body".to_string(),
6✔
1482
                    syn.span,
2✔
1483
                    None,
2✔
1484
                ));
1485
            }
1486

1487
            let mut pair_iter = l.args.into_iter();
1488
            let pair_object =
34,853✔
1489
                PatternPair::new(pair_iter.next().unwrap(), pair_iter.next().unwrap())?;
1✔
1490
            pairs.push(pair_object);
1491
        } else {
1492
            return Err(ParseError::SyntaxError(
×
1493
                "syntax-rules requires pattern to expressions to be in a list".to_string(),
×
1494
                syn.span,
×
1495
                None,
×
1496
            ));
1497
        }
1498
    }
1499

1500
    Ok(SyntaxRules::new(syntax_vec, pairs, syn))
10,246✔
1501
}
1502

1503
// Lower define-syntax down from the list representation
1504
pub fn lower_macro_and_require_definitions(expr: ExprKind) -> Result<ExprKind> {
80,528✔
1505
    let as_list = expr.list();
241,584✔
1506

1507
    // If this qualifies as
1508
    if as_list.map(List::is_define_syntax).unwrap_or_default()
241,584✔
1509
        && as_list
10,251✔
1510
            .unwrap()
10,251✔
1511
            .get(2)
10,251✔
1512
            .and_then(ExprKind::list)
10,251✔
1513
            .map(List::is_syntax_rules)
10,251✔
1514
            .unwrap_or_default()
10,251✔
1515
    {
1516
        let mut value_iter = expr.into_list().into_iter();
40,996✔
1517

1518
        let define_syntax = value_iter.next().unwrap();
40,996✔
1519

1520
        let name = value_iter.next().unwrap();
40,996✔
1521
        let syntax = lower_syntax_rules(value_iter.next().unwrap())?;
51,245✔
1522

1523
        return Ok(ExprKind::Macro(Box::new(Macro::new(
1524
            name,
1525
            Box::new(syntax),
1526
            define_syntax.into_atom_syntax_object().unwrap(),
1527
        ))));
1528
    }
1529

1530
    if as_list.map(List::is_require).unwrap_or_default() {
1531
        let mut raw = expr.into_list().args;
7,276✔
1532

1533
        let syn = raw.remove(0).into_atom_syntax_object().unwrap();
18,190✔
1534

1535
        if raw.is_empty() {
7,276✔
1536
            return Err(ParseError::ArityMismatch(
×
1537
                "require expects at least one identifier or string".to_string(),
×
1538
                syn.span,
×
1539
                None,
×
1540
            ));
1541
        }
1542

1543
        return Ok(ExprKind::Require(Box::new(ast::Require::new(raw, syn))));
1544
    }
1545

1546
    let mut expr = expr;
1547

1548
    // TODO: Here, we should lower syntax-case itself
1549
    // to a defmacro, so that things seem to work out correctly.
1550

1551
    // HACK:
1552
    // If we get here, we can convert the define-syntax back into an identifier
1553
    // so that other macro expansion can occur on it.
1554
    if let Some(first) = expr
66,613✔
1555
        .list_mut()
1556
        .and_then(|x| x.args.first_mut().and_then(|x| x.atom_syntax_object_mut()))
266,486✔
1557
    {
1558
        if first.ty == TokenType::DefineSyntax {
3✔
1559
            first.ty = TokenType::Identifier("define-syntax".into());
6✔
1560
        }
1561
    }
1562

1563
    Ok(expr)
1564
}
1565

1566
struct ASTLowerPass {
1567
    quote_depth: usize,
1568
}
1569

1570
impl ASTLowerPass {
1571
    fn lower(&mut self, expr: &mut ExprKind) -> Result<()> {
13,756,809✔
1572
        match expr {
13,756,809✔
1573
            ExprKind::List(ref mut value) => {
2,915,840✔
1574
                if value.is_quote() {
5,843,720✔
1575
                    // println!("Found quote: {:?}", value);
1576
                    self.quote_depth += 1;
12,040✔
1577
                }
1578

1579
                // Visit the children first, on the way back up, assign into the
1580
                // correct AST node
1581
                // value.args = value
1582
                //     .args
1583
                //     .into_iter()
1584
                //     .map(|x| self.lower(x))
1585
                //     .collect::<Result<_>>()?;
1586

1587
                for expr in value.args.iter_mut() {
14,102,461✔
1588
                    self.lower(expr)?;
24,812,343✔
1589
                }
1590

1591
                if value.is_quote() {
2,927,880✔
1592
                    self.quote_depth -= 1;
12,040✔
1593
                }
1594

1595
                if let Some(f) = value.args.first_mut().and_then(|x| {
5,764,888✔
1596
                    if let ExprKind::Atom(a) = x {
5,764,888✔
1597
                        if a.syn.ty == TokenType::DefineSyntax {
189✔
1598
                            a.syn.ty = TokenType::Identifier("define-syntax".into());
378✔
1599
                        }
1600

1601
                        Some(x.clone())
1602
                    } else {
1603
                        None
66,392✔
1604
                    }
1605
                }) {
1606
                    match f {
2,837,208✔
1607
                        ExprKind::Atom(a) if self.quote_depth == 0 && value.is_quote() => {
8,566,856✔
1608
                            match &a.syn.ty {
12,040✔
1609
                                TokenType::Quote => {
1610
                                    *expr = parse_single_argument(
24,080✔
1611
                                        std::mem::take(&mut value.args).into_iter(),
36,120✔
1612
                                        a.syn.clone(),
24,080✔
1613
                                        "quote",
1614
                                        |expr, syn| ast::Quote::new(expr, syn).into(),
48,160✔
1615
                                    )?;
1616

1617
                                    Ok(())
1618
                                }
1619
                                _ => unreachable!(),
1620
                            }
1621
                        }
1622
                        ExprKind::Atom(a) if self.quote_depth == 0 => {
5,669,448✔
1623
                            let value = std::mem::replace(value, List::new(vec![]));
14,173,620✔
1624

1625
                            *expr = match &a.syn.ty {
5,441,245✔
1626
                                TokenType::If => {
1627
                                    parse_if(value.args_proper(TokenType::If)?.into_iter(), a.syn)
128,546✔
1628
                                }
1629
                                TokenType::Identifier(expr) if *expr == *IF => {
5,213,060✔
1630
                                    parse_if(value.args_proper(TokenType::If)?.into_iter(), a.syn)
×
1631
                                }
1632

1633
                                TokenType::Define => parse_define(
87,336✔
1634
                                    value.args_proper(TokenType::Define)?.into_iter(),
262,008✔
1635
                                    a.syn,
1636
                                ),
1637
                                TokenType::Identifier(expr) if *expr == *DEFINE => parse_define(
2,606,530✔
1638
                                    value.args_proper(TokenType::Define)?.into_iter(),
×
1639
                                    a.syn,
1640
                                ),
1641

1642
                                TokenType::Let => parse_let(
17,861✔
1643
                                    value.args_proper(TokenType::Let)?.into_iter(),
53,583✔
1644
                                    a.syn.clone(),
1645
                                ),
1646
                                TokenType::Identifier(expr) if *expr == *LET => {
2,606,530✔
1647
                                    parse_let(value.args_proper(TokenType::Let)?.into_iter(), a.syn)
×
1648
                                }
1649

1650
                                // TODO: Deprecate
1651
                                TokenType::TestLet => parse_new_let(
1,513✔
1652
                                    value.args_proper(TokenType::TestLet)?.into_iter(),
4,539✔
1653
                                    a.syn,
1654
                                ),
1655
                                TokenType::Identifier(expr) if *expr == *PLAIN_LET => {
2,606,530✔
1656
                                    parse_new_let(
×
1657
                                        value.args_proper(TokenType::TestLet)?.into_iter(),
×
1658
                                        a.syn,
1659
                                    )
1660
                                }
1661

1662
                                TokenType::Quote => parse_single_argument(
×
1663
                                    value.args_proper(TokenType::Quote)?.into_iter(),
×
1664
                                    a.syn,
1665
                                    "quote",
1666
                                    |expr, syn| ast::Quote::new(expr, syn).into(),
×
1667
                                ),
1668
                                TokenType::Identifier(expr) if *expr == *QUOTE => {
2,606,530✔
1669
                                    parse_single_argument(
×
1670
                                        value.args_proper(TokenType::Quote)?.into_iter(),
×
1671
                                        a.syn,
1672
                                        "quote",
1673
                                        |expr, syn| ast::Quote::new(expr, syn).into(),
×
1674
                                    )
1675
                                }
1676

1677
                                TokenType::Return => parse_single_argument(
225✔
1678
                                    value.args_proper(TokenType::Return)?.into_iter(),
675✔
1679
                                    a.syn,
1680
                                    "return!",
1681
                                    |expr, syn| ast::Return::new(expr, syn).into(),
900✔
1682
                                ),
1683
                                TokenType::Identifier(expr) if *expr == *RETURN => {
2,606,530✔
1684
                                    parse_single_argument(
×
1685
                                        value.args_proper(TokenType::Return)?.into_iter(),
×
1686
                                        a.syn,
1687
                                        "return!",
1688
                                        |expr, syn| ast::Return::new(expr, syn).into(),
×
1689
                                    )
1690
                                }
1691

1692
                                TokenType::Require => {
1693
                                    parse_require(&a, value.args_proper(TokenType::Require)?)
×
1694
                                }
1695
                                TokenType::Identifier(expr) if *expr == *REQUIRE => {
2,606,530✔
1696
                                    parse_require(&a, value.args_proper(TokenType::Require)?)
×
1697
                                }
1698

1699
                                TokenType::Set => parse_set(&a, value.args_proper(TokenType::Set)?),
31,115✔
1700
                                TokenType::Identifier(expr) if *expr == *SET => {
2,606,530✔
1701
                                    parse_set(&a, value.args_proper(TokenType::Set)?)
×
1702
                                }
1703

1704
                                TokenType::Begin => {
1705
                                    parse_begin(a, value.args_proper(TokenType::Begin)?)
253,745✔
1706
                                }
1707
                                TokenType::Identifier(expr) if *expr == *BEGIN => {
2,606,530✔
1708
                                    parse_begin(a, value.args_proper(TokenType::Begin)?)
×
1709
                                }
1710

1711
                                TokenType::Lambda => {
1712
                                    parse_lambda(a, value.args_proper(TokenType::Lambda)?)
×
1713
                                }
1714
                                TokenType::Identifier(expr)
1715
                                    if *expr == *LAMBDA
1716
                                        || *expr == *LAMBDA_FN
2,606,530✔
1717
                                        || *expr == *LAMBDA_SYMBOL =>
2,606,530✔
1718
                                {
1719
                                    parse_lambda(a, value.args_proper(TokenType::Lambda)?)
×
1720
                                }
1721

1722
                                _ => Ok(ExprKind::List(value)),
2,606,544✔
1723
                            }?;
1724

1725
                            Ok(())
1726
                        }
1727
                        _ => Ok(()),
2,484✔
1728
                    }
1729
                } else {
1730
                    Ok(())
66,592✔
1731
                }
1732
            }
1733
            ExprKind::Atom(_) => Ok(()),
7,323,390✔
1734
            ExprKind::If(iff) => {
109,668✔
1735
                self.lower(&mut iff.test_expr)?;
329,004✔
1736
                self.lower(&mut iff.then_expr)?;
109,668✔
1737
                self.lower(&mut iff.else_expr)?;
109,668✔
1738
                Ok(())
109,668✔
1739
            }
1740
            ExprKind::Let(l) => {
10,398✔
1741
                for (left, right) in l.bindings.iter_mut() {
83,176✔
1742
                    self.lower(left)?;
93,570✔
1743
                    self.lower(right)?;
31,190✔
1744
                }
1745

1746
                self.lower(&mut l.body_expr)?;
10,398✔
1747

1748
                Ok(())
10,398✔
1749
            }
1750
            ExprKind::Define(d) => {
1,409,611✔
1751
                self.lower(&mut d.name)?;
4,228,833✔
1752
                self.lower(&mut d.body)?;
1,409,611✔
1753

1754
                Ok(())
1,409,611✔
1755
            }
1756

1757
            ExprKind::LambdaFunction(f) => {
227,419✔
1758
                for arg in f.args.iter_mut() {
713,155✔
1759
                    self.lower(arg)?;
774,951✔
1760
                }
1761

1762
                self.lower(&mut f.body)?;
227,419✔
1763

1764
                Ok(())
227,419✔
1765
            }
1766
            ExprKind::Begin(b) => {
94,259✔
1767
                for expr in b.exprs.iter_mut() {
1,748,558✔
1768
                    self.lower(expr)?;
4,680,120✔
1769
                }
1770

1771
                Ok(())
94,259✔
1772
            }
1773
            // Ok(ExprKind::Begin(ast::Begin::new(
1774
            //     b.exprs
1775
            //         .into_iter()
1776
            //         .map(|x| self.lower(x))
1777
            //         .collect::<Result<_>>()?,
1778
            //     b.location,
1779
            // ))),
1780
            ExprKind::Return(r) => {
422✔
1781
                self.lower(&mut r.expr)?;
1,266✔
1782
                Ok(())
422✔
1783
            }
1784
            // Ok(ExprKind::Return(Box::new(ast::Return::new(
1785
            //     self.lower(r.expr)?,
1786
            //     r.location,
1787
            // )))),
1788
            ExprKind::Quote(_) => Ok(()),
1,631,917✔
1789
            ExprKind::Macro(_) => Ok(()),
1✔
1790
            ExprKind::SyntaxRules(_) => Ok(()),
×
1791
            ExprKind::Set(s) => {
33,407✔
1792
                self.lower(&mut s.variable)?;
100,221✔
1793
                self.lower(&mut s.expr)?;
33,407✔
1794

1795
                Ok(())
33,407✔
1796
            }
1797
            // Ok(ExprKind::Set(Box::new(ast::Set::new(
1798
            //     self.lower(s.variable)?,
1799
            //     self.lower(s.expr)?,
1800
            //     s.location,
1801
            // )))),
1802
            ExprKind::Require(_) => Ok(()),
×
1803
            ExprKind::Vector(v) => {
477✔
1804
                for arg in &mut v.args {
2,913✔
1805
                    self.lower(arg)?;
3,654✔
1806
                }
1807

1808
                Ok(())
477✔
1809
            }
1810
        }
1811
    }
1812
}
1813

1814
// TODO: Lower the rest of the AST post expansion, such that
1815
pub fn lower_entire_ast(expr: &mut ExprKind) -> Result<()> {
150,794✔
1816
    ASTLowerPass { quote_depth: 0 }.lower(expr)
1817
}
1818

1819
#[derive(Debug)]
1820
struct Frame {
1821
    open: Span,
1822
    paren: Paren,
1823
    paren_mod: Option<ParenMod>,
1824
    exprs: Vec<ExprKind>,
1825
    dot: Option<(u32, Span)>,
1826
    comment: u8,
1827
}
1828

1829
impl Frame {
1830
    fn into_expr(self, close: Span) -> Result<ExprKind> {
1,807,587✔
1831
        self.build_expr(close, |exprs| Ok(List::new(exprs).into()))
10,838,331✔
1832
    }
1833

1834
    fn build_expr(
3,915,506✔
1835
        self,
1836
        close: Span,
1837
        builder: impl FnOnce(Vec<ExprKind>) -> Result<ExprKind>,
1838
    ) -> Result<ExprKind> {
1839
        if self.comment > 0 {
3,915,506✔
1840
            return Err(ParseError::SyntaxError(
1✔
1841
                "invalid datum comment".into(),
3✔
1842
                self.open,
1✔
1843
                None,
1✔
1844
            ));
1845
        }
1846

1847
        if let Some(paren_mod) = self.paren_mod {
2,707✔
1848
            let bytes = matches!(paren_mod, ParenMod::Bytes);
2,604✔
1849

1850
            return Ok(Vector {
×
1851
                args: self.exprs,
×
1852
                bytes,
×
1853
                span: Span::merge(self.open, close),
×
1854
            }
1855
            .into());
×
1856
        };
1857

1858
        let improper = self.improper()?;
11,738,394✔
1859

1860
        let mut expr = builder(self.exprs)?;
3,912,797✔
1861

1862
        match &mut expr {
405✔
1863
            ExprKind::List(list) => {
3,912,381✔
1864
                list.location = Span::merge(self.open, close);
×
1865

1866
                if improper {
5,748✔
1867
                    list.make_improper();
5,748✔
1868
                }
1869
            }
1870
            _ if improper => todo!(),
1871
            _ => {}
405✔
1872
        };
1873

1874
        Ok(expr)
3,912,786✔
1875
    }
1876

1877
    fn push(&mut self, expr: ExprKind) -> Result<()> {
10,552,284✔
1878
        if let Some(idx) = self.dot.as_ref().map(|x| x.0) {
31,662,606✔
1879
            debug_assert!(!self.exprs.is_empty());
1880

1881
            if idx as usize != self.exprs.len() {
11,508✔
1882
                debug_assert_eq!(idx + 1, self.exprs.len() as _);
8✔
1883

1884
                return Err(ParseError::SyntaxError(
2✔
1885
                    "improper list must have a single cdr".to_owned(),
6✔
1886
                    expr.span(),
4✔
1887
                    None,
2✔
1888
                ));
1889
            }
1890
        }
1891

1892
        let valid_for_bytes = match (self.paren_mod, &expr) {
10,552,282✔
1893
            (Some(ParenMod::Bytes), ExprKind::Atom(atom)) if atom.byte().is_some() => true,
1,448✔
1894
            (Some(ParenMod::Bytes), _) => false,
2✔
1895
            _ => true,
10,551,991✔
1896
        };
1897

1898
        if !valid_for_bytes {
1899
            return Err(ParseError::SyntaxError(
2✔
1900
                "bytevector literals can only contain integer literals in the 0-255 range".into(),
2✔
1901
                expr.span(),
2✔
1902
                None,
2✔
1903
            ));
1904
        }
1905

1906
        if self.comment > 0 {
10,552,280✔
1907
            self.comment -= 1;
1✔
1908

1909
            return Ok(());
1✔
1910
        }
1911

1912
        self.exprs.push(expr);
1913

1914
        Ok(())
1915
    }
1916

1917
    fn improper(&self) -> Result<bool> {
3,912,798✔
1918
        match self.dot {
5,749✔
1919
            Some((idx, _)) if idx + 1 == self.exprs.len() as _ => Ok(true),
34,491✔
1920
            Some((idx, span)) => {
1✔
1921
                debug_assert_eq!(idx, self.exprs.len() as _);
1922

1923
                Err(ParseError::SyntaxError(
1✔
1924
                    "improper list must have a single cdr".into(),
3✔
1925
                    span,
1✔
1926
                    None,
1✔
1927
                ))
1928
            }
1929
            None => Ok(false),
3,907,049✔
1930
        }
1931
    }
1932
}
1933

1934
#[cfg(test)]
1935
mod parser_tests {
1936
    // use super::TokenType::*;
1937
    use super::*;
1938
    use crate::parser::ast::{Begin, Define, If, LambdaFunction, Quote, Return};
1939
    use crate::tokens::{Paren, RealLiteral};
1940
    use crate::visitors::Eraser;
1941
    use crate::{parser::ast::ExprKind, tokens::IntLiteral};
1942

1943
    fn atom(ident: &str) -> ExprKind {
1944
        ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::Identifier(
1945
            ident.into(),
1946
        ))))
1947
    }
1948

1949
    fn int(num: isize) -> ExprKind {
1950
        ExprKind::Atom(Atom::new(SyntaxObject::default(
1951
            IntLiteral::Small(num).into(),
1952
        )))
1953
    }
1954

1955
    fn character(c: char) -> ExprKind {
1956
        ExprKind::Atom(Atom::new(SyntaxObject::default(
1957
            TokenType::CharacterLiteral(c),
1958
        )))
1959
    }
1960

1961
    #[test]
1962
    fn check_quote_parsing() {
1963
        println!("{:?}", Parser::parse("'(a b 'c)"));
1964
    }
1965

1966
    fn parses(s: &str) {
1967
        let a: Result<Vec<_>> = Parser::new(s, SourceId::none()).collect();
1968
        a.unwrap();
1969
    }
1970

1971
    fn parse_err(s: &str) -> ParseError {
1972
        let a: Result<Vec<_>> = Parser::new(s, SourceId::none()).collect();
1973
        a.unwrap_err()
1974
    }
1975

1976
    fn assert_parse(s: &str, result: &[ExprKind]) {
1977
        let a: Result<Vec<ExprKind>> = Parser::new(s, SourceId::none()).collect();
1978
        let mut a = a.unwrap();
1979

1980
        let mut eraser = Eraser;
1981

1982
        eraser.visit_many(&mut a);
1983

1984
        assert_eq!(a.as_slice(), result);
1985
    }
1986

1987
    fn assert_syntax_err(s: &str, expected: &str) {
1988
        let a: Result<Vec<ExprKind>> = Parser::new(s, SourceId::none()).collect();
1989
        let Err(ParseError::SyntaxError(err, _, _)) = a else {
1990
            panic!("expected syntax error, got {a:?}");
1991
        };
1992

1993
        assert_eq!(err, expected);
1994
    }
1995

1996
    fn assert_parse_is_err(s: &str) {
1997
        let a: Result<Vec<ExprKind>> = Parser::new(s, SourceId::none()).collect();
1998
        assert!(a.is_err());
1999
    }
2000

2001
    #[test]
2002
    fn check_resulting_parsing() {
2003
        let expr = r#"`(a `(b ,(+ 1 2) ,(foo ,(+ 1 3) d) e) f)"#;
2004

2005
        let a: Result<Vec<ExprKind>> = Parser::new(expr, SourceId::none()).collect();
2006
        let a = a.unwrap();
2007

2008
        println!("{}", a[0]);
2009
    }
2010

2011
    #[test]
2012
    fn check_double_unquote_parsing() {
2013
        let expr = r#"(let ([name1 'x] [name2 'y]) `(a `(b ,,name1 ,',name2 d) e))"#;
2014

2015
        let a: Result<Vec<ExprKind>> = Parser::new(expr, SourceId::none()).collect();
2016
        let a = a.unwrap();
2017

2018
        println!("{}", a[0]);
2019
    }
2020

2021
    #[test]
2022
    fn check_parser_with_doc_comments() {
2023
        let expr = r#"
2024
        ;;@doc
2025
        ;; This is a fancy cool comment, that I want to attach to a top level definition!
2026
        ;; This is the second line of the comment, I want this attached as well!
2027
        ;; Macro for creating a new struct, in the form of:
2028
        ;; `(struct <struct-name> (fields ...) options ...)`
2029
        ;; The options can consist of the following:
2030
        ;;
2031
        ;; Single variable options (those which their presence indicates #true)
2032
        ;; - #:mutable
2033
        ;; - #:transparent
2034
        ;;
2035
        ;; Other options must be presented as key value pairs, and will get stored
2036
        ;; in the struct instance. They will also be bound to the variable
2037
        ;; ___<struct-name>-options___ in the same lexical environment where the
2038
        ;; struct was defined. For example:
2039
        ;;
2040
        ;; (Applesauce (a b c) #:mutable #:transparent #:unrecognized-option 1234)
2041
        ;;
2042
        ;; Will result in the value `___Applesauce-options___` like so:
2043
        ;; (hash #:mutable #true #:transparent #true #:unrecognized-option 1234)
2044
        ;;
2045
        ;; By default, structs are immutable, which means setter functions will not
2046
        ;; be generated. Also by default, structs are not transparent, which means
2047
        ;; printing them will result in an opaque struct that does not list the fields
2048
        (define foo 12345)
2049
        "#;
2050

2051
        let parser = Parser::doc_comment_parser(expr, SourceId::none());
2052

2053
        let result: Result<Vec<_>> = parser.collect();
2054

2055
        println!("{:?}", result.unwrap());
2056
    }
2057

2058
    #[test]
2059
    fn parses_make_struct() {
2060
        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)))")
2061
    }
2062

2063
    #[test]
2064
    fn parses_quasiquote() {
2065
        parses(r#"(quasiquote ((unquote x) xs ...)) "#);
2066
    }
2067

2068
    #[test]
2069
    fn parse_syntax_rules() {
2070
        parses(
2071
            r#"
2072
            (syntax-rules (unquote unquote-splicing)
2073
              ((quasiquote ((unquote x) xs ...))          (cons x (quasiquote (xs ...))))
2074
              ((quasiquote ((unquote-splicing x)))        (append (list x) '()))
2075
              ((quasiquote ((unquote-splicing x) xs ...)) (append x (quasiquote (xs ...))))
2076
              ((quasiquote (unquote x))                 x)
2077
              ((quasiquote (x))                          '(x))
2078
              ((quasiquote (x xs ...))                   (cons (quasiquote x) (quasiquote (xs ...))))
2079
              ((quasiquote x)                           'x))
2080
            "#,
2081
        );
2082
    }
2083

2084
    #[test]
2085
    fn parse_define_syntax() {
2086
        parses(
2087
            r#"
2088
        (define-syntax quasiquote
2089
            (syntax-rules (unquote unquote-splicing)
2090
              ((quasiquote ((unquote x) xs ...))          (cons x (quasiquote (xs ...))))
2091
              ((quasiquote ((unquote-splicing x)))        (append (list x) '()))
2092
              ((quasiquote ((unquote-splicing x) xs ...)) (append x (quasiquote (xs ...))))
2093
              ((quasiquote (unquote x))                 x)
2094
              ((quasiquote (x))                          '(x))
2095
              ((quasiquote (x xs ...))                   (cons (quasiquote x) (quasiquote (xs ...))))
2096
              ((quasiquote x)                           'x)))
2097
        "#,
2098
        );
2099
    }
2100

2101
    #[test]
2102
    fn parse_quote() {
2103
        // parses("(displayln (match (quote (lambda y z)) '(x y z)))")
2104
        parses("(displayln (match '(lambda y z) '(x y z)))")
2105
    }
2106

2107
    #[test]
2108
    fn parse_unicode() {
2109
        assert_parse("#\\¡", &[character('¡')]);
2110
        assert_parse("#\\u{b}", &[character('\u{b}')]);
2111
    }
2112

2113
    #[test]
2114
    fn parse_more_unicode() {
2115
        assert_parse("#\\u{a0}", &[character('\u{a0}')]);
2116
    }
2117

2118
    #[test]
2119
    fn parse_strange_characters() {
2120
        assert_parse("#\\^", &[character('^')]);
2121
    }
2122

2123
    #[test]
2124
    fn parse_character_sequence() {
2125
        assert_parse(
2126
            "#\\¡ #\\SPACE #\\g",
2127
            &[character('¡'), character(' '), character('g')],
2128
        )
2129
    }
2130

2131
    #[test]
2132
    fn parse_character_sequence_inside_if() {
2133
        assert_parse(
2134
            "(if #\\¡ #\\SPACE #\\g)",
2135
            &[ExprKind::If(Box::new(If::new(
2136
                character('¡'),
2137
                character(' '),
2138
                character('g'),
2139
                SyntaxObject::default(TokenType::If),
2140
            )))],
2141
        )
2142
    }
2143

2144
    #[test]
2145
    fn parse_close_paren_character() {
2146
        assert_parse("#\\)", &[character(')')]);
2147
        assert_parse("#\\]", &[character(']')])
2148
    }
2149

2150
    #[test]
2151
    fn parse_open_paren_character() {
2152
        assert_parse("#\\(", &[character('(')])
2153
    }
2154

2155
    macro_rules! assert_matches {
2156
        ($expr:expr, $pat:pat) => {{
2157
            let value = $expr;
2158
            match value {
2159
                $pat => {}
2160
                _ => panic!("{value:?} does not match"),
2161
            }
2162
        }};
2163
    }
2164

2165
    #[test]
2166
    fn test_error() {
2167
        assert_matches![parse_err("("), ParseError::UnexpectedEOF(..)];
2168
        assert_matches![parse_err("(abc"), ParseError::UnexpectedEOF(..)];
2169
        assert_matches![parse_err("(ab 1 2"), ParseError::UnexpectedEOF(..)];
2170
        assert_matches![parse_err("((((ab 1 2) ("), ParseError::UnexpectedEOF(..)];
2171
        assert_matches![parse_err("())"), ParseError::UnexpectedChar(')', ..)];
2172
        assert_matches![parse_err("() (((("), ParseError::UnexpectedEOF(..)];
2173
        assert_matches![parse_err("')"), ParseError::UnexpectedChar(')', ..)];
2174
        assert_matches![parse_err("(')"), ParseError::UnexpectedChar(')', ..)];
2175
        assert_matches![parse_err("('"), ParseError::UnexpectedEOF(..)];
2176
        assert_matches![parse_err(r#""abc"#), ParseError::UnexpectedEOF(..)];
2177
        assert_matches![
2178
            parse_err("(]"),
2179
            ParseError::MismatchedParen(Paren::Round, _, None)
2180
        ];
2181
    }
2182

2183
    #[test]
2184
    fn quote_multiple_args_should_err() {
2185
        assert_parse_is_err("(quote a b c)");
2186
    }
2187

2188
    #[test]
2189
    fn test_let_should_err() {
2190
        assert_parse_is_err("(let)");
2191
        assert_parse_is_err("(let (a) 10)");
2192
    }
2193

2194
    #[test]
2195
    fn test_if_should_err() {
2196
        assert_parse_is_err("(if)");
2197
        assert_parse_is_err("(if 1)");
2198
        // assert_parse_is_err("(if 1 2)");
2199
        assert_parse_is_err("(if 1 2 3 4)");
2200
    }
2201

2202
    #[test]
2203
    fn test_define_should_err() {
2204
        assert_parse_is_err("(define)");
2205
        assert_parse_is_err("(define blagh)");
2206
        assert_parse_is_err("(define test 1 2)");
2207
        assert_parse_is_err("(define () test");
2208
    }
2209

2210
    #[test]
2211
    fn test_lambda_should_err() {
2212
        assert_parse_is_err("(lambda)");
2213
        assert_parse_is_err("(lambda (x))");
2214
    }
2215

2216
    #[test]
2217
    fn test_empty() {
2218
        assert_parse("", &[]);
2219
        assert_parse("()", &[ExprKind::List(List::new(vec![]))]);
2220
    }
2221

2222
    #[test]
2223
    fn test_empty_quote_inside_if() {
2224
        assert_parse(
2225
            "(if #\\¡ (quote ()) #\\g)",
2226
            &[ExprKind::If(Box::new(If::new(
2227
                character('¡'),
2228
                ExprKind::Quote(
2229
                    Quote::new(
2230
                        List::new(vec![]).into(),
2231
                        SyntaxObject::default(TokenType::Quote),
2232
                    )
2233
                    .into(),
2234
                ),
2235
                character('g'),
2236
                SyntaxObject::default(TokenType::If),
2237
            )))],
2238
        )
2239
    }
2240

2241
    #[test]
2242
    fn test_empty_quote() {
2243
        assert_parse(
2244
            "'()",
2245
            &[ExprKind::Quote(
2246
                Quote::new(
2247
                    List::new(vec![]).into(),
2248
                    SyntaxObject::default(TokenType::Quote),
2249
                )
2250
                .into(),
2251
            )],
2252
        )
2253
    }
2254

2255
    #[test]
2256
    fn test_empty_quote_nested() {
2257
        assert_parse(
2258
            "(list '())",
2259
            &[ExprKind::List(List::new(vec![
2260
                atom("list"),
2261
                ExprKind::Quote(
2262
                    Quote::new(
2263
                        List::new(vec![]).into(),
2264
                        SyntaxObject::default(TokenType::Quote),
2265
                    )
2266
                    .into(),
2267
                ),
2268
            ]))],
2269
        )
2270
    }
2271

2272
    #[test]
2273
    fn test_multi_parse_simple() {
2274
        assert_parse("a b +", &[atom("a"), atom("b"), atom("+")]);
2275
    }
2276

2277
    #[test]
2278
    fn test_multi_parse_complicated() {
2279
        assert_parse(
2280
            "a b (funcall  1 (+ 2 3.5))",
2281
            &[
2282
                atom("a"),
2283
                atom("b"),
2284
                ExprKind::List(List::new(vec![
2285
                    atom("funcall"),
2286
                    int(1),
2287
                    ExprKind::List(List::new(vec![
2288
                        atom("+"),
2289
                        int(2),
2290
                        ExprKind::Atom(Atom::new(SyntaxObject::default(
2291
                            RealLiteral::Float(3.5).into(),
2292
                        ))),
2293
                    ])),
2294
                ])),
2295
            ],
2296
        )
2297
    }
2298
    #[test]
2299
    fn test_parse_simple() {
2300
        assert_parse(
2301
            "(+ 1 2 3) (- 4 3)",
2302
            &[
2303
                ExprKind::List(List::new(vec![atom("+"), int(1), int(2), int(3)])),
2304
                ExprKind::List(List::new(vec![atom("-"), int(4), int(3)])),
2305
            ],
2306
        );
2307
    }
2308

2309
    #[test]
2310
    fn test_parse_nested() {
2311
        assert_parse(
2312
            "(+ 1 (foo (bar 2 3)))",
2313
            &[ExprKind::List(List::new(vec![
2314
                atom("+"),
2315
                int(1),
2316
                ExprKind::List(List::new(vec![
2317
                    atom("foo"),
2318
                    ExprKind::List(List::new(vec![atom("bar"), int(2), int(3)])),
2319
                ])),
2320
            ]))],
2321
        );
2322
        assert_parse(
2323
            "(+ 1 (+ 2 3) (foo (bar 2 3)))",
2324
            &[ExprKind::List(List::new(vec![
2325
                atom("+"),
2326
                int(1),
2327
                ExprKind::List(List::new(vec![atom("+"), int(2), int(3)])),
2328
                ExprKind::List(List::new(vec![
2329
                    atom("foo"),
2330
                    ExprKind::List(List::new(vec![atom("bar"), int(2), int(3)])),
2331
                ])),
2332
            ]))],
2333
        );
2334
    }
2335

2336
    #[test]
2337
    fn test_if() {
2338
        assert_parse(
2339
            "(+ 1 (if 2 3 4) (foo (+ (bar 1 1) 3) 5))",
2340
            &[ExprKind::List(List::new(vec![
2341
                atom("+"),
2342
                int(1),
2343
                ExprKind::If(Box::new(If::new(
2344
                    int(2),
2345
                    int(3),
2346
                    int(4),
2347
                    SyntaxObject::default(TokenType::If),
2348
                ))),
2349
                ExprKind::List(List::new(vec![
2350
                    atom("foo"),
2351
                    ExprKind::List(List::new(vec![
2352
                        atom("+"),
2353
                        ExprKind::List(List::new(vec![atom("bar"), int(1), int(1)])),
2354
                        int(3),
2355
                    ])),
2356
                    int(5),
2357
                ])),
2358
            ]))],
2359
        );
2360
    }
2361

2362
    #[test]
2363
    fn test_quote() {
2364
        assert_parse(
2365
            "(quote (if 1 2))",
2366
            &[ExprKind::Quote(Box::new(Quote::new(
2367
                ExprKind::List(List::new(vec![
2368
                    ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2369
                    int(1),
2370
                    int(2),
2371
                ])),
2372
                SyntaxObject::default(TokenType::Quote),
2373
            )))],
2374
        )
2375
    }
2376

2377
    #[test]
2378
    fn test_quote_shorthand() {
2379
        assert_parse(
2380
            "'(if 1 2)",
2381
            &[ExprKind::Quote(Box::new(Quote::new(
2382
                ExprKind::List(List::new(vec![
2383
                    ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2384
                    int(1),
2385
                    int(2),
2386
                ])),
2387
                SyntaxObject::default(TokenType::Quote),
2388
            )))],
2389
        )
2390
    }
2391

2392
    #[test]
2393
    fn test_quote_nested() {
2394
        assert_parse(
2395
            "(quote (if (if 1 2) 3))",
2396
            &[ExprKind::Quote(Box::new(Quote::new(
2397
                ExprKind::List(List::new(vec![
2398
                    ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2399
                    ExprKind::List(List::new(vec![
2400
                        ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2401
                        int(1),
2402
                        int(2),
2403
                    ])),
2404
                    int(3),
2405
                ])),
2406
                SyntaxObject::default(TokenType::Quote),
2407
            )))],
2408
        )
2409
    }
2410

2411
    #[test]
2412
    fn test_quote_shorthand_nested() {
2413
        assert_parse(
2414
            "'(if (if 1 2) 3)",
2415
            &[ExprKind::Quote(Box::new(Quote::new(
2416
                ExprKind::List(List::new(vec![
2417
                    ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2418
                    ExprKind::List(List::new(vec![
2419
                        ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2420
                        int(1),
2421
                        int(2),
2422
                    ])),
2423
                    int(3),
2424
                ])),
2425
                SyntaxObject::default(TokenType::Quote),
2426
            )))],
2427
        )
2428
    }
2429

2430
    #[test]
2431
    fn test_quote_shorthand_multiple_exprs() {
2432
        assert_parse(
2433
            "'(if (if 1 2) 3) (+ 1 (if 2 3 4) (foo (+ (bar 1 1) 3) 5))",
2434
            &[
2435
                ExprKind::Quote(Box::new(Quote::new(
2436
                    ExprKind::List(List::new(vec![
2437
                        ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2438
                        ExprKind::List(List::new(vec![
2439
                            ExprKind::Atom(Atom::new(SyntaxObject::default(TokenType::If))),
2440
                            int(1),
2441
                            int(2),
2442
                        ])),
2443
                        int(3),
2444
                    ])),
2445
                    SyntaxObject::default(TokenType::Quote),
2446
                ))),
2447
                ExprKind::List(List::new(vec![
2448
                    atom("+"),
2449
                    int(1),
2450
                    ExprKind::If(Box::new(If::new(
2451
                        int(2),
2452
                        int(3),
2453
                        int(4),
2454
                        SyntaxObject::default(TokenType::If),
2455
                    ))),
2456
                    ExprKind::List(List::new(vec![
2457
                        atom("foo"),
2458
                        ExprKind::List(List::new(vec![
2459
                            atom("+"),
2460
                            ExprKind::List(List::new(vec![atom("bar"), int(1), int(1)])),
2461
                            int(3),
2462
                        ])),
2463
                        int(5),
2464
                    ])),
2465
                ])),
2466
            ],
2467
        )
2468
    }
2469

2470
    #[test]
2471
    fn test_quote_inner() {
2472
        assert_parse(
2473
            "'(applesauce 'one)",
2474
            &[ExprKind::Quote(Box::new(Quote::new(
2475
                ExprKind::List(List::new(vec![
2476
                    atom("applesauce"),
2477
                    ExprKind::Quote(Box::new(Quote::new(
2478
                        atom("one"),
2479
                        SyntaxObject::default(TokenType::Quote),
2480
                    ))),
2481
                ])),
2482
                SyntaxObject::default(TokenType::Quote),
2483
            )))],
2484
        )
2485
    }
2486

2487
    #[test]
2488
    fn test_quote_inner_without_shorthand() {
2489
        assert_parse(
2490
            "(quote (applesauce 'one))",
2491
            &[ExprKind::Quote(Box::new(Quote::new(
2492
                ExprKind::List(List::new(vec![
2493
                    atom("applesauce"),
2494
                    ExprKind::Quote(Box::new(Quote::new(
2495
                        atom("one"),
2496
                        SyntaxObject::default(TokenType::Quote),
2497
                    ))),
2498
                ])),
2499
                SyntaxObject::default(TokenType::Quote),
2500
            )))],
2501
        )
2502
    }
2503

2504
    #[test]
2505
    fn test_quasiquote_shorthand() {
2506
        assert_parse(
2507
            "`(+ 1 2)",
2508
            &[ExprKind::List(List::new(vec![
2509
                atom("quasiquote"),
2510
                ExprKind::List(List::new(vec![atom("+"), int(1), int(2)])),
2511
            ]))],
2512
        )
2513
    }
2514

2515
    #[test]
2516
    fn test_quasiquote_normal() {
2517
        assert_parse(
2518
            "(quasiquote (+ 1 2))",
2519
            &[ExprKind::List(List::new(vec![
2520
                atom("quasiquote"),
2521
                ExprKind::List(List::new(vec![atom("+"), int(1), int(2)])),
2522
            ]))],
2523
        )
2524
    }
2525

2526
    #[test]
2527
    fn test_unquote_shorthand() {
2528
        assert_parse(
2529
            ",(+ 1 2)",
2530
            &[ExprKind::List(List::new(vec![
2531
                atom("unquote"),
2532
                ExprKind::List(List::new(vec![atom("+"), int(1), int(2)])),
2533
            ]))],
2534
        )
2535
    }
2536

2537
    #[test]
2538
    fn test_unquote_normal() {
2539
        assert_parse(
2540
            "(unquote (+ 1 2))",
2541
            &[ExprKind::List(List::new(vec![
2542
                atom("unquote"),
2543
                ExprKind::List(List::new(vec![atom("+"), int(1), int(2)])),
2544
            ]))],
2545
        )
2546
    }
2547

2548
    #[test]
2549
    fn test_unquote_splicing_shorthand() {
2550
        assert_parse(
2551
            ",@(+ 1 2)",
2552
            &[ExprKind::List(List::new(vec![
2553
                atom("unquote-splicing"),
2554
                ExprKind::List(List::new(vec![atom("+"), int(1), int(2)])),
2555
            ]))],
2556
        )
2557
    }
2558

2559
    #[test]
2560
    fn test_unquote_splicing_normal() {
2561
        assert_parse(
2562
            "(unquote-splicing (+ 1 2))",
2563
            &[ExprKind::List(List::new(vec![
2564
                atom("unquote-splicing"),
2565
                ExprKind::List(List::new(vec![atom("+"), int(1), int(2)])),
2566
            ]))],
2567
        )
2568
    }
2569

2570
    #[test]
2571
    fn test_define_simple() {
2572
        assert_parse(
2573
            "(define a 10)",
2574
            &[ExprKind::Define(Box::new(Define::new(
2575
                atom("a"),
2576
                int(10),
2577
                SyntaxObject::default(TokenType::Define),
2578
            )))],
2579
        )
2580
    }
2581

2582
    #[test]
2583
    fn test_define_func_simple() {
2584
        assert_parse(
2585
            "(define (foo x) (+ x 10))",
2586
            &[ExprKind::Define(Box::new(Define::new(
2587
                atom("foo"),
2588
                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2589
                    vec![atom("x")],
2590
                    ExprKind::List(List::new(vec![atom("+"), atom("x"), int(10)])),
2591
                    SyntaxObject::default(TokenType::Lambda),
2592
                ))),
2593
                SyntaxObject::default(TokenType::Define),
2594
            )))],
2595
        )
2596
    }
2597

2598
    #[test]
2599
    fn test_define_func_multiple_args() {
2600
        assert_parse(
2601
            "(define (foo x y z) (+ x 10))",
2602
            &[ExprKind::Define(Box::new(Define::new(
2603
                atom("foo"),
2604
                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2605
                    vec![atom("x"), atom("y"), atom("z")],
2606
                    ExprKind::List(List::new(vec![atom("+"), atom("x"), int(10)])),
2607
                    SyntaxObject::default(TokenType::Lambda),
2608
                ))),
2609
                SyntaxObject::default(TokenType::Define),
2610
            )))],
2611
        )
2612
    }
2613

2614
    #[test]
2615
    fn test_define_func_multiple_args_multiple_body_exprs() {
2616
        assert_parse(
2617
            "(define (foo x y z) (+ x 10) (+ y 20) (+ z 30))",
2618
            &[ExprKind::Define(Box::new(Define::new(
2619
                atom("foo"),
2620
                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2621
                    vec![atom("x"), atom("y"), atom("z")],
2622
                    ExprKind::Begin(Box::new(Begin::new(
2623
                        vec![
2624
                            ExprKind::List(List::new(vec![atom("+"), atom("x"), int(10)])),
2625
                            ExprKind::List(List::new(vec![atom("+"), atom("y"), int(20)])),
2626
                            ExprKind::List(List::new(vec![atom("+"), atom("z"), int(30)])),
2627
                        ],
2628
                        SyntaxObject::default(TokenType::Begin),
2629
                    ))),
2630
                    SyntaxObject::default(TokenType::Lambda),
2631
                ))),
2632
                SyntaxObject::default(TokenType::Define),
2633
            )))],
2634
        )
2635
    }
2636

2637
    #[test]
2638
    fn test_recursive_function() {
2639
        assert_parse(
2640
            "(define (test) (define (foo) (bar)) (define (bar) (foo)))",
2641
            &[ExprKind::Define(Box::new(Define::new(
2642
                atom("test"),
2643
                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2644
                    vec![],
2645
                    ExprKind::Begin(Box::new(Begin::new(
2646
                        vec![
2647
                            ExprKind::Define(Box::new(Define::new(
2648
                                atom("foo"),
2649
                                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2650
                                    vec![],
2651
                                    ExprKind::List(List::new(vec![atom("bar")])),
2652
                                    SyntaxObject::default(TokenType::Lambda),
2653
                                ))),
2654
                                SyntaxObject::default(TokenType::Define),
2655
                            ))),
2656
                            ExprKind::Define(Box::new(Define::new(
2657
                                atom("bar"),
2658
                                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2659
                                    vec![],
2660
                                    ExprKind::List(List::new(vec![atom("foo")])),
2661
                                    SyntaxObject::default(TokenType::Lambda),
2662
                                ))),
2663
                                SyntaxObject::default(TokenType::Define),
2664
                            ))),
2665
                        ],
2666
                        SyntaxObject::default(TokenType::Begin),
2667
                    ))),
2668
                    SyntaxObject::default(TokenType::Lambda),
2669
                ))),
2670
                SyntaxObject::default(TokenType::Define),
2671
            )))],
2672
        )
2673
    }
2674

2675
    #[test]
2676
    fn test_return_normal() {
2677
        assert_parse(
2678
            "(return! 10)",
2679
            &[ExprKind::Return(Box::new(Return::new(
2680
                int(10),
2681
                SyntaxObject::default(TokenType::Return),
2682
            )))],
2683
        )
2684
    }
2685

2686
    #[test]
2687
    fn test_begin() {
2688
        assert_parse(
2689
            "(begin 1 2 3)",
2690
            &[ExprKind::Begin(Box::new(Begin::new(
2691
                vec![int(1), int(2), int(3)],
2692
                SyntaxObject::default(TokenType::Begin),
2693
            )))],
2694
        )
2695
    }
2696

2697
    #[test]
2698
    fn test_lambda_function() {
2699
        assert_parse(
2700
            "(lambda (x) 10)",
2701
            &[ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2702
                vec![atom("x")],
2703
                int(10),
2704
                SyntaxObject::default(TokenType::Lambda),
2705
            )))],
2706
        )
2707
    }
2708

2709
    #[test]
2710
    fn test_lambda_function_with_rest() {
2711
        assert_parse(
2712
            "(lambda (x . y) 10)",
2713
            &[ExprKind::LambdaFunction(Box::new(
2714
                LambdaFunction::new_maybe_rest(
2715
                    vec![atom("x"), atom("y")],
2716
                    int(10),
2717
                    SyntaxObject::default(TokenType::Lambda),
2718
                    true,
2719
                ),
2720
            ))],
2721
        )
2722
    }
2723

2724
    #[test]
2725
    fn test_lambda_function_with_rest_only() {
2726
        assert_parse(
2727
            "(lambda x 10)",
2728
            &[ExprKind::LambdaFunction(Box::new(
2729
                LambdaFunction::new_maybe_rest(
2730
                    vec![atom("x")],
2731
                    int(10),
2732
                    SyntaxObject::default(TokenType::Lambda),
2733
                    true,
2734
                ),
2735
            ))],
2736
        )
2737
    }
2738

2739
    #[test]
2740
    fn test_lambda_matches_let() {
2741
        assert_parse(
2742
            "((lambda (a) (+ a 20)) 10)",
2743
            &[ExprKind::List(List::new(vec![
2744
                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2745
                    vec![atom("a")],
2746
                    ExprKind::List(List::new(vec![atom("+"), atom("a"), int(20)])),
2747
                    SyntaxObject::default(TokenType::Lambda),
2748
                ))),
2749
                int(10),
2750
            ]))],
2751
        );
2752
    }
2753

2754
    #[test]
2755
    fn test_let() {
2756
        assert_parse(
2757
            "(let ([a 10]) (+ a 20))",
2758
            &[ExprKind::List(List::new(vec![
2759
                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2760
                    vec![atom("a")],
2761
                    ExprKind::List(List::new(vec![atom("+"), atom("a"), int(20)])),
2762
                    SyntaxObject::default(TokenType::Lambda),
2763
                ))),
2764
                int(10),
2765
            ]))],
2766
        )
2767
    }
2768

2769
    #[test]
2770
    fn test_quote_with_inner_nested() {
2771
        assert_parse(
2772
            "'(#f '())",
2773
            &[ExprKind::Quote(
2774
                Quote::new(
2775
                    ExprKind::List(List::new(vec![
2776
                        ExprKind::Atom(Atom::new(SyntaxObject::default(
2777
                            TokenType::BooleanLiteral(false),
2778
                        ))),
2779
                        ExprKind::Quote(
2780
                            Quote::new(
2781
                                List::new(vec![]).into(),
2782
                                SyntaxObject::default(TokenType::Quote),
2783
                            )
2784
                            .into(),
2785
                        ),
2786
                    ])),
2787
                    SyntaxObject::default(TokenType::Quote),
2788
                )
2789
                .into(),
2790
            )],
2791
        )
2792
    }
2793

2794
    #[test]
2795
    fn test_quote_with_inner_nested_sub_expr() {
2796
        assert_parse(
2797
            "(if (null? contents)
2798
                '(#f '())
2799
                (list (car contents) (cdr contents)))",
2800
            &[ExprKind::If(Box::new(If::new(
2801
                ExprKind::List(List::new(vec![atom("null?"), atom("contents")])),
2802
                ExprKind::Quote(
2803
                    Quote::new(
2804
                        ExprKind::List(List::new(vec![
2805
                            ExprKind::Atom(Atom::new(SyntaxObject::default(
2806
                                TokenType::BooleanLiteral(false),
2807
                            ))),
2808
                            ExprKind::Quote(
2809
                                Quote::new(
2810
                                    List::new(vec![]).into(),
2811
                                    SyntaxObject::default(TokenType::Quote),
2812
                                )
2813
                                .into(),
2814
                            ),
2815
                        ])),
2816
                        SyntaxObject::default(TokenType::Quote),
2817
                    )
2818
                    .into(),
2819
                ),
2820
                ExprKind::List(List::new(vec![
2821
                    atom("list"),
2822
                    ExprKind::List(List::new(vec![atom("car"), atom("contents")])),
2823
                    ExprKind::List(List::new(vec![atom("cdr"), atom("contents")])),
2824
                ])),
2825
                SyntaxObject::default(TokenType::If),
2826
            )))],
2827
        );
2828
    }
2829

2830
    #[test]
2831
    fn test_quote_normal_with_inner_nested_sub_expr() {
2832
        assert_parse(
2833
            "(if (null? contents)
2834
                (quote (#f '()))
2835
                (list (car contents) (cdr contents)))",
2836
            &[ExprKind::If(Box::new(If::new(
2837
                ExprKind::List(List::new(vec![atom("null?"), atom("contents")])),
2838
                ExprKind::Quote(
2839
                    Quote::new(
2840
                        ExprKind::List(List::new(vec![
2841
                            ExprKind::Atom(Atom::new(SyntaxObject::default(
2842
                                TokenType::BooleanLiteral(false),
2843
                            ))),
2844
                            ExprKind::Quote(
2845
                                Quote::new(
2846
                                    List::new(vec![]).into(),
2847
                                    SyntaxObject::default(TokenType::Quote),
2848
                                )
2849
                                .into(),
2850
                            ),
2851
                        ])),
2852
                        SyntaxObject::default(TokenType::Quote),
2853
                    )
2854
                    .into(),
2855
                ),
2856
                ExprKind::List(List::new(vec![
2857
                    atom("list"),
2858
                    ExprKind::List(List::new(vec![atom("car"), atom("contents")])),
2859
                    ExprKind::List(List::new(vec![atom("cdr"), atom("contents")])),
2860
                ])),
2861
                SyntaxObject::default(TokenType::If),
2862
            )))],
2863
        );
2864
    }
2865

2866
    #[test]
2867
    fn test_quote_with_inner_sub_expr_even_more_nested() {
2868
        assert_parse(
2869
            "(list
2870
                (if (null? contents)
2871
                '(#f '())
2872
                (list (car contents) (cdr contents))))",
2873
            &[ExprKind::List(List::new(vec![
2874
                atom("list"),
2875
                ExprKind::If(Box::new(If::new(
2876
                    ExprKind::List(List::new(vec![atom("null?"), atom("contents")])),
2877
                    ExprKind::Quote(
2878
                        Quote::new(
2879
                            ExprKind::List(List::new(vec![
2880
                                ExprKind::Atom(Atom::new(SyntaxObject::default(
2881
                                    TokenType::BooleanLiteral(false),
2882
                                ))),
2883
                                ExprKind::Quote(
2884
                                    Quote::new(
2885
                                        List::new(vec![]).into(),
2886
                                        SyntaxObject::default(TokenType::Quote),
2887
                                    )
2888
                                    .into(),
2889
                                ),
2890
                            ])),
2891
                            SyntaxObject::default(TokenType::Quote),
2892
                        )
2893
                        .into(),
2894
                    ),
2895
                    ExprKind::List(List::new(vec![
2896
                        atom("list"),
2897
                        ExprKind::List(List::new(vec![atom("car"), atom("contents")])),
2898
                        ExprKind::List(List::new(vec![atom("cdr"), atom("contents")])),
2899
                    ])),
2900
                    SyntaxObject::default(TokenType::If),
2901
                ))),
2902
            ]))],
2903
        );
2904
    }
2905

2906
    #[test]
2907
    fn test_define_with_datum_syntax_name() {
2908
        assert_parse(
2909
            "(define (datum->syntax var) (car ret-value))",
2910
            &[ExprKind::Define(Box::new(Define::new(
2911
                ExprKind::List(List::new(vec![atom("datum->syntax"), atom("var")])),
2912
                ExprKind::List(List::new(vec![atom("car"), atom("ret-value")])),
2913
                SyntaxObject::default(TokenType::Define),
2914
            )))],
2915
        )
2916
    }
2917

2918
    #[test]
2919
    fn test_define_with_datum_syntax_function_name() {
2920
        assert_parse(
2921
            "(define ((datum->syntax var) arg) 10)",
2922
            &[ExprKind::Define(Box::new(Define::new(
2923
                ExprKind::List(List::new(vec![atom("datum->syntax"), atom("var")])),
2924
                ExprKind::LambdaFunction(Box::new(LambdaFunction::new(
2925
                    vec![atom("arg")],
2926
                    int(10),
2927
                    SyntaxObject::default(TokenType::Lambda),
2928
                ))),
2929
                SyntaxObject::default(TokenType::Define),
2930
            )))],
2931
        )
2932
    }
2933

2934
    #[test]
2935
    fn test_parse_without_lowering_ast() {
2936
        let a: Result<Vec<ExprKind>> =
2937
            Parser::new_flat("(define (quote a) 10) (require foo bar)", SourceId::none())
2938
                .map(|x| x.and_then(lower_macro_and_require_definitions))
2939
                .collect();
2940

2941
        let a = a.unwrap();
2942

2943
        println!("{:#?}", a);
2944
    }
2945

2946
    #[test]
2947
    fn test_delayed_lowering() {
2948
        let a: Result<Vec<ExprKind>> = Parser::new_flat(
2949
            r#"
2950
            ;; (define foo (quote a)) (require foo bar)
2951

2952
               ;;  (define (foo) (if 10 20 30))
2953

2954
               ;; (define (foo) (quote (define 10 20)))
2955

2956
               ;; (define foo '())
2957

2958
            (define-syntax
2959
   with-handler
2960
   (syntax-rules
2961
      ()
2962
      ((with-handler handler expr)
2963
         (reset
2964
            (call-with-exception-handler
2965
               (λ (err)
2966
                 (begin (handler err) (shift k (k void))))
2967
               (λ ()
2968
                 expr))))
2969
      ((with-handler handler expr ...)
2970
         (reset
2971
            (call-with-exception-handler
2972
               (λ (err)
2973
                 (begin (handler err) (shift k (k void))))
2974
               (λ ()
2975
                 (begin expr ...)))))))
2976

2977

2978

2979
                "#,
2980
            SourceId::none(),
2981
        )
2982
        .map(|x| x.and_then(lower_macro_and_require_definitions))
2983
        .map(|x| {
2984
            x.and_then(|mut expr| {
2985
                lower_entire_ast(&mut expr)?;
2986
                Ok(expr)
2987
            })
2988
        })
2989
        .collect();
2990

2991
        let a = a.unwrap();
2992

2993
        println!("{:#?}", a);
2994
    }
2995

2996
    #[test]
2997
    fn test_improper_list() {
2998
        let mut pair = List::new(vec![atom("x"), atom("y")]);
2999
        pair.make_improper();
3000

3001
        assert_parse("(x . y)", &[ExprKind::List(pair)]);
3002

3003
        assert_parse(
3004
            "(x . (y . ()))",
3005
            &[ExprKind::List(List::new(vec![atom("x"), atom("y")]))],
3006
        )
3007
    }
3008

3009
    #[test]
3010
    fn test_improper_list_failures() {
3011
        assert_syntax_err(
3012
            "(. a)",
3013
            "improper lists must have a car element before the dot",
3014
        );
3015
        assert_syntax_err("(a .)", "improper list must have a single cdr");
3016
        assert_syntax_err("(a . b . )", "improper lists can only have a single dot");
3017
        assert_syntax_err("(a . b . c)", "improper lists can only have a single dot");
3018
        assert_syntax_err("(a . b c)", "improper list must have a single cdr");
3019
        assert_syntax_err("(a . b (c))", "improper list must have a single cdr");
3020
    }
3021

3022
    #[test]
3023
    fn test_vectors() {
3024
        assert_parse(
3025
            "#(a b)",
3026
            &[ExprKind::Vector(Vector {
3027
                args: vec![atom("a"), atom("b")],
3028
                bytes: false,
3029
                span: Span::default(),
3030
            })],
3031
        );
3032

3033
        assert_parse(
3034
            "#u8(1 3)",
3035
            &[ExprKind::Vector(Vector {
3036
                args: vec![int(1), int(3)],
3037
                bytes: true,
3038
                span: Span::default(),
3039
            })],
3040
        );
3041
    }
3042

3043
    #[test]
3044
    fn test_malformed_vectors() {
3045
        assert_syntax_err(
3046
            "#u8(#\\a)",
3047
            "bytevector literals can only contain integer literals in the 0-255 range",
3048
        );
3049

3050
        assert_syntax_err(
3051
            "#u8(())",
3052
            "bytevector literals can only contain integer literals in the 0-255 range",
3053
        );
3054

3055
        assert_syntax_err("#u8(1 . 2)", "bytevector literals cannot contain dots");
3056

3057
        assert_syntax_err("#(1 . 2)", "vector literals cannot contain dots");
3058
    }
3059

3060
    #[test]
3061
    fn test_datum_comments() {
3062
        assert_parse("#; 1 2", &[int(2)]);
3063

3064
        assert_parse("#; #; #false (2) 3", &[int(3)]);
3065

3066
        assert_parse("#; ,@foo 4", &[int(4)]);
3067

3068
        assert_parse(
3069
            "(1 #; #(a b c) 2)",
3070
            &[ExprKind::List(List::new(vec![int(1), int(2)]))],
3071
        )
3072
    }
3073

3074
    #[test]
3075
    fn test_invalid_datum_comments() {
3076
        assert_syntax_err("( 1 #; )", "invalid datum comment");
3077

3078
        assert_syntax_err(
3079
            "( 1 2 #; . b)",
3080
            "commented-out datum cannot start with a dot",
3081
        );
3082
    }
3083
}
3084

3085
use std::cell::RefCell;
3086
use std::default::Default;
3087
use std::ops::{Deref, DerefMut};
3088

3089
pub trait Recyclable {
3090
    fn put(self);
3091
    fn get() -> Self;
3092
    fn get_with_capacity(capacity: usize) -> Self;
3093
}
3094

3095
pub struct Recycle<T: Recyclable + Default> {
3096
    t: T,
3097
}
3098

3099
impl<T: Recyclable + Default> Default for Recycle<T> {
NEW
3100
    fn default() -> Self {
×
NEW
3101
        Self::new()
×
3102
    }
3103
}
3104

3105
impl<T: Recyclable + Default> Recycle<T> {
3106
    pub fn new() -> Self {
×
3107
        Recycle { t: T::get() }
×
3108
    }
3109

3110
    pub fn new_with_capacity(capacity: usize) -> Self {
×
3111
        Recycle {
3112
            t: T::get_with_capacity(capacity),
×
3113
        }
3114
    }
3115
}
3116

3117
impl<T: Recyclable + Default> Drop for Recycle<T> {
3118
    fn drop(&mut self) {
×
3119
        T::put(std::mem::take(&mut self.t))
×
3120
    }
3121
}
3122

3123
impl<T: Recyclable + Default> Deref for Recycle<T> {
3124
    type Target = T;
3125

3126
    fn deref(&self) -> &T {
×
3127
        &self.t
×
3128
    }
3129
}
3130

3131
impl<T: Recyclable + Default + 'static> DerefMut for Recycle<T> {
3132
    fn deref_mut(&mut self) -> &mut T {
×
3133
        &mut self.t
×
3134
    }
3135
}
3136

3137
impl<T: Recyclable + Clone + Default> Clone for Recycle<T> {
3138
    fn clone(&self) -> Self {
×
3139
        Recycle { t: self.t.clone() }
×
3140
    }
3141
}
3142

3143
impl<T: Recyclable + std::fmt::Debug + Default> std::fmt::Debug for Recycle<T> {
3144
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
×
3145
        f.debug_struct("Recycle").field("t", &self.t).finish()
×
3146
    }
3147
}
3148

3149
impl<T: Recyclable + std::hash::Hash + Default> std::hash::Hash for Recycle<T> {
3150
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
×
3151
        self.t.hash(state);
×
3152
    }
3153
}
3154

3155
macro_rules! impl_recyclable {
3156
    ($tl:ident, $t:ty) => {
3157
        impl_recyclable!($tl, $t, Default::default(), Self::with_capacity);
3158
    };
3159
    ($tl:ident, $t:ty, $constructor:expr, $constructor_capacity:expr) => {
3160
        thread_local! {
3161
            static $tl: RefCell<Vec<$t>> = RefCell::new(Vec::new())
3162
        }
3163

3164
        impl Recyclable for $t {
3165
            fn put(mut self) {
×
3166
                let _ = $tl.try_with(|p| {
×
3167
                    let p = p.try_borrow_mut();
×
3168

3169
                    if let Ok(mut p) = p {
×
3170
                        // This _should_ be cleared, but it seems it is not!
3171
                        // debug_assert!(self.is_empty());
3172
                        // self.clear();
3173

3174
                        // for frame in &self {
3175
                        //     for expr in &frame.exprs {
3176
                        //         println!("dropping: {}", expr);
3177
                        //     }
3178
                        // }
3179

3180
                        // dbg!(&self);
3181
                        self.clear();
×
3182

3183
                        p.push(self);
×
3184
                    }
3185
                });
3186
            }
3187

3188
            fn get() -> Self {
×
3189
                $tl.with(|p| {
×
3190
                    let mut p = p.borrow_mut();
×
3191
                    p.pop()
×
3192
                })
3193
                .unwrap_or($constructor)
×
3194
            }
3195

3196
            fn get_with_capacity(capacity: usize) -> Self {
×
3197
                $tl.with(|p| {
×
3198
                    let mut p = p.borrow_mut();
×
3199
                    p.pop()
×
3200
                })
3201
                .unwrap_or(($constructor_capacity)(capacity))
×
3202
            }
3203
        }
3204
    };
3205
}
3206

3207
impl_recyclable!(TL_V_STEELVAL, Vec<Frame>);
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc