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