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
168impl TryFrom<Expr> for Term {
169 type Error = Error;
170
171 fn try_from(expr: Expr) -> Result<Self> {
172 Self::lower(expr)
173 }
174}
175
176impl From<Term> for Expr {
177 fn from(term: Term) -> Self {
178 match term {
179 Term::Literal(datum) => Self::from(datum),
180 Term::Ref(reference) => ref_to_expr(reference),
181 Term::Local(symbol) => Self::Local(symbol),
182 Term::Let { name, value, body } => Self::Extension {
183 tag: core_symbol("term-let"),
184 payload: Box::new(Self::Map(vec![
185 (Self::Symbol(Symbol::new("name")), Self::Symbol(name)),
186 (Self::Symbol(Symbol::new("value")), Self::from(*value)),
187 (Self::Symbol(Symbol::new("body")), Self::from(*body)),
188 ])),
189 },
190 Term::Op { op, input } => Self::Extension {
191 tag: core_symbol("term-op"),
192 payload: Box::new(Self::Map(vec![
193 (
194 Self::Symbol(Symbol::new("op")),
195 Self::from(op_key_datum(op)),
196 ),
197 (Self::Symbol(Symbol::new("input")), Self::from(*input)),
198 ])),
199 },
200 Term::Call { target, args } => Self::Call {
201 operator: Box::new(Self::from(*target)),
202 args: args.into_iter().map(Self::from).collect(),
203 },
204 Term::Seq(items) => Self::Block(items.into_iter().map(Self::from).collect()),
205 Term::Quote { mode, datum } => Self::Quote {
206 mode,
207 expr: Box::new(Self::from(datum)),
208 },
209 Term::Annotated { term, annotations } => Self::Annotated {
210 expr: Box::new(Self::from(*term)),
211 annotations: annotations
212 .into_iter()
213 .map(|(name, datum)| (name, Self::from(datum)))
214 .collect(),
215 },
216 Term::Extension { tag, payload } => Self::Extension {
217 tag,
218 payload: Box::new(Self::from(payload)),
219 },
220 }
221 }
222}
223
224fn lower_terms(exprs: Vec<Expr>) -> Result<Vec<Term>> {
225 exprs.into_iter().map(Term::lower).collect()
226}
227
228fn data_literal(expr: Expr) -> Result<Term> {
229 Datum::try_from(expr).map(Term::Literal)
230}
231
232fn ref_to_expr(reference: Ref) -> Expr {
233 match reference {
234 Ref::Symbol(symbol) => Expr::Symbol(symbol),
235 other => Expr::from(ref_datum(other)),
236 }
237}
238
239fn ref_datum(reference: Ref) -> Datum {
240 match reference {
241 Ref::Symbol(symbol) => Datum::Node {
242 tag: core_symbol("ref"),
243 fields: vec![
244 (Symbol::new("kind"), Datum::Symbol(core_symbol("symbol"))),
245 (Symbol::new("symbol"), Datum::Symbol(symbol)),
246 ],
247 },
248 Ref::Content(content) => Datum::Node {
249 tag: core_symbol("ref"),
250 fields: vec![
251 (Symbol::new("kind"), Datum::Symbol(core_symbol("content"))),
252 (Symbol::new("content"), content_id_datum(content)),
253 ],
254 },
255 Ref::Handle(handle) => Datum::Node {
256 tag: core_symbol("ref"),
257 fields: vec![
258 (Symbol::new("kind"), Datum::Symbol(core_symbol("handle"))),
259 (Symbol::new("id"), handle_id_datum(handle)),
260 ],
261 },
262 Ref::Coord(coordinate) => coordinate_datum(coordinate),
263 }
264}
265
266fn coordinate_datum(coordinate: Coordinate) -> Datum {
267 Datum::Node {
268 tag: core_symbol("ref"),
269 fields: vec![
270 (Symbol::new("kind"), Datum::Symbol(core_symbol("coord"))),
271 (Symbol::new("space"), Datum::Symbol(coordinate.space)),
272 (Symbol::new("ordinal"), content_id_datum(coordinate.ordinal)),
273 ],
274 }
275}
276
277fn content_id_datum(content: ContentId) -> Datum {
278 Datum::Node {
279 tag: core_symbol("content-id"),
280 fields: vec![
281 (Symbol::new("algorithm"), Datum::Symbol(content.algorithm)),
282 (Symbol::new("bytes"), Datum::Bytes(content.bytes.to_vec())),
283 ],
284 }
285}
286
287fn handle_id_datum(handle: HandleId) -> Datum {
288 Datum::Bytes(handle.0.to_be_bytes().to_vec())
289}
290
291fn op_key_datum(op: OpKey) -> Datum {
292 Datum::Node {
293 tag: core_symbol("op-key"),
294 fields: vec![
295 (Symbol::new("namespace"), Datum::Symbol(op.namespace)),
296 (Symbol::new("name"), Datum::Symbol(op.name)),
297 (
298 Symbol::new("version"),
299 Datum::Number(NumberLiteral {
300 domain: core_symbol("u16"),
301 canonical: op.version.to_string(),
302 }),
303 ),
304 ],
305 }
306}
307
308fn core_symbol(name: &str) -> Symbol {
309 Symbol::qualified("core", name)
310}