Skip to main content

scheme_rs/syntax/
mod.rs

1//! Rust representation of S-expressions.
2
3use crate::{
4    ast::Primitive,
5    env::{Binding, Environment, Scope, add_binding, resolve},
6    exceptions::{CompoundCondition, Exception, Message, SyntaxViolation, Who},
7    gc::{Gc, Trace},
8    ports::Port,
9    proc::{ContBarrier, Procedure},
10    records::{RecordTypeDescriptor, SchemeCompatible, rtd},
11    registry::bridge,
12    symbols::Symbol,
13    syntax::parse::ParseSyntaxError,
14    value::{Expect1, UnpackedValue, Value},
15};
16use scheme_rs_macros::{maybe_async, maybe_await};
17use std::{
18    collections::BTreeSet,
19    fmt,
20    hash::Hash,
21    io::Cursor,
22    sync::{Arc, LazyLock},
23};
24
25#[cfg(feature = "async")]
26use futures::future::BoxFuture;
27
28pub mod lex;
29pub mod parse;
30
31/// Source location for an s-expression.
32#[derive(Debug, Clone, PartialEq, Eq, Hash, Trace)]
33pub struct Span {
34    pub line: u32,
35    pub column: usize,
36    pub offset: usize,
37    pub file: Arc<str>,
38}
39
40impl Span {
41    pub fn new(file: &str) -> Self {
42        Self {
43            file: Arc::from(file.to_string()),
44            ..Default::default()
45        }
46    }
47}
48
49impl fmt::Display for Span {
50    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51        write!(f, "{}:{}:{}", self.file, self.line, self.column)
52    }
53}
54
55impl Default for Span {
56    fn default() -> Self {
57        static UNKNOWN: LazyLock<Arc<str>> = LazyLock::new(|| Arc::from("<unknown>".to_string()));
58        Self {
59            line: 1,
60            column: 0,
61            offset: 0,
62            file: UNKNOWN.clone(),
63        }
64    }
65}
66
67impl SchemeCompatible for Span {
68    fn rtd() -> Arc<RecordTypeDescriptor> {
69        rtd!(name: "span", sealed: true, opaque: true)
70    }
71}
72
73/// Representation of a Scheme syntax object, or s-expression.
74#[derive(Clone, Trace)]
75#[repr(align(16))]
76pub enum Syntax {
77    /// A wrapped value.
78    Wrapped {
79        value: Value,
80        span: Span,
81    },
82    /// A nested grouping of pairs. If the expression is a proper list, then the
83    /// last element of expression will be Null. This vector is guaranteed to contain
84    /// at least two elements.
85    List {
86        list: Vec<Syntax>,
87        span: Span,
88    },
89    Vector {
90        vector: Vec<Syntax>,
91        span: Span,
92    },
93    Identifier {
94        ident: Identifier,
95        span: Span,
96    },
97}
98
99impl Syntax {
100    pub(crate) fn adjust_scope(&mut self, scope: Scope, op: fn(&mut Identifier, Scope)) {
101        match self {
102            Self::List { list, .. } => {
103                for item in list {
104                    item.adjust_scope(scope, op);
105                }
106            }
107            Self::Vector { vector, .. } => {
108                for item in vector {
109                    item.adjust_scope(scope, op);
110                }
111            }
112            Self::Identifier { ident, .. } => op(ident, scope),
113            _ => (),
114        }
115    }
116
117    pub fn add_scope(&mut self, scope: Scope) {
118        self.adjust_scope(scope, Identifier::add_scope)
119    }
120
121    pub fn flip_scope(&mut self, scope: Scope) {
122        self.adjust_scope(scope, Identifier::flip_scope)
123    }
124
125    pub fn remove_scope(&mut self, scope: Scope) {
126        self.adjust_scope(scope, Identifier::remove_scope)
127    }
128
129    pub fn wrap(value: Value, span: &Span) -> Syntax {
130        match value.unpack() {
131            UnpackedValue::Pair(pair) => {
132                let (car, cdr) = pair.into();
133                let car = Self::wrap(car, span);
134                let cdr = Self::wrap(cdr, span);
135                match cdr {
136                    Syntax::List { mut list, span } => {
137                        list.insert(0, car);
138                        Syntax::List { list, span }
139                    }
140                    _ => Syntax::List {
141                        list: vec![car, cdr],
142                        span: span.clone(),
143                    },
144                }
145            }
146            UnpackedValue::Vector(vec) => Syntax::Vector {
147                vector: vec.iter().map(|value| Syntax::wrap(value, span)).collect(),
148                span: span.clone(),
149            },
150            UnpackedValue::Syntax(syn) => syn.as_ref().clone(),
151            value => Syntax::Wrapped {
152                value: value.into_value(),
153                span: Span::default(),
154            },
155        }
156    }
157
158    pub fn unwrap(self) -> Value {
159        match self {
160            Self::Wrapped { value, .. } => value,
161            Self::List { mut list, .. } => {
162                let mut cdr = Self::unwrap(list.pop().unwrap());
163                for car in list.into_iter().map(Self::unwrap).rev() {
164                    cdr = Value::from((car, cdr));
165                }
166                cdr
167            }
168            Self::Vector { vector, .. } => {
169                Value::from(vector.into_iter().map(Syntax::unwrap).collect::<Vec<_>>())
170            }
171            _ => Value::from(self),
172        }
173    }
174
175    pub fn datum_to_syntax(scopes: &BTreeSet<Scope>, value: Value, span: &Span) -> Syntax {
176        match value.unpack() {
177            UnpackedValue::Pair(pair) => {
178                let (car, cdr) = pair.into();
179                let car = Self::datum_to_syntax(scopes, car, span);
180                let cdr = Self::datum_to_syntax(scopes, cdr, span);
181                match cdr {
182                    Syntax::List { mut list, span } => {
183                        list.insert(0, car);
184                        Syntax::List { list, span }
185                    }
186                    _ => Syntax::List {
187                        list: vec![car, cdr],
188                        span: span.clone(),
189                    },
190                }
191            }
192            UnpackedValue::Vector(vec) => Syntax::Vector {
193                vector: vec
194                    .iter()
195                    .map(|value| Syntax::datum_to_syntax(scopes, value, span))
196                    .collect(),
197                span: Span::default(),
198            },
199            UnpackedValue::Syntax(syn) => {
200                let mut syn = syn.as_ref().clone();
201                for scope in scopes {
202                    syn.add_scope(*scope);
203                }
204                syn
205            }
206            UnpackedValue::Symbol(sym) => Syntax::Identifier {
207                ident: Identifier {
208                    sym,
209                    scopes: scopes.clone(),
210                },
211                span: Span::default(),
212            },
213            value => Syntax::Wrapped {
214                value: value.into_value(),
215                span: span.clone(),
216            },
217        }
218    }
219
220    pub fn syntax_to_datum(value: Value) -> Value {
221        match value.unpack() {
222            UnpackedValue::Pair(pair) => {
223                let (car, cdr) = pair.into();
224                Value::from((Self::syntax_to_datum(car), Self::syntax_to_datum(cdr)))
225            }
226            UnpackedValue::Vector(vec) => {
227                Value::from(vec.iter().map(Self::syntax_to_datum).collect::<Vec<_>>())
228            }
229            UnpackedValue::Syntax(syn) => match syn.as_ref() {
230                Syntax::Identifier { ident, .. } => Value::from(ident.sym),
231                Syntax::Wrapped { value, .. } => value.clone(),
232                syn => Syntax::syntax_to_datum(Self::unwrap(syn.clone())),
233            },
234            unpacked => unpacked.into_value(),
235        }
236    }
237
238    #[maybe_async]
239    fn apply_transformer(&self, transformer: &Procedure) -> Result<Expansion, Exception> {
240        // Create a new scope for the expansion
241        let intro_scope = Scope::new();
242
243        // Apply the new scope to the input
244        let mut input = self.clone();
245        input.add_scope(intro_scope);
246
247        // Call the transformer with the input:
248        let transformer_output =
249            maybe_await!(transformer.call(&[Value::from(input)], &mut ContBarrier::new()))?;
250
251        let output: Value = transformer_output.expect1()?;
252        let mut output = Syntax::wrap(output, self.span());
253        output.flip_scope(intro_scope);
254
255        Ok(Expansion::Expanded(output))
256    }
257
258    #[cfg(not(feature = "async"))]
259    fn expand_once(&self, env: &Environment) -> Result<Expansion, Exception> {
260        self.expand_once_inner(env)
261    }
262
263    #[cfg(feature = "async")]
264    fn expand_once<'a>(
265        &'a self,
266        env: &'a Environment,
267    ) -> BoxFuture<'a, Result<Expansion, Exception>> {
268        Box::pin(self.expand_once_inner(env))
269    }
270
271    #[maybe_async]
272    fn expand_once_inner(&self, env: &Environment) -> Result<Expansion, Exception> {
273        match self {
274            Self::List { list, .. } => {
275                let ident = match list.first() {
276                    Some(Self::Identifier { ident, .. }) => ident,
277                    _ => return Ok(Expansion::Unexpanded),
278                };
279                if let Some(binding) = ident.resolve() {
280                    if let Some(transformer) = maybe_await!(env.lookup_keyword(binding))? {
281                        return maybe_await!(self.apply_transformer(&transformer));
282                    } else if let Some(Primitive::Set) = env.lookup_primitive(binding)
283                        && let [Syntax::Identifier { ident, .. }, ..] = &list.as_slice()[1..]
284                    {
285                        // Check for set! macro
286                        // Look for a variable transformer
287                        if let Some(binding) = ident.resolve()
288                            && let Some(transformer) = maybe_await!(env.lookup_keyword(binding))?
289                        {
290                            if !transformer.is_variable_transformer() {
291                                return Err(Exception::error(format!(
292                                    "{} is not a variable transformer",
293                                    ident.sym
294                                )));
295                            }
296                            return maybe_await!(self.apply_transformer(&transformer));
297                        }
298                    }
299                }
300            }
301            Self::Identifier { ident, .. } => {
302                if let Some(binding) = ident.resolve()
303                    && let Some(transformer) = maybe_await!(env.lookup_keyword(binding))?
304                {
305                    return maybe_await!(self.apply_transformer(&transformer));
306                }
307            }
308            _ => (),
309        }
310        Ok(Expansion::Unexpanded)
311    }
312
313    /// Fully expand the outermost syntax object.
314    #[maybe_async]
315    pub(crate) fn expand(mut self, env: &Environment) -> Result<Syntax, Exception> {
316        loop {
317            match maybe_await!(self.expand_once(env)) {
318                Ok(Expansion::Unexpanded) => {
319                    return Ok(self);
320                }
321                Ok(Expansion::Expanded(syntax)) => {
322                    self = syntax;
323                }
324                Err(condition) => {
325                    return Err(condition.add_condition(SyntaxViolation::new(self, None)));
326                }
327            }
328        }
329    }
330
331    #[cfg(not(feature = "async"))]
332    pub fn from_str(s: &str, file_name: Option<&str>) -> Result<Self, ParseSyntaxError> {
333        use crate::ports::{BufferMode, Transcoder};
334
335        let file_name = file_name.unwrap_or("<unknown>");
336        let bytes = Cursor::new(s.as_bytes().to_vec());
337        let port = Port::new(
338            file_name,
339            bytes,
340            BufferMode::Block,
341            Some(Transcoder::native()),
342        );
343        port.all_sexprs(Span::new(file_name))
344    }
345
346    #[cfg(feature = "async")]
347    pub fn from_str(s: &str, file_name: Option<&str>) -> Result<Self, ParseSyntaxError> {
348        use crate::ports::{BufferMode, Transcoder};
349
350        let file_name = file_name.unwrap_or("<unknown>");
351        let bytes = Cursor::new(s.as_bytes().to_vec());
352
353        // This is kind of convoluted, but convenient
354        let port = Arc::into_inner(
355            Port::new(
356                file_name,
357                bytes,
358                BufferMode::Block,
359                Some(Transcoder::native()),
360            )
361            .0,
362        )
363        .unwrap();
364        let info = port.info;
365        let mut data = port.data.into_inner();
366
367        // This is safe since we don't need the async executor to drive anything
368        // here
369        futures::executor::block_on(async move {
370            use crate::syntax::parse::Parser;
371
372            let mut parser = Parser::new(&mut data, &info, Span::new(file_name));
373            parser.all_sexprs().await
374        })
375    }
376
377    /// Returns true if the syntax item is a list with a car that is an
378    /// identifier equal to the passed argument.
379    pub(crate) fn has_car(&self, car: &str) -> bool {
380        matches!(self.as_list(), Some([Self::Identifier { ident, .. }, .. ]) if ident == car)
381    }
382
383    pub fn span(&self) -> &Span {
384        match self {
385            Self::Wrapped { span, .. } => span,
386            Self::List { span, .. } => span,
387            Self::Vector { span, .. } => span,
388            Self::Identifier { span, .. } => span,
389        }
390    }
391
392    pub fn as_ident(&self) -> Option<&Identifier> {
393        if let Syntax::Identifier { ident, .. } = self {
394            Some(ident)
395        } else {
396            None
397        }
398    }
399
400    pub fn new_list(list: Vec<Syntax>, span: impl Into<Span>) -> Self {
401        Self::List {
402            list,
403            span: span.into(),
404        }
405    }
406
407    pub fn as_list(&self) -> Option<&[Syntax]> {
408        if let Syntax::List { list, .. } = self {
409            Some(list)
410        } else {
411            None
412        }
413    }
414
415    pub fn as_list_mut(&mut self) -> Option<&mut [Syntax]> {
416        if let Syntax::List { list, .. } = self {
417            Some(list)
418        } else {
419            None
420        }
421    }
422
423    pub fn is_list(&self) -> bool {
424        matches!(self, Self::List { .. })
425    }
426
427    pub fn car(&self) -> Option<&Syntax> {
428        if let Syntax::List { list, .. } = self {
429            list.first()
430        } else {
431            None
432        }
433    }
434
435    pub fn new_vector(vector: Vec<Syntax>, span: impl Into<Span>) -> Self {
436        Self::Vector {
437            vector,
438            span: span.into(),
439        }
440    }
441
442    pub fn is_vector(&self) -> bool {
443        matches!(self, Self::Vector { .. })
444    }
445
446    pub fn new_wrapped(value: Value, span: impl Into<Span>) -> Self {
447        Self::Wrapped {
448            value,
449            span: span.into(),
450        }
451    }
452
453    pub fn new_identifier(name: &str, span: impl Into<Span>) -> Self {
454        Self::Identifier {
455            ident: Identifier::new(name),
456            span: span.into(),
457        }
458    }
459
460    pub fn is_identifier(&self) -> bool {
461        matches!(self, Self::Identifier { .. })
462    }
463
464    pub fn is_null(&self) -> bool {
465        matches!(self, Self::Wrapped { value, .. } if value.is_null())
466    }
467}
468
469impl fmt::Debug for Syntax {
470    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
471        match self {
472            Syntax::List { list, .. } => {
473                let proper_list = list.last().unwrap().is_null();
474                let len = list.len();
475                write!(f, "(")?;
476                for (i, item) in list.iter().enumerate() {
477                    if i == len - 1 {
478                        if proper_list {
479                            break;
480                        } else {
481                            write!(f, " . {item:?}")?;
482                        }
483                    } else {
484                        if i > 0 {
485                            write!(f, " ")?;
486                        }
487                        write!(f, "{item:?}")?;
488                    }
489                }
490                write!(f, ")")
491            }
492            Syntax::Wrapped { value, .. } => {
493                write!(f, "{value:?}")
494            }
495            Syntax::Vector { vector, .. } => {
496                write!(f, "#(")?;
497                for (i, item) in vector.iter().enumerate() {
498                    if i > 0 {
499                        write!(f, " ")?;
500                    }
501                    write!(f, "{item:?}")?;
502                }
503                write!(f, ")")
504            }
505            Syntax::Identifier { ident, .. } => {
506                write!(f, "{}", ident.sym)
507            }
508        }
509    }
510}
511
512pub(crate) enum Expansion {
513    /// Syntax remained unchanged after expansion
514    Unexpanded,
515    /// Syntax was expanded, producing a new expansion context
516    Expanded(Syntax),
517}
518
519#[derive(Clone, Trace, PartialEq, Eq, Hash)]
520pub struct Identifier {
521    pub(crate) sym: Symbol,
522    pub(crate) scopes: BTreeSet<Scope>,
523}
524
525impl fmt::Debug for Identifier {
526    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
527        write!(f, "{} ({:?})", self.sym, self.scopes)
528    }
529}
530
531impl Identifier {
532    pub fn new(name: &str) -> Self {
533        Self {
534            sym: Symbol::intern(name),
535            scopes: BTreeSet::new(),
536        }
537    }
538
539    pub fn symbol(&self) -> Symbol {
540        self.sym
541    }
542
543    pub fn from_symbol(sym: Symbol, scope: Scope) -> Self {
544        Self {
545            sym,
546            scopes: BTreeSet::from([scope]),
547        }
548    }
549
550    pub fn add_scope(&mut self, scope: Scope) {
551        self.scopes.insert(scope);
552    }
553
554    pub fn remove_scope(&mut self, scope: Scope) {
555        self.scopes.remove(&scope);
556    }
557
558    pub fn flip_scope(&mut self, scope: Scope) {
559        if self.scopes.contains(&scope) {
560            self.scopes.remove(&scope);
561        } else {
562            self.scopes.insert(scope);
563        }
564    }
565
566    pub fn free_identifier_equal(&self, rhs: &Self) -> bool {
567        match (self.resolve(), rhs.resolve()) {
568            (Some(lhs), Some(rhs)) => lhs == rhs,
569            (None, None) => self.sym == rhs.sym,
570            _ => false,
571        }
572    }
573
574    pub fn resolve(&self) -> Option<Binding> {
575        resolve(self)
576    }
577
578    pub(crate) fn bind(&self) -> Binding {
579        if let Some(binding) = self.resolve() {
580            binding
581        } else {
582            self.new_bind()
583        }
584    }
585
586    pub(crate) fn new_bind(&self) -> Binding {
587        let new_binding = Binding::new();
588        add_binding(self.clone(), new_binding);
589        new_binding
590    }
591}
592
593impl PartialEq<str> for Identifier {
594    fn eq(&self, rhs: &str) -> bool {
595        self.sym.to_str().as_ref() == rhs
596    }
597}
598
599#[bridge(name = "syntax->datum", lib = "(rnrs syntax-case builtins (6))")]
600pub fn syntax_to_datum(value: &Value) -> Result<Vec<Value>, Exception> {
601    // This is quite slow and could be improved
602    Ok(vec![Syntax::syntax_to_datum(value.clone())])
603}
604
605#[bridge(name = "datum->syntax", lib = "(rnrs syntax-case builtins (6))")]
606pub fn datum_to_syntax(template_id: Identifier, datum: &Value) -> Result<Vec<Value>, Exception> {
607    Ok(vec![Value::from(Syntax::datum_to_syntax(
608        &template_id.scopes,
609        datum.clone(),
610        &Span::default(),
611    ))])
612}
613
614#[bridge(name = "identifier?", lib = "(rnrs syntax-case builtins (6))")]
615pub fn identifier_pred(obj: &Value) -> Result<Vec<Value>, Exception> {
616    Ok(vec![Value::from(
617        obj.cast_to_scheme_type::<Identifier>().is_some(),
618    )])
619}
620
621#[bridge(name = "bound-identifier=?", lib = "(rnrs syntax-case builtins (6))")]
622pub fn bound_identifier_eq_pred(id1: Identifier, id2: Identifier) -> Result<Vec<Value>, Exception> {
623    Ok(vec![Value::from(id1 == id2)])
624}
625
626#[bridge(name = "free-identifier=?", lib = "(rnrs syntax-case builtins (6))")]
627pub fn free_identifier_eq_pred(id1: Identifier, id2: Identifier) -> Result<Vec<Value>, Exception> {
628    Ok(vec![Value::from(id1.free_identifier_equal(&id2))])
629}
630
631#[bridge(name = "generate-temporaries", lib = "(rnrs syntax-case builtins (6))")]
632pub fn generate_temporaries(list: &Value) -> Result<Vec<Value>, Exception> {
633    let length = if let Syntax::List { list, .. } = Syntax::wrap(list.clone(), &Span::default())
634        && list.last().unwrap().is_null()
635    {
636        list.len() - 1
637    } else {
638        return Err(Exception::error("expected proper list"));
639    };
640
641    let mut temporaries = Value::null();
642    for _ in 0..length {
643        let ident = Syntax::Identifier {
644            ident: Identifier {
645                sym: Symbol::gensym(),
646                scopes: BTreeSet::new(),
647            },
648            span: Span::default(),
649        };
650        temporaries = Value::from((Value::from(ident), temporaries));
651    }
652
653    Ok(vec![temporaries])
654}
655
656#[bridge(name = "syntax-violation", lib = "(rnrs base builtins (6))")]
657pub fn syntax_violation(
658    who: &Value,
659    message: &Value,
660    form: &Value,
661    subform: &[Value],
662) -> Result<Vec<Value>, Exception> {
663    let subform = match subform {
664        [] => None,
665        [subform] => Some(subform.clone()),
666        _ => return Err(Exception::wrong_num_of_var_args(3..4, 3 + subform.len())),
667    };
668    let mut conditions = Vec::new();
669    if who.is_true() {
670        conditions.push(Value::from_rust_type(Who::new(who.clone())));
671    } else if let Some(syntax) = form.cast_to_scheme_type::<Gc<Syntax>>() {
672        let who = if let Syntax::Identifier { ident, .. } = syntax.as_ref() {
673            Some(ident.sym)
674        } else if let Some([Syntax::Identifier { ident, .. }, ..]) = syntax.as_list() {
675            Some(ident.sym)
676        } else {
677            None
678        };
679        conditions.push(Value::from_rust_type(Who::new(Value::from(who))));
680    }
681    conditions.push(Value::from_rust_type(Message::new(message)));
682    conditions.push(Value::from_rust_type(SyntaxViolation::new_from_values(
683        form.clone(),
684        subform,
685    )));
686    Err(Exception(Value::from(Exception::from(CompoundCondition(
687        conditions,
688    )))))
689}