feat(uplc): add Case and Const terms

- parsering
- interning
- flat encoding and decoding
- pretty printing
- debruijn conversion

Co-authored-by: Lucas Rosa <x@rvcas.dev>
This commit is contained in:
microproofs 2023-08-01 22:33:25 -04:00 committed by Kasey
parent dfe433ea46
commit e566c4e1de
9 changed files with 213 additions and 8 deletions

View File

@ -171,7 +171,7 @@ impl<'b> Decoder<'b> {
/// Otherwise we decode an item in the list with the decoder function passed in.
/// Then decode the next bit in the buffer and repeat above.
/// Returns a list of items decoded with the decoder function.
pub fn decode_list_with<T: Decode<'b>, F>(&mut self, decoder_func: F) -> Result<Vec<T>, Error>
pub fn decode_list_with<T, F>(&mut self, decoder_func: F) -> Result<Vec<T>, Error>
where
F: Copy + FnOnce(&mut Decoder) -> Result<T, Error>,
{

View File

@ -196,10 +196,7 @@ impl Encoder {
&mut self,
list: &[T],
encoder_func: for<'r> fn(&T, &'r mut Encoder) -> Result<(), Error>,
) -> Result<&mut Self, Error>
where
T: Encode,
{
) -> Result<&mut Self, Error> {
for item in list {
self.one();
encoder_func(item, self)?;

View File

@ -196,6 +196,14 @@ pub enum Term<T> {
Error,
// tag: 7
Builtin(DefaultFunction),
Constr {
tag: usize,
fields: Vec<Term<T>>,
},
Case {
constr: Rc<Term<T>>,
branches: Vec<Term<T>>,
},
}
impl<T> Term<T> {

View File

@ -79,6 +79,20 @@ impl Converter {
Term::Force(term) => Term::Force(Rc::new(self.name_to_named_debruijn(term)?)),
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.name_to_named_debruijn(field))
.collect::<Result<_, _>>()?,
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.name_to_named_debruijn(constr)?),
branches: branches
.iter()
.map(|branch| self.name_to_named_debruijn(branch))
.collect::<Result<_, _>>()?,
},
};
Ok(converted_term)
@ -117,6 +131,20 @@ impl Converter {
Term::Force(term) => Term::Force(Rc::new(self.name_to_debruijn(term)?)),
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.name_to_debruijn(field))
.collect::<Result<_, _>>()?,
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.name_to_debruijn(constr)?),
branches: branches
.iter()
.map(|branch| self.name_to_debruijn(branch))
.collect::<Result<_, _>>()?,
},
};
Ok(converted_term)
@ -167,6 +195,20 @@ impl Converter {
Term::Force(term) => Term::Force(Rc::new(self.named_debruijn_to_name(term)?)),
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.named_debruijn_to_name(field))
.collect::<Result<_, _>>()?,
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.named_debruijn_to_name(constr)?),
branches: branches
.iter()
.map(|branch| self.named_debruijn_to_name(branch))
.collect::<Result<_, _>>()?,
},
};
Ok(converted_term)
@ -218,6 +260,20 @@ impl Converter {
Term::Force(term) => Term::Force(Rc::new(self.debruijn_to_name(term)?)),
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.debruijn_to_name(field))
.collect::<Result<_, _>>()?,
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.debruijn_to_name(constr)?),
branches: branches
.iter()
.map(|branch| self.debruijn_to_name(branch))
.collect::<Result<_, _>>()?,
},
};
Ok(converted_term)
@ -243,6 +299,20 @@ impl Converter {
Term::Force(term) => Term::Force(Rc::new(self.named_debruijn_to_debruijn(term))),
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.named_debruijn_to_debruijn(field))
.collect(),
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.named_debruijn_to_debruijn(constr)),
branches: branches
.iter()
.map(|branch| self.named_debruijn_to_debruijn(branch))
.collect(),
},
}
}
@ -272,6 +342,20 @@ impl Converter {
Term::Force(term) => Term::Force(Rc::new(self.debruijn_to_named_debruijn(term))),
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.debruijn_to_named_debruijn(field))
.collect(),
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.debruijn_to_named_debruijn(constr)),
branches: branches
.iter()
.map(|branch| self.debruijn_to_named_debruijn(branch))
.collect(),
},
}
}
@ -302,6 +386,20 @@ impl Converter {
}
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.fake_named_debruijn_to_named_debruijn(field))
.collect(),
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.fake_named_debruijn_to_named_debruijn(constr)),
branches: branches
.iter()
.map(|branch| self.fake_named_debruijn_to_named_debruijn(branch))
.collect(),
},
}
}
@ -332,6 +430,20 @@ impl Converter {
}
Term::Error => Term::Error,
Term::Builtin(builtin) => Term::Builtin(*builtin),
Term::Constr { tag, fields } => Term::Constr {
tag: *tag,
fields: fields
.iter()
.map(|field| self.named_debruijn_to_fake_named_debruijn(field))
.collect(),
},
Term::Case { constr, branches } => Term::Case {
constr: Rc::new(self.named_debruijn_to_fake_named_debruijn(constr)),
branches: branches
.iter()
.map(|branch| self.named_debruijn_to_fake_named_debruijn(branch))
.collect(),
},
}
}

View File

@ -165,6 +165,20 @@ where
builtin.encode(e)?;
}
Term::Constr { tag, fields } => {
encode_term_tag(8, e)?;
tag.encode(e)?;
e.encode_list_with(fields, |term, e| (*term).encode(e))?;
}
Term::Case { constr, branches } => {
encode_term_tag(9, e)?;
constr.encode(e)?;
e.encode_list_with(branches, |term, e| (*term).encode(e))?;
}
}
Ok(())
@ -192,6 +206,24 @@ where
5 => Ok(Term::Force(Rc::new(Term::decode(d)?))),
6 => Ok(Term::Error),
7 => Ok(Term::Builtin(DefaultFunction::decode(d)?)),
8 => {
let fields = d.decode_list_with(|d| Term::<T>::decode(d))?;
Ok(Term::Constr {
tag: usize::decode(d)?,
fields,
})
}
9 => {
let constr = Term::<T>::decode(d)?;
let branches = d.decode_list_with(|d| Term::<T>::decode(d))?;
Ok(Term::Case {
constr: Rc::new(constr),
branches,
})
}
x => {
let buffer_slice: Vec<u8> = d
.buffer

View File

@ -147,6 +147,8 @@ impl Machine {
Value::Builtin { fun, runtime },
))
}
Term::Constr { .. } => todo!(),
Term::Case { .. } => todo!(),
}
}

View File

@ -81,8 +81,8 @@ peg::parser! {
rule comma() = _* "," _*
rule version() -> (usize, usize, usize)
= major:number() "." minor:number() "." patch:number() {
(major as usize, minor as usize, patch as usize)
= major:decimal() "." minor:decimal() "." patch:decimal() {
(major, minor, patch)
}
pub rule term() -> Term<Name>
@ -94,6 +94,8 @@ peg::parser! {
/ delay()
/ force()
/ error()
/ constr()
/ case()
rule constant() -> Term<Name>
= "(" _* "con" _+ con:(
@ -142,6 +144,17 @@ peg::parser! {
rule error() -> Term<Name>
= "(" _* "error" _* ")" { Term::Error }
rule constr() -> Term<Name>
= "(" _* "constr" _+ tag:decimal() _+ fields:(t:term() _* { t })+ ")" {
Term::Constr { tag, fields }
}
#[cache_left_rec]
rule case() -> Term<Name>
= "(" _* "case" _+ constr:term() _* branches:(t:term() _* { t })+ ")" {
Term::Case { constr: constr.into(), branches }
}
rule constant_integer() -> Constant
= "integer" _+ i:big_number() { Constant::Integer(i) }
@ -173,6 +186,9 @@ peg::parser! {
rule pair(type_info: Option<(&Type, &Type)>) -> (Constant, Constant)
= "(" _* x:typed_constant(type_info.map(|t| t.0)) comma() y:typed_constant(type_info.map(|t| t.1)) _* ")" { (x, y) }
rule decimal() -> usize
= n:$(['0'..='9']+) {? n.parse().or(Err("usize")) }
rule number() -> isize
= n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) }
@ -199,7 +215,7 @@ peg::parser! {
/ expected!("or any valid ascii character")
rule data() -> PlutusData
= _* "Constr" _+ t:number() _+ fs:plutus_list() {?
= _* "Constr" _+ t:decimal() _+ fs:plutus_list() {?
Ok(PlutusData::Constr(pallas_primitives::babbage::Constr {
tag: u64::try_from(t).or(Err("tag"))?,
any_constructor: None,

View File

@ -48,6 +48,18 @@ impl Interner {
Term::Force(term) => self.term(Rc::make_mut(term)),
Term::Error => (),
Term::Builtin(_) => (),
Term::Constr { fields, .. } => {
for field in fields {
self.term(field);
}
}
Term::Case { constr, branches } => {
self.term(Rc::make_mut(constr));
for branch in branches {
self.term(branch);
}
}
}
}

View File

@ -145,6 +145,32 @@ where
)
.append(RcDoc::line_())
.append(RcDoc::text(")")),
Term::Constr { tag, fields } => RcDoc::text("(")
.append(
RcDoc::text("constr")
.append(RcDoc::line())
.append(RcDoc::as_string(tag))
.nest(2),
)
.append(RcDoc::line_())
.append(RcDoc::intersperse(
fields.iter().map(|f| f.to_doc()),
RcDoc::line_(),
))
.append(RcDoc::text(")")),
Term::Case { constr, branches } => RcDoc::text("(")
.append(
RcDoc::text("case")
.append(RcDoc::line())
.append(constr.to_doc())
.nest(2),
)
.append(RcDoc::line_())
.append(RcDoc::intersperse(
branches.iter().map(|f| f.to_doc()),
RcDoc::line_(),
))
.append(RcDoc::text(")")),
}
.group()
}