1mod compile;
2
3#[cfg(all(feature = "codec-lisp", feature = "codec-binary"))]
4use sim_kernel::Symbol;
5use sim_kernel::{Cx, Lib, LibLoader, LibSource, Result};
6
7#[cfg(not(feature = "shape"))]
8use super::reexport::ReexportLib;
9#[cfg(feature = "shape")]
10use super::reexport::SourceLib;
11
12#[cfg(feature = "codec-lisp")]
14pub struct LispSourceLoader {
15 codec: sim_kernel::Symbol,
16}
17
18#[cfg(feature = "codec-lisp")]
19impl Default for LispSourceLoader {
20 fn default() -> Self {
21 Self::new(sim_kernel::Symbol::qualified("codec", "lisp"))
22 }
23}
24
25#[cfg(feature = "codec-lisp")]
26impl LispSourceLoader {
27 pub fn new(codec: sim_kernel::Symbol) -> Self {
29 Self { codec }
30 }
31}
32
33#[cfg(feature = "codec-lisp")]
34impl LibLoader for LispSourceLoader {
35 fn can_load(&self, source: &LibSource) -> bool {
36 matches!(source, LibSource::Path(path) if path.extension().is_some_and(|ext| ext == "lisp"))
37 }
38
39 fn load(&self, cx: &mut Cx, source: LibSource) -> Result<Box<dyn Lib>> {
40 let path = match source {
41 LibSource::Path(path) => path,
42 _ => {
43 return Err(sim_kernel::Error::HostError(
44 "lisp source loader received unsupported source".to_owned(),
45 ));
46 }
47 };
48 let text = std::fs::read_to_string(&path).map_err(|err| {
49 sim_kernel::Error::HostError(format!(
50 "failed to read lisp source {}: {err}",
51 path.display()
52 ))
53 })?;
54 let expr = sim_codec::decode_with_codec(
55 cx,
56 &self.codec,
57 sim_codec::Input::Text(text),
58 sim_kernel::ReadPolicy::default(),
59 )?;
60 compile_lisp_source_lib(path, expr)
61 }
62
63 fn inspect_manifest(
64 &self,
65 cx: &mut Cx,
66 source: &LibSource,
67 ) -> Result<Option<sim_kernel::LibManifest>> {
68 let path = match source {
69 LibSource::Path(path) => path.clone(),
70 _ => return Ok(None),
71 };
72 let text = std::fs::read_to_string(&path).map_err(|err| {
73 sim_kernel::Error::HostError(format!(
74 "failed to read lisp source {}: {err}",
75 path.display()
76 ))
77 })?;
78 let expr = sim_codec::decode_with_codec(
79 cx,
80 &self.codec,
81 sim_codec::Input::Text(text),
82 sim_kernel::ReadPolicy::default(),
83 )?;
84 Ok(Some(
85 compile::compile_lisp_source_parts(path, expr)?.manifest,
86 ))
87 }
88}
89
90#[cfg(all(feature = "codec-lisp", feature = "codec-binary"))]
91pub fn compile_lisp_source_text_to_pack(
93 cx: &mut Cx,
94 codec: &sim_kernel::Symbol,
95 source_path: impl Into<std::path::PathBuf>,
96 text: impl Into<String>,
97) -> Result<super::binary_pack::BinaryLibPack> {
98 let path = source_path.into();
99 let expr = sim_codec::decode_with_codec(
100 cx,
101 codec,
102 sim_codec::Input::Text(text.into()),
103 sim_kernel::ReadPolicy::default(),
104 )?;
105 compile_lisp_source_pack(path, expr)
106}
107
108#[cfg(all(feature = "codec-lisp", feature = "codec-binary"))]
109pub fn encode_lisp_source_text_to_binary_pack(
111 cx: &mut Cx,
112 codec: &Symbol,
113 source_path: impl Into<std::path::PathBuf>,
114 text: impl Into<String>,
115) -> Result<Vec<u8>> {
116 let pack = compile_lisp_source_text_to_pack(cx, codec, source_path, text)?;
117 super::binary_pack::encode_binary_lib_pack(&pack)
118}
119
120#[cfg(all(feature = "codec-lisp", feature = "codec-binary"))]
121pub fn export_lisp_source_file_to_binary_pack(
123 cx: &mut Cx,
124 codec: &Symbol,
125 source_path: impl AsRef<std::path::Path>,
126 output_path: impl AsRef<std::path::Path>,
127) -> Result<()> {
128 let source_path = source_path.as_ref();
129 let output_path = output_path.as_ref();
130 let text = std::fs::read_to_string(source_path).map_err(|err| {
131 sim_kernel::Error::HostError(format!(
132 "failed to read lisp source {}: {err}",
133 source_path.display()
134 ))
135 })?;
136 let bytes = encode_lisp_source_text_to_binary_pack(cx, codec, source_path.to_path_buf(), text)?;
137 std::fs::write(output_path, bytes).map_err(|err| {
138 sim_kernel::Error::HostError(format!(
139 "failed to write binary lib pack {}: {err}",
140 output_path.display()
141 ))
142 })?;
143 Ok(())
144}
145
146#[cfg(all(feature = "codec-lisp", not(feature = "codec-binary")))]
147fn compile_lisp_source_lib(
148 path: std::path::PathBuf,
149 expr: sim_kernel::Expr,
150) -> Result<Box<dyn Lib>> {
151 let compiled = compile::compile_lisp_source_parts(path, expr)?;
152 #[cfg(feature = "shape")]
153 {
154 Ok(Box::new(SourceLib::new(
155 compiled.manifest,
156 compiled.exports,
157 compiled.macros,
158 )))
159 }
160 #[cfg(not(feature = "shape"))]
161 {
162 if !compiled.macros.is_empty() {
163 return Err(sim_kernel::Error::Lib(
164 "lisp-source defmacro requires the shape feature".to_owned(),
165 ));
166 }
167 Ok(Box::new(ReexportLib::new(
168 compiled.manifest,
169 compiled.exports,
170 )))
171 }
172}
173
174#[cfg(all(feature = "codec-lisp", feature = "codec-binary"))]
175fn compile_lisp_source_lib(
176 path: std::path::PathBuf,
177 expr: sim_kernel::Expr,
178) -> Result<Box<dyn Lib>> {
179 let compiled = compile::compile_lisp_source_parts(path, expr)?;
180 #[cfg(feature = "shape")]
181 {
182 Ok(Box::new(SourceLib::new(
183 compiled.manifest,
184 compiled.exports,
185 compiled.macros,
186 )))
187 }
188 #[cfg(not(feature = "shape"))]
189 {
190 if !compiled.macros.is_empty() {
191 return Err(sim_kernel::Error::Lib(
192 "lisp-source defmacro requires the shape feature".to_owned(),
193 ));
194 }
195 Ok(Box::new(ReexportLib::new(
196 compiled.manifest,
197 compiled.exports,
198 )))
199 }
200}
201
202#[cfg(all(feature = "codec-lisp", feature = "codec-binary"))]
203pub fn compile_lisp_source_pack(
205 path: std::path::PathBuf,
206 expr: sim_kernel::Expr,
207) -> Result<super::binary_pack::BinaryLibPack> {
208 let compiled = compile::compile_lisp_source_parts(path, expr)?;
209 if !compiled.macros.is_empty() {
210 return Err(sim_kernel::Error::Lib(
211 "binary lib packs cannot yet encode Lisp-authored defmacro bodies".to_owned(),
212 ));
213 }
214 Ok(super::binary_pack::BinaryLibPack {
215 manifest: compiled.manifest,
216 exports: compiled.exports,
217 })
218}