diff --git a/CHANGELOG.md b/CHANGELOG.md index 87470ec4..6530d19c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,21 +4,32 @@ ### Added +- **aiken-lang**: ChooseUnit builtin uses a more efficient way of handling the + first arg (unit) by just assigning to lambda + ### Fixed - -- **aiken-lang**: Negative numbers now show up as a constant instead of 0 - that number +- **aiken-lang**: Negative numbers now show up as a constant instead of 0 - that + number - **aiken-lang**: Expect on constructors without field maps no longer panics -- **aiken-lang**: Expect on constructors with discard as assigned field names now no longer throws free unique +- **aiken-lang**: Expect on constructors with discard as assigned field names + now no longer throws free unique + +### Changed + +- **aiken-lang**: Refactor how builtins are processed to uplc in code gen ## v1.0.3.alpha - 2023-04-28 ### Added -- **aiken-lang**: added optimization to help prevent unnecessary data wraps or unwraps +- **aiken-lang**: added optimization to help prevent unnecessary data wraps or + unwraps - **aiken-lang**: optimization to strip unnecessary lambdas -- **aiken-lang**: implement Clone for ParseError and tipo::Error for the playground -- **aiken-project**: added end to end tests on conversion from aiken lang to uplc +- **aiken-lang**: implement Clone for ParseError and tipo::Error for the + playground +- **aiken-project**: added end to end tests on conversion from aiken lang to + uplc ### Fixed @@ -26,15 +37,18 @@ - **aiken-lang**: Add name of var to the unused var warning - **aiken-lang**: fix expect on an empty list - **aiken-lang**: pattern match on boolean with simple clause bodies -- **aiken-lang**: fix for inline_direct_reduce to be applied to pattern match function instead of argument -- **aiken-lang**: code gen function dependencies won't be hoisted to the top, instead hoisted at the location depended on. +- **aiken-lang**: fix for inline_direct_reduce to be applied to pattern match + function instead of argument +- **aiken-lang**: code gen function dependencies won't be hoisted to the top, + instead hoisted at the location depended on. ## v1.0.2.alpha - 2023-04-17 ### Fixed - **aiken-lang**: needed to assert_no_assignment in when and if blocks -- **uplc**: need to return deserialization error in some cases for the machine builtins +- **uplc**: need to return deserialization error in some cases for the machine + builtins ## v1.0.1-alpha - 2023-04-16 @@ -51,22 +65,30 @@ ### Changed -- **aiken-project**: tests filtering with `-m` during check now happens in `Project::collect_tests` -- **aiken-project**: fixed generation of blueprints for recursive and mutually recursive data-types +- **aiken-project**: tests filtering with `-m` during check now happens in + `Project::collect_tests` +- **aiken-project**: fixed generation of blueprints for recursive and mutually + recursive data-types - **aiken-project**: perform validation of parameters on `blueprint apply` - **aiken-lang**: block `Data` and `String` from unifying when casting -- **aiken-lang**: remove ability for a type with many variants with matching field labels and types to support field access +- **aiken-lang**: remove ability for a type with many variants with matching + field labels and types to support field access - **aiken-lang**: various uplc code gen fixes - **aiken-lang**: update todo warning to include type -- **aiken-lang**: `|>` operator can now be formatted as a single (short) line or forced over multiline in a flexible manner -- **aiken-lang**: the compiler now provides better feedback for type holes (i.e. `_`) in type annotations -- **aiken-lang**: assignment and clause guard are now always formatted on a new line -- **aiken-lang**: unused let-bindings are now fully removed from generated code and discarded unused let-binding now raise a warning +- **aiken-lang**: `|>` operator can now be formatted as a single (short) line or + forced over multiline in a flexible manner +- **aiken-lang**: the compiler now provides better feedback for type holes (i.e. + `_`) in type annotations +- **aiken-lang**: assignment and clause guard are now always formatted on a new + line +- **aiken-lang**: unused let-bindings are now fully removed from generated code + and discarded unused let-binding now raise a warning - **aiken-lang**: support multi-clause patterns (only as a syntactic sugar) - **aiken-lang**: fix lexer panic when parsing too large (> u32) tuple-indexes -- **uplc**: Greatly improved the Plutus virtual machine performances for script evaluation +- **uplc**: Greatly improved the Plutus virtual machine performances for script + evaluation ## v0.0.29 - 2023-02-23 @@ -107,7 +129,8 @@ N/A ### Changed -- **uplc**: Reward accounts are now correctly turned into script credentials in ScriptContext. +- **uplc**: Reward accounts are now correctly turned into script credentials in + ScriptContext. - **all**: bump pallas version to `v0.16.0` ### Removed @@ -121,8 +144,8 @@ N/A - **aiken-lang**: integrated unit tests Aiken now supports writing unit tests directly in source files using the new - `test` keyword. Tests are functions with no arguments that are implicitly typed - to `bool`. For example: + `test` keyword. Tests are functions with no arguments that are implicitly + typed to `bool`. For example: ```gleam test foo () { @@ -134,8 +157,10 @@ N/A ### Changed -- **aiken**: `check` now also runs and reports on any `test` found in the project -- **aiken**: fix Plutus V1 `to_plutus_data()` for post-alonzo txout with no datum hash +- **aiken**: `check` now also runs and reports on any `test` found in the + project +- **aiken**: fix Plutus V1 `to_plutus_data()` for post-alonzo txout with no + datum hash ### Removed @@ -166,24 +191,28 @@ N/A - **aiken-lang**: add `Data` to prelude - **aiken-lang**: allow `Data` to unify with anything that's not in the prelude - **aiken-project**: validate if validator function return bool -- **aiken-project**: validate if validator function has minimum number of arguments +- **aiken-project**: validate if validator function has minimum number of + arguments - **aiken-lsp**: new crate that contains the aiken language server ### Changed -- **uplc**: `Converter::get_index` now takes the full name to provide better error messages for `Error::FreeUnique` +- **uplc**: `Converter::get_index` now takes the full name to provide better + error messages for `Error::FreeUnique` ## v0.0.24 - 2022-11-04 ### Changed -- **uplc**: Sorted remaining structured in the ScriptContext (Value, Wdrl, (Ref) Inputs, Mint, Required signers, Data, Redeemers) +- **uplc**: Sorted remaining structured in the ScriptContext (Value, Wdrl, (Ref) + Inputs, Mint, Required signers, Data, Redeemers) ## v0.0.23 - 2022-11-03 ### Changed -- **uplc**: sort inputs for script context fixes an issue in lucid https://github.com/spacebudz/lucid/issues/109 +- **uplc**: sort inputs for script context fixes an issue in lucid + https://github.com/spacebudz/lucid/issues/109 ## v0.0.22 - 2022-10-31 @@ -191,14 +220,18 @@ N/A - **aiken**: Fancy errors using [miette](https://github.com/zkat/miette) - **aiken**: Typechecking -- **aiken**: Inject `aiken/builtin` module with some functions from `DefaultFunction` in UPLC directly exposed -- **aiken-lang**: add `infer` method to `UntypedModule` which returns a `TypedModule` -- **uplc**: Expose various Pallas primitives from UPLC to make constructing - UPLC types possible for consumers +- **aiken**: Inject `aiken/builtin` module with some functions from + `DefaultFunction` in UPLC directly exposed +- **aiken-lang**: add `infer` method to `UntypedModule` which returns a + `TypedModule` +- **uplc**: Expose various Pallas primitives from UPLC to make constructing UPLC + types possible for consumers ### Changed -- **aiken**: Project structure is now a bit different. See [examples/sample](https://github.com/aiken-lang/aiken/tree/main/examples/sample) for more +- **aiken**: Project structure is now a bit different. See + [examples/sample](https://github.com/aiken-lang/aiken/tree/main/examples/sample) + for more ## v0.0.21 - 2022-10-23 @@ -208,15 +241,19 @@ N/A ### Changed -- **uplc**: Fixed overflow issue by changing `i64` to `i128` in `BigInt::Int` instances -- **uplc**: Added `apply_params_to_script` function (applies params to script and serializes the new script). +- **uplc**: Fixed overflow issue by changing `i64` to `i128` in `BigInt::Int` + instances +- **uplc**: Added `apply_params_to_script` function (applies params to script + and serializes the new script). ## v0.0.20 - 2022-10-17 ### Added -- **aiken**: `Project` module which is responsible loading modules and running the compilation steps -- **aiken**: `UplcCommand::Flat` flip the cbor_hex if condition so that the correct logic runs when using the flag +- **aiken**: `Project` module which is responsible loading modules and running + the compilation steps +- **aiken**: `UplcCommand::Flat` flip the cbor_hex if condition so that the + correct logic runs when using the flag - **uplc**: use i128 for `Constant::Integer` - **flat-rs**: add support for i128 encode and decode - **flat-rs**: add i128 zigzag function diff --git a/crates/aiken-lang/src/gen_uplc.rs b/crates/aiken-lang/src/gen_uplc.rs index b81e25bb..659a4796 100644 --- a/crates/aiken-lang/src/gen_uplc.rs +++ b/crates/aiken-lang/src/gen_uplc.rs @@ -4051,97 +4051,42 @@ impl<'a> CodeGenerator<'a> { Air::Builtin { func, tipo, count, .. } => { - let mut term: Term = Term::Builtin(func); - for _ in 0..func.force_count() { - term = term.force(); - } - let mut arg_vec = vec![]; for _ in 0..count { arg_vec.push(arg_stack.pop().unwrap()); } - for (index, arg) in arg_vec.into_iter().enumerate() { - let arg = if matches!(func, DefaultFunction::ChooseData) && index > 0 { - arg.delay() - } else { - arg - }; - term = term.apply(arg.clone()); - } + let term = match &func { + DefaultFunction::IfThenElse + | DefaultFunction::ChooseUnit + | DefaultFunction::Trace + | DefaultFunction::ChooseList + | DefaultFunction::ChooseData + | DefaultFunction::UnConstrData => { + builder::special_case_builtin(&func, count, arg_vec) + } - match func { DefaultFunction::FstPair | DefaultFunction::SndPair | DefaultFunction::HeadList => { - let temp_var = format!("__item_{}", self.id_gen.next()); - - if count == 0 { - term = term.apply(Term::var(temp_var.clone())); - } - - term = builder::convert_data_to_type(term, &tipo); - - if count == 0 { - term = term.lambda(temp_var); - } + builder::undata_builtin(&func, count, &tipo, arg_vec) } - DefaultFunction::UnConstrData => { - let temp_tuple = format!("__unconstr_tuple_{}", self.id_gen.next()); - let temp_var = format!("__item_{}", self.id_gen.next()); - - if count == 0 { - term = term.apply(Term::var(temp_var.clone())); - } - - term = Term::mk_pair_data() - .apply( - Term::i_data() - .apply(Term::fst_pair().apply(Term::var(temp_tuple.clone()))), - ) - .apply( - Term::list_data() - .apply(Term::snd_pair().apply(Term::var(temp_tuple.clone()))), - ) - .lambda(temp_tuple) - .apply(term); - - if count == 0 { - term = term.lambda(temp_var); - } + DefaultFunction::MkCons | DefaultFunction::MkPairData => { + builder::to_data_builtin(&func, count, &tipo, arg_vec) } - DefaultFunction::MkCons => { - unimplemented!("Use brackets instead."); - } - DefaultFunction::IfThenElse - | DefaultFunction::ChooseList - | DefaultFunction::Trace => unimplemented!("{func:#?}"), - DefaultFunction::ChooseData => { - let temp_vars = (0..func.arity()) - .map(|_| format!("__item_{}", self.id_gen.next())) - .collect_vec(); + _ => { + let mut term: Term = func.into(); - if count == 0 { - for (index, temp_var) in temp_vars.iter().enumerate() { - term = term.apply(if index > 0 { - Term::var(temp_var.clone()).delay() - } else { - Term::var(temp_var.clone()) - }); - } - } - - term = term.force(); - - if count == 0 { - for temp_var in temp_vars.into_iter().rev() { - term = term.lambda(temp_var); - } + term = builder::apply_builtin_forces(term, func.force_count()); + + for arg in arg_vec { + term = term.apply(arg.clone()); } + term } - _ => {} - } + }; + arg_stack.push(term); } Air::BinOp { name, tipo, .. } => { diff --git a/crates/aiken-lang/src/gen_uplc/builder.rs b/crates/aiken-lang/src/gen_uplc/builder.rs index a0301338..7c6edd37 100644 --- a/crates/aiken-lang/src/gen_uplc/builder.rs +++ b/crates/aiken-lang/src/gen_uplc/builder.rs @@ -1805,3 +1805,150 @@ pub fn handle_clause_guard( } } } + +pub fn apply_builtin_forces(mut term: Term, force_count: u32) -> Term { + for _ in 0..force_count { + term = term.force(); + } + term +} + +pub fn undata_builtin( + func: &DefaultFunction, + count: usize, + tipo: &Arc, + args: Vec>, +) -> Term { + let mut term: Term = (*func).into(); + + term = apply_builtin_forces(term, func.force_count()); + + for arg in args { + term = term.apply(arg); + } + + let temp_var = "__item_x"; + + if count == 0 { + term = term.apply(Term::var(temp_var)); + } + + term = convert_data_to_type(term, tipo); + + if count == 0 { + term = term.lambda(temp_var); + } + term +} + +pub fn to_data_builtin( + func: &DefaultFunction, + count: usize, + tipo: &Arc, + args: Vec>, +) -> Term { + let mut term: Term = (*func).into(); + + term = apply_builtin_forces(term, func.force_count()); + + for arg in args { + term = term.apply(arg); + } + + let temp_var = "__item_x"; + + if count == 0 { + term = term.apply(Term::var(temp_var)); + } + + term = convert_type_to_data(term, tipo); + + if count == 0 { + term = term.lambda(temp_var); + } + term +} + +pub fn special_case_builtin( + func: &DefaultFunction, + count: usize, + mut args: Vec>, +) -> Term { + match func { + DefaultFunction::IfThenElse + | DefaultFunction::ChooseList + | DefaultFunction::ChooseData + | DefaultFunction::Trace => { + let mut term: Term = (*func).into(); + + term = apply_builtin_forces(term, func.force_count()); + + if count == 0 { + assert!(args.is_empty()); + + for arg_index in 0..func.arity() { + let temp_var = format!("__item_index_{}", arg_index); + + args.push(Term::var(temp_var)) + } + } + + for (index, arg) in args.into_iter().enumerate() { + if index == 0 { + term = term.apply(arg); + } else { + term = term.apply(arg.delay()); + } + } + + term = term.force(); + + if count == 0 { + for arg_index in (0..func.arity()).rev() { + let temp_var = format!("__item_index_{}", arg_index); + term = term.lambda(temp_var); + } + } + + term + } + DefaultFunction::ChooseUnit => { + if count == 0 { + unimplemented!("Honestly, why are you doing this?") + } else { + let term = args.pop().unwrap(); + let unit = args.pop().unwrap(); + + term.lambda("_").apply(unit) + } + } + DefaultFunction::UnConstrData => { + let mut term: Term = (*func).into(); + + let temp_tuple = "__unconstr_tuple"; + + for arg in args { + term = term.apply(arg); + } + + let temp_var = "__item_x"; + + if count == 0 { + term = term.apply(Term::var(temp_var)); + } + + term = Term::mk_pair_data() + .apply(Term::i_data().apply(Term::fst_pair().apply(Term::var(temp_tuple)))) + .apply(Term::list_data().apply(Term::snd_pair().apply(Term::var(temp_tuple)))) + .lambda(temp_tuple) + .apply(term); + + if count == 0 { + term = term.lambda(temp_var); + } + + term + } + _ => unreachable!(), + } +} diff --git a/crates/aiken-project/src/blueprint/validator.rs b/crates/aiken-project/src/blueprint/validator.rs index 09e45680..46aea288 100644 --- a/crates/aiken-project/src/blueprint/validator.rs +++ b/crates/aiken-project/src/blueprint/validator.rs @@ -415,8 +415,8 @@ mod test { "$ref": "#/definitions/test_module~1Input" } }, - "compiledCode": "5902ad0100003232323232323232323232322223232533300a4a22930b1980519919119299980699b87480000044c8c8c8c8c8c94ccc060c0680084cc050c94ccc050cdc3a400000226464a666036603a0042930a9980c2481334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a6036002602400c2a6602c9212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e74001630120053301433009003232498dd7000a4c2a6602a9201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c603000260300046eb0c058004c058008c050004c02c00854cc03d2412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300b0013001001222533301100214984cc034c004c048008ccc00c00cc04c008004010010cc024c94ccc024cdc3a40000022a66601c600e0062930a99805a4811d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153330093370e90010008a99980718038018a4c2a6601692011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153330093370e90020008a99980718038018a4c2a6601692011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300b4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300700200233001001480008888cccc01ccdc38008018069199980280299b8000448008c03c0040080088c01cdd5000918029baa0015734ae6d5ce2ab9d5573caae7d5d0aba201", - "hash": "dfd982261c46e048a8d2a7ffb45258d2e98ab88b563709a47d69e37d", + "compiledCode": "5902a201000032323232323232323232322223232533300a4a22930b1900299919119299980699b87480000044c8c8c8c8c8c94ccc05cc0640084c8c9263300a004232498dd700099299980a19b87480000044c8c94ccc068c07000852615330174901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a6034002602400c2a6602a9212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016301200515330144901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c602e002602e0046eb0c054004c054008c04c004c02c00854cc0392412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300b0013001001222533301000214984c8ccc010010c04c00c008c004c044008010c800cc94ccc024cdc3a40000022a66601a600e0062930a9980524811d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153330093370e90010008a99980698038018a4c2a6601492011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153330093370e90020008a99980698038018a4c2a6601492011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300a4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300700233001001480008888cccc01ccdc38008018061199980280299b8000448008c0380040080088c018dd5000918021baa0015734ae7155ceaab9e5573eae855d11", + "hash": "b57f3d9e610afae77ef6d2662d945b3bb1e1c8698ff55fe8e9287b00", "definitions": { "ByteArray": { "dataType": "bytes" @@ -596,8 +596,8 @@ mod test { "$ref": "#/definitions/test_module~1Either$ByteArray_test_module~1Interval$Int" } }, - "compiledCode": "590213010000323232323232323232323232223253330084a22930b1980419299980419b87480000044c8c94ccc03cc044008526153300c491334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c601e002600c0062a66601066e1d200200113232533300f301100213300b32533300b3370e9000000899192999809180a0010a4c2a6601e9201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a602400260120042a66601666e1d2002001153330103009002149854cc03524011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300d4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300900149854cc031241334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016300f0013006003153300a4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300600200233001001480008888cccc01ccdc38008018069199980280299b8000448008c03c0040080088c01cdd5000918029baa0015734ae6d5ce2ab9d5573caae7d5d0aba201", - "hash": "bfca0d21daa5694b321ee99bb82a74976f998a691f0a08b1ac2bac7d", + "compiledCode": "59020c0100003232323232323232323232223253330084a22930b1900199299980419b87480000044c8c94ccc038c040008526153300b491334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c601c002600c0062a66601066e1d200200113232533300e3010002132498c94ccc02ccdc3a400000226464a66602260260042930a99807249334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a602200260120042a66601666e1d20020011533300f3009002149854cc03124011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300c4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e7400163009001153300b4901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016300e001300600315330094912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300600233001001480008888cccc01ccdc38008018061199980280299b8000448008c0380040080088c018dd5000918021baa0015734ae7155ceaab9e5573eae855d11", + "hash": "80d2bf8e5785ac1fd753a00c28cc808e1c9f0dac08e42bdb0d2a3142", "definitions": { "ByteArray": { "dataType": "bytes" @@ -680,8 +680,8 @@ mod test { "$ref": "#/definitions/test_module~1Dict$test_module~1UUID_Int" } }, - "compiledCode": "59011c01000032323232323232323232223253330064a22930b1980319919119299980499b87480000044c8c94ccc040c0480084cc030cc0140048c8c926375a60220046eb8c03c00526153300d491334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564001637566020002601a6ea800854cc02d2412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300b37540026002002444a66601a00429309980498009807001199801801980780100080100119800800a40004444666600a66e1c00400c02c8cccc014014cdc000224004601a002004004ae695cdab9c5573aaae7955cfaba157441", - "hash": "6f4ac35fb024ddddca4ea209d49943096c735c1b2348d63983c5bf08", + "compiledCode": "590115010000323232323232323232223253330064a22930b1900199919119299980499b87480000044c8c94ccc03cc0440084c9263300500123232498dd698080011bae300e001153300c4901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163756601e00260186ea800854cc0292412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300a37540026002002444a66601800429309919980200218078018011800980680100119800800a40004444666600a66e1c00400c0288cccc014014cdc0002240046018002004004ae695ce2ab9d5573caae7d5d0aba21", + "hash": "780668561f5650bba680ecc5a1ccee2829df0bbe27d29f9c5c456bbc", "definitions": { "ByteArray": { "dataType": "bytes" @@ -743,8 +743,8 @@ mod test { "$ref": "#/definitions/test_module~1Dict$test_module~1UUID_Int" } }, - "compiledCode": "585b01000032323232323232223253330044a22930b19198029999180080091129998058010a4c26601060026018004666006006601a00400200246464931bad3009002375c600e0020026eac0095cd2b9b5573aaae7955cfaba157441", - "hash": "96974ac55a06ba32cec8ba5d1f603a1c4e82a4ec9ef13b7bb838d7d9", + "compiledCode": "5855010000323232323232223253330044a22930b19190011999180080091129998050010a4c264666008008601a0060046002601600400246464931bad3008002375c600c0026eac0095cd2ab9d5573caae7d5d0aba21", + "hash": "857336762a5637afaacef8f0b536f23763fa05006e5f4f2401e3c7d9", "definitions": { "ByteArray": { "dataType": "bytes" @@ -795,8 +795,8 @@ mod test { "$ref": "#/definitions/Int" } }, - "compiledCode": "58e801000032323232323232323232222323253330084a22930b1980419299980419b87480000044c8c94ccc03cc044008526153300c4901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016300f001300c375400a2a660149212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300a37540080086eb4008cc0040052000222233330053370e0020060164666600a00a66e000112002300d0010020025734ae6d5ce2ab9d5573caae7d5d0aba21", - "hash": "5efeb108e67807af47a66b3c3537e7210ac7c1d6892e3ff512706163", + "compiledCode": "58e4010000323232323232323232222323253330084a22930b1900299299980419b87480000044c8c94ccc038c040008526153300b4901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016300e001300b375400a2a660129212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300937540086eb4008cc0040052000222233330053370e0020060144666600a00a66e000112002300c0010020025734ae7155ceaab9e5573eae855d101", + "hash": "b8bce36b335ed232d2204ac8de888fc3bf28bf0bc2b4c4c8116d409f", "definitions": { "Data": { "title": "Data", @@ -850,8 +850,8 @@ mod test { "$ref": "#/definitions/test_module~1Expr" } }, - "compiledCode": "5901d30100003232323232323232323232223253330074a22930b1980399918008009119299980499b87480000044c8c94ccc040c048008526153300d491334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a602000260100042a66601266e1d20020011323232325333012301400213300e330070070033300e3300700700149854cc03d2401334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163012001301200230100013008002153330093370e90020008991919192999809180a001099807198038038019980719803803800a4c2a6601e9201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163012001301200230100013008002153300b4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300b37540020040046600200290001111199980319b8700100300c233330050053370000890011807000801001118031baa0015734ae6d5ce2ab9d5573caae7d5d0aba21", - "hash": "2fffd5b9f5a372ec180ebec76cecd630c7bfdf680a5ffd7353b67c18", + "compiledCode": "5901c901000032323232323232323232223253330074a22930b1900199918008009119299980499b87480000044c8c94ccc03cc044008526153300c491334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a601e00260100042a66601266e1d20020011323232325333011301300213232498cc020020008cc01c01c00c54cc0392401334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564001630110013011002300f0013008002153330093370e9002000899191919299980898098010991924c660100100046600e00e0062a6601c9201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564001630110013011002300f0013008002153300a4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300a37540020046600200290001111199980319b8700100300b233330050053370000890011806800801001118029baa0015734ae7155ceaab9e5573eae855d101", + "hash": "d89d1c0bdde26ab12979ff50a140f3f1f7a47d50ccf4cf633b3ef3d3", "definitions": { "Int": { "dataType": "integer" @@ -941,8 +941,8 @@ mod test { "$ref": "#/definitions/test_module~1LinkedList$Int" } }, - "compiledCode": "59037601000032323232323232323232323222232323232533300c4a22930b19806199191919119299980899b87480000044c8c94ccc060c0680084cc050c01c0052615330154901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163018001300f002153330113370e9001000899191919299980d180e001099191980c1980480091980c9807800a4c931bac301a002375c60300022a6602e9201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163232337606038004603800260380026eb0c068004c068008dd6980c00098078010a99809a4812b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300f0013001001222533301500214984cc044c004c058008ccc00c00cc05c008004c00400488c94ccc038cdc3a4000002264646464a66602e60320042660266600e00e002930a9980a2481334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016301700130170023370e900118091baa3015001300c0021533300e3370e90010008a99980998060010a4c2a660209211d4578706563746564206e6f206669656c647320666f7220436f6e737472001615330104912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300c0010060063300b300100400430010012232533300b3370e9000000899191919299980a180b00109980819803803800a4c2a660229201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564001630140013014002375a602400260120042a66601666e1d2002001153330103009002149854cc03524011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300d4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300900133001001480008888cccc01ccdc38008018069199980280299b8000448008c03c0040080088c01cdd5000918029baa0015734ae6d5ce2ab9d5573caae7d5d0aba21", - "hash": "2e61d226dd9f4d5cafda093e8156f7f574ca95d10bee886581dd4bc2", + "compiledCode": "590366010000323232323232323232323222232323232533300c4a22930b19003999191919119299980899b87480000044c8c94ccc05cc0640084c92630070011533014491334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163017001300f002153330113370e9001000899191919299980c980d801099191924c660120024649318078009bac3019002375c602e0022a6602c9201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163232337606036004603600260360026eb0c064004c064008dd6980b80098078010a9980924812b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300f0013001001222533301400214984c8ccc010010c05c00c008c004c054008c00400488c94ccc038cdc3a4000002264646464a66602c603000426493198038038008a99809a481334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016301600130160023370e900118089baa3014001300c0021533300e3370e90010008a99980918060010a4c2a6601e9211d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300f4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300c00100632005300100430010012232533300b3370e90000008991919192999809980a80109924c6600e00e0022a66020921334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564001630130013013002375a602200260120042a66601666e1d20020011533300f3009002149854cc03124011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300c4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300900133001001480008888cccc01ccdc38008018061199980280299b8000448008c0380040080088c018dd5000918021baa0015734ae7155ceaab9e5573eae855d11", + "hash": "b5da17417d29be9264832a3550a73b4fddd4f82a74a488c91d861262", "definitions": { "Bool": { "title": "Bool", diff --git a/crates/uplc/src/optimize/shrinker.rs b/crates/uplc/src/optimize/shrinker.rs index 1ad05a79..a4e72bf3 100644 --- a/crates/uplc/src/optimize/shrinker.rs +++ b/crates/uplc/src/optimize/shrinker.rs @@ -51,6 +51,7 @@ impl Program { let mut term = self.term; inline_basic_reduce(&mut term); inline_direct_reduce(&mut term); + inline_identity_reduce(&mut term); Program { version: self.version, @@ -201,6 +202,50 @@ fn inline_direct_reduce(term: &mut Term) { } } +fn inline_identity_reduce(term: &mut Term) { + match term { + Term::Delay(d) => { + let d = Rc::make_mut(d); + inline_identity_reduce(d); + } + Term::Lambda { body, .. } => { + let body = Rc::make_mut(body); + inline_identity_reduce(body); + } + Term::Apply { function, argument } => { + let func = Rc::make_mut(function); + let arg = Rc::make_mut(argument); + + inline_identity_reduce(func); + inline_identity_reduce(arg); + + let Term::Lambda { parameter_name, body } = func + else { + return; + }; + + let Term::Lambda { parameter_name: identity_name, body: identity_body } = arg + else { + return; + }; + + let Term::Var(identity_var) = Rc::make_mut(identity_body) + else { + return; + }; + + if identity_var.as_ref() == identity_name.as_ref() { + *term = replace_identity_usage(body, parameter_name.clone()); + } + } + Term::Force(f) => { + let f = Rc::make_mut(f); + inline_identity_reduce(f); + } + _ => {} + } +} + fn inline_basic_reduce(term: &mut Term) { match term { Term::Delay(d) => { @@ -212,11 +257,11 @@ fn inline_basic_reduce(term: &mut Term) { inline_basic_reduce(body); } Term::Apply { function, argument } => { - let arg = Rc::make_mut(argument); - inline_basic_reduce(arg); - let func = Rc::make_mut(function); + let arg = Rc::make_mut(argument); + inline_basic_reduce(func); + inline_basic_reduce(arg); if let Term::Lambda { parameter_name, @@ -408,6 +453,51 @@ fn substitute_term(term: &Term, original: Rc, replace_with: &Term, original: Rc) -> Term { + match term { + Term::Delay(body) => Term::Delay(replace_identity_usage(body.as_ref(), original).into()), + Term::Lambda { + parameter_name, + body, + } => { + if parameter_name.as_ref() != original.as_ref() { + Term::Lambda { + parameter_name: parameter_name.clone(), + body: Rc::new(replace_identity_usage(body.as_ref(), original)), + } + } else { + Term::Lambda { + parameter_name: parameter_name.clone(), + body: body.clone(), + } + } + } + Term::Apply { function, argument } => { + let func = function.as_ref(); + let arg = argument.as_ref(); + + let func = replace_identity_usage(func, original.clone()); + let arg = replace_identity_usage(arg, original.clone()); + + let Term::Var(f) = function.as_ref() + else { + return Term::Apply { function: func.into(), argument: arg.into() } + }; + + if f.as_ref() == original.as_ref() { + arg + } else { + Term::Apply { + function: func.into(), + argument: arg.into(), + } + } + } + Term::Force(x) => Term::Force(Rc::new(replace_identity_usage(x.as_ref(), original))), + x => x.clone(), + } +} + #[cfg(test)] mod test { diff --git a/examples/acceptance_tests/071/plutus.json b/examples/acceptance_tests/071/plutus.json index 4b39fedf..275e4ee3 100644 --- a/examples/acceptance_tests/071/plutus.json +++ b/examples/acceptance_tests/071/plutus.json @@ -19,8 +19,8 @@ "$ref": "#/definitions/spend~1PoolRedeemer" } }, - "compiledCode": "59073201000032323232323232323232323232222323232533300b3232323232323253330123370e90000008992513010007153330123370e9001000899191919299980b19b87480080044c8c8c8c8c8c8c9289811800980c99299980e19b8748000c06c004400454cc07924012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300d0140033021001301732533301a3370e9000180c80088008a9980e24812a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300a012001300848901ff00301e001301400214a0602800266020602401a9001180d0009808003899191919299980b19b87480080044c8c8c8c8c8c8c9289811800980c99299980e19b8748000c06c004400454cc0792412a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300d0140033021001301732533301a3370e9000180c80088008a9980e24812a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300a012001300848901ff00301e001301400214a0602800266020602401a9001180d00098080039808003119ba548000cc05ccdd2a40046602e6ea40052f5c06602e98103d87a80004bd7011198021bac3300d300f3300d300f00248001200423375e6601c6020002900000111198019bac3300c300e3300c300e00248001200023375e6601a601e6601a601e0029001240000046002002444a6660280042980103d87a8000132325333011300300213374a90001980b80125eb804ccc01401400400cc06000cc058008cc01cc0240092000149858cc02cc94ccc02ccdc3a40000022646464646464a66602c6032004266024601200a930a99809a481334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a602e002602e0046eb4c054004c054008c04c004c02401854cc0352412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e74001630090050053300a32533300a3370e9000000899192999808980a00109980699299980699b87480000044c8c94ccc050c05c00852615330114901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a602a00260160042a66601a66e1d200200113232533301430170021330103253330103370e9000000899191919299980c980e00109980a9806001a4c2a6602c9201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a603400260340046030002601c0042a660249212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300e00149854cc045241334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163015001300b0021533300d3370e900200089919299980a180b80109980819299980819b87480000044c8c8c8c94ccc064c0700084cc054c03000d2615330164901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a603400260340046030002601c0042a660249212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300e00149854cc045241334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163015001300b002153300f4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300b00149854cc039241334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564001630120013008004153300c4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e7400163008003003232533300a3370e90000008991919192999809980b0010a4c2a660209201334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c602800260280046eb8c048004c02000854cc0312412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300800133001001480008888cccc01ccdc38008018071199980280299b8000448008c0400040080088c01cdd5000918029baa0015734ae6d5ce2ab9d5573caae7d5d02ba157441", - "hash": "e5eb76a233e7d81172fb991975806b3adcc16ddf1cc3297ab5cf9a7a" + "compiledCode": "590722010000323232323232323232323232222323232533300b3232323232323253330123370e90000008992513010007153330123370e9001000899191919299980b19b87480080044c8c8c8c8c8c8c9289811000980c99299980e19b8748000c06c004400454cc07524012a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300d0140033020001301732533301a3370e9000180c80088008a9980da4812a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300a012001300848901ff00301d001301400214a0602800266020602401a9001180c8009808003899191919299980b19b87480080044c8c8c8c8c8c8c9289811000980c99299980e19b8748000c06c004400454cc0752412a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300d0140033020001301732533301a3370e9000180c80088008a9980da4812a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163300a012001300848901ff00301d001301400214a0602800266020602401a9001180c80098080039808003119ba548000cc058cdd2a40046602c6ea40052f5c06602c98103d87a80004bd7011198021bac3300d300f3300d300f00248001200423375e6601c6020002900000111198019bac3300c300e3300c300e00248001200023375e6601a601e6601a601e0029001240000046002002444a6660260042980103d87a8000132325333011300300213374a90001980b00125eb804ccc01401400400cc05c00cc054008cc01cc0240092000149858c8018c94ccc02ccdc3a40000022646464646464a66602a60300042649318048028a99809249334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a602c002602c0046eb4c050004c050008c048004c02401854cc0312412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e74001630090053200432533300a3370e9000000899192999808180980109924c64a66601a66e1d20000011323253330133016002149854cc041241334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a602800260160042a66601a66e1d20020011323253330133016002132498c94ccc040cdc3a4000002264646464a66603060360042649318060018a9980aa481334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a60320026032004602e002601c0042a660229212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300e00115330104901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163014001300b0021533300d3370e9002000899192999809980b00109924c64a66602066e1d20000011323232325333018301b002132498c03000c54cc055241334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a60320026032004602e002601c0042a660229212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300e00115330104901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163014001300b002153300e4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300b001153300d4901334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e206578706563746564001630110013008004153300b4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e7400163008003232533300a3370e90000008991919192999809180a8010a4c2a6601e921334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375c602600260260046eb8c044004c02000854cc02d2412b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016300800133001001480008888cccc01ccdc38008018069199980280299b8000448008c03c0040080088c018dd5000918021baa0015734ae7155ceaab9e5573eae815d0aba21", + "hash": "b0e1ce90ece6e3bbb745025cce93a6361e1c9f4c06d8cdebd65a5a8a" } ], "definitions": { diff --git a/examples/acceptance_tests/077/plutus.json b/examples/acceptance_tests/077/plutus.json index ca818292..e351dfed 100644 --- a/examples/acceptance_tests/077/plutus.json +++ b/examples/acceptance_tests/077/plutus.json @@ -27,8 +27,8 @@ } } ], - "compiledCode": "5902db0100003232323232323232323232323223222232533300b323232323232323232323232323232533301f30220021323232533301d3370e90000008a99980e9999180080091129998128010a50132325333022300300214a2266600a00a0020066052006604e004016466ebccc068c07000520000171533301d3370e0049001099b8f00301714a02a6603e921254578706563746564206f6e20696e636f727265637420626f6f6c65616e2076617269616e74001616301b012375a603e0046eb8c07400454cc0712401334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e20657870656374656400163020001333232223232533301e3370e90010008a5eb7bdb1804c8dd59813000980e001180e00099801801000980080091129998100010a6103d87a8000132323232533301f3371e00a002266e95200033025374c00497ae01333007007003005375c60420066eacc084008c09000cc088008004020dd5980f000980f000980e800980e000980d8011bac3019001300f005375c602e002601aa66601e66e1d2000300e001100115330114912a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163015001301500230130013009002149858cc02cc94ccc02ccdc3a40000022a66602060120062930a99806a491d4578706563746564206e6f206669656c647320666f7220436f6e73747200161533300b3370e90010008a99980818048018a4c2a6601a92011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300d4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e7400163009002002375c0026600200290001111199980399b8700100300e233330050053370000890011808000801001118039baa001230053754002ae695cdab9c5573aaae7955cfaba05742ae881", - "hash": "8a55b753ccf7071f5549d4ce3896f94f8c4b2bb53fa2bbc812f02f2c" + "compiledCode": "5902d601000032323232323232323232323223222232533300b323232323232323232323232323232533301e30210021323232533301d3370e90000008a99980e9999180080091129998120010a50132325333022300300214a2266600a00a0020066050006604c004016466ebccc068c07000520000171533301d3370e0049001099b8f00301714a02a6603c921254578706563746564206f6e20696e636f727265637420626f6f6c65616e2076617269616e74001616301b012375a603c0046eb8c07000454cc06d2401334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016301f001333232223232533301e3370e90010008a5eb7bdb1804c8dd59812800980e001180e000998018010009800800911299980f8010a6103d87a8000132323232533301f3371e00a002266e95200033024374c00497ae01333007007003005375c60400066eacc080008c08c00cc084008004020dd5980e800980e800980e000980d800980d0011bac3018001300f005375c602c002601aa66601e66e1d2000300e001100115330104912a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e00163014001301400230120013009002149858c800cc94ccc02ccdc3a40000022a66601e60120062930a998062491d4578706563746564206e6f206669656c647320666f7220436f6e73747200161533300b3370e90010008a99980798048018a4c2a6601892011d4578706563746564206e6f206669656c647320666f7220436f6e7374720016153300c4912b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e7400163009002375c0026600200290001111199980399b8700100300d233330050053370000890011807800801001118031baa001230043754002ae695ce2ab9d5573caae7d5d02ba15745", + "hash": "47f04b17991835e079855a20d5c4506bee37d7917260a688ceae8266" } ], "definitions": { diff --git a/examples/acceptance_tests/script_context/plutus.json b/examples/acceptance_tests/script_context/plutus.json index 6a390669..31c557aa 100644 --- a/examples/acceptance_tests/script_context/plutus.json +++ b/examples/acceptance_tests/script_context/plutus.json @@ -36,8 +36,8 @@ "$ref": "#/definitions/Data" } }, - "compiledCode": "5903b2010000323232323232323232323232322223232533300a3230020013301033300a323375e00c0026601693260103d87980004c0103d87a80004c0103d87980003301033300a33232323223232330123253330123370e900000089919299980c980e0010a4c2a6602c921334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a603400260200042a660289212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e740016301000153330113375e98106d8799f182aff0000113370e600800690020a503017001300d3253330103370e9000180780088008a998092492a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001632330050020013237280026ecd300106d8799f182aff0030010012253330130011480004c8cdc02400466006006002602c0026002002444a6660240042980103d87a800013232323253330113371e00a002266e952000330170024bd7009998038038018029bae301300330130023016003301400237566600c60106600c6010006900024028980103d87a80004c0103d87980003301033300a325333010001161325333011001161323232325333010323008001330163330103375e66018601c004900226126d87a9f5820fcaa61fb85676101d9e3398a484674e71c45c3fd41b492682f3b0054f4cf3273ff004c0103d87a80004c0103d8798000330163330103375e66018601c0049003260122d8799f581ce37db487fbd58c45d059bcbf5cd6b1604d3bec16cf888f1395a4ebc4ff004c0103d87a80004c0103d87980004bd7009918040009980b19980819baf3300c300e3300c300e0014800120024c12ad8799fd8799fd8799f581c66666666666666666666666666666666666666666666666666666666ffffff004c0103d87a80004c0103d879800033016333010323253330123370e900200089925130100021630100013300c300e0014801130103d87a80004c0103d87980004bd700a5030160043015004163014001301300137586600c60106600c601000690002400898103d87a80004c0103d87980004bd700a4c2c600200244a66601e00229444c8c94ccc0300084cc010010004528180980119b8748008c034dd5180880099800800a40004444666600e66e1c00400c0388cccc014014cdc00022400460200020040044600e6ea80048c014dd5000ab9a5736ae7155ceaab9e5573eae815d0aba21", - "hash": "619406d554d37e4e1791d2f9e1914fdaef34c398db3b89bb6851be54" + "compiledCode": "5903b1010000323232323232323232323232322223232533300a3230020013301033300a323375e00c0026601693260103d87980004c0103d87a80004c0103d87980003301033300a332323232232323253330123375e98106d8799f182aff0000213370e600a00890020a503253330123370e900000089919299980c980e0010a4c2a6602c921334c6973742f5475706c652f436f6e73747220636f6e7461696e73206d6f7265206974656d73207468616e2065787065637465640016375a603400260200042a660289212b436f6e73747220696e64657820646964206e6f74206d6174636820616e7920747970652076617269616e74001630100013017001300d3253330103370e9000180780088008a9980924812a4578706563746564206f6e20696e636f727265637420636f6e7374727563746f722076617269616e742e001632330050020013237280026ecd300106d8799f182aff0030010012253330130011480004c8cdc02400466006006002602c0026002002444a6660240042980103d87a800013232323253330113371e00a002266e952000330170024bd7009998038038018029bae301300330130023016003301400237566600c60106600c6010006900024028980103d87a80004c0103d87980003301033300a325333010001161325333011001161323232325333010323008001330163330103375e66018601c004900226126d87a9f5820fcaa61fb85676101d9e3398a484674e71c45c3fd41b492682f3b0054f4cf3273ff004c0103d87a80004c0103d8798000330163330103375e66018601c0049003260122d8799f581ce37db487fbd58c45d059bcbf5cd6b1604d3bec16cf888f1395a4ebc4ff004c0103d87a80004c0103d87980004bd7009918040009980b19980819baf3300c300e3300c300e0014800120024c12ad8799fd8799fd8799f581c66666666666666666666666666666666666666666666666666666666ffffff004c0103d87a80004c0103d879800033016333010323253330123370e900200089925130100021630100013300c300e0014801130103d87a80004c0103d87980004bd700a5030160043015004163014001301300137586600c60106600c601000690002400898103d87a80004c0103d87980004bd700a4c2c600200244a66601e00229444c8c94ccc0300084cc010010004528180980119b8748008c034dd5180880099800800a40004444666600e66e1c00400c0388cccc014014cdc00022400460200020040044600e6ea80048c014dd5000ab9a5736ae7155ceaab9e5573eae815d0aba21", + "hash": "a29971e3525c7d2f66af7b40e5cb700aa4fa9fc2dad3ddd078bb2c30" }, { "title": "mint.mint",