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