diff --git a/book/src/uplc/builtins.md b/book/src/uplc/builtins.md index 956c10fd..7528dca2 100644 --- a/book/src/uplc/builtins.md +++ b/book/src/uplc/builtins.md @@ -14,8 +14,6 @@ | `equalsInteger` | \- | (integer, integer) | bool | | `lessThanInteger` | \- | (integer, integer) | bool | | `lessThanEqualsInteger` | \- | (integer, integer) | bool | -| `greaterThanInteger` | \- | (integer, integer) | bool | -| `greaterThanEqualsInteger` | \- | (integer, integer) | bool | | --- | --- | --- | --- | | `appendString` | \- | (string, string) | string | | `emptyString` | \- | (string) | bool | @@ -24,15 +22,12 @@ | --- | --- | --- | --- | | `appendByteString` | \- | (bytestring, bytestring) | bytestring | | `consByteString` | \- | (integer, bytestring) | bytestring | -| `indexByteString` | \- | (integer, bytestring) | integer | +| `indexByteString` | \- | (bytestring, integer) | integer | | `sliceByteString` | \- | (integer, integer, bytestring) | bytestring | | `lengthOfByteString` | \- | (bytestring) | integer | -| `emptyByteString` | \- | (bytestring) | bool | | `equalsByteString` | \- | (bytestring, bytestring) | bool | | `lessThanByteString` | \- | (bytestring, bytestring) | bool | | `lessThanEqualsByteString` | \- | (bytestring, bytestring) | bool | -| `greaterThanByteString` | \- | (bytestring, bytestring) | bool | -| `greaterThanEqualsByteString` | \- | (bytestring, bytestring) | bool | | `decodeUtf8` | \- | (bytestring) | string | | --- | --- | --- | --- | | `chooseData`[^2] | \\(α\\) | (data, \\(α\\), \\(α\\), \\(α\\), \\(α\\), \\(α\\)) | \\(α\\) | diff --git a/book/src/uplc/syntax.md b/book/src/uplc/syntax.md index 5a119956..2f8827d5 100644 --- a/book/src/uplc/syntax.md +++ b/book/src/uplc/syntax.md @@ -4,22 +4,26 @@ Let's start with a little reminder about the syntax. The complete syntax for Unt ## Primitive Types -Plutus Core has 5 primitive types: `unit`, `bool`, `integer`, `string` and -`bytestring`. One can construct constants using the `con` keyword, followed by -the name of the primitive type and its value. +Plutus Core has 7 primitive types (a.k.a. constants): `unit`, `bool`, `integer`, `bytestring`, `string`, `pair` and `list`. +One can construct constants using the `con` keyword, followed by the name of the primitive type and its value. - Unit is denoted `()`; - Bool are `True` or `False`; - Bytestrings are denoted with a leading `#` followed by an hexadecimal sequence; -- Strings are UTF-8 text strings, between double quotes `"`. +- Strings are UTF-8 text strings, between double quotes `"` `"`; +- Pair and lists are encapsulated between brackets `[` and `]`. -| Primitive Type | Example | -| --- | --- | -| `unit` | `con unit ()` | -| `bool` | `con bool True` | -| `integer` | `con integer 42` | -| `bytestring` | `con bytestring #41696b656e` | -| `string` | `con string "Aiken"` | +Note that each constant is named after its type. For pairs and lists -- which are compound types --, the type of their elements is specified between chevrons `<` and `>`. + +| Primitive Type | Example | +| --- | --- | +| `unit` | `con unit ()` | +| `bool` | `con bool True` | +| `integer` | `con integer 42` | +| `bytestring` | `con bytestring #41696b656e` | +| `string` | `con string "Aiken"` | +| `pair` | `con pair [True, 42]` | +| `list` | `con list [#00, #aa]` | ## Functions diff --git a/crates/uplc/src/parser.rs b/crates/uplc/src/parser.rs index a1d55326..510ea4d9 100644 --- a/crates/uplc/src/parser.rs +++ b/crates/uplc/src/parser.rs @@ -1,7 +1,7 @@ use std::{rc::Rc, str::FromStr}; use crate::{ - ast::{Constant, Name, Program, Term}, + ast::{Constant, Name, Program, Term, Type}, builtins::DefaultFunction, }; @@ -38,6 +38,22 @@ pub fn term(src: &str) -> Result, ParseError> { Ok(term) } +// Returns the inner type of a list, provided that the given type is a list. +fn list_sub_type(type_info: Option<&Type>) -> Option<&Type> { + match type_info { + Some(Type::List(t)) => Some(t), + _ => None, + } +} + +// Returns the left and right types of a pair, provided that the given type is a pair. +fn pair_sub_type(type_info: Option<&Type>) -> Option<(&Type, &Type)> { + match type_info { + Some(Type::Pair(l, r)) => Some((l, r)), + _ => None, + } +} + peg::parser! { grammar uplc() for str { pub rule program() -> Program @@ -68,6 +84,8 @@ peg::parser! { / constant_unit() / constant_bool() / constant_data() + / constant_list() + / constant_pair() ) _* ")" { Term::Constant(con) } @@ -109,33 +127,121 @@ peg::parser! { = "integer" _+ i:big_number() { Constant::Integer(i as i128) } rule constant_bytestring() -> Constant - = "bytestring" _+ "#" i:ident()* { - Constant::ByteString(hex::decode(String::from_iter(i)).unwrap()) - } + = "bytestring" _+ bs:bytestring() { Constant::ByteString(bs) } rule constant_string() -> Constant - = "string" _+ "\"" s:[^ '"']* "\"" { Constant::String(String::from_iter(s)) } + = "string" _+ s:string() { Constant::String(s) } rule constant_bool() -> Constant - = "bool" _+ b:$("True" / "False") { Constant::Bool(b == "True") } + = "bool" _+ b:boolean() { Constant::Bool(b) } rule constant_unit() -> Constant = "unit" _+ "()" { Constant::Unit } + rule constant_data() -> Constant + = "data" _+ d:data() { Constant::Data(d) } + + rule constant_list() -> Constant + = "list" _* "<" _* t:type_info() _* ">" _+ ls:list(Some(&t)) { + Constant::ProtoList(t, ls) + } + + rule constant_pair() -> Constant + = "pair" _* "<" _* l:type_info() _* "," r:type_info() _* ">" _+ p:pair(Some((&l, &r))) { + Constant::ProtoPair(l, r, Box::new(p.0), Box::new(p.1)) + } + + 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) } + rule number() -> isize = n:$("-"* ['0'..='9']+) {? n.parse().or(Err("isize")) } rule big_number() -> i128 = n:$("-"* ['0'..='9']+) {? n.parse().or(Err("i128")) } - rule constant_data() -> Constant - = "data" _+ "#" i:ident()* { - Constant::Data( + rule boolean() -> bool + = b:$("True" / "False") { b == "True" } + + rule bytestring() -> Vec + = "#" i:ident()* { hex::decode(String::from_iter(i)).unwrap() } + + rule string() -> String + = "\"" s:[^ '"']* "\"" { String::from_iter(s) } + + rule data() -> PlutusData + = "#" i:ident()* { PlutusData::decode_fragment( hex::decode(String::from_iter(i)).unwrap().as_slice() ).unwrap() - ) - } + } + + rule list(type_info: Option<&Type>) -> Vec + = "[" _* xs:(typed_constant(type_info) ** (_* "," _*)) _* "]" { xs } + + rule typed_constant(type_info : Option<&Type>) -> Constant + = "()" {? + match type_info { + Some(Type::Unit) => Ok(Constant::Unit), + _ => Err("found 'Unit' instead of expected type") + } + } + / b:boolean() {? + match type_info { + Some(Type::Bool) => Ok(Constant::Bool(b)), + _ => Err("found 'Bool' instead of expected type") + } + } + / n:big_number() {? + match type_info { + Some(Type::Integer) => Ok(Constant::Integer(n)), + _ => Err("found 'Integer' instead of expected type") + } + } + / bs:bytestring() {? + match type_info { + Some(Type::ByteString) => Ok(Constant::ByteString(bs)), + _ => Err("found 'ByteString' instead of expected type") + } + } + / s:string() {? + match type_info { + Some(Type::String) => Ok(Constant::String(s)), + _ => Err("found 'String' instead of expected type") + } + } + / s:data() {? + match type_info { + Some(Type::Data) => Ok(Constant::Data(s)), + _ => Err("found 'Data' instead of expected type") + } + } + / ls:list(list_sub_type(type_info)) {? + match type_info { + Some(Type::List(t)) => Ok(Constant::ProtoList(*t.clone(), ls)), + _ => Err("found 'List' instead of expected type") + } + } + / p:pair(pair_sub_type(type_info)) {? + match type_info { + Some(Type::Pair(l, r)) => Ok(Constant::ProtoPair(*l.clone(), *r.clone(), Box::new(p.0), Box::new(p.1))), + _ => Err("found 'Pair' instead of expected type") + } + } + + rule type_info() -> Type + = _* "unit" { Type::Unit } + / _* "bool" { Type::Bool } + / _* "integer" { Type::Integer } + / _* "bytestring" { Type::ByteString } + / _* "string" { Type::String } + / _* "data" { Type::Data } + / _* "list" _* "<" _* t:type_info() _* ">" { + Type::List(Box::new(t)) + } + / _* "pair" _* "<" l:type_info() "," r:type_info() ">" { + Type::Pair(Box::new(l), Box::new(r)) + } rule name() -> Name = text:ident() { Name { text, unique: 0.into() } } @@ -151,23 +257,569 @@ peg::parser! { #[cfg(test)] mod test { - use crate::ast::{Constant, Name, Program, Term}; + use crate::ast::{Constant, Name, Program, Term, Type, Unique}; + use crate::builtins::DefaultFunction; + use std::rc::Rc; #[test] - fn parse_program() { - let code = r#" + fn parse_apply() { + let uplc = "(program 1.0.0 [(lam x x) (con integer 0)])"; + let x = Name { + text: "x".to_string(), + unique: Unique::new(0), + }; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Lambda { + parameter_name: x.clone(), + body: Rc::new(Term::Var(x)), + }), + argument: Rc::new(Term::Constant(Constant::Integer(0))) + } + } + ) + } + + #[test] + fn parse_lambda() { + let uplc = "(program 1.0.0 (lam x x))"; + let x = Name { + text: "x".to_string(), + unique: Unique::new(0), + }; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Lambda { + parameter_name: x.clone(), + body: Rc::new(Term::Var(x)), + } + } + ) + } + + #[test] + fn parse_delay_lambda() { + let uplc = "(program 1.0.0 (lam x (delay x)))"; + let x = Name { + text: "x".to_string(), + unique: Unique::new(0), + }; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Lambda { + parameter_name: x.clone(), + body: Rc::new(Term::Delay(Rc::new(Term::Var(x)))), + } + } + ) + } + + #[test] + fn parse_error() { + let uplc = "(program 1.0.0 (error))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Error + } + ) + } + + #[test] + fn parse_formatted() { + let uplc = r#" (program 11.22.33 (con integer 11) ) "#; - let program = super::program(code).unwrap(); - assert_eq!( - program, + super::program(uplc).unwrap(), Program:: { version: (11, 22, 33), term: Term::Constant(Constant::Integer(11)), } ); } + + #[test] + fn parse_builtin_add_integer_curried() { + parse_builtin_integer( + "(program 1.0.0 [ [ (builtin addInteger) (con integer 1)] (con integer 1) ])", + DefaultFunction::AddInteger, + 1, + 1, + ); + } + + #[test] + fn parse_builtin_add_integer() { + parse_builtin_integer( + "(program 1.0.0 [ (builtin addInteger) (con integer 1) (con integer 2) ])", + DefaultFunction::AddInteger, + 1, + 2, + ); + } + + #[test] + fn parse_builtin_subtract_integer() { + parse_builtin_integer( + "(program 1.0.0 [ (builtin subtractInteger) (con integer 42) (con integer 14) ])", + DefaultFunction::SubtractInteger, + 42, + 14, + ) + } + + #[test] + fn parse_builtin_multiply_integer() { + parse_builtin_integer( + "(program 1.0.0 [ (builtin multiplyInteger) (con integer 1) (con integer -1) ])", + DefaultFunction::MultiplyInteger, + 1, + -1, + ) + } + + #[test] + fn parse_builtin_divide_integer() { + parse_builtin_integer( + "(program 1.0.0 [ (builtin divideInteger) (con integer 1) (con integer 0) ])", + DefaultFunction::DivideInteger, + 1, + 0, + ) + } + + #[test] + fn parse_builtin_quotient_integer() { + parse_builtin_integer( + "(program 1.0.0 [ (builtin quotientInteger) (con integer 1) (con integer 0) ])", + DefaultFunction::QuotientInteger, + 1, + 0, + ) + } + + #[test] + fn parse_builtin_remainder_integer() { + parse_builtin_integer( + "(program 1.0.0 [ (builtin remainderInteger) (con integer 1) (con integer 0) ])", + DefaultFunction::RemainderInteger, + 1, + 0, + ) + } + + #[test] + fn parse_builtin_mod_integer() { + parse_builtin_integer( + "(program 1.0.0 [ [ (builtin modInteger) (con integer 2) ] (con integer 3) ])", + DefaultFunction::ModInteger, + 2, + 3, + ) + } + + #[test] + fn parse_builtin_equals_integer() { + parse_builtin_integer( + "(program 1.0.0 [ [ (builtin equalsInteger) (con integer 1) ] (con integer 2) ])", + DefaultFunction::EqualsInteger, + 1, + 2, + ) + } + + #[test] + fn parse_builtin_less_than_integer() { + parse_builtin_integer( + "(program 1.0.0 [ [ (builtin lessThanInteger) (con integer 1) ] (con integer 2) ])", + DefaultFunction::LessThanInteger, + 1, + 2, + ) + } + + #[test] + fn parse_builtin_less_than_equals_integer() { + parse_builtin_integer( + "(program 1.0.0 [ [ (builtin lessThanEqualsInteger) (con integer 1) ] (con integer 2) ])", + DefaultFunction::LessThanEqualsInteger, + 1, + 2, + ) + } + + #[test] + fn parse_builtin_append_bytestring() { + let uplc = "(program 1.0.0 [ [(builtin appendByteString) (con bytestring #00FF)] (con bytestring #FF00) ])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::AppendByteString)), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00, 0xFF]))), + }), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0xFF, 0x00]))) + } + } + ) + } + + #[test] + fn parse_builtin_cons_bytestring() { + let uplc = + "(program 1.0.0 [(builtin consByteString) (con integer 256) (con bytestring #)])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::ConsByteString)), + argument: Rc::new(Term::Constant(Constant::Integer(256))), + }), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![]))) + } + } + ) + } + + #[test] + fn parse_builtin_slice_bytestring() { + let uplc = "(program 0.0.0 [ [ [ (builtin sliceByteString) (con integer 1)] (con integer 2) ] (con bytestring #00ffaa) ])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::SliceByteString)), + argument: Rc::new(Term::Constant(Constant::Integer(1))), + }), + argument: Rc::new(Term::Constant(Constant::Integer(2))), + }), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00, 0xFF, 0xAA]))) + } + } + ) + } + + #[test] + fn parse_builtin_length_of_bytestring() { + let uplc = "(program 0.0.0 [ (builtin lengthOfByteString) (con bytestring #00ffaa) ])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::LengthOfByteString)), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00, 0xFF, 0xAA]))) + }, + } + ) + } + + #[test] + fn parse_builtin_index_bytestring() { + let uplc = "(program 1.0.0 [(builtin indexByteString) (con bytestring #00) (con integer 9223372036854775808)])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::IndexByteString)), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00]))) + }), + argument: Rc::new(Term::Constant(Constant::Integer(9223372036854775808))), + } + } + ) + } + + #[test] + fn parse_builtin_equals_bytestring() { + let uplc = "(program 0.0.0 [ [ (builtin equalsByteString) (con bytestring #00ffaa) ] (con bytestring #00ffaa) ])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::EqualsByteString)), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![ + 0x00, 0xff, 0xaa + ]))) + }), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00, 0xff, 0xaa]))), + } + } + ) + } + + #[test] + fn parse_builtin_less_than_bytestring() { + let uplc = "(program 0.0.0 [ [(builtin lessThanByteString) (con bytestring #00ff)] (con bytestring #00ffaa) ])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::LessThanByteString)), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00, 0xff]))) + }), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00, 0xff, 0xaa]))), + } + } + ) + } + + #[test] + fn parse_builtin_less_than_equals_bytestring() { + let uplc = "(program 0.0.0 [ [(builtin lessThanEqualsByteString) (con bytestring #00ff)] (con bytestring #00) ])"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(DefaultFunction::LessThanEqualsByteString)), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00, 0xff]))) + }), + argument: Rc::new(Term::Constant(Constant::ByteString(vec![0x00]))), + } + } + ) + } + + #[test] + fn parse_list_empty() { + let uplc = "(program 0.0.0 (con list []))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoList(Type::Unit, vec![])) + } + ) + } + + #[test] + fn parse_list_singleton_unit() { + let uplc = "(program 0.0.0 (con list [ () ]))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoList(Type::Unit, vec![Constant::Unit])) + } + ) + } + + #[test] + fn parse_list_bools() { + let uplc = "(program 0.0.0 (con list [True, False, True]))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoList( + Type::Bool, + vec![ + Constant::Bool(true), + Constant::Bool(false), + Constant::Bool(true) + ] + )) + } + ) + } + + #[test] + fn parse_list_bytestrings() { + let uplc = "(program 0.0.0 (con list [#00, #01]))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoList( + Type::ByteString, + vec![ + Constant::ByteString(vec![0x00]), + Constant::ByteString(vec![0x01]), + ] + )) + } + ) + } + + #[test] + fn parse_list_list_integers() { + let uplc = "(program 0.0.0 (con list> [[14,42], [1337]]))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoList( + Type::List(Box::new(Type::Integer)), + vec![ + Constant::ProtoList( + Type::Integer, + vec![Constant::Integer(14), Constant::Integer(42)] + ), + Constant::ProtoList(Type::Integer, vec![Constant::Integer(1337)]) + ] + )) + } + ) + } + + #[test] + fn parse_list_multiline() { + let uplc = r#" + (program 0.0.0 + (con list + + [ 14 + , 42 + ] + ) + )"#; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoList( + Type::Integer, + vec![Constant::Integer(14), Constant::Integer(42)], + )) + } + ) + } + + #[test] + fn parse_pair_unit_unit() { + let uplc = "(program 0.0.0 (con pair [(),()]))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoPair( + Type::Unit, + Type::Unit, + Box::new(Constant::Unit), + Box::new(Constant::Unit) + )) + } + ) + } + + #[test] + fn parse_pair_bool_pair_integer_bytestring() { + let uplc = "(program 0.0.0 (con pair> [True, [14, #42]]))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoPair( + Type::Bool, + Type::Pair(Box::new(Type::Integer), Box::new(Type::ByteString)), + Box::new(Constant::Bool(true)), + Box::new(Constant::ProtoPair( + Type::Integer, + Type::ByteString, + Box::new(Constant::Integer(14)), + Box::new(Constant::ByteString(vec![0x42])), + )) + )) + } + ) + } + + #[test] + fn parse_pair_string_list_integer() { + let uplc = "(program 0.0.0 (con pair> [\"foo\", [14, 42]]))"; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoPair( + Type::String, + Type::List(Box::new(Type::Integer)), + Box::new(Constant::String(String::from("foo"))), + Box::new(Constant::ProtoList( + Type::Integer, + vec![Constant::Integer(14), Constant::Integer(42)], + )) + )) + } + ) + } + + #[test] + fn parse_pair_multiline() { + let uplc = r#" + (program 0.0.0 + (con pair + + [14, 42] + ) + )"#; + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (0, 0, 0), + term: Term::Constant(Constant::ProtoPair( + Type::Integer, + Type::Integer, + Box::new(Constant::Integer(14)), + Box::new(Constant::Integer(42)) + )) + } + ) + } + + #[test] + fn parse_list_type_mismatch() { + let uplc = "(program 0.0.0 (con list [True, False]))"; + assert!(super::program(uplc).is_err()) + } + + #[test] + fn parse_list_mixed_types() { + let uplc = "(program 0.0.0 (con list [14, False]))"; + assert!(super::program(uplc).is_err()) + } + + // Helper function for all simple programs that involve only a direct application of a builtin + // function operating on two integers. + fn parse_builtin_integer(uplc: &str, default_function: DefaultFunction, x: i128, y: i128) { + assert_eq!( + super::program(uplc).unwrap(), + Program:: { + version: (1, 0, 0), + term: Term::Apply { + function: Rc::new(Term::Apply { + function: Rc::new(Term::Builtin(default_function)), + argument: Rc::new(Term::Constant(Constant::Integer(x))), + }), + argument: Rc::new(Term::Constant(Constant::Integer(y))) + } + } + ) + } } diff --git a/crates/uplc/src/pretty.rs b/crates/uplc/src/pretty.rs index b360805d..df03a8a8 100644 --- a/crates/uplc/src/pretty.rs +++ b/crates/uplc/src/pretty.rs @@ -193,14 +193,9 @@ impl Constant { Constant::Bool(b) => RcDoc::text("bool") .append(RcDoc::line()) .append(RcDoc::text(if *b { "True" } else { "False" })), - Constant::ProtoList(r#type, items) => RcDoc::text("(") - .append( - RcDoc::text("list") - .append(RcDoc::line()) - .append(r#type.to_doc()), - ) + Constant::ProtoList(r#type, items) => RcDoc::text("list") .append(RcDoc::line_()) - .append(RcDoc::text(")")) + .append(r#type.to_doc()) .append(RcDoc::line()) .append(RcDoc::text("[")) .append(RcDoc::intersperse( @@ -208,22 +203,19 @@ impl Constant { RcDoc::text(","), )) .append(RcDoc::text("]")), - Constant::ProtoPair(type1, type2, left, right) => RcDoc::text("(") - .append( - RcDoc::text("pair") - .append(RcDoc::line()) - .append(type1.to_doc()) - .append(RcDoc::line()) - .append(type2.to_doc()), - ) + Constant::ProtoPair(type_left, type_right, left, right) => RcDoc::text("pair") .append(RcDoc::line_()) - .append(RcDoc::text(")")) + .append(RcDoc::text("<")) + .append(type_left.to_doc()) + .append(RcDoc::text(", ")) + .append(type_right.to_doc()) + .append(RcDoc::text(">")) .append(RcDoc::line()) - .append(RcDoc::text("(")) + .append(RcDoc::text("[")) .append(left.to_doc_list()) .append(RcDoc::text(",")) .append(right.to_doc_list()) - .append(RcDoc::text(")")), + .append(RcDoc::text("]")), d @ Constant::Data(_) => RcDoc::text("data ").append(d.to_doc_list()), } } @@ -264,24 +256,16 @@ impl Type { Type::String => RcDoc::text("string"), Type::ByteString => RcDoc::text("bytestring"), Type::Unit => RcDoc::text("unit"), - Type::List(r#type) => RcDoc::text("(") - .append( - RcDoc::text("list") - .append(RcDoc::line()) - .append(r#type.to_doc()), - ) - .append(RcDoc::line_()) - .append(RcDoc::text(")")), - Type::Pair(type1, type2) => RcDoc::text("(") - .append( - RcDoc::text("list") - .append(RcDoc::line()) - .append(type1.to_doc()) - .append(RcDoc::line()) - .append(type2.to_doc()), - ) - .append(RcDoc::line_()) - .append(RcDoc::text(")")), + Type::List(r#type) => RcDoc::text("list") + .append(RcDoc::text("<")) + .append(r#type.to_doc()) + .append(RcDoc::text(">")), + Type::Pair(l, r) => RcDoc::text("pair") + .append(RcDoc::text("<")) + .append(l.to_doc()) + .append(RcDoc::text(", ")) + .append(r.to_doc()) + .append(RcDoc::text(">")), Type::Data => RcDoc::text("data"), } }