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! {
grammar uplc() for str {
pub rule program() -> Program<Name>
= _* "(" _* "program" _+ v:version() _+ t:term() _* ")" _* {
Program {version: v, term: t}
}
rule comma() = _* "," _*
rule version() -> (usize, usize, usize)
= major:number() "." minor:number() "." patch:number() {
(major as usize, minor as usize, patch as usize)
@ -155,7 +158,7 @@ peg::parser! {
= "unit" _+ "()" { Constant::Unit }
rule constant_data() -> Constant
= "data" _+ d:data() { Constant::Data(d) }
= "data" _+ "(" d:data() ")" { Constant::Data(d) }
rule constant_list() -> Constant
= "(" _* "list" _* t:type_info() _* ")" _+ ls:list(Some(&t)) {
@ -168,7 +171,7 @@ peg::parser! {
}
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
= n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) }
@ -196,14 +199,35 @@ peg::parser! {
/ expected!("or any valid ascii character")
rule data() -> PlutusData
= "#" i:ident()* {
PlutusData::decode_fragment(
hex::decode(String::from_iter(i)).unwrap().as_slice()
).unwrap()
}
= _* "Constr" _+ t:number() _+ fs:plutus_list() {?
Ok(PlutusData::Constr(pallas_primitives::babbage::Constr {
tag: u64::try_from(t).or(Err("tag"))?,
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>
= "[" _* xs:(typed_constant(type_info) ** (_* "," _*)) _* "]" { xs }
= "[" _* xs:(typed_constant(type_info) ** comma()) _* "]" { xs }
rule typed_constant(type_info : Option<&Type>) -> Constant
= "()" {?
@ -262,10 +286,10 @@ peg::parser! {
/ _* "bytestring" { Type::ByteString }
/ _* "string" { Type::String }
/ _* "data" { Type::Data }
/ _* "(" _* "list" _+ t:type_info() _* ")" _* {
/ _* "(" _* "list" _+ t:type_info() _* ")" {
Type::List(t.into())
}
/ _* "(" _* "pair" _+ l:type_info() _+ r:type_info() _* ")" _* {
/ _* "(" _* "pair" _+ l:type_info() _+ r:type_info() _* ")" {
Type::Pair(l.into(), r.into())
}
@ -657,7 +681,7 @@ mod tests {
#[test]
fn parse_list_empty() {
let uplc = "(program 0.0.0 (con list<unit> []))";
let uplc = "(program 0.0.0 (con (list unit) []))";
assert_eq!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -669,7 +693,7 @@ mod tests {
#[test]
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!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -681,7 +705,7 @@ mod tests {
#[test]
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!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -703,7 +727,7 @@ mod tests {
#[test]
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!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -724,7 +748,7 @@ mod tests {
#[test]
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!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -753,8 +777,7 @@ mod tests {
fn parse_list_multiline() {
let uplc = r#"
(program 0.0.0
(con list
<integer>
(con (list integer)
[ 14
, 42
]
@ -777,7 +800,7 @@ mod tests {
#[test]
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!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -797,7 +820,7 @@ mod tests {
#[test]
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!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -823,7 +846,7 @@ mod tests {
#[test]
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!(
super::program(uplc).unwrap(),
Program::<Name> {
@ -849,9 +872,8 @@ mod tests {
fn parse_pair_multiline() {
let uplc = r#"
(program 0.0.0
(con pair
<integer, integer>
[14, 42]
(con (pair integer integer)
(14, 42)
)
)"#;
assert_eq!(
@ -873,13 +895,13 @@ mod tests {
#[test]
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())
}
#[test]
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())
}

View File

@ -1,12 +1,13 @@
use num_bigint::ToBigInt;
use uplc::{
ast::{Constant, Term, Type, Name},
Constr, PlutusData, parser::term,
ast::{Constant, Name, Term, Type},
parser::term,
Constr, PlutusData,
};
// 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);
let new_term = term(pp).expect("failed to parse");
assert_eq!(new_term, old_term);