1use core::fmt;
2
3use crate::{
4 ipld_error::IpldError,
5 name::Name,
6 position::Pos,
7};
8use sp_cid::Cid;
9use sp_ipld::Ipld;
10
11use sp_std::{
12 borrow::ToOwned,
13 boxed::Box,
14};
15
16use alloc::string::ToString;
17
18#[derive(PartialEq, Clone, Debug)]
20pub enum Meta {
21 Var(Pos, Name),
22 Lam(Pos, Name, Box<Meta>),
23 App(Pos, Box<(Meta, Meta)>),
24 All(Pos, Name, Box<(Meta, Meta)>),
25 Slf(Pos, Name, Box<Meta>),
26 Dat(Pos, Box<Meta>),
27 Cse(Pos, Box<Meta>),
28 Ref(Pos, Name, Cid),
29 Let(Pos, Name, Box<(Meta, Meta, Meta)>),
30 Typ(Pos),
31 Ann(Pos, Box<(Meta, Meta)>),
32 Lit(Pos),
33 LTy(Pos),
34 Opr(Pos),
35 Rec(Pos),
36}
37
38impl Meta {
39 pub fn to_ipld(&self) -> Ipld {
41 match self {
42 Self::Var(pos, nam) => Ipld::List(vec![
43 Ipld::Integer(0),
44 pos.to_ipld(),
45 Ipld::String(nam.to_string()),
46 ]),
47 Self::Lam(pos, nam, bod) => Ipld::List(vec![
48 Ipld::Integer(1),
49 pos.to_ipld(),
50 Ipld::String(nam.to_string()),
51 bod.to_ipld(),
52 ]),
53 Self::App(pos, fun_arg) => {
54 let (fun, arg) = (*fun_arg).as_ref();
55 Ipld::List(vec![
56 Ipld::Integer(2),
57 pos.to_ipld(),
58 fun.to_ipld(),
59 arg.to_ipld(),
60 ])
61 }
62 Self::All(pos, nam, dom_img) => {
63 let (dom, img) = (*dom_img).as_ref();
64 Ipld::List(vec![
65 Ipld::Integer(3),
66 pos.to_ipld(),
67 Ipld::String(nam.to_string()),
68 dom.to_ipld(),
69 img.to_ipld(),
70 ])
71 }
72 Self::Slf(pos, nam, bod) => Ipld::List(vec![
73 Ipld::Integer(4),
74 pos.to_ipld(),
75 Ipld::String(nam.to_string()),
76 bod.to_ipld(),
77 ]),
78 Self::Dat(pos, bod) => {
79 Ipld::List(vec![Ipld::Integer(5), pos.to_ipld(), bod.to_ipld()])
80 }
81 Self::Cse(pos, bod) => {
82 Ipld::List(vec![Ipld::Integer(6), pos.to_ipld(), bod.to_ipld()])
83 }
84 Self::Ref(pos, nam, cid) => Ipld::List(vec![
85 Ipld::Integer(7),
86 pos.to_ipld(),
87 Ipld::String(nam.to_string()),
88 Ipld::Link(*cid),
89 ]),
90 Self::Let(pos, nam, typ_exp_bod) => {
91 let (typ, exp, bod) = (*typ_exp_bod).as_ref();
92 Ipld::List(vec![
93 Ipld::Integer(8),
94 pos.to_ipld(),
95 Ipld::String(nam.to_string()),
96 typ.to_ipld(),
97 exp.to_ipld(),
98 bod.to_ipld(),
99 ])
100 }
101 Self::Typ(pos) => Ipld::List(vec![Ipld::Integer(9), pos.to_ipld()]),
102 Self::Ann(pos, typ_exp) => {
103 let (typ, exp) = (*typ_exp).as_ref();
104 Ipld::List(vec![
105 Ipld::Integer(10),
106 pos.to_ipld(),
107 typ.to_ipld(),
108 exp.to_ipld(),
109 ])
110 }
111 Self::Lit(pos) => Ipld::List(vec![Ipld::Integer(11), pos.to_ipld()]),
112 Self::LTy(pos) => Ipld::List(vec![Ipld::Integer(12), pos.to_ipld()]),
113 Self::Opr(pos) => Ipld::List(vec![Ipld::Integer(13), pos.to_ipld()]),
114 Self::Rec(pos) => Ipld::List(vec![Ipld::Integer(14), pos.to_ipld()]),
115 }
116 }
117
118 pub fn from_ipld(ipld: &Ipld) -> Result<Self, IpldError> {
120 match ipld {
121 Ipld::List(xs) => match xs.as_slice() {
122 [Ipld::Integer(0), pos, Ipld::String(nam)] => {
123 let pos = Pos::from_ipld(pos)?;
124 Ok(Meta::Var(pos, Name::from(nam.clone())))
125 }
126 [Ipld::Integer(1), pos, Ipld::String(nam), bod] => {
127 let pos = Pos::from_ipld(pos)?;
128 let bod = Meta::from_ipld(bod)?;
129 Ok(Meta::Lam(pos, Name::from(nam.clone()), Box::new(bod)))
130 }
131 [Ipld::Integer(2), pos, fun, arg] => {
132 let pos = Pos::from_ipld(pos)?;
133 let fun = Meta::from_ipld(fun)?;
134 let arg = Meta::from_ipld(arg)?;
135 Ok(Meta::App(pos, Box::new((fun, arg))))
136 }
137 [Ipld::Integer(3), pos, Ipld::String(nam), dom, img] => {
138 let pos = Pos::from_ipld(pos)?;
139 let dom = Meta::from_ipld(dom)?;
140 let img = Meta::from_ipld(img)?;
141 Ok(Meta::All(pos, Name::from(nam.clone()), Box::new((dom, img))))
142 }
143 [Ipld::Integer(4), pos, Ipld::String(nam), bod] => {
144 let pos = Pos::from_ipld(pos)?;
145 let bod = Meta::from_ipld(bod)?;
146 Ok(Meta::Slf(pos, Name::from(nam.clone()), Box::new(bod)))
147 }
148 [Ipld::Integer(5), pos, bod] => {
149 let pos = Pos::from_ipld(pos)?;
150 let bod = Meta::from_ipld(bod)?;
151 Ok(Meta::Dat(pos, Box::new(bod)))
152 }
153 [Ipld::Integer(6), pos, bod] => {
154 let pos = Pos::from_ipld(pos)?;
155 let bod = Meta::from_ipld(bod)?;
156 Ok(Meta::Cse(pos, Box::new(bod)))
157 }
158 [Ipld::Integer(7), pos, Ipld::String(nam), Ipld::Link(cid)] => {
159 let pos = Pos::from_ipld(pos)?;
160 Ok(Meta::Ref(pos, Name::from(nam.clone()), *cid))
161 }
162 [Ipld::Integer(8), pos, Ipld::String(nam), typ, exp, bod] => {
163 let pos = Pos::from_ipld(pos)?;
164 let typ = Meta::from_ipld(typ)?;
165 let exp = Meta::from_ipld(exp)?;
166 let bod = Meta::from_ipld(bod)?;
167 Ok(Meta::Let(pos, Name::from(nam.clone()), Box::new((typ, exp, bod))))
168 }
169 [Ipld::Integer(9), pos] => {
170 let pos = Pos::from_ipld(pos)?;
171 Ok(Meta::Typ(pos))
172 }
173 [Ipld::Integer(10), pos, typ, exp] => {
174 let pos = Pos::from_ipld(pos)?;
175 let typ = Meta::from_ipld(typ)?;
176 let exp = Meta::from_ipld(exp)?;
177 Ok(Meta::Ann(pos, Box::new((typ, exp))))
178 }
179 [Ipld::Integer(11), pos] => {
180 let pos = Pos::from_ipld(pos)?;
181 Ok(Self::Lit(pos))
182 }
183 [Ipld::Integer(12), pos] => {
184 let pos = Pos::from_ipld(pos)?;
185 Ok(Self::LTy(pos))
186 }
187 [Ipld::Integer(13), pos] => {
188 let pos = Pos::from_ipld(pos)?;
189 Ok(Self::Opr(pos))
190 }
191 [Ipld::Integer(14), pos] => {
192 let pos = Pos::from_ipld(pos)?;
193 Ok(Self::Rec(pos))
194 }
195 xs => Err(IpldError::Meta(Ipld::List(xs.to_owned()))),
196 },
197 xs => Err(IpldError::Meta(xs.to_owned())),
198 }
199 }
200}
201
202impl fmt::Display for Meta {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 use Meta::*;
205 match self.clone() {
206 Var(_, name) => write!(f, "Var({})", name),
207 Lam(_, name, b) => write!(f, "Lam({}, {}", name, *b),
208 App(_, b) => write!(f, "App({}, {})", (*b).0, (*b).1),
209 All(_, name, b) => write!(f, "All({}, {}, {})", name, (*b).0, (*b).1),
210 Slf(_, name, b) => writeln!(f, "Slf({}, {})", name, *b),
211 Dat(_, b) => write!(f, "Dat({})", *b),
212 Cse(_, b) => write!(f, "Cse({})", *b),
213 Ref(_, name, cid) => write!(f, "Ref({}, {})", name, cid),
214 Let(_, name, b) => {
215 write!(f, "Let({}, {}, {}, {})", name, (*b).0, (*b).1, (*b).2)
216 }
217 Typ(_) => write!(f, "Typ"),
218 Ann(_, b) => write!(f, "Ann({}, {})", (*b).0, (*b).1),
219 Lit(_) => write!(f, "Lit"),
220 LTy(_) => write!(f, "LTy"),
221 Opr(_) => write!(f, "Opr"),
222 Rec(_) => write!(f, "Rec"),
223 }
224 }
225}
226
227#[cfg(test)]
228pub mod tests {
229 use super::*;
230 use quickcheck::{
231 Arbitrary,
232 Gen,
233 };
234
235 use crate::term::Term;
236
237 impl Arbitrary for Meta {
238 fn arbitrary(g: &mut Gen) -> Self {
239 let term: Term = Arbitrary::arbitrary(g);
240 let (_, meta) = term.embed();
241 meta
242 }
243 }
244
245 #[quickcheck]
246 fn meta_ipld(x: Meta) -> bool {
247 match Meta::from_ipld(&x.to_ipld()) {
248 Ok(y) => x == y,
249 _ => false,
250 }
251 }
252}