Data parsing, tests

This commit is contained in:
Pi Lanningham 2023-07-04 09:32:56 -04:00 committed by Lucas
parent 6d9a95ef2d
commit c4690c6e00
2 changed files with 51 additions and 28 deletions

View File

@ -72,11 +72,14 @@ pub fn escape(string: &str) -> String {
peg::parser! { peg::parser! {
grammar uplc() for str { grammar uplc() for str {
pub rule program() -> Program<Name> pub rule program() -> Program<Name>
= _* "(" _* "program" _+ v:version() _+ t:term() _* ")" _* { = _* "(" _* "program" _+ v:version() _+ t:term() _* ")" _* {
Program {version: v, term: t} Program {version: v, term: t}
} }
rule comma() = _* "," _*
rule version() -> (usize, usize, usize) rule version() -> (usize, usize, usize)
= major:number() "." minor:number() "." patch:number() { = major:number() "." minor:number() "." patch:number() {
(major as usize, minor as usize, patch as usize) (major as usize, minor as usize, patch as usize)
@ -155,7 +158,7 @@ peg::parser! {
= "unit" _+ "()" { Constant::Unit } = "unit" _+ "()" { Constant::Unit }
rule constant_data() -> Constant rule constant_data() -> Constant
= "data" _+ d:data() { Constant::Data(d) } = "data" _+ "(" d:data() ")" { Constant::Data(d) }
rule constant_list() -> Constant rule constant_list() -> Constant
= "(" _* "list" _* t:type_info() _* ")" _+ ls:list(Some(&t)) { = "(" _* "list" _* t:type_info() _* ")" _+ ls:list(Some(&t)) {
@ -168,7 +171,7 @@ peg::parser! {
} }
rule pair(type_info: Option<(&Type, &Type)>) -> (Constant, Constant) rule pair(type_info: Option<(&Type, &Type)>) -> (Constant, Constant)
= "(" _* x:typed_constant(type_info.map(|t| t.0)) _* "," _* y:typed_constant(type_info.map(|t| t.1)) _* ")" { (x, y) } = "(" _* x:typed_constant(type_info.map(|t| t.0)) comma() y:typed_constant(type_info.map(|t| t.1)) _* ")" { (x, y) }
rule number() -> isize rule number() -> isize
= n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) } = n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) }
@ -196,14 +199,35 @@ peg::parser! {
/ expected!("or any valid ascii character") / expected!("or any valid ascii character")
rule data() -> PlutusData rule data() -> PlutusData
= "#" i:ident()* { = _* "Constr" _+ t:number() _+ fs:plutus_list() {?
PlutusData::decode_fragment( Ok(PlutusData::Constr(pallas_primitives::babbage::Constr {
hex::decode(String::from_iter(i)).unwrap().as_slice() tag: u64::try_from(t).or(Err("tag"))?,
).unwrap() any_constructor: None,
fields: fs
}))
}
/ _* "Map" _+ kvps:plutus_key_value_pairs() {
PlutusData::Map(pallas_codec::utils::KeyValuePairs::Def(kvps))
}
/ _* "List" _+ ls:plutus_list() { PlutusData::Array(ls) }
/ _* "I" _+ n:number() {? Ok(PlutusData::BigInt(pallas_primitives::babbage::BigInt::Int(i64::try_from(n).or(Err("int"))?.into()))) }
/ _* "B" _+ "#" i:ident()* {?
Ok(PlutusData::BoundedBytes(
hex::decode(String::from_iter(i)).or(Err("bytes"))?.into()
))
} }
rule plutus_list() -> Vec<PlutusData>
= "[" _* xs:(data() ** comma()) _* "]" { xs }
rule plutus_key_value_pairs() -> Vec<(PlutusData, PlutusData)>
= "[" _* kvps:(plutus_key_value_pair() ** comma()) _* "]" { kvps }
rule plutus_key_value_pair() -> (PlutusData, PlutusData)
= "(" _* k:data() comma() v:data() _* ")" { (k, v) }
rule list(type_info: Option<&Type>) -> Vec<Constant> rule list(type_info: Option<&Type>) -> Vec<Constant>
= "[" _* xs:(typed_constant(type_info) ** (_* "," _*)) _* "]" { xs } = "[" _* xs:(typed_constant(type_info) ** comma()) _* "]" { xs }
rule typed_constant(type_info : Option<&Type>) -> Constant rule typed_constant(type_info : Option<&Type>) -> Constant
= "()" {? = "()" {?
@ -262,10 +286,10 @@ peg::parser! {
/ _* "bytestring" { Type::ByteString } / _* "bytestring" { Type::ByteString }
/ _* "string" { Type::String } / _* "string" { Type::String }
/ _* "data" { Type::Data } / _* "data" { Type::Data }
/ _* "(" _* "list" _+ t:type_info() _* ")" _* { / _* "(" _* "list" _+ t:type_info() _* ")" {
Type::List(t.into()) Type::List(t.into())
} }
/ _* "(" _* "pair" _+ l:type_info() _+ r:type_info() _* ")" _* { / _* "(" _* "pair" _+ l:type_info() _+ r:type_info() _* ")" {
Type::Pair(l.into(), r.into()) Type::Pair(l.into(), r.into())
} }
@ -657,7 +681,7 @@ mod tests {
#[test] #[test]
fn parse_list_empty() { fn parse_list_empty() {
let uplc = "(program 0.0.0 (con list<unit> []))"; let uplc = "(program 0.0.0 (con (list unit) []))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -669,7 +693,7 @@ mod tests {
#[test] #[test]
fn parse_list_singleton_unit() { fn parse_list_singleton_unit() {
let uplc = "(program 0.0.0 (con list<unit> [ () ]))"; let uplc = "(program 0.0.0 (con (list unit) [ () ]))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -681,7 +705,7 @@ mod tests {
#[test] #[test]
fn parse_list_bools() { fn parse_list_bools() {
let uplc = "(program 0.0.0 (con list<bool> [True, False, True]))"; let uplc = "(program 0.0.0 (con (list bool) [True, False, True]))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -703,7 +727,7 @@ mod tests {
#[test] #[test]
fn parse_list_bytestrings() { fn parse_list_bytestrings() {
let uplc = "(program 0.0.0 (con list<bytestring> [#00, #01]))"; let uplc = "(program 0.0.0 (con (list bytestring) [#00, #01]))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -724,7 +748,7 @@ mod tests {
#[test] #[test]
fn parse_list_list_integers() { fn parse_list_list_integers() {
let uplc = "(program 0.0.0 (con list<list<integer>> [[14,42], [1337]]))"; let uplc = "(program 0.0.0 (con (list (list integer)) [[14,42], [1337]]))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -753,8 +777,7 @@ mod tests {
fn parse_list_multiline() { fn parse_list_multiline() {
let uplc = r#" let uplc = r#"
(program 0.0.0 (program 0.0.0
(con list (con (list integer)
<integer>
[ 14 [ 14
, 42 , 42
] ]
@ -777,7 +800,7 @@ mod tests {
#[test] #[test]
fn parse_pair_unit_unit() { fn parse_pair_unit_unit() {
let uplc = "(program 0.0.0 (con pair <unit,unit> [(),()]))"; let uplc = "(program 0.0.0 (con (pair unit unit) ((),())))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -797,7 +820,7 @@ mod tests {
#[test] #[test]
fn parse_pair_bool_pair_integer_bytestring() { fn parse_pair_bool_pair_integer_bytestring() {
let uplc = "(program 0.0.0 (con pair<bool, pair<integer, bytestring>> [True, [14, #42]]))"; let uplc = "(program 0.0.0 (con (pair bool (pair integer bytestring)) (True, (14, #42))))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -823,7 +846,7 @@ mod tests {
#[test] #[test]
fn parse_pair_string_list_integer() { fn parse_pair_string_list_integer() {
let uplc = "(program 0.0.0 (con pair<string, list<integer>> [\"foo\", [14, 42]]))"; let uplc = "(program 0.0.0 (con (pair string (list integer)) (\"foo\", [14, 42])))";
assert_eq!( assert_eq!(
super::program(uplc).unwrap(), super::program(uplc).unwrap(),
Program::<Name> { Program::<Name> {
@ -849,9 +872,8 @@ mod tests {
fn parse_pair_multiline() { fn parse_pair_multiline() {
let uplc = r#" let uplc = r#"
(program 0.0.0 (program 0.0.0
(con pair (con (pair integer integer)
<integer, integer> (14, 42)
[14, 42]
) )
)"#; )"#;
assert_eq!( assert_eq!(
@ -873,13 +895,13 @@ mod tests {
#[test] #[test]
fn parse_list_type_mismatch() { fn parse_list_type_mismatch() {
let uplc = "(program 0.0.0 (con list<integer> [True, False]))"; let uplc = "(program 0.0.0 (con (list integer) [True, False]))";
assert!(super::program(uplc).is_err()) assert!(super::program(uplc).is_err())
} }
#[test] #[test]
fn parse_list_mixed_types() { fn parse_list_mixed_types() {
let uplc = "(program 0.0.0 (con list<integer> [14, False]))"; let uplc = "(program 0.0.0 (con (list integer) [14, False]))";
assert!(super::program(uplc).is_err()) assert!(super::program(uplc).is_err())
} }

View File

@ -1,12 +1,13 @@
use num_bigint::ToBigInt; use num_bigint::ToBigInt;
use uplc::{ use uplc::{
ast::{Constant, Term, Type, Name}, ast::{Constant, Name, Term, Type},
Constr, PlutusData, parser::term, parser::term,
Constr, PlutusData,
}; };
// Examples sourced from https://github.com/input-output-hk/plutus/issues/4751#issuecomment-1538377273 // Examples sourced from https://github.com/input-output-hk/plutus/issues/4751#issuecomment-1538377273
fn round_trip(old_term: Term::<Name>, pp: &str) { fn round_trip(old_term: Term<Name>, pp: &str) {
//assert_eq!(old_term.to_pretty(), pp); //assert_eq!(old_term.to_pretty(), pp);
let new_term = term(pp).expect("failed to parse"); let new_term = term(pp).expect("failed to parse");
assert_eq!(new_term, old_term); assert_eq!(new_term, old_term);