diff --git a/Cargo.lock b/Cargo.lock index f69ff64a..d5740c49 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -92,6 +92,7 @@ dependencies = [ "pallas", "petgraph", "pretty_assertions", + "serde", "strum", "thiserror", "uplc", diff --git a/crates/aiken-lang/Cargo.toml b/crates/aiken-lang/Cargo.toml index 4f5f6d76..02c7c5b7 100644 --- a/crates/aiken-lang/Cargo.toml +++ b/crates/aiken-lang/Cargo.toml @@ -7,9 +7,9 @@ repository = "https://github.com/aiken-lang/aiken" homepage = "https://github.com/aiken-lang/aiken" license = "Apache-2.0" authors = [ - "Lucas Rosa ", - "Kasey White ", - "KtorZ ", + "Lucas Rosa ", + "Kasey White ", + "KtorZ ", ] rust-version = "1.66.1" @@ -29,13 +29,14 @@ uplc = { path = '../uplc', version = "1.0.24-alpha" } num-bigint = "0.4.3" petgraph = "0.6.3" blst = "0.3.11" +serde = { version = "1.0.197", features = ["derive", "rc"] } [target.'cfg(not(target_family="wasm"))'.dependencies] chumsky = "0.9.2" [target.'cfg(target_family="wasm")'.dependencies] chumsky = { version = "0.9.2", features = [ - "ahash", - "std", + "ahash", + "std", ], default-features = false } [dev-dependencies] diff --git a/crates/aiken-lang/src/ast.rs b/crates/aiken-lang/src/ast.rs index 6dc09bab..9c61b85c 100644 --- a/crates/aiken-lang/src/ast.rs +++ b/crates/aiken-lang/src/ast.rs @@ -22,7 +22,7 @@ pub const PIPE_VARIABLE: &str = "_pipe"; pub type TypedModule = Module; pub type UntypedModule = Module<(), UntypedDefinition>; -#[derive(Debug, Copy, Clone, PartialEq, Eq)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum ModuleKind { Lib, Validator, @@ -38,7 +38,7 @@ impl ModuleKind { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Module { pub name: String, pub docs: Vec, @@ -222,7 +222,7 @@ pub type UntypedFunction = Function<(), UntypedExpr, UntypedArg>; pub type TypedTest = Function, TypedExpr, TypedArgVia>; pub type UntypedTest = Function<(), UntypedExpr, UntypedArgVia>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct Function { pub arguments: Vec, pub body: Expr, @@ -273,7 +273,57 @@ impl From for TypedFunction { } } -#[derive(Debug, Clone, PartialEq)] +impl TypedTest { + pub fn test_hint(&self) -> Option<(BinOp, Box, Box)> { + if self.arguments.is_empty() { + do_test_hint(&self.body) + } else { + None + } + } +} + +pub fn do_test_hint(body: &TypedExpr) -> Option<(BinOp, Box, Box)> { + match body { + TypedExpr::BinOp { + name, + tipo, + left, + right, + .. + } if tipo == &bool() => Some((*name, left.clone(), right.clone())), + TypedExpr::Sequence { expressions, .. } | TypedExpr::Pipeline { expressions, .. } => { + if let Some((binop, left, right)) = do_test_hint(&expressions[expressions.len() - 1]) { + let mut new_left_expressions = expressions.clone(); + new_left_expressions.pop(); + new_left_expressions.push(*left); + + let mut new_right_expressions = expressions.clone(); + new_right_expressions.pop(); + new_right_expressions.push(*right); + + Some(( + binop, + TypedExpr::Sequence { + expressions: new_left_expressions, + location: Span::empty(), + } + .into(), + TypedExpr::Sequence { + expressions: new_right_expressions, + location: Span::empty(), + } + .into(), + )) + } else { + None + } + } + _ => None, + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct TypeAlias { pub alias: String, pub annotation: Annotation, @@ -443,7 +493,7 @@ impl TypedDataType { pub type UntypedDataType = DataType<()>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct DataType { pub constructors: Vec>, pub doc: Option, @@ -458,7 +508,7 @@ pub struct DataType { pub type TypedUse = Use; pub type UntypedUse = Use<()>; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct Use { pub as_name: Option, pub location: Span, @@ -470,7 +520,7 @@ pub struct Use { pub type TypedModuleConstant = ModuleConstant>; pub type UntypedModuleConstant = ModuleConstant<()>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct ModuleConstant { pub doc: Option, pub location: Span, @@ -484,7 +534,7 @@ pub struct ModuleConstant { pub type TypedValidator = Validator, TypedExpr>; pub type UntypedValidator = Validator<(), UntypedExpr>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct Validator { pub doc: Option, pub end_position: usize, @@ -530,7 +580,7 @@ impl TypedValidator { pub type TypedDefinition = Definition, TypedExpr, String>; pub type UntypedDefinition = Definition<(), UntypedExpr, ()>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum Definition { Fn(Function>), @@ -660,7 +710,7 @@ pub struct DefinitionLocation<'module> { pub span: Span, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum Constant { Int { location: Span, @@ -712,7 +762,7 @@ impl Constant { pub type TypedCallArg = CallArg; pub type ParsedCallArg = CallArg>; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct CallArg { pub label: Option, pub location: Span, @@ -734,7 +784,7 @@ impl TypedCallArg { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct RecordConstructor { pub location: Span, pub name: String, @@ -749,7 +799,7 @@ impl RecordConstructor { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct RecordConstructorArg { pub label: Option, // ast @@ -768,7 +818,7 @@ impl RecordConstructorArg { pub type TypedArg = Arg>; pub type UntypedArg = Arg<()>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct Arg { pub arg_name: ArgName, pub location: Span, @@ -800,7 +850,7 @@ impl Arg { pub type TypedArgVia = ArgVia, TypedExpr>; pub type UntypedArgVia = ArgVia<(), UntypedExpr>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct ArgVia { pub arg_name: ArgName, pub location: Span, @@ -821,7 +871,7 @@ impl From> for Arg { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum ArgName { Discarded { name: String, @@ -852,7 +902,7 @@ impl ArgName { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct UnqualifiedImport { pub location: Span, pub name: String, @@ -871,7 +921,7 @@ impl UnqualifiedImport { } // TypeAst -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] pub enum Annotation { Constructor { location: Span, @@ -1015,7 +1065,7 @@ impl Annotation { } } -#[derive(Debug, Clone, PartialEq, Eq, Default)] +#[derive(Debug, Clone, PartialEq, Eq, Default, serde::Serialize, serde::Deserialize)] pub enum Layer { #[default] Value, @@ -1029,7 +1079,7 @@ impl Layer { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum BinOp { // Boolean logic And, @@ -1062,11 +1112,11 @@ impl From for BinOp { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum UnOp { - // ! + /// ! Not, - // - + /// - Negate, } @@ -1093,7 +1143,7 @@ impl BinOp { pub type UntypedPattern = Pattern<(), ()>; pub type TypedPattern = Pattern>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum Pattern { Int { location: Span, @@ -1241,7 +1291,7 @@ impl TypedPattern { } } -#[derive(Debug, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)] pub enum ByteArrayFormatPreference { HexadecimalString, ArrayOfBytes(Base), @@ -1292,7 +1342,7 @@ impl Display for Bls12_381PointType { } } -#[derive(Debug, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)] pub enum Curve { Bls12_381(Bls12_381Point), } @@ -1320,6 +1370,112 @@ pub enum Bls12_381Point { G2(blst::blst_p2), } +impl serde::Serialize for Bls12_381Point { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + match *self { + Bls12_381Point::G1(ref p1) => { + // Assuming `to_bytes` for compression to Vec + let bytes = p1.compress(); + + // Serialize as a tuple with a tag for differentiation + serializer.serialize_newtype_variant("Bls12_381Point", 0, "G1", &bytes) + } + Bls12_381Point::G2(ref p2) => { + let bytes = p2.compress(); + + serializer.serialize_newtype_variant("Bls12_381Point", 1, "G2", &bytes) + } + } + } +} + +impl<'de> serde::Deserialize<'de> for Bls12_381Point { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + enum Field { + G1, + G2, + } + + impl<'de> serde::Deserialize<'de> for Field { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct FieldVisitor; + + impl<'de> serde::de::Visitor<'de> for FieldVisitor { + type Value = Field; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("`G1` or `G2`") + } + + fn visit_str(self, value: &str) -> Result + where + E: serde::de::Error, + { + match value { + "G1" => Ok(Field::G1), + "G2" => Ok(Field::G2), + _ => Err(serde::de::Error::unknown_field(value, FIELDS)), + } + } + } + + deserializer.deserialize_identifier(FieldVisitor) + } + } + + struct Bls12_381PointVisitor; + + impl<'de> serde::de::Visitor<'de> for Bls12_381PointVisitor { + type Value = Bls12_381Point; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct Bls12_381Point") + } + + fn visit_seq(self, mut seq: V) -> Result + where + V: serde::de::SeqAccess<'de>, + { + let tag = seq + .next_element::()? + .ok_or_else(|| serde::de::Error::invalid_length(0, &self))?; + + let bytes = seq + .next_element::>()? + .ok_or_else(|| serde::de::Error::invalid_length(1, &self))?; + + match tag { + Field::G1 => { + let p1 = + blst::blst_p1::uncompress(&bytes).map_err(serde::de::Error::custom)?; + + Ok(Bls12_381Point::G1(p1)) + } + Field::G2 => { + let p2 = + blst::blst_p2::uncompress(&bytes).map_err(serde::de::Error::custom)?; + + Ok(Bls12_381Point::G2(p2)) + } + } + } + } + + const FIELDS: &[&str] = &["G1", "G2"]; + + deserializer.deserialize_enum("Bls12_381Point", FIELDS, Bls12_381PointVisitor) + } +} + impl Bls12_381Point { pub fn tipo(&self) -> Rc { match self { @@ -1335,7 +1491,7 @@ impl Default for Bls12_381Point { } } -#[derive(Debug, Clone, PartialEq, Eq, Copy)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, serde::Serialize, serde::Deserialize)] pub enum AssignmentKind { Let, Expect, @@ -1371,7 +1527,7 @@ pub struct UntypedClause { pub then: UntypedExpr, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct TypedClause { pub location: Span, pub pattern: Pattern>, @@ -1397,7 +1553,7 @@ impl TypedClause { pub type UntypedClauseGuard = ClauseGuard<()>; pub type TypedClauseGuard = ClauseGuard>; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum ClauseGuard { Not { location: Span, @@ -1515,14 +1671,14 @@ impl TypedClauseGuard { pub type TypedIfBranch = IfBranch; pub type UntypedIfBranch = IfBranch; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct IfBranch { pub condition: Expr, pub body: Expr, pub location: Span, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct TypedRecordUpdateArg { pub label: String, pub location: Span, @@ -1607,7 +1763,7 @@ impl Display for TraceLevel { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[derive(Copy, Clone, PartialEq, Eq, Hash, serde::Serialize, serde::Deserialize)] pub struct Span { pub start: usize, pub end: usize, diff --git a/crates/aiken-lang/src/expr.rs b/crates/aiken-lang/src/expr.rs index 62deead8..33bac7aa 100644 --- a/crates/aiken-lang/src/expr.rs +++ b/crates/aiken-lang/src/expr.rs @@ -23,7 +23,7 @@ use uplc::{ }; use vec1::Vec1; -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum TypedExpr { UInt { location: Span, @@ -125,7 +125,7 @@ pub enum TypedExpr { If { location: Span, - branches: Vec1>, + branches: Vec>, final_else: Box, tipo: Rc, }, @@ -289,7 +289,7 @@ impl TypedExpr { | Self::RecordUpdate { location, .. } | Self::CurvePoint { location, .. } => *location, - Self::If { branches, .. } => branches.first().body.type_defining_location(), + Self::If { branches, .. } => branches.first().unwrap().body.type_defining_location(), Self::Sequence { expressions, diff --git a/crates/aiken-lang/src/line_numbers.rs b/crates/aiken-lang/src/line_numbers.rs index cefc509b..9ecb8ada 100644 --- a/crates/aiken-lang/src/line_numbers.rs +++ b/crates/aiken-lang/src/line_numbers.rs @@ -1,6 +1,6 @@ use std::fmt::{self, Display}; -#[derive(Debug, PartialEq, Eq, Clone)] +#[derive(Debug, PartialEq, Eq, Clone, serde::Serialize, serde::Deserialize)] pub struct LineNumbers { line_starts: Vec, length: usize, diff --git a/crates/aiken-lang/src/parser/extra.rs b/crates/aiken-lang/src/parser/extra.rs index 27638197..4c8d575c 100644 --- a/crates/aiken-lang/src/parser/extra.rs +++ b/crates/aiken-lang/src/parser/extra.rs @@ -1,7 +1,7 @@ use crate::ast::Span; use std::iter::Peekable; -#[derive(Debug, PartialEq, Eq, Default, Clone)] +#[derive(Debug, PartialEq, Eq, Default, Clone, serde::Serialize, serde::Deserialize)] pub struct ModuleExtra { pub module_comments: Vec, pub doc_comments: Vec, diff --git a/crates/aiken-lang/src/parser/token.rs b/crates/aiken-lang/src/parser/token.rs index d48e1179..607eeaf6 100644 --- a/crates/aiken-lang/src/parser/token.rs +++ b/crates/aiken-lang/src/parser/token.rs @@ -1,6 +1,6 @@ use std::fmt; -#[derive(Clone, Debug, PartialEq, Hash, Eq, Copy)] +#[derive(Clone, Debug, PartialEq, Hash, Eq, Copy, serde::Serialize, serde::Deserialize)] pub enum Base { Decimal { numeric_underscore: bool }, Hexadecimal, diff --git a/crates/aiken-lang/src/tipo.rs b/crates/aiken-lang/src/tipo.rs index 62a3ca8d..5ffc2c57 100644 --- a/crates/aiken-lang/src/tipo.rs +++ b/crates/aiken-lang/src/tipo.rs @@ -30,7 +30,7 @@ pub struct TypeAliasAnnotation { pub annotation: Annotation, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum Type { /// A nominal (named) type such as `Int`, `Float`, or a programmer defined /// custom type such as `Person`. The type can take other types as @@ -797,7 +797,7 @@ pub fn find_and_replace_generics( } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum TypeVar { /// Unbound is an unbound variable. It is one specific type but we don't /// know what yet in the inference process. It has a unique id which can be used to @@ -971,7 +971,7 @@ impl TypeVar { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub struct ValueConstructor { pub public: bool, pub variant: ValueConstructorVariant, @@ -1022,7 +1022,7 @@ impl ValueConstructor { } } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum ValueConstructorVariant { /// A locally defined variable or function parameter LocalVariable { location: Span }, @@ -1119,7 +1119,7 @@ impl ValueConstructorVariant { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct TypeInfo { pub name: String, pub kind: ModuleKind, @@ -1131,7 +1131,7 @@ pub struct TypeInfo { pub annotations: HashMap>, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct TypeConstructor { pub public: bool, pub location: Span, @@ -1140,14 +1140,14 @@ pub struct TypeConstructor { pub tipo: Rc, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct AccessorsMap { pub public: bool, pub tipo: Rc, pub accessors: HashMap, } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct RecordAccessor { // TODO: smaller int. Doesn't need to be this big pub index: u64, @@ -1155,7 +1155,7 @@ pub struct RecordAccessor { pub tipo: Rc, } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub enum PatternConstructor { Record { name: String, @@ -1163,7 +1163,7 @@ pub enum PatternConstructor { }, } -#[derive(Debug, Clone, PartialEq)] +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] pub enum ModuleValueConstructor { Record { name: String, diff --git a/crates/aiken-lang/src/tipo/expr.rs b/crates/aiken-lang/src/tipo/expr.rs index d0a444d0..b5fd2c78 100644 --- a/crates/aiken-lang/src/tipo/expr.rs +++ b/crates/aiken-lang/src/tipo/expr.rs @@ -453,7 +453,7 @@ impl<'a, 'b> ExprTyper<'a, 'b> { TraceLevel::Silent => Ok(typed_value), TraceLevel::Verbose | TraceLevel::Compact => Ok(TypedExpr::If { location, - branches: vec1::vec1![IfBranch { + branches: vec![IfBranch { condition: typed_value, body: var_true, location, @@ -1428,11 +1428,11 @@ impl<'a, 'b> ExprTyper<'a, 'b> { let tipo = body.tipo(); - let mut typed_branches = Vec1::new(TypedIfBranch { + let mut typed_branches = vec![TypedIfBranch { body, condition, location: first.location, - }); + }]; for branch in &branches[1..] { let condition = self.infer(branch.condition.clone())?; diff --git a/crates/aiken-lang/src/tipo/fields.rs b/crates/aiken-lang/src/tipo/fields.rs index 17afc9cc..b68bd884 100644 --- a/crates/aiken-lang/src/tipo/fields.rs +++ b/crates/aiken-lang/src/tipo/fields.rs @@ -5,7 +5,7 @@ use itertools::Itertools; use super::error::{Error, UnknownLabels}; use crate::ast::{CallArg, Span}; -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct FieldMap { pub arity: usize, pub fields: HashMap, diff --git a/crates/aiken-project/src/module.rs b/crates/aiken-project/src/module.rs index d7a579b8..caf22af6 100644 --- a/crates/aiken-project/src/module.rs +++ b/crates/aiken-project/src/module.rs @@ -169,7 +169,7 @@ fn find_cycle( false } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)] pub struct CheckedModule { pub name: String, pub code: String, diff --git a/crates/uplc/src/builtins.rs b/crates/uplc/src/builtins.rs index 15239af8..3ffd9b84 100644 --- a/crates/uplc/src/builtins.rs +++ b/crates/uplc/src/builtins.rs @@ -8,7 +8,7 @@ use crate::ast::Term; /// All the possible builtin functions in Untyped Plutus Core. #[repr(u8)] #[allow(non_camel_case_types)] -#[derive(Debug, Clone, PartialEq, Eq, Copy, EnumIter)] +#[derive(Debug, Clone, PartialEq, Eq, Copy, EnumIter, serde::Serialize, serde::Deserialize)] pub enum DefaultFunction { // Integer functions AddInteger = 0,