Skip to main content

sim/macros/
runtime.rs

1use std::sync::Arc;
2
3use sim_kernel::{
4    CORE_MACRO_CLASS_ID, ClassRef, Cx, Expr, Factory, Object, Result, Symbol, TableRef, Value,
5};
6use sim_shape::{Bindings, Shape};
7
8use crate::macros::{LispMacro, MacroCx, NativeMacroImpl};
9
10const CORE_MACRO_CLASS: &str = "Macro";
11
12/// Macro implemented by a native Rust expansion function.
13#[derive(Clone)]
14pub struct NativeExprMacro {
15    symbol: Symbol,
16    syntax_shape: Arc<dyn Shape>,
17    implementation: NativeMacroImpl,
18}
19
20impl NativeExprMacro {
21    /// Creates a native macro from its symbol, syntax shape, and expansion
22    /// function.
23    pub fn new(
24        symbol: Symbol,
25        syntax_shape: Arc<dyn Shape>,
26        implementation: NativeMacroImpl,
27    ) -> Self {
28        Self {
29            symbol,
30            syntax_shape,
31            implementation,
32        }
33    }
34}
35
36impl LispMacro for NativeExprMacro {
37    fn symbol(&self) -> Symbol {
38        self.symbol.clone()
39    }
40
41    fn syntax_shape(&self) -> Arc<dyn Shape> {
42        self.syntax_shape.clone()
43    }
44
45    fn expand(&self, cx: &mut MacroCx<'_>, input: Expr, captures: Bindings) -> Result<Expr> {
46        (self.implementation)(cx, input, captures)
47    }
48}
49
50/// Macro defined in source by a template expression instantiated from captures.
51#[derive(Clone)]
52pub struct SourceTemplateMacro {
53    symbol: Symbol,
54    syntax_shape: Arc<dyn Shape>,
55    template: Expr,
56}
57
58impl SourceTemplateMacro {
59    /// Creates a template macro from its symbol, syntax shape, and template.
60    pub fn new(symbol: Symbol, syntax_shape: Arc<dyn Shape>, template: Expr) -> Self {
61        Self {
62            symbol,
63            syntax_shape,
64            template,
65        }
66    }
67}
68
69impl LispMacro for SourceTemplateMacro {
70    fn symbol(&self) -> Symbol {
71        self.symbol.clone()
72    }
73
74    fn syntax_shape(&self) -> Arc<dyn Shape> {
75        self.syntax_shape.clone()
76    }
77
78    fn expand(&self, _cx: &mut MacroCx<'_>, _input: Expr, captures: Bindings) -> Result<Expr> {
79        super::template::instantiate_macro_template(&self.template, &captures)
80    }
81}
82
83/// Runtime object wrapping a macro and whether its parser output is trusted.
84#[derive(Clone)]
85pub struct MacroObject {
86    inner: Arc<dyn LispMacro>,
87    parser_trusted: bool,
88}
89
90impl MacroObject {
91    /// Wraps a macro with its parser-trust flag.
92    pub fn new(inner: Arc<dyn LispMacro>, parser_trusted: bool) -> Self {
93        Self {
94            inner,
95            parser_trusted,
96        }
97    }
98
99    /// Borrows the wrapped macro.
100    pub fn macro_ref(&self) -> &dyn LispMacro {
101        self.inner.as_ref()
102    }
103
104    /// Returns the wrapped macro's syntax shape.
105    pub fn syntax_shape(&self) -> Arc<dyn Shape> {
106        self.inner.syntax_shape()
107    }
108
109    /// Returns whether the macro's parser output is trusted.
110    pub fn parser_trusted(&self) -> bool {
111        self.parser_trusted
112    }
113}
114
115impl Object for MacroObject {
116    fn display(&self, _cx: &mut Cx) -> Result<String> {
117        Ok(format!("#<macro {}>", self.inner.symbol()))
118    }
119
120    fn as_any(&self) -> &dyn std::any::Any {
121        self
122    }
123}
124
125impl sim_kernel::ObjectCompat for MacroObject {
126    fn class(&self, cx: &mut Cx) -> Result<ClassRef> {
127        if let Some(value) = cx
128            .registry()
129            .class_by_symbol(&Symbol::qualified("core", CORE_MACRO_CLASS))
130        {
131            return Ok(value.clone());
132        }
133        cx.factory().class_stub(
134            CORE_MACRO_CLASS_ID,
135            Symbol::qualified("core", CORE_MACRO_CLASS),
136        )
137    }
138    fn as_expr(&self, _cx: &mut Cx) -> Result<Expr> {
139        Ok(Expr::Symbol(self.inner.symbol()))
140    }
141    fn as_table(&self, cx: &mut Cx) -> Result<TableRef> {
142        let shape = self.inner.syntax_shape();
143        let doc = shape.describe(cx)?;
144        let mut entries = vec![
145            (
146                Symbol::new("symbol"),
147                cx.factory().string(self.inner.symbol().to_string())?,
148            ),
149            (Symbol::new("syntax-shape"), cx.factory().string(doc.name)?),
150            (
151                Symbol::new("parser-trusted"),
152                cx.factory().bool(self.parser_trusted)?,
153            ),
154        ];
155        for (index, detail) in doc.details.into_iter().enumerate() {
156            entries.push((
157                Symbol::qualified("syntax-detail", index.to_string()),
158                cx.factory().string(detail)?,
159            ));
160        }
161        cx.factory().table(entries)
162    }
163}
164
165/// Boxes a macro into a value, trusting its parser output.
166pub fn macro_value(mac: Arc<dyn LispMacro>) -> Value {
167    macro_value_with_parser_trust(mac, true)
168}
169
170/// Boxes a macro into a value with an explicit parser-trust flag.
171pub fn macro_value_with_parser_trust(mac: Arc<dyn LispMacro>, parser_trusted: bool) -> Value {
172    sim_kernel::DefaultFactory
173        .opaque(Arc::new(MacroObject::new(mac, parser_trusted)))
174        .expect("macro object should always be boxable")
175}