Data parsing, tests
This commit is contained in:
parent
6d9a95ef2d
commit
c4690c6e00
|
@ -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())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in New Issue