diff --git a/crates/flat-rs/src/decode/decoder.rs b/crates/flat-rs/src/decode/decoder.rs index 7b2a966b..0c1cfca9 100644 --- a/crates/flat-rs/src/decode/decoder.rs +++ b/crates/flat-rs/src/decode/decoder.rs @@ -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, F>(&mut self, decoder_func: F) -> Result, Error> + pub fn decode_list_with(&mut self, decoder_func: F) -> Result, Error> where F: Copy + FnOnce(&mut Decoder) -> Result, { diff --git a/crates/flat-rs/src/encode/encoder.rs b/crates/flat-rs/src/encode/encoder.rs index 67044f0b..127d1bae 100644 --- a/crates/flat-rs/src/encode/encoder.rs +++ b/crates/flat-rs/src/encode/encoder.rs @@ -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)?; diff --git a/crates/uplc/src/ast.rs b/crates/uplc/src/ast.rs index df29c098..a4647ab5 100644 --- a/crates/uplc/src/ast.rs +++ b/crates/uplc/src/ast.rs @@ -196,6 +196,14 @@ pub enum Term { Error, // tag: 7 Builtin(DefaultFunction), + Constr { + tag: usize, + fields: Vec>, + }, + Case { + constr: Rc>, + branches: Vec>, + }, } impl Term { diff --git a/crates/uplc/src/debruijn.rs b/crates/uplc/src/debruijn.rs index d0f94584..8e6d69a9 100644 --- a/crates/uplc/src/debruijn.rs +++ b/crates/uplc/src/debruijn.rs @@ -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::>()?, + }, + 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::>()?, + }, }; 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::>()?, + }, + 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::>()?, + }, }; 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::>()?, + }, + 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::>()?, + }, }; 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::>()?, + }, + 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::>()?, + }, }; 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(), + }, } } diff --git a/crates/uplc/src/flat.rs b/crates/uplc/src/flat.rs index 159ecdac..3809eee4 100644 --- a/crates/uplc/src/flat.rs +++ b/crates/uplc/src/flat.rs @@ -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::::decode(d))?; + + Ok(Term::Constr { + tag: usize::decode(d)?, + fields, + }) + } + 9 => { + let constr = Term::::decode(d)?; + + let branches = d.decode_list_with(|d| Term::::decode(d))?; + + Ok(Term::Case { + constr: Rc::new(constr), + branches, + }) + } x => { let buffer_slice: Vec = d .buffer diff --git a/crates/uplc/src/machine.rs b/crates/uplc/src/machine.rs index 26e40477..287fe656 100644 --- a/crates/uplc/src/machine.rs +++ b/crates/uplc/src/machine.rs @@ -147,6 +147,8 @@ impl Machine { Value::Builtin { fun, runtime }, )) } + Term::Constr { .. } => todo!(), + Term::Case { .. } => todo!(), } } diff --git a/crates/uplc/src/parser.rs b/crates/uplc/src/parser.rs index 5b33b6b2..4a70c1e2 100644 --- a/crates/uplc/src/parser.rs +++ b/crates/uplc/src/parser.rs @@ -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 @@ -94,6 +94,8 @@ peg::parser! { / delay() / force() / error() + / constr() + / case() rule constant() -> Term = "(" _* "con" _+ con:( @@ -142,6 +144,17 @@ peg::parser! { rule error() -> Term = "(" _* "error" _* ")" { Term::Error } + rule constr() -> Term + = "(" _* "constr" _+ tag:decimal() _+ fields:(t:term() _* { t })+ ")" { + Term::Constr { tag, fields } + } + + #[cache_left_rec] + rule case() -> Term + = "(" _* "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, diff --git a/crates/uplc/src/parser/interner.rs b/crates/uplc/src/parser/interner.rs index b6c67cbe..561464ba 100644 --- a/crates/uplc/src/parser/interner.rs +++ b/crates/uplc/src/parser/interner.rs @@ -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); + } + } } } diff --git a/crates/uplc/src/pretty.rs b/crates/uplc/src/pretty.rs index 93cadf09..9fde6b7d 100644 --- a/crates/uplc/src/pretty.rs +++ b/crates/uplc/src/pretty.rs @@ -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() }