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#[derive(Clone)]
14pub struct NativeExprMacro {
15 symbol: Symbol,
16 syntax_shape: Arc<dyn Shape>,
17 implementation: NativeMacroImpl,
18}
19
20impl NativeExprMacro {
21 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#[derive(Clone)]
52pub struct SourceTemplateMacro {
53 symbol: Symbol,
54 syntax_shape: Arc<dyn Shape>,
55 template: Expr,
56}
57
58impl SourceTemplateMacro {
59 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#[derive(Clone)]
85pub struct MacroObject {
86 inner: Arc<dyn LispMacro>,
87 parser_trusted: bool,
88}
89
90impl MacroObject {
91 pub fn new(inner: Arc<dyn LispMacro>, parser_trusted: bool) -> Self {
93 Self {
94 inner,
95 parser_trusted,
96 }
97 }
98
99 pub fn macro_ref(&self) -> &dyn LispMacro {
101 self.inner.as_ref()
102 }
103
104 pub fn syntax_shape(&self) -> Arc<dyn Shape> {
106 self.inner.syntax_shape()
107 }
108
109 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
165pub fn macro_value(mac: Arc<dyn LispMacro>) -> Value {
167 macro_value_with_parser_trust(mac, true)
168}
169
170pub 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}