1use crate::{
7 datum::Datum,
8 error::{Error, Result},
9 expr::{Expr, NumberLiteral, QuoteMode},
10 id::Symbol,
11 ref_id::{ContentId, Coordinate, HandleId, Ref},
12};
13
14#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct OpKey {
21 pub namespace: Symbol,
23 pub name: Symbol,
25 pub version: u16,
27}
28
29impl OpKey {
30 pub fn new(namespace: Symbol, name: Symbol, version: u16) -> Self {
32 Self {
33 namespace,
34 name,
35 version,
36 }
37 }
38}
39
40#[derive(Clone, Debug, PartialEq, Eq, Hash)]
55pub enum Term {
56 Literal(Datum),
58 Ref(Ref),
60 Local(Symbol),
62 Let {
64 name: Symbol,
66 value: Box<Term>,
68 body: Box<Term>,
70 },
71 Op {
73 op: OpKey,
75 input: Box<Term>,
77 },
78 Call {
80 target: Box<Term>,
82 args: Vec<Term>,
84 },
85 Seq(Vec<Term>),
87 Quote {
89 mode: QuoteMode,
91 datum: Datum,
93 },
94 Annotated {
96 term: Box<Term>,
98 annotations: Vec<(Symbol, Datum)>,
100 },
101 Extension {
103 tag: Symbol,
105 payload: Datum,
107 },
108}
109
110impl Term {
111 pub fn lower(expr: Expr) -> Result<Self> {
117 match expr {
118 Expr::Nil => Ok(Self::Literal(Datum::Nil)),
119 Expr::Bool(value) => Ok(Self::Literal(Datum::Bool(value))),
120 Expr::Number(value) => Ok(Self::Literal(Datum::Number(value))),
121 Expr::Symbol(symbol) => Ok(Self::Ref(Ref::Symbol(symbol))),
122 Expr::Local(symbol) => Ok(Self::Local(symbol)),
123 Expr::String(value) => Ok(Self::Literal(Datum::String(value))),
124 Expr::Bytes(value) => Ok(Self::Literal(Datum::Bytes(value))),
125 Expr::List(items) => data_literal(Expr::List(items)),
126 Expr::Vector(items) => data_literal(Expr::Vector(items)),
127 Expr::Map(entries) => data_literal(Expr::Map(entries)),
128 Expr::Set(items) => data_literal(Expr::Set(items)),
129 Expr::Call { operator, args } => Ok(Self::Call {
130 target: Box::new(Self::lower(*operator)?),
131 args: lower_terms(args)?,
132 }),
133 Expr::Infix {
134 operator,
135 left,
136 right,
137 } => Ok(Self::Call {
138 target: Box::new(Self::Ref(Ref::Symbol(operator))),
139 args: vec![Self::lower(*left)?, Self::lower(*right)?],
140 }),
141 Expr::Prefix { operator, arg } | Expr::Postfix { operator, arg } => Ok(Self::Call {
142 target: Box::new(Self::Ref(Ref::Symbol(operator))),
143 args: vec![Self::lower(*arg)?],
144 }),
145 Expr::Block(items) => Ok(Self::Seq(lower_terms(items)?)),
146 Expr::Quote { mode, expr } => Ok(Self::Quote {
147 mode,
148 datum: Datum::try_from(*expr)?,
149 }),
150 Expr::Annotated { expr, annotations } => {
151 let annotations = annotations
152 .into_iter()
153 .map(|(name, expr)| Ok((name, Datum::try_from(expr)?)))
154 .collect::<Result<Vec<_>>>()?;
155 Ok(Self::Annotated {
156 term: Box::new(Self::lower(*expr)?),
157 annotations,
158 })
159 }
160 Expr::Extension { tag, payload } => Ok(Self::Extension {
161 tag,
162 payload: Datum::try_from(*payload)?,
163 }),
164 }
165 }
166
167 pub fn to_datum(&self) -> Datum {
169 term_datum(self)
170 }
171}
172
173impl TryFrom<Expr> for Term {
174 type Error = Error;
175
176 fn try_from(expr: Expr) -> Result<Self> {
177 Self::lower(expr)
178 }
179}
180
181impl From<Term> for Datum {
182 fn from(term: Term) -> Self {
183 term.to_datum()
184 }
185}
186
187impl From<Term> for Expr {
188 fn from(term: Term) -> Self {
189 match term {
190 Term::Literal(datum) => Self::from(datum),
191 Term::Ref(reference) => ref_to_expr(reference),
192 Term::Local(symbol) => Self::Local(symbol),
193 Term::Let { name, value, body } => Self::Extension {
194 tag: core_symbol("term-let"),
195 payload: Box::new(Self::Map(vec![
196 (Self::Symbol(Symbol::new("name")), Self::Symbol(name)),
197 (Self::Symbol(Symbol::new("value")), Self::from(*value)),
198 (Self::Symbol(Symbol::new("body")), Self::from(*body)),
199 ])),
200 },
201 Term::Op { op, input } => Self::Extension {
202 tag: core_symbol("term-op"),
203 payload: Box::new(Self::Map(vec![
204 (
205 Self::Symbol(Symbol::new("op")),
206 Self::from(op_key_datum(op)),
207 ),
208 (Self::Symbol(Symbol::new("input")), Self::from(*input)),
209 ])),
210 },
211 Term::Call { target, args } => Self::Call {
212 operator: Box::new(Self::from(*target)),
213 args: args.into_iter().map(Self::from).collect(),
214 },
215 Term::Seq(items) => Self::Block(items.into_iter().map(Self::from).collect()),
216 Term::Quote { mode, datum } => Self::Quote {
217 mode,
218 expr: Box::new(Self::from(datum)),
219 },
220 Term::Annotated { term, annotations } => Self::Annotated {
221 expr: Box::new(Self::from(*term)),
222 annotations: annotations
223 .into_iter()
224 .map(|(name, datum)| (name, Self::from(datum)))
225 .collect(),
226 },
227 Term::Extension { tag, payload } => Self::Extension {
228 tag,
229 payload: Box::new(Self::from(payload)),
230 },
231 }
232 }
233}
234
235fn lower_terms(exprs: Vec<Expr>) -> Result<Vec<Term>> {
236 exprs.into_iter().map(Term::lower).collect()
237}
238
239fn data_literal(expr: Expr) -> Result<Term> {
240 Datum::try_from(expr).map(Term::Literal)
241}
242
243fn term_datum(term: &Term) -> Datum {
244 match term {
245 Term::Literal(datum) => term_node("literal", vec![(Symbol::new("datum"), datum.clone())]),
246 Term::Ref(reference) => term_node(
247 "ref",
248 vec![(Symbol::new("ref"), ref_datum(reference.clone()))],
249 ),
250 Term::Local(symbol) => term_node(
251 "local",
252 vec![(Symbol::new("symbol"), Datum::Symbol(symbol.clone()))],
253 ),
254 Term::Let { name, value, body } => term_node(
255 "let",
256 vec![
257 (Symbol::new("name"), Datum::Symbol(name.clone())),
258 (Symbol::new("value"), term_datum(value)),
259 (Symbol::new("body"), term_datum(body)),
260 ],
261 ),
262 Term::Op { op, input } => term_node(
263 "op",
264 vec![
265 (Symbol::new("op"), op_key_datum(op.clone())),
266 (Symbol::new("input"), term_datum(input)),
267 ],
268 ),
269 Term::Call { target, args } => term_node(
270 "call",
271 vec![
272 (Symbol::new("target"), term_datum(target)),
273 (Symbol::new("args"), terms_datum(args)),
274 ],
275 ),
276 Term::Seq(items) => term_node("seq", vec![(Symbol::new("items"), terms_datum(items))]),
277 Term::Quote { mode, datum } => term_node(
278 "quote",
279 vec![
280 (Symbol::new("mode"), Datum::Symbol(quote_mode_symbol(*mode))),
281 (Symbol::new("datum"), datum.clone()),
282 ],
283 ),
284 Term::Annotated { term, annotations } => term_node(
285 "annotated",
286 vec![
287 (Symbol::new("term"), term_datum(term)),
288 (
289 Symbol::new("annotations"),
290 Datum::Vector(
291 annotations
292 .iter()
293 .map(|(name, datum)| Datum::Node {
294 tag: core_symbol("term-annotation"),
295 fields: vec![
296 (Symbol::new("name"), Datum::Symbol(name.clone())),
297 (Symbol::new("datum"), datum.clone()),
298 ],
299 })
300 .collect(),
301 ),
302 ),
303 ],
304 ),
305 Term::Extension { tag, payload } => term_node(
306 "extension",
307 vec![
308 (Symbol::new("tag"), Datum::Symbol(tag.clone())),
309 (Symbol::new("payload"), payload.clone()),
310 ],
311 ),
312 }
313}
314
315fn term_node(kind: &str, fields: Vec<(Symbol, Datum)>) -> Datum {
316 let mut node_fields = vec![(Symbol::new("kind"), Datum::Symbol(core_symbol(kind)))];
317 node_fields.extend(fields);
318 Datum::Node {
319 tag: core_symbol("term"),
320 fields: node_fields,
321 }
322}
323
324fn terms_datum(terms: &[Term]) -> Datum {
325 Datum::Vector(terms.iter().map(term_datum).collect())
326}
327
328fn quote_mode_symbol(mode: QuoteMode) -> Symbol {
329 core_symbol(match mode {
330 QuoteMode::Quote => "quote",
331 QuoteMode::QuasiQuote => "quasiquote",
332 QuoteMode::Unquote => "unquote",
333 QuoteMode::Splice => "splice",
334 QuoteMode::Syntax => "syntax",
335 })
336}
337
338fn ref_to_expr(reference: Ref) -> Expr {
339 match reference {
340 Ref::Symbol(symbol) => Expr::Symbol(symbol),
341 other => Expr::from(ref_datum(other)),
342 }
343}
344
345fn ref_datum(reference: Ref) -> Datum {
346 match reference {
347 Ref::Symbol(symbol) => Datum::Node {
348 tag: core_symbol("ref"),
349 fields: vec![
350 (Symbol::new("kind"), Datum::Symbol(core_symbol("symbol"))),
351 (Symbol::new("symbol"), Datum::Symbol(symbol)),
352 ],
353 },
354 Ref::Content(content) => Datum::Node {
355 tag: core_symbol("ref"),
356 fields: vec![
357 (Symbol::new("kind"), Datum::Symbol(core_symbol("content"))),
358 (Symbol::new("content"), content_id_datum(content)),
359 ],
360 },
361 Ref::Handle(handle) => Datum::Node {
362 tag: core_symbol("ref"),
363 fields: vec![
364 (Symbol::new("kind"), Datum::Symbol(core_symbol("handle"))),
365 (Symbol::new("id"), handle_id_datum(handle)),
366 ],
367 },
368 Ref::Coord(coordinate) => coordinate_datum(coordinate),
369 }
370}
371
372fn coordinate_datum(coordinate: Coordinate) -> Datum {
373 Datum::Node {
374 tag: core_symbol("ref"),
375 fields: vec![
376 (Symbol::new("kind"), Datum::Symbol(core_symbol("coord"))),
377 (Symbol::new("space"), Datum::Symbol(coordinate.space)),
378 (Symbol::new("ordinal"), content_id_datum(coordinate.ordinal)),
379 ],
380 }
381}
382
383fn content_id_datum(content: ContentId) -> Datum {
384 Datum::Node {
385 tag: core_symbol("content-id"),
386 fields: vec![
387 (Symbol::new("algorithm"), Datum::Symbol(content.algorithm)),
388 (Symbol::new("bytes"), Datum::Bytes(content.bytes.to_vec())),
389 ],
390 }
391}
392
393fn handle_id_datum(handle: HandleId) -> Datum {
394 Datum::Bytes(handle.0.to_be_bytes().to_vec())
395}
396
397fn op_key_datum(op: OpKey) -> Datum {
398 Datum::Node {
399 tag: core_symbol("op-key"),
400 fields: vec![
401 (Symbol::new("namespace"), Datum::Symbol(op.namespace)),
402 (Symbol::new("name"), Datum::Symbol(op.name)),
403 (
404 Symbol::new("version"),
405 Datum::Number(NumberLiteral {
406 domain: core_symbol("u16"),
407 canonical: op.version.to_string(),
408 }),
409 ),
410 ],
411 }
412}
413
414fn core_symbol(name: &str) -> Symbol {
415 Symbol::qualified("core", name)
416}