diff --git a/extras/dev-shells/build.nix b/extras/dev-shells/build.nix new file mode 100644 index 00000000..32d2f2ed --- /dev/null +++ b/extras/dev-shells/build.nix @@ -0,0 +1,6 @@ +{ + imports = [ + ./plutus-haskell/build.nix + ./prelude-haskell/build.nix + ]; +} diff --git a/extras/dev-shells/plutus-haskell/.envrc b/extras/dev-shells/plutus-haskell/.envrc new file mode 100644 index 00000000..ff23f84e --- /dev/null +++ b/extras/dev-shells/plutus-haskell/.envrc @@ -0,0 +1 @@ +use flake .#dev-plutus-haskell diff --git a/extras/dev-shells/plutus-haskell/build.nix b/extras/dev-shells/plutus-haskell/build.nix new file mode 100644 index 00000000..81769bae --- /dev/null +++ b/extras/dev-shells/plutus-haskell/build.nix @@ -0,0 +1,49 @@ +{ inputs, ... }: +{ + perSystem = { config, system, ... }: + let + hsFlake = inputs.flake-lang.lib.${system}.haskellPlutusFlake { + src = ./.; + + name = "dev-plutus-haskell"; + + inherit (config.settings.haskell) index-state compiler-nix-name; + + dependencies = [ + # Haskell native backend + "${config.packages.lbr-prelude-haskell-src}" + "${config.packages.lbf-prelude-haskell}" + "${config.packages.lbr-plutus-haskell-src}" + "${config.packages.lbf-plutus-haskell}" + + # PlutusTx backend + "${config.packages.lbr-plutustx-src}" + "${config.packages.lbf-plutus-plutustx}" + "${config.packages.lbf-prelude-plutustx}" + + # Plutarch backend + "${config.packages.lbr-plutarch-src}" + "${config.packages.lbf-prelude-plutarch}" + "${config.packages.lbf-plutus-plutarch}" + + # Plutarch itself + "${inputs.plutarch}" + "${inputs.plutarch}/plutarch-extra" + ]; + + devShellTools = config.settings.shell.tools ++ [ + config.packages.lbf-prelude-to-haskell + config.packages.lbf-plutus-to-haskell + config.packages.lbf-plutus-to-plutarch + config.packages.lbf-plutus-to-plutustx + ]; + + devShellHook = config.settings.shell.hook; + }; + in + { + # Develop Plutus applications with Haskell, Plutarch and PlutusTx + devShells.dev-plutus-haskell = hsFlake.devShell; + packages.play-plutus-haskell-lib = hsFlake.packages."plutus-haskell:lib:plutus-haskell"; + }; +} diff --git a/extras/dev-shells/plutus-haskell/cabal.project b/extras/dev-shells/plutus-haskell/cabal.project new file mode 100644 index 00000000..bd0d96f4 --- /dev/null +++ b/extras/dev-shells/plutus-haskell/cabal.project @@ -0,0 +1,3 @@ +packages: ./. + +tests: true diff --git a/extras/dev-shells/plutus-haskell/plutus-haskell.cabal b/extras/dev-shells/plutus-haskell/plutus-haskell.cabal new file mode 100644 index 00000000..6f278b63 --- /dev/null +++ b/extras/dev-shells/plutus-haskell/plutus-haskell.cabal @@ -0,0 +1,109 @@ +cabal-version: 3.0 +name: plutus-haskell +version: 0.1.0.0 +synopsis: Dev shell for LambdaBuffers Plutus Haskell +author: Drazen Popovic +maintainer: bladyjoker@gmail.com + +flag dev + description: Enable non-strict compilation for development + manual: True + +common common-language + ghc-options: + -Wall -Wcompat -fprint-explicit-foralls -fprint-explicit-kinds + -fwarn-missing-import-lists -Weverything -Wno-unsafe + -Wno-missing-safe-haskell-mode -Wno-implicit-prelude + -Wno-missing-kind-signatures -Wno-all-missed-specializations + + if !flag(dev) + ghc-options: -Werror + + default-extensions: + BangPatterns + BinaryLiterals + ConstrainedClassMethods + ConstraintKinds + DataKinds + DeriveAnyClass + DeriveDataTypeable + DeriveFoldable + DeriveFunctor + DeriveGeneric + DeriveLift + DeriveTraversable + DerivingStrategies + DerivingVia + DoAndIfThenElse + DuplicateRecordFields + EmptyCase + EmptyDataDecls + EmptyDataDeriving + ExistentialQuantification + ExplicitForAll + ExplicitNamespaces + FlexibleContexts + FlexibleInstances + ForeignFunctionInterface + GADTSyntax + GeneralizedNewtypeDeriving + HexFloatLiterals + ImportQualifiedPost + InstanceSigs + KindSignatures + LambdaCase + MonomorphismRestriction + MultiParamTypeClasses + NamedFieldPuns + NamedWildCards + NoStarIsType + NumericUnderscores + OverloadedLabels + OverloadedStrings + PackageImports + PartialTypeSignatures + PatternGuards + PolyKinds + PostfixOperators + RankNTypes + RecordWildCards + RelaxedPolyRec + ScopedTypeVariables + StandaloneDeriving + StandaloneKindSignatures + TemplateHaskell + TraditionalRecordSyntax + TupleSections + TypeApplications + TypeFamilies + TypeOperators + TypeSynonymInstances + ViewPatterns + + default-language: Haskell2010 + +library + import: common-language + build-depends: + , aeson >=2.2 + , base >=4.16 + , bytestring >=0.11 + , containers >=0.6 + , lbf-plutus >=0.1 + , lbf-plutus-plutarch >=0.1 + , lbf-plutus-plutustx >=0.1 + , lbf-prelude >=0.1 + , lbf-prelude-plutarch >=0.1 + , lbf-prelude-plutustx >=0.1 + , lbr-plutarch >=0.1 + , lbr-plutus >=0.1 + , lbr-plutustx >=0.1 + , lbr-prelude >=0.1 + , plutarch >=1.5 + , plutarch-extra >=1.2 + , plutus-ledger-api >=1.20 + , plutus-tx >=1.1 + , text >=2.0 + + hs-source-dirs: src + exposed-modules: LambdaBuffers.Plutus.Play diff --git a/extras/dev-shells/plutus-haskell/src/LambdaBuffers/Plutus/Play.hs b/extras/dev-shells/plutus-haskell/src/LambdaBuffers/Plutus/Play.hs new file mode 100644 index 00000000..6494aea6 --- /dev/null +++ b/extras/dev-shells/plutus-haskell/src/LambdaBuffers/Plutus/Play.hs @@ -0,0 +1,26 @@ +module LambdaBuffers.Plutus.Play () where + +import "aeson" Data.Aeson () +import "bytestring" Data.ByteString () +import "containers" Data.Map () +import "containers" Data.Set () +import "lbf-prelude" LambdaBuffers.Prelude () +import "lbr-prelude" LambdaBuffers.Runtime.Prelude () +import "text" Data.Text () + +import "lbf-plutus" LambdaBuffers.Plutus.V1 () +import "lbr-plutus" LambdaBuffers.Runtime.Plutus () + +import "lbf-plutus-plutustx" LambdaBuffers.Plutus.V1.PlutusTx () +import "lbf-plutus-plutustx" LambdaBuffers.Plutus.V2.PlutusTx () +import "lbf-prelude-plutustx" LambdaBuffers.Prelude.PlutusTx () +import "lbr-plutustx" LambdaBuffers.Runtime.PlutusTx.List () +import "plutus-ledger-api" PlutusLedgerApi.Common () +import "plutus-tx" PlutusTx () + +import "lbf-plutus-plutarch" LambdaBuffers.Plutus.V1.Plutarch () +import "lbf-plutus-plutarch" LambdaBuffers.Plutus.V2.Plutarch () +import "lbf-prelude-plutarch" LambdaBuffers.Prelude.Plutarch () +import "lbr-plutarch" LambdaBuffers.Runtime.Plutarch () +import "plutarch" Plutarch () +import "plutarch-extra" Plutarch.Extra () diff --git a/extras/dev-shells/prelude-haskell/.envrc b/extras/dev-shells/prelude-haskell/.envrc new file mode 100644 index 00000000..725bf92f --- /dev/null +++ b/extras/dev-shells/prelude-haskell/.envrc @@ -0,0 +1 @@ +use flake .#dev-prelude-haskell diff --git a/extras/dev-shells/prelude-haskell/build.nix b/extras/dev-shells/prelude-haskell/build.nix new file mode 100644 index 00000000..aec16d70 --- /dev/null +++ b/extras/dev-shells/prelude-haskell/build.nix @@ -0,0 +1,27 @@ +{ inputs, ... }: +{ + perSystem = { config, system, ... }: + let + hsFlake = inputs.flake-lang.lib.${system}.haskellFlake { + src = ./.; + + name = "dev-prelude-haskell"; + + inherit (config.settings.haskell) index-state compiler-nix-name; + + dependencies = [ + "${config.packages.lbr-prelude-haskell-src}" + "${config.packages.lbf-prelude-haskell}" + ]; + + devShellTools = config.settings.shell.tools ++ [ config.packages.lbf-prelude-to-haskell ]; + devShellHook = config.settings.shell.hook; + }; + in + { + # Develop Prelude applications with Haskell + devShells.dev-prelude-haskell = hsFlake.devShell; + packages.play-prelude-haskell-lib = hsFlake.packages."prelude-haskell:lib:prelude-haskell"; + }; +} + diff --git a/extras/dev-shells/prelude-haskell/cabal.project b/extras/dev-shells/prelude-haskell/cabal.project new file mode 100644 index 00000000..bd0d96f4 --- /dev/null +++ b/extras/dev-shells/prelude-haskell/cabal.project @@ -0,0 +1,3 @@ +packages: ./. + +tests: true diff --git a/extras/dev-shells/prelude-haskell/prelude-haskell.cabal b/extras/dev-shells/prelude-haskell/prelude-haskell.cabal new file mode 100644 index 00000000..6c014095 --- /dev/null +++ b/extras/dev-shells/prelude-haskell/prelude-haskell.cabal @@ -0,0 +1,97 @@ +cabal-version: 3.0 +name: prelude-haskell +version: 0.1.0.0 +synopsis: Dev shell for LambdaBuffers Prelude Haskell +author: Drazen Popovic +maintainer: bladyjoker@gmail.com + +flag dev + description: Enable non-strict compilation for development + manual: True + +common common-language + ghc-options: + -Wall -Wcompat -fprint-explicit-foralls -fprint-explicit-kinds + -fwarn-missing-import-lists -Weverything -Wno-unsafe + -Wno-missing-safe-haskell-mode -Wno-implicit-prelude + -Wno-missing-kind-signatures -Wno-all-missed-specializations + + if !flag(dev) + ghc-options: -Werror + + default-extensions: + BangPatterns + BinaryLiterals + ConstrainedClassMethods + ConstraintKinds + DataKinds + DeriveAnyClass + DeriveDataTypeable + DeriveFoldable + DeriveFunctor + DeriveGeneric + DeriveLift + DeriveTraversable + DerivingStrategies + DerivingVia + DoAndIfThenElse + DuplicateRecordFields + EmptyCase + EmptyDataDecls + EmptyDataDeriving + ExistentialQuantification + ExplicitForAll + ExplicitNamespaces + FlexibleContexts + FlexibleInstances + ForeignFunctionInterface + GADTSyntax + GeneralizedNewtypeDeriving + HexFloatLiterals + ImportQualifiedPost + InstanceSigs + KindSignatures + LambdaCase + MonomorphismRestriction + MultiParamTypeClasses + NamedFieldPuns + NamedWildCards + NoStarIsType + NumericUnderscores + OverloadedLabels + OverloadedStrings + PackageImports + PartialTypeSignatures + PatternGuards + PolyKinds + PostfixOperators + RankNTypes + RecordWildCards + RelaxedPolyRec + ScopedTypeVariables + StandaloneDeriving + StandaloneKindSignatures + TemplateHaskell + TraditionalRecordSyntax + TupleSections + TypeApplications + TypeFamilies + TypeOperators + TypeSynonymInstances + ViewPatterns + + default-language: Haskell2010 + +library + import: common-language + build-depends: + , aeson >=2.2 + , base >=4.16 + , bytestring >=0.11 + , containers >=0.6 + , lbf-prelude >=0.1 + , lbr-prelude >=0.1 + , text >=2.0 + + hs-source-dirs: src + exposed-modules: LambdaBuffers.Prelude.Play diff --git a/extras/dev-shells/prelude-haskell/src/LambdaBuffers/Prelude/Play.hs b/extras/dev-shells/prelude-haskell/src/LambdaBuffers/Prelude/Play.hs new file mode 100644 index 00000000..c1483992 --- /dev/null +++ b/extras/dev-shells/prelude-haskell/src/LambdaBuffers/Prelude/Play.hs @@ -0,0 +1,9 @@ +module LambdaBuffers.Prelude.Play () where + +import "aeson" Data.Aeson () +import "bytestring" Data.ByteString () +import "containers" Data.Map () +import "containers" Data.Set () +import "lbf-prelude" LambdaBuffers.Prelude () +import "lbr-prelude" LambdaBuffers.Runtime.Prelude () +import "text" Data.Text () diff --git a/extras/lbf-nix/build.nix b/extras/lbf-nix/build.nix index c6f5f69a..994dbd9c 100644 --- a/extras/lbf-nix/build.nix +++ b/extras/lbf-nix/build.nix @@ -4,6 +4,7 @@ lbg-haskell = "${config.packages.lbg-haskell}/bin/lbg-haskell"; lbg-typescript = "${config.packages.lbg-typescript}/bin/lbg-typescript"; lbg-plutarch = "${config.packages.lbg-plutarch}/bin/lbg-plutarch"; + lbg-plutustx = "${config.packages.lbg-plutustx}/bin/lbg-plutustx"; lbg-purescript = "${config.packages.lbg-purescript}/bin/lbg-purescript"; lbg-rust = "${config.packages.lbg-rust}/bin/lbg-rust"; @@ -14,9 +15,11 @@ lbfBuild = import ./lbf-build.nix pkgs config.packages.lbf; lbfHaskell = import ./lbf-haskell.nix pkgs config.packages.lbf lbg-haskell; lbfPreludeHaskell = import ./lbf-prelude-hs.nix pkgs config.packages.lbf lbg-haskell; - lbfPlutusHaskell = import ./lbf-plutus-hs-plutustx.nix pkgs config.packages.lbf lbg-haskell; - lbfPlutarch' = import ./lbf-plutarch.nix pkgs config.packages.lbf lbg-plutarch; - lbfPlutarch = import ./lbf-plutus-plutarch.nix pkgs config.packages.lbf lbg-plutarch; + lbfPlutusHaskell = import ./lbf-plutus-hs.nix pkgs config.packages.lbf lbg-haskell; + lbfPlutarchBase = import ./lbf-plutarch-base.nix pkgs config.packages.lbf lbg-plutarch; + lbfPlutarch = import ./lbf-plutarch.nix pkgs config.packages.lbf lbg-plutarch; + lbfPlutusTxBase = import ./lbf-plutustx-base.nix pkgs config.packages.lbf lbg-plutustx; + lbfPlutusTx = import ./lbf-plutustx.nix pkgs config.packages.lbf lbg-plutustx; lbfPurescript = import ./lbf-purescript.nix pkgs config.packages.lbf lbg-purescript; lbfPreludePurescript = import ./lbf-prelude-purescript.nix pkgs config.packages.lbf lbg-purescript; lbfPlutusPurescript = import ./lbf-plutus-purescript.nix pkgs config.packages.lbf lbg-purescript; diff --git a/extras/lbf-nix/lbf-plutarch-base.nix b/extras/lbf-nix/lbf-plutarch-base.nix new file mode 100644 index 00000000..81c75bf7 --- /dev/null +++ b/extras/lbf-nix/lbf-plutarch-base.nix @@ -0,0 +1,3 @@ +# Build .lbf schemas and generate Haskell's Plutarch library. +pkgs: lbf: lbg-plutarch: lbfPlutarchOpts: +import ./lbf-haskell.nix pkgs lbf lbg-plutarch lbfPlutarchOpts diff --git a/extras/lbf-nix/lbf-plutarch.nix b/extras/lbf-nix/lbf-plutarch.nix index 81c75bf7..31a27c3c 100644 --- a/extras/lbf-nix/lbf-plutarch.nix +++ b/extras/lbf-nix/lbf-plutarch.nix @@ -1,3 +1,28 @@ -# Build .lbf schemas and generate Haskell's Plutarch library. +# Build .lbf schemas that use LB Plutus (and by extension LB Prelude) package and targets Haskell's Plutarch library. pkgs: lbf: lbg-plutarch: lbfPlutarchOpts: -import ./lbf-haskell.nix pkgs lbf lbg-plutarch lbfPlutarchOpts +let + utils = import ./utils.nix pkgs; + + lbfPlutarch = import ./lbf-plutarch-base.nix pkgs lbf lbg-plutarch; + lbfPlutarchOptsForPlutus = utils.overrideAttrs + { + imports = { + default = [ ]; + override = libs: libs ++ [ ../../libs/lbf-prelude ../../libs/lbf-plutus ]; + }; + dependencies = { + default = [ ]; + override = deps: deps ++ [ "lbf-prelude-plutarch" "lbf-plutus-plutarch" ]; + }; + classes = { + default = [ ]; + override = cls: cls ++ [ "Prelude.Eq" "Plutus.V1.PlutusData" ]; + }; + configs = { + default = [ ]; + override = _: [ ../../lambda-buffers-codegen/data/plutarch-prelude.json ../../lambda-buffers-codegen/data/plutarch-plutus.json ]; + }; + } + lbfPlutarchOpts; +in +lbfPlutarch lbfPlutarchOptsForPlutus diff --git a/extras/lbf-nix/lbf-plutus-hs-plutustx.nix b/extras/lbf-nix/lbf-plutus-hs.nix similarity index 100% rename from extras/lbf-nix/lbf-plutus-hs-plutustx.nix rename to extras/lbf-nix/lbf-plutus-hs.nix diff --git a/extras/lbf-nix/lbf-plutus-plutarch.nix b/extras/lbf-nix/lbf-plutus-plutarch.nix deleted file mode 100644 index 4ec74b93..00000000 --- a/extras/lbf-nix/lbf-plutus-plutarch.nix +++ /dev/null @@ -1,28 +0,0 @@ -# Build .lbf schemas that use LB Plutus (and by extension LB Prelude) package and targets Haskell's Plutarch library. -pkgs: lbf: lbg-plutarch: lbfPlutarchOpts: -let - utils = import ./utils.nix pkgs; - - lbfPlutarch = import ./lbf-plutarch.nix pkgs lbf lbg-plutarch; - lbfPlutarchOptsForPlutus = utils.overrideAttrs - { - imports = { - default = [ ]; - override = libs: libs ++ [ ../../libs/lbf-prelude ../../libs/lbf-plutus ]; - }; - dependencies = { - default = [ ]; - override = deps: deps ++ [ "lbf-prelude-plutarch" "lbf-plutus-plutarch" ]; - }; - classes = { - default = [ ]; - override = cls: cls ++ [ "Prelude.Eq" "Plutus.V1.PlutusData" ]; - }; - configs = { - default = [ ]; - override = _: [ ../../lambda-buffers-codegen/data/plutarch-prelude.json ../../lambda-buffers-codegen/data/plutarch-plutus.json ]; - }; - } - lbfPlutarchOpts; -in -lbfPlutarch lbfPlutarchOptsForPlutus diff --git a/extras/lbf-nix/lbf-plutustx-base.nix b/extras/lbf-nix/lbf-plutustx-base.nix new file mode 100644 index 00000000..f6f8e016 --- /dev/null +++ b/extras/lbf-nix/lbf-plutustx-base.nix @@ -0,0 +1,3 @@ +# Build .lbf schemas and generate Haskell's PlutusTX library. +pkgs: lbf: lbg-plutustx: lbfPlutusTxOpts: +import ./lbf-haskell.nix pkgs lbf lbg-plutustx lbfPlutusTxOpts diff --git a/extras/lbf-nix/lbf-plutustx.nix b/extras/lbf-nix/lbf-plutustx.nix new file mode 100644 index 00000000..31ba0a00 --- /dev/null +++ b/extras/lbf-nix/lbf-plutustx.nix @@ -0,0 +1,28 @@ +# Build .lbf schemas that use LB Plutus (and by extension LB Prelude) package and targets Haskell's PlutusTx language (not library). +pkgs: lbf: lbg-plutustx: lbfPlutusTxOpts: +let + utils = import ./utils.nix pkgs; + + lbfPlutusTx = import ./lbf-plutustx-base.nix pkgs lbf lbg-plutustx; + lbfPlutusTxOptsForPlutus = utils.overrideAttrs + { + imports = { + default = [ ]; + override = libs: libs ++ [ ../../libs/lbf-prelude ../../libs/lbf-plutus ]; + }; + dependencies = { + default = [ ]; + override = deps: deps ++ [ "lbf-prelude-plutustx" "lbf-plutus-plutustx" ]; + }; + classes = { + default = [ ]; + override = cls: cls ++ [ "Prelude.Eq" "Plutus.V1.PlutusData" ]; + }; + configs = { + default = [ ]; + override = _: [ ../../lambda-buffers-codegen/data/plutustx-prelude.json ../../lambda-buffers-codegen/data/plutustx-plutus.json ]; + }; + } + lbfPlutusTxOpts; +in +lbfPlutusTx lbfPlutusTxOptsForPlutus diff --git a/flake.lock b/flake.lock index 207b3d43..f7d1a0cc 100644 --- a/flake.lock +++ b/flake.lock @@ -39107,11 +39107,11 @@ "prelude-typescript": "prelude-typescript_3" }, "locked": { - "lastModified": 1709976751, - "narHash": "sha256-UazLkZZRSQBqQW/8p5cPhfivDOSYsNMw84niTRm616o=", + "lastModified": 1718984225, + "narHash": "sha256-u2/7Z4WvGYa4NeVt+vYl3MVn+yMMlvM4atvA7ifyEpg=", "owner": "mlabs-haskell", "repo": "plutus-ledger-api-typescript", - "rev": "609e447fcf440c3f35fd078f37f0877840c926b8", + "rev": "f601bc2b13c6866641a009e869586ce90138e7c7", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index fe9f8d08..f91b37d4 100644 --- a/flake.nix +++ b/flake.nix @@ -49,6 +49,7 @@ ./docs/plutarch/build.nix ./extras/build.nix ./extras/lbf-nix/build.nix + ./extras/dev-shells/build.nix ./libs/build.nix ./api/build.nix ./lambda-buffers-compiler/build.nix @@ -56,6 +57,7 @@ ./lambda-buffers-frontend/build.nix ./runtimes/haskell/lbr-prelude/build.nix ./runtimes/haskell/lbr-plutus/build.nix + ./runtimes/haskell/lbr-plutustx/build.nix ./runtimes/haskell/lbr-plutarch/build.nix ./runtimes/purescript/lbr-prelude/build.nix ./runtimes/purescript/lbr-plutus/build.nix @@ -75,6 +77,7 @@ ./testsuites/lbt-plutus/lbt-plutus-purescript/build.nix ./testsuites/lbt-plutus/lbt-plutus-typescript/build.nix ./testsuites/lbt-plutus/lbt-plutus-plutarch/build.nix + ./testsuites/lbt-plutus/lbt-plutus-plutustx/build.nix ./testsuites/lbt-plutus/lbt-plutus-rust/build.nix ./experimental/build.nix ./docs/typescript-prelude/build.nix diff --git a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/Gen.hs b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/Gen.hs index 2112fa06..20bc4563 100644 --- a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/Gen.hs +++ b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/Gen.hs @@ -31,12 +31,12 @@ import System.FilePath (takeDirectory, ()) import System.FilePath.Lens (extension) data GenOpts = GenOpts - { _inputFile :: FilePath - , _outputFile :: FilePath - , _genDir :: FilePath - , _debug :: Bool - , _requestedClasses :: [String] - , _requestedModules :: NonEmpty String + { _inputFile :: !FilePath + , _outputFile :: !FilePath + , _genDir :: !FilePath + , _debug :: !Bool + , _requestedClasses :: ![String] + , _requestedModules :: !(NonEmpty String) } deriving stock (Eq, Show) @@ -51,9 +51,9 @@ logError "" msg = putStrLn $ msg <> " [ERROR]" logError fp msg = putStrLn $ fp <> ": " <> msg <> " [ERROR]" data Generated = Generated - { _generatedFilePath :: FilePath - , _generatedCode :: Text - , _generatedPackageDeps :: Set Text + { _generatedFilePath :: !FilePath + , _generatedCode :: !Text + , _generatedPackageDeps :: !(Set Text) } deriving stock (Show, Eq, Ord) diff --git a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenHaskell.hs b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenHaskell.hs index 0bf783d9..8f4c63bf 100644 --- a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenHaskell.hs +++ b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenHaskell.hs @@ -5,15 +5,15 @@ import Control.Monad (unless) import Data.Aeson (decodeFileStrict') import LambdaBuffers.Codegen.Cli.Gen (logError) import LambdaBuffers.Codegen.Cli.Gen qualified as Gen -import LambdaBuffers.Codegen.Haskell (runPrint) +import LambdaBuffers.Codegen.Haskell (runBackend) import LambdaBuffers.Codegen.Haskell.Config qualified as H import Paths_lambda_buffers_codegen qualified as Paths import System.Directory (doesFileExist) import System.Directory.Internal.Prelude (exitFailure) data GenOpts = MkGenOpts - { _config :: [FilePath] - , _common :: Gen.GenOpts + { _config :: ![FilePath] + , _common :: !Gen.GenOpts } makeLenses 'MkGenOpts @@ -30,7 +30,7 @@ gen opts = do Gen.gen (opts ^. common) - (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runPrint cfg ci <$> (ci ^. #modules)) + (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runBackend cfg ci <$> (ci ^. #modules)) readHaskellConfig :: FilePath -> IO H.Config readHaskellConfig f = do diff --git a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPlutarch.hs b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPlutarch.hs index 870e52e0..83e8e395 100644 --- a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPlutarch.hs +++ b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPlutarch.hs @@ -11,8 +11,8 @@ import System.Directory (doesFileExist) import System.Directory.Internal.Prelude (exitFailure) data GenOpts = MkGenOpts - { _config :: [FilePath] - , _common :: Gen.GenOpts + { _config :: ![FilePath] + , _common :: !Gen.GenOpts } makeLenses 'MkGenOpts @@ -29,7 +29,7 @@ gen opts = do Gen.gen (opts ^. common) - (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . Plutarch.runPrint cfg ci <$> (ci ^. #modules)) + (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . Plutarch.runBackend cfg ci <$> (ci ^. #modules)) readPlutarchConfig :: FilePath -> IO Haskell.Config readPlutarchConfig f = do diff --git a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPlutusTx.hs b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPlutusTx.hs new file mode 100644 index 00000000..58f941c4 --- /dev/null +++ b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPlutusTx.hs @@ -0,0 +1,48 @@ +module LambdaBuffers.Codegen.Cli.GenPlutusTx (GenOpts (..), gen) where + +import Control.Lens (makeLenses, (^.)) +import Control.Monad (unless) +import Data.Aeson (decodeFileStrict') +import LambdaBuffers.Codegen.Cli.Gen (logError) +import LambdaBuffers.Codegen.Cli.Gen qualified as Gen +import LambdaBuffers.Codegen.Haskell.Config qualified as Haskell +import LambdaBuffers.Codegen.PlutusTx qualified as PlutusTx +import System.Directory (doesFileExist) +import System.Directory.Internal.Prelude (exitFailure) + +data GenOpts = MkGenOpts + { _config :: ![FilePath] + , _common :: !Gen.GenOpts + } + +makeLenses 'MkGenOpts + +gen :: GenOpts -> IO () +gen opts = do + cfg <- case opts ^. config of + [] -> do + logError "" "No PlutusTx configuration file given" + exitFailure + fps -> do + cfgs <- traverse readPlutusTxConfig fps + return (mconcat cfgs) + + Gen.gen + (opts ^. common) + (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . PlutusTx.runBackend cfg ci <$> (ci ^. #modules)) + +readPlutusTxConfig :: FilePath -> IO Haskell.Config +readPlutusTxConfig f = do + fExists <- doesFileExist f + unless + fExists + ( do + logError "" $ "Provided PlutusTx Codegen configuration file doesn't exists: " <> f + exitFailure + ) + mayCfg <- decodeFileStrict' f + case mayCfg of + Nothing -> do + logError "" $ "Invalid PlutusTx configuration file " <> f + exitFailure + Just cfg -> return cfg diff --git a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPurescript.hs b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPurescript.hs index 9280755c..0e3d7d3a 100644 --- a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPurescript.hs +++ b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenPurescript.hs @@ -5,15 +5,15 @@ import Control.Monad (unless) import Data.Aeson (decodeFileStrict) import LambdaBuffers.Codegen.Cli.Gen (logError) import LambdaBuffers.Codegen.Cli.Gen qualified as Gen -import LambdaBuffers.Codegen.Purescript (runPrint) +import LambdaBuffers.Codegen.Purescript (runBackend) import LambdaBuffers.Codegen.Purescript.Config qualified as H import Paths_lambda_buffers_codegen qualified as Paths import System.Directory (doesFileExist) import System.Exit (exitFailure) data GenOpts = MkGenOpts - { _config :: [FilePath] - , _common :: Gen.GenOpts + { _config :: ![FilePath] + , _common :: !Gen.GenOpts } makeLenses 'MkGenOpts @@ -30,7 +30,7 @@ gen opts = do Gen.gen (opts ^. common) - (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runPrint cfg ci <$> (ci ^. #modules)) + (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runBackend cfg ci <$> (ci ^. #modules)) readPurescriptConfig :: FilePath -> IO H.Config readPurescriptConfig f = do diff --git a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenRust.hs b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenRust.hs index f5af384c..0d9ef78b 100644 --- a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenRust.hs +++ b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenRust.hs @@ -6,7 +6,7 @@ import Data.Aeson (decodeFileStrict') import Debug.Trace (trace) import LambdaBuffers.Codegen.Cli.Gen (logError) import LambdaBuffers.Codegen.Cli.Gen qualified as Gen -import LambdaBuffers.Codegen.Rust (runPrint) +import LambdaBuffers.Codegen.Rust (runBackend) import LambdaBuffers.Codegen.Rust.Config qualified as R import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as RS import Paths_lambda_buffers_codegen qualified as Paths @@ -14,9 +14,9 @@ import System.Directory (doesFileExist) import System.Directory.Internal.Prelude (exitFailure) data GenOpts = MkGenOpts - { _config :: [FilePath] - , _packages :: FilePath - , _common :: Gen.GenOpts + { _config :: ![FilePath] + , _packages :: !FilePath + , _common :: !Gen.GenOpts } makeLenses 'MkGenOpts @@ -36,7 +36,7 @@ gen opts = do Gen.gen (opts ^. common) - (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runPrint cfg pkgs ci <$> (ci ^. #modules)) + (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runBackend pkgs cfg ci <$> (ci ^. #modules)) readRustConfig :: FilePath -> IO R.Config readRustConfig f = do diff --git a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenTypescript.hs b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenTypescript.hs index 69d5cc27..0155881e 100644 --- a/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenTypescript.hs +++ b/lambda-buffers-codegen/app/LambdaBuffers/Codegen/Cli/GenTypescript.hs @@ -5,7 +5,7 @@ import Control.Monad (unless) import Data.Aeson (decodeFileStrict') import LambdaBuffers.Codegen.Cli.Gen (logError) import LambdaBuffers.Codegen.Cli.Gen qualified as Gen -import LambdaBuffers.Codegen.Typescript (runPrint) +import LambdaBuffers.Codegen.Typescript (runBackend) import LambdaBuffers.Codegen.Typescript.Config qualified as H import LambdaBuffers.Codegen.Typescript.Syntax qualified as Typescript.Syntax import Paths_lambda_buffers_codegen qualified as Paths @@ -13,9 +13,9 @@ import System.Directory (doesFileExist) import System.Exit (exitFailure) data GenOpts = MkGenOpts - { _config :: [FilePath] - , _packages :: FilePath - , _common :: Gen.GenOpts + { _config :: ![FilePath] + , _packages :: !FilePath + , _common :: !Gen.GenOpts } makeLenses 'MkGenOpts @@ -34,7 +34,7 @@ gen opts = do Gen.gen (opts ^. common) - (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runPrint cfg pkgs ci <$> (ci ^. #modules)) + (\ci -> fmap (\(fp, code, deps) -> Gen.Generated fp code deps) . runBackend cfg pkgs ci <$> (ci ^. #modules)) readTypescriptConfig :: FilePath -> IO H.Config readTypescriptConfig f = do diff --git a/lambda-buffers-codegen/app/Main.hs b/lambda-buffers-codegen/app/Main.hs index 6fbba1d2..33727a52 100644 --- a/lambda-buffers-codegen/app/Main.hs +++ b/lambda-buffers-codegen/app/Main.hs @@ -5,6 +5,7 @@ import GHC.IO.Encoding (setLocaleEncoding, utf8) import LambdaBuffers.Codegen.Cli.Gen (GenOpts (GenOpts)) import LambdaBuffers.Codegen.Cli.GenHaskell qualified as Haskell import LambdaBuffers.Codegen.Cli.GenPlutarch qualified as Plutarch +import LambdaBuffers.Codegen.Cli.GenPlutusTx qualified as PlutusTx import LambdaBuffers.Codegen.Cli.GenPurescript qualified as Purescript import LambdaBuffers.Codegen.Cli.GenRust qualified as Rust import LambdaBuffers.Codegen.Cli.GenTypescript qualified as Typescript @@ -40,6 +41,7 @@ data Command | GenTypescript Typescript.GenOpts | GenPlutarch Plutarch.GenOpts | GenRust Rust.GenOpts + | GenPlutusTx PlutusTx.GenOpts genOptsP :: Parser GenOpts genOptsP = @@ -138,6 +140,19 @@ plutarchGenOptsP = ) <*> genOptsP +plutusTxGenOptsP :: Parser PlutusTx.GenOpts +plutusTxGenOptsP = + PlutusTx.MkGenOpts + <$> many + ( strOption + ( long "config" + <> short 'c' + <> metavar "FILEPATH" + <> help "Configuration file for the PlutusTx Codegen module (multiple `config`s are merged with left first merge conflict strategy)" + ) + ) + <*> genOptsP + rustGenOptsP :: Parser Rust.GenOpts rustGenOptsP = Rust.MkGenOpts @@ -198,6 +213,12 @@ commandP = (GenRust <$> (helper *> rustGenOptsP)) (mkProgDesc "Rust") ) + <> command + "gen-plutustx" + ( info + (GenPlutusTx <$> (helper *> plutusTxGenOptsP)) + (mkProgDesc "PlutusTx") + ) parserInfo :: ParserInfo Command parserInfo = info (commandP <**> helper) (fullDesc <> progDesc "LambdaBuffers Codegen command-line interface tool") @@ -212,3 +233,4 @@ main = do GenTypescript opts -> Typescript.gen opts GenPlutarch opts -> Plutarch.gen opts GenRust opts -> Rust.gen opts + GenPlutusTx opts -> PlutusTx.gen opts diff --git a/lambda-buffers-codegen/build.nix b/lambda-buffers-codegen/build.nix index 373ce101..3811784f 100644 --- a/lambda-buffers-codegen/build.nix +++ b/lambda-buffers-codegen/build.nix @@ -45,6 +45,9 @@ lbg-plutarch = pkgs.writeShellScriptBin "lbg-plutarch" '' ${config.packages.lbg}/bin/lbg gen-plutarch $@ ''; + lbg-plutustx = pkgs.writeShellScriptBin "lbg-plutustx" '' + ${config.packages.lbg}/bin/lbg gen-plutustx $@ + ''; lbg-typescript = pkgs.writeShellScriptBin "lbg-typescript" '' ${config.packages.lbg}/bin/lbg gen-typescript $@ ''; diff --git a/lambda-buffers-codegen/data/haskell-plutus-plutustx.json b/lambda-buffers-codegen/data/haskell-plutus-plutustx.json index 563ed41c..0f89e70f 100644 --- a/lambda-buffers-codegen/data/haskell-plutus-plutustx.json +++ b/lambda-buffers-codegen/data/haskell-plutus-plutustx.json @@ -150,31 +150,16 @@ "PlutusTx.AssocMap", "Map" ], - "Plutus.V1.Todo.DCert": [ - "plutus-ledger-api", - "PlutusLedgerApi.V1.DCert", - "DCert" - ], - "Plutus.V1.Todo.ScriptContext": [ + "Plutus.V1.ScriptContext": [ "plutus-ledger-api", "PlutusLedgerApi.V1.Contexts", "ScriptContext" ], - "Plutus.V1.Todo.ScriptPurpose": [ + "Plutus.V1.ScriptPurpose": [ "plutus-ledger-api", "PlutusLedgerApi.V1.Contexts", "ScriptPurpose" ], - "Plutus.V1.Todo.TxInInfo": [ - "plutus-ledger-api", - "PlutusLedgerApi.V1.Contexts", - "TxInInfo" - ], - "Plutus.V1.Todo.TxInfo": [ - "plutus-ledger-api", - "PlutusLedgerApi.V1.Contexts", - "TxInfo" - ], "Plutus.V2.TxInInfo": [ "plutus-ledger-api", "PlutusLedgerApi.V2.Contexts", @@ -190,25 +175,18 @@ "PlutusLedgerApi.V2.Tx", "TxOut" ], - "Plutus.V2.Todo.ScriptContext": [ + "Plutus.V2.ScriptContext": [ "plutus-ledger-api", "PlutusLedgerApi.V2.Contexts", "ScriptContext" ], - "Plutus.V2.Todo.TxInfo": [ + "Plutus.V2.TxInfo": [ "plutus-ledger-api", "PlutusLedgerApi.V2.Contexts", "TxInfo" ] }, "classesConfig": { - "Prelude.Eq": [ - [ - "plutus-tx", - "PlutusTx.Eq", - "Eq" - ] - ], "Plutus.V1.PlutusData": [ [ "plutus-tx", diff --git a/lambda-buffers-codegen/data/plutarch-plutus.json b/lambda-buffers-codegen/data/plutarch-plutus.json index 88bf778c..9a8cd32f 100644 --- a/lambda-buffers-codegen/data/plutarch-plutus.json +++ b/lambda-buffers-codegen/data/plutarch-plutus.json @@ -125,11 +125,6 @@ "Plutarch.Api.V1", "PTxInInfo" ], - "Plutus.V1.TxInfo": [ - "plutarch", - "Plutarch.Api.V1", - "PTxInfo" - ], "Plutus.V1.TxId": [ "plutarch", "Plutarch.Api.V1", @@ -150,6 +145,11 @@ "LambdaBuffers.Runtime.Plutarch", "PMap" ], + "Plutus.V1.TxInfo": [ + "plutarch", + "Plutarch.Api.V1", + "PTxInfo" + ], "Plutus.V2.TxInInfo": [ "plutarch", "Plutarch.Api.V2", @@ -164,6 +164,16 @@ "plutarch", "Plutarch.Api.V2", "PTxOut" + ], + "Plutus.V2.TxInfo": [ + "plutarch", + "Plutarch.Api.V2", + "PTxInfo" + ], + "Plutus.V2.ScriptContext": [ + "plutarch", + "Plutarch.Api.V2", + "PScriptContext" ] }, "classesConfig": { diff --git a/lambda-buffers-codegen/data/plutustx-plutus.json b/lambda-buffers-codegen/data/plutustx-plutus.json new file mode 100644 index 00000000..ac746efe --- /dev/null +++ b/lambda-buffers-codegen/data/plutustx-plutus.json @@ -0,0 +1,193 @@ +{ + "opaquesConfig": { + "Plutus.V1.PlutusData": [ + "plutus-tx", + "PlutusTx.Builtins", + "BuiltinData" + ], + "Plutus.V1.Address": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Address", + "Address" + ], + "Plutus.V1.Credential": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Credential", + "Credential" + ], + "Plutus.V1.StakingCredential": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Credential", + "StakingCredential" + ], + "Plutus.V1.PubKeyHash": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Crypto", + "PubKeyHash" + ], + "Plutus.V1.DCert": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.DCert", + "DCert" + ], + "Plutus.V1.Bytes": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Bytes", + "LedgerBytes" + ], + "Plutus.V1.Interval": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Interval", + "Interval" + ], + "Plutus.V1.Extended": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Interval", + "Extended" + ], + "Plutus.V1.LowerBound": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Interval", + "LowerBound" + ], + "Plutus.V1.UpperBound": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Interval", + "UpperBound" + ], + "Plutus.V1.POSIXTime": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Time", + "POSIXTime" + ], + "Plutus.V1.POSIXTimeRange": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Time", + "POSIXTimeRange" + ], + "Plutus.V1.Value": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Value", + "Value" + ], + "Plutus.V1.CurrencySymbol": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Value", + "CurrencySymbol" + ], + "Plutus.V1.AssetClass": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Value", + "AssetClass" + ], + "Plutus.V1.TokenName": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Value", + "TokenName" + ], + "Plutus.V1.Redeemer": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Scripts", + "Redeemer" + ], + "Plutus.V1.Datum": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Scripts", + "Datum" + ], + "Plutus.V1.DatumHash": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Scripts", + "DatumHash" + ], + "Plutus.V1.RedeemerHash": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Scripts", + "RedeemerHash" + ], + "Plutus.V1.ScriptHash": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Scripts", + "ScriptHash" + ], + "Plutus.V1.ScriptContext": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Contexts", + "ScriptContext" + ], + "Plutus.V1.ScriptPurpose": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Contexts", + "ScriptPurpose" + ], + "Plutus.V1.TxInInfo": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Contexts", + "TxInInfo" + ], + "Plutus.V1.TxInfo": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Contexts", + "TxInfo" + ], + "Plutus.V1.TxId": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Tx", + "TxId" + ], + "Plutus.V1.TxOut": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Tx", + "TxOut" + ], + "Plutus.V1.TxOutRef": [ + "plutus-ledger-api", + "PlutusLedgerApi.V1.Tx", + "TxOutRef" + ], + "Plutus.V1.Map": [ + "plutus-tx", + "PlutusTx.AssocMap", + "Map" + ], + "Plutus.V2.TxInInfo": [ + "plutus-ledger-api", + "PlutusLedgerApi.V2.Contexts", + "TxInInfo" + ], + "Plutus.V2.OutputDatum": [ + "plutus-ledger-api", + "PlutusLedgerApi.V2.Tx", + "OutputDatum" + ], + "Plutus.V2.TxOut": [ + "plutus-ledger-api", + "PlutusLedgerApi.V2.Tx", + "TxOut" + ], + "Plutus.V2.ScriptContext": [ + "plutus-ledger-api", + "PlutusLedgerApi.V2.Contexts", + "ScriptContext" + ], + "Plutus.V2.TxInfo": [ + "plutus-ledger-api", + "PlutusLedgerApi.V2.Contexts", + "TxInfo" + ] + }, + "classesConfig": { + "Plutus.V1.PlutusData": [ + [ + "plutus-tx", + "PlutusTx", + "ToData" + ], + [ + "plutus-tx", + "PlutusTx", + "FromData" + ] + ] + } +} diff --git a/lambda-buffers-codegen/data/haskell-prelude-plutustx.json b/lambda-buffers-codegen/data/plutustx-prelude.json similarity index 75% rename from lambda-buffers-codegen/data/haskell-prelude-plutustx.json rename to lambda-buffers-codegen/data/plutustx-prelude.json index 1aef0eab..cf77f3ab 100644 --- a/lambda-buffers-codegen/data/haskell-prelude-plutustx.json +++ b/lambda-buffers-codegen/data/plutustx-prelude.json @@ -5,14 +5,9 @@ "PlutusTx.AssocMap", "Map" ], - "Prelude.Set": [ - "containers", - "Data.Set", - "Set" - ], "Prelude.List": [ - "lbr-prelude", - "LambdaBuffers.Runtime.Prelude", + "lbr-plutustx", + "LambdaBuffers.Runtime.PlutusTx.List", "List" ], "Prelude.Either": [ @@ -49,6 +44,11 @@ "plutus-tx", "PlutusTx.Bool", "Bool" + ], + "Prelude.Set": [ + "lbr-plutustx", + "LambdaBuffers.Runtime.PlutusTx.NotImplemented", + "Set" ] }, "classesConfig": { @@ -57,18 +57,6 @@ "plutus-tx", "PlutusTx.Eq", "Eq" - ], - [ - "base", - "Prelude", - "Eq" - ] - ], - "Prelude.Json": [ - [ - "lbr-prelude", - "LambdaBuffers.Runtime.Prelude", - "Json" ] ] } diff --git a/lambda-buffers-codegen/data/purescript-plutus-ctl.json b/lambda-buffers-codegen/data/purescript-plutus-ctl.json index 805fb96a..cf50c4bc 100644 --- a/lambda-buffers-codegen/data/purescript-plutus-ctl.json +++ b/lambda-buffers-codegen/data/purescript-plutus-ctl.json @@ -120,16 +120,56 @@ "Ctl.Internal.Plutus.Types.AssocMap", "Map" ], + "Plutus.V1.DCert": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], + "Plutus.V1.TxOut": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], + "Plutus.V1.TxInInfo": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], + "Plutus.V1.TxInfo": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], + "Plutus.V1.ScriptPurpose": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], + "Plutus.V1.ScriptContext": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], "Plutus.V2.TxOut": [ - "cardano-transaction-lib", + "lbr-plutus", "LambdaBuffers.Runtime.Plutus", - "TxInInfo" + "NotImplemented" ], "Plutus.V2.TxInInfo": [ "lbr-plutus", "LambdaBuffers.Runtime.Plutus", "TxInInfo" ], + "Plutus.V2.TxInfo": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], + "Plutus.V2.ScriptContext": [ + "lbr-plutus", + "LambdaBuffers.Runtime.Plutus", + "NotImplemented" + ], "Plutus.V2.OutputDatum": [ "cardano-transaction-lib", "Ctl.Internal.Types.OutputDatum", diff --git a/lambda-buffers-codegen/data/rust-plutus-pla.json b/lambda-buffers-codegen/data/rust-plutus-pla.json index 45cf3238..138b5952 100644 --- a/lambda-buffers-codegen/data/rust-plutus-pla.json +++ b/lambda-buffers-codegen/data/rust-plutus-pla.json @@ -154,31 +154,31 @@ "collections", "BTreeMap" ], - "Plutus.V1.Todo.DCert": [ + "Plutus.V1.DCert": [ "plutus-ledger-api", "v1", "transaction", "DCert" ], - "Plutus.V1.Todo.ScriptContext": [ + "Plutus.V1.ScriptContext": [ "plutus-ledger-api", "v1", "transaction", "ScriptContext" ], - "Plutus.V1.Todo.ScriptPurpose": [ + "Plutus.V1.ScriptPurpose": [ "plutus-ledger-api", "v1", "transaction", "ScriptPurpose" ], - "Plutus.V1.Todo.TxInInfo": [ + "Plutus.V1.TxInInfo": [ "plutus-ledger-api", "v1", "transaction", "TxInInfo" ], - "Plutus.V1.Todo.TxInfo": [ + "Plutus.V1.TxInfo": [ "plutus-ledger-api", "v1", "transaction", @@ -202,13 +202,13 @@ "transaction", "TransactionOutput" ], - "Plutus.V2.Todo.ScriptContext": [ + "Plutus.V2.ScriptContext": [ "plutus-ledger-api", "v2", "transaction", "ScriptContext" ], - "Plutus.V2.Todo.TxInfo": [ + "Plutus.V2.TxInfo": [ "plutus-ledger-api", "v2", "transaction", diff --git a/lambda-buffers-codegen/data/typescript-plutus.json b/lambda-buffers-codegen/data/typescript-plutus.json index 3be39f00..9f3628be 100644 --- a/lambda-buffers-codegen/data/typescript-plutus.json +++ b/lambda-buffers-codegen/data/typescript-plutus.json @@ -15,6 +15,11 @@ "LbrPlutusV1", "Credential" ], + "Plutus.V1.DCert": [ + "lbr-plutus/V1.js", + "LbrPlutusV1", + "DCert" + ], "Plutus.V1.StakingCredential": [ "lbr-plutus/V1.js", "LbrPlutusV1", @@ -120,6 +125,31 @@ "LbrPlutusV1", "Map" ], + "Plutus.V1.TxOut": [ + "lbr-plutus/V1.js", + "LbrPlutusV1", + "TxOut" + ], + "Plutus.V1.TxInInfo": [ + "lbr-plutus/V1.js", + "LbrPlutusV1", + "TxInInfo" + ], + "Plutus.V1.TxInfo": [ + "lbr-plutus/V1.js", + "LbrPlutusV1", + "TxInfo" + ], + "Plutus.V1.ScriptPurpose": [ + "lbr-plutus/V1.js", + "LbrPlutusV1", + "ScriptPurpose" + ], + "Plutus.V1.ScriptContext": [ + "lbr-plutus/V1.js", + "LbrPlutusV1", + "ScriptContext" + ], "Plutus.V2.TxOut": [ "lbr-plutus/V2.js", "LbrPlutusV2", @@ -134,6 +164,16 @@ "lbr-plutus/V2.js", "LbrPlutusV2", "OutputDatum" + ], + "Plutus.V2.TxInfo": [ + "lbr-plutus/V2.js", + "LbrPlutusV2", + "TxInfo" + ], + "Plutus.V2.ScriptContext": [ + "lbr-plutus/V2.js", + "LbrPlutusV2", + "ScriptContext" ] }, "classesConfig": { diff --git a/lambda-buffers-codegen/lambda-buffers-codegen.cabal b/lambda-buffers-codegen/lambda-buffers-codegen.cabal index b131d789..b571e1a8 100644 --- a/lambda-buffers-codegen/lambda-buffers-codegen.cabal +++ b/lambda-buffers-codegen/lambda-buffers-codegen.cabal @@ -112,12 +112,22 @@ library LambdaBuffers.Codegen.Check LambdaBuffers.Codegen.Config LambdaBuffers.Codegen.Haskell + LambdaBuffers.Codegen.Haskell.Backend + LambdaBuffers.Codegen.Haskell.Backend.Native + LambdaBuffers.Codegen.Haskell.Backend.Native.Derive + LambdaBuffers.Codegen.Haskell.Backend.Native.LamVal + LambdaBuffers.Codegen.Haskell.Backend.Plutarch + LambdaBuffers.Codegen.Haskell.Backend.Plutarch.Derive + LambdaBuffers.Codegen.Haskell.Backend.Plutarch.LamVal + LambdaBuffers.Codegen.Haskell.Backend.Plutarch.Refs + LambdaBuffers.Codegen.Haskell.Backend.Plutarch.TyDef + LambdaBuffers.Codegen.Haskell.Backend.PlutusTx + LambdaBuffers.Codegen.Haskell.Backend.PlutusTx.Derive + LambdaBuffers.Codegen.Haskell.Backend.PlutusTx.LamVal LambdaBuffers.Codegen.Haskell.Config LambdaBuffers.Codegen.Haskell.Print - LambdaBuffers.Codegen.Haskell.Print.Derive LambdaBuffers.Codegen.Haskell.Print.InstanceDef LambdaBuffers.Codegen.Haskell.Print.LamVal - LambdaBuffers.Codegen.Haskell.Print.MonadPrint LambdaBuffers.Codegen.Haskell.Print.Syntax LambdaBuffers.Codegen.Haskell.Print.TyDef LambdaBuffers.Codegen.LamVal @@ -127,41 +137,36 @@ library LambdaBuffers.Codegen.LamVal.MonadPrint LambdaBuffers.Codegen.LamVal.PlutusData LambdaBuffers.Codegen.Plutarch - LambdaBuffers.Codegen.Plutarch.Print - LambdaBuffers.Codegen.Plutarch.Print.Derive - LambdaBuffers.Codegen.Plutarch.Print.LamVal - LambdaBuffers.Codegen.Plutarch.Print.Refs - LambdaBuffers.Codegen.Plutarch.Print.Syntax - LambdaBuffers.Codegen.Plutarch.Print.TyDef + LambdaBuffers.Codegen.PlutusTx LambdaBuffers.Codegen.Print LambdaBuffers.Codegen.Purescript + LambdaBuffers.Codegen.Purescript.Backend LambdaBuffers.Codegen.Purescript.Config LambdaBuffers.Codegen.Purescript.Print LambdaBuffers.Codegen.Purescript.Print.Derive LambdaBuffers.Codegen.Purescript.Print.InstanceDef LambdaBuffers.Codegen.Purescript.Print.LamVal - LambdaBuffers.Codegen.Purescript.Print.MonadPrint LambdaBuffers.Codegen.Purescript.Print.Names LambdaBuffers.Codegen.Purescript.Print.Ty LambdaBuffers.Codegen.Purescript.Print.TyDef LambdaBuffers.Codegen.Purescript.Syntax LambdaBuffers.Codegen.Rust + LambdaBuffers.Codegen.Rust.Backend LambdaBuffers.Codegen.Rust.Config LambdaBuffers.Codegen.Rust.Print LambdaBuffers.Codegen.Rust.Print.Derive LambdaBuffers.Codegen.Rust.Print.InstanceDef LambdaBuffers.Codegen.Rust.Print.LamVal - LambdaBuffers.Codegen.Rust.Print.MonadPrint LambdaBuffers.Codegen.Rust.Print.Refs LambdaBuffers.Codegen.Rust.Print.Syntax LambdaBuffers.Codegen.Rust.Print.TyDef LambdaBuffers.Codegen.Typescript + LambdaBuffers.Codegen.Typescript.Backend LambdaBuffers.Codegen.Typescript.Config LambdaBuffers.Codegen.Typescript.Print LambdaBuffers.Codegen.Typescript.Print.Derive LambdaBuffers.Codegen.Typescript.Print.InstanceDef LambdaBuffers.Codegen.Typescript.Print.LamVal - LambdaBuffers.Codegen.Typescript.Print.MonadPrint LambdaBuffers.Codegen.Typescript.Print.Names LambdaBuffers.Codegen.Typescript.Print.Ty LambdaBuffers.Codegen.Typescript.Print.TyDef @@ -190,6 +195,7 @@ executable lbg LambdaBuffers.Codegen.Cli.Gen LambdaBuffers.Codegen.Cli.GenHaskell LambdaBuffers.Codegen.Cli.GenPlutarch + LambdaBuffers.Codegen.Cli.GenPlutusTx LambdaBuffers.Codegen.Cli.GenPurescript LambdaBuffers.Codegen.Cli.GenRust LambdaBuffers.Codegen.Cli.GenTypescript diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen.hs index 34ef0465..081a0484 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen.hs @@ -1,4 +1 @@ -module LambdaBuffers.Codegen (runCodegen) where - -runCodegen :: forall {a}. a -runCodegen = error "not implemented" +module LambdaBuffers.Codegen () where diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Check.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Check.hs index 9da09991..787ed265 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Check.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Check.hs @@ -16,12 +16,13 @@ import Data.Set (Set) import Data.Set qualified as Set import Data.Text qualified as Text import LambdaBuffers.Codegen.Config (Config, cfgClasses, cfgOpaques) +import LambdaBuffers.Codegen.Print (IsBackend (BackendContext, BackendQualifiedClassName, BackendQualifiedTyName)) import LambdaBuffers.Codegen.Print qualified as Print import LambdaBuffers.ProtoCompat qualified as PC import Proto.Codegen qualified as P import Proto.Codegen_Fields qualified as P -type MonadCheck qtn qcn m = (MonadRWS (CheckRead qtn qcn) () (CheckState qtn qcn) m, MonadError CheckErr m) +type MonadCheck backend m = (IsBackend backend, MonadRWS (CheckRead backend) () (CheckState backend) m, MonadError CheckErr m) data CheckCtx = ModuleCtx PC.ModuleName @@ -30,24 +31,30 @@ data CheckCtx | RuleDefCtx PC.ModuleName deriving stock (Eq, Ord, Show) -type CheckRead qtn qcn = (Config qtn qcn, CheckCtx) +type CheckRead backend = (Config (BackendQualifiedTyName backend) (BackendQualifiedClassName backend), CheckCtx) type CheckErr = P.Error -data CheckState qtn qcn = CheckState +data CheckState backend = CheckState { moduleTyImports :: Set PC.QTyName - , moduleOpaqueImports :: Set qtn - , moduleClassImports :: Set qcn + , moduleOpaqueImports :: Set (BackendQualifiedTyName backend) + , moduleClassImports :: Set (BackendQualifiedClassName backend) , moduleRuleImports :: Set (PC.InfoLess PC.ModuleName) , moduleTyExports :: Set (PC.InfoLess PC.TyName) } - deriving stock (Eq, Ord, Show) -initialCheckState :: (Ord qtn, Ord qcn) => CheckState qtn qcn +initialCheckState :: IsBackend backend => CheckState backend initialCheckState = CheckState mempty mempty mempty mempty mempty -runCheck :: forall qtn qcn. (Ord qtn, Ord qcn) => Config qtn qcn -> PC.CodegenInput -> PC.Module -> Either P.Error (Print.Context qtn qcn) -runCheck cfg ci m = +runCheck :: + forall backend. + IsBackend backend => + Config (BackendQualifiedTyName backend) (BackendQualifiedClassName backend) -> + BackendContext backend -> + PC.CodegenInput -> + PC.Module -> + Either P.Error (Print.Context backend) +runCheck cfg bctx ci m = let p = runRWST (checkModule m) @@ -56,20 +63,31 @@ runCheck cfg ci m = p' = runExcept p in go p' where - go :: Either CheckErr ((), CheckState qtn qcn, ()) -> Either P.Error (Print.Context qtn qcn) - go (Right ((), CheckState lbtyImps opqImps clImps ruleImps tyExprts, _)) = Right $ Print.Context ci m lbtyImps opqImps clImps ruleImps tyExprts cfg + go :: Either CheckErr ((), CheckState backend, ()) -> Either P.Error (Print.Context backend) + go (Right ((), CheckState lbtyImps opqImps clImps ruleImps tyExprts, _)) = + Right $ + Print.Context @backend + ci + m + lbtyImps + opqImps + clImps + ruleImps + tyExprts + cfg + bctx go (Left printErr) = Left printErr -askConfig :: MonadCheck qtn qcn m => m (Config qtn qcn) +askConfig :: MonadCheck backend m => m (Config (BackendQualifiedTyName backend) (BackendQualifiedClassName backend)) askConfig = asks fst -askCtx :: MonadCheck qtn qcn m => m CheckCtx +askCtx :: MonadCheck backend m => m CheckCtx askCtx = asks snd -throwInternalError :: MonadCheck qtn qcn m => String -> m a +throwInternalError :: MonadCheck backend m => String -> m a throwInternalError msg = throwError $ defMessage & P.internalErrors .~ [defMessage & P.msg .~ "[LambdaBuffers.Codegen.Check] " <> Text.pack msg] -throwUnsupportedOpaqueError :: MonadCheck qtn qcn m => PC.ModuleName -> PC.TyName -> m a +throwUnsupportedOpaqueError :: MonadCheck backend m => PC.ModuleName -> PC.TyName -> m a throwUnsupportedOpaqueError mn tyN = throwError $ defMessage @@ -79,7 +97,7 @@ throwUnsupportedOpaqueError mn tyN = & P.tyName .~ PC.toProto tyN ] -throwUnsupportedClassError :: MonadCheck qtn qcn m => PC.ModuleName -> PC.ClassName -> m a +throwUnsupportedClassError :: MonadCheck backend m => PC.ModuleName -> PC.ClassName -> m a throwUnsupportedClassError mn clN = throwError $ defMessage @@ -89,37 +107,37 @@ throwUnsupportedClassError mn clN = & P.className .~ PC.toProto clN ] -askTyDefCtx :: MonadCheck qtn qcn m => m (PC.ModuleName, PC.TyDef) +askTyDefCtx :: MonadCheck backend m => m (PC.ModuleName, PC.TyDef) askTyDefCtx = do ctx <- askCtx case ctx of TyDefCtx mn td -> return (mn, td) other -> throwInternalError $ "Wanted TyDefCtx got " <> show other -askClassDefCtx :: MonadCheck qtn qcn m => m PC.ModuleName +askClassDefCtx :: MonadCheck backend m => m PC.ModuleName askClassDefCtx = do ctx <- askCtx case ctx of ClassDefCtx mn -> return mn other -> throwInternalError $ "Wanted ClassDefCtx got " <> show other -exportTy :: MonadCheck qtn qcn m => PC.InfoLess PC.TyName -> m () +exportTy :: MonadCheck backend m => PC.InfoLess PC.TyName -> m () exportTy htyN = modify (\s -> s {moduleTyExports = Set.union (moduleTyExports s) (Set.singleton htyN)}) -importTy :: MonadCheck qtn qcn m => PC.QTyName -> m () +importTy :: MonadCheck backend m => PC.QTyName -> m () importTy qtyn = modify (\s -> s {moduleTyImports = Set.union (moduleTyImports s) (Set.singleton qtyn)}) -importOpaqueTy :: Ord qtn => MonadCheck qtn qcn m => qtn -> m () +importOpaqueTy :: MonadCheck backend m => BackendQualifiedTyName backend -> m () importOpaqueTy qtyn = modify (\s -> s {moduleOpaqueImports = Set.union (moduleOpaqueImports s) (Set.singleton qtyn)}) -importClass :: (MonadCheck qtn qcn m, Ord qcn) => qcn -> m () +importClass :: MonadCheck backend m => BackendQualifiedClassName backend -> m () importClass qcn = modify (\s -> s {moduleClassImports = Set.union (moduleClassImports s) (Set.singleton qcn)}) -importRulesFrom :: MonadCheck qtn qcn m => PC.InfoLess PC.ModuleName -> m () +importRulesFrom :: MonadCheck backend m => PC.InfoLess PC.ModuleName -> m () importRulesFrom mn = modify (\s -> s {moduleRuleImports = Set.union (moduleRuleImports s) (Set.singleton mn)}) -- | Traverse the module and collect imports and exports, erroring if anything is not configured. -checkModule :: (MonadCheck qtn qcn m, Ord qtn, Ord qcn) => PC.Module -> m () +checkModule :: MonadCheck backend m => PC.Module -> m () checkModule m = do for_ (m ^. #typeDefs) @@ -137,21 +155,21 @@ checkModule m = do (Map.keys $ m ^. #imports) importRulesFrom -checkTyDef :: (MonadCheck qtn qcn m, Ord qtn) => PC.TyDef -> m () +checkTyDef :: MonadCheck backend m => PC.TyDef -> m () checkTyDef td = do checkTyAbs $ td ^. #tyAbs exportTy (PC.mkInfoLess $ td ^. #tyName) -checkTyAbs :: (MonadCheck qtn qcn m, Ord qtn) => PC.TyAbs -> m () +checkTyAbs :: MonadCheck backend m => PC.TyAbs -> m () checkTyAbs (PC.TyAbs _ body _) = checkTyBody body -checkTyBody :: (MonadCheck qtn qcn m, Ord qtn) => PC.TyBody -> m () +checkTyBody :: MonadCheck backend m => PC.TyBody -> m () checkTyBody (PC.SumI s) = checkSum s checkTyBody (PC.ProductI p) = checkProduct p checkTyBody (PC.RecordI r) = checkRecord r checkTyBody (PC.OpaqueI _) = checkOpaque -checkOpaque :: (MonadCheck qtn qcn m, Ord qtn) => m () +checkOpaque :: MonadCheck backend m => m () checkOpaque = do cfg <- askConfig (currentModuleName, currentTyDef) <- askTyDefCtx @@ -161,34 +179,34 @@ checkOpaque = do Just qhtyn -> return qhtyn importOpaqueTy qotyn -checkSum :: MonadCheck qtn qcn m => PC.Sum -> m () +checkSum :: MonadCheck backend m => PC.Sum -> m () checkSum s = for_ (s ^. #constructors) (\c -> checkProduct (c ^. #product)) -checkProduct :: MonadCheck qtn qcn m => PC.Product -> m () +checkProduct :: MonadCheck backend m => PC.Product -> m () checkProduct p = for_ (p ^. #fields) checkTy -checkRecord :: MonadCheck qtn qcn m => PC.Record -> m () +checkRecord :: MonadCheck backend m => PC.Record -> m () checkRecord r = for_ (r ^. #fields) (\f -> checkTy $ f ^. #fieldTy) -checkTy :: MonadCheck qtn qcn m => PC.Ty -> m () +checkTy :: MonadCheck backend m => PC.Ty -> m () checkTy (PC.TyRefI (PC.ForeignI fr)) = importTy (PC.mkInfoLess $ fr ^. #moduleName, PC.mkInfoLess $ fr ^. #tyName) checkTy (PC.TyAppI ta) = checkTy (ta ^. #tyFunc) >> for_ (ta ^. #tyArgs) checkTy checkTy _ = return () -- TODO(bladyjoker): This is where you should lookup instance implementation and report if an instance implementation is missing. -checkInstanceClause :: MonadCheck qtn qcn m => PC.InstanceClause -> m () +checkInstanceClause :: MonadCheck backend m => PC.InstanceClause -> m () checkInstanceClause ic = do checkConstraint $ ic ^. #head for_ (ic ^. #constraints) checkConstraint -checkDerive :: MonadCheck qtn qcn m => PC.Derive -> m () +checkDerive :: MonadCheck backend m => PC.Derive -> m () checkDerive drv = checkConstraint $ drv ^. #constraint -checkConstraint :: MonadCheck qtn qcn m => PC.Constraint -> m () +checkConstraint :: MonadCheck backend m => PC.Constraint -> m () checkConstraint c = do checkTy $ c ^. #argument -checkClassDef :: (MonadCheck qtn qcn m, Ord qcn) => PC.ClassDef -> m () +checkClassDef :: MonadCheck backend m => PC.ClassDef -> m () checkClassDef cd = do cfg <- askConfig mn <- askClassDefCtx diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell.hs index eb0f9b29..76921d66 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell.hs @@ -1,48 +1,17 @@ module LambdaBuffers.Codegen.Haskell ( - runPrint, + runBackend, ) where -import Control.Lens ((^.)) import Data.Set (Set) import Data.Text (Text) -import LambdaBuffers.Codegen.Check (runCheck) -import LambdaBuffers.Codegen.Haskell.Config qualified as HsConfig -import LambdaBuffers.Codegen.Haskell.Print qualified as HsPrint -import LambdaBuffers.Codegen.Haskell.Print.Derive qualified as HsDerive -import LambdaBuffers.Codegen.Haskell.Print.MonadPrint (MonadPrint) -import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsSyntax -import LambdaBuffers.Codegen.Haskell.Print.TyDef qualified as HsPrint -import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Haskell.Backend qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Backend.Native (NativeHaskellBackend) +import LambdaBuffers.Codegen.Haskell.Config qualified as Haskell import LambdaBuffers.ProtoCompat.Types qualified as PC -import Prettyprinter (defaultLayoutOptions, layoutPretty) -import Prettyprinter.Render.Text (renderStrict) import Proto.Codegen qualified as P -{- | `runPrint cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Haskell configuration file in `cfg`. +{- | `runBackend cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Haskell configuration file in `cfg`. It either errors with an API error message or succeeds with a module filepath, code and package dependencies. -} -runPrint :: HsConfig.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) -runPrint cfg ci m = case runCheck cfg ci m of - Left err -> Left err - Right ctx -> case Print.runPrint ctx (HsPrint.printModule hsPrintModuleEnv) of - Left err -> Left err - Right (modDoc, deps) -> - Right - ( HsSyntax.filepathFromModuleName (m ^. #moduleName) - , renderStrict $ layoutPretty defaultLayoutOptions modDoc - , deps - ) - -hsPrintModuleEnv :: MonadPrint m => HsPrint.PrintModuleEnv m ann -hsPrintModuleEnv = - HsPrint.PrintModuleEnv - HsSyntax.printModName - HsDerive.hsClassImplPrinters - HsPrint.printTyDef - ["NoImplicitPrelude", "NoPolyKinds"] -- NOTE(bladyjoker): NoPolyKinds is needed for PlutusTx compiler, quite safe. - [ "-fno-ignore-interface-pragmas" -- NOTE(bladyjoker): All this is necessary for PlutusTx compiler, apparently safe. - , "-fno-omit-interface-pragmas" - , "-fno-specialise" - , "-fno-strictness" - , "-fobject-code" - ] +runBackend :: Haskell.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) +runBackend = Haskell.runBackend @NativeHaskellBackend () () diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend.hs new file mode 100644 index 00000000..780e6af2 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend.hs @@ -0,0 +1,53 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE UndecidableInstances #-} + +module LambdaBuffers.Codegen.Haskell.Backend (runBackend, MonadHaskellBackend, HaskellBackendM, HaskellBackend, IsHaskellBackend (..)) where + +import Control.Lens ((^.)) +import Data.Map (Map) +import Data.Set (Set) +import Data.Text (Text) +import LambdaBuffers.Codegen.Check qualified as Check +import LambdaBuffers.Codegen.Haskell.Config qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as H +import LambdaBuffers.Codegen.Print (IsBackend) +import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.ProtoCompat qualified as PC +import Prettyprinter (Doc, defaultLayoutOptions, layoutPretty) +import Prettyprinter.Render.Text (renderStrict) +import Proto.Codegen qualified as P + +class IsBackend (HaskellBackend t) => IsHaskellBackend t where + type HaskellBackendContext t + type HaskellBackendState t + fromLbModuleName :: PC.ModuleName -> H.ModuleName + filepathFromLbModuleName :: PC.ModuleName -> FilePath + printModule :: MonadHaskellBackend t m => m (Doc ann, Set Text) + printImplementation :: forall m ann. MonadHaskellBackend t m => Map H.QClassName (PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann)) + printTyDef :: MonadHaskellBackend t m => PC.TyDef -> m (Doc ann) + languageExtensions :: [Text] + ghcOptions :: [Text] + +data HaskellBackend t + +instance IsBackend (HaskellBackend t) where + type BackendContext (HaskellBackend t) = HaskellBackendContext t + type BackendState (HaskellBackend t) = HaskellBackendState t + type BackendQualifiedValueName (HaskellBackend t) = H.QValName + type BackendQualifiedTyName (HaskellBackend t) = H.QTyName + type BackendQualifiedClassName (HaskellBackend t) = H.QClassName + +type MonadHaskellBackend t m = (IsHaskellBackend t, Print.MonadPrint (HaskellBackend t) m) +type HaskellBackendM t = Print.PrintM (HaskellBackend t) + +runBackend :: forall t. IsHaskellBackend t => HaskellBackendContext t -> HaskellBackendState t -> Haskell.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) +runBackend hsBackendCtx hsBackendState cfg ci m = case Check.runCheck @(HaskellBackend t) cfg hsBackendCtx ci m of + Left err -> Left err + Right ctx -> case Print.runPrint hsBackendState ctx (printModule @t) of + Left err -> Left err + Right (modDoc, deps) -> + Right + ( filepathFromLbModuleName @t (m ^. #moduleName) + , renderStrict $ layoutPretty defaultLayoutOptions modDoc + , deps + ) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native.hs new file mode 100644 index 00000000..b8fe8cc2 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native.hs @@ -0,0 +1,22 @@ +module LambdaBuffers.Codegen.Haskell.Backend.Native (NativeHaskellBackend) where + +import Control.Lens ((^.)) +import Data.Text qualified as Text +import LambdaBuffers.Codegen.Haskell.Backend (IsHaskellBackend (HaskellBackendContext, HaskellBackendState, filepathFromLbModuleName, fromLbModuleName, ghcOptions, languageExtensions, printImplementation, printModule, printTyDef)) +import LambdaBuffers.Codegen.Haskell.Backend.Native.Derive qualified as NativeHaskellBackend +import LambdaBuffers.Codegen.Haskell.Print qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.TyDef qualified as Haskell + +data NativeHaskellBackend + +instance IsHaskellBackend NativeHaskellBackend where + type HaskellBackendContext NativeHaskellBackend = () + type HaskellBackendState NativeHaskellBackend = () + fromLbModuleName mn = Haskell.MkModuleName $ Text.intercalate "." ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) + filepathFromLbModuleName mn = Text.unpack (Text.replace "." "/" (let Haskell.MkModuleName txt = fromLbModuleName @NativeHaskellBackend mn in txt)) <> ".hs" + printImplementation = NativeHaskellBackend.hsClassImplPrinters + printModule = Haskell.printModule + printTyDef = Haskell.printTyDef + languageExtensions = [] + ghcOptions = [] diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/Derive.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native/Derive.hs similarity index 61% rename from lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/Derive.hs rename to lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native/Derive.hs index 7c8e78c6..9fdc4db7 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/Derive.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native/Derive.hs @@ -1,30 +1,32 @@ -module LambdaBuffers.Codegen.Haskell.Print.Derive (printDeriveEqBase, printDeriveEqPlutusTx, printDeriveToPlutusData, printDeriveFromPlutusData, printDeriveJson, hsClassImplPrinters) where +module LambdaBuffers.Codegen.Haskell.Backend.Native.Derive (printValue, printDeriveEqBase, printDeriveToPlutusData, printDeriveFromPlutusData, printDeriveJson, hsClassImplPrinters) where import Control.Lens ((^.)) import Data.Foldable (for_) import Data.Map (Map) import Data.Map qualified as Map import Data.Set (Set) -import LambdaBuffers.Codegen.Haskell.Print (MonadPrint) -import LambdaBuffers.Codegen.Haskell.Print.LamVal (printValueE) +import LambdaBuffers.Codegen.Haskell.Backend (MonadHaskellBackend) +import LambdaBuffers.Codegen.Haskell.Backend.Native.LamVal qualified as Native +import LambdaBuffers.Codegen.Haskell.Print.LamVal qualified as Haskell import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as H +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell +import LambdaBuffers.Codegen.LamVal qualified as Lv import LambdaBuffers.Codegen.LamVal.Eq (deriveEqImpl) import LambdaBuffers.Codegen.LamVal.Json (deriveFromJsonImpl, deriveToJsonImpl) import LambdaBuffers.Codegen.LamVal.MonadPrint qualified as LV import LambdaBuffers.Codegen.LamVal.PlutusData (deriveFromPlutusDataImpl, deriveToPlutusDataImpl) import LambdaBuffers.Codegen.Print qualified as Print import LambdaBuffers.ProtoCompat qualified as PC -import Prettyprinter (Doc, align, equals, hardline, vsep, (<+>)) -import Proto.Codegen qualified as P +import Prettyprinter (Doc, align, equals, vsep, (<+>)) import Proto.Codegen_Fields qualified as P hsClassImplPrinters :: - MonadPrint m => + MonadHaskellBackend t m => Map H.QClassName ( PC.ModuleName -> PC.TyDefs -> - (Doc ann -> Doc ann) -> + (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) ) @@ -34,10 +36,6 @@ hsClassImplPrinters = ( (H.MkCabalPackageName "base", H.MkModuleName "Prelude", H.MkClassName "Eq") , printDeriveEqBase ) - , - ( (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Eq", H.MkClassName "Eq") - , printDeriveEqPlutusTx - ) , ( (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkClassName "ToData") , printDeriveToPlutusData @@ -51,11 +49,15 @@ hsClassImplPrinters = , printDeriveJson ) ] + +printValue :: (Lv.Ref -> Maybe Haskell.QValName) -> Lv.ValueE -> Either LV.PrintError (Doc ann, Set Haskell.QValName) +printValue builtins valE = LV.runPrint (LV.Context builtins Native.lamValContext) (Haskell.printValueE valE) + eqClassMethodName :: H.ValueName eqClassMethodName = H.MkValueName "==" -lvEqBuiltinsBase :: LV.PrintRead (H.CabalPackageName, H.ModuleName, H.ValueName) -lvEqBuiltinsBase = LV.MkPrintRead $ \(_ty, refName) -> +lvEqBuiltinsBase :: Lv.Ref -> Maybe Haskell.QValName +lvEqBuiltinsBase (_ty, refName) = Map.lookup refName $ Map.fromList [ ("eq", (H.MkCabalPackageName "base", H.MkModuleName "Prelude", H.MkValueName "==")) @@ -64,45 +66,20 @@ lvEqBuiltinsBase = LV.MkPrintRead $ \(_ty, refName) -> , ("false", (H.MkCabalPackageName "base", H.MkModuleName "Prelude", H.MkValueName "False")) ] -printDeriveEqBase :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDeriveEqBase :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) printDeriveEqBase mn iTyDefs mkInstanceDoc ty = do case deriveEqImpl mn iTyDefs ty of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Prelude.Eq LamVal implementation from a type failed with: " <> err ^. P.msg) Right valE -> do - case LV.runPrint lvEqBuiltinsBase (printValueE valE) of + case printValue lvEqBuiltinsBase valE of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Interpreting LamVal into Haskell failed with: " <> err ^. P.msg) Right (implDoc, imps) -> do - let instanceDoc = mkInstanceDoc (printValueDef eqClassMethodName implDoc) + instanceDoc <- mkInstanceDoc (printValueDef eqClassMethodName implDoc) for_ imps Print.importValue return instanceDoc -lvEqBuiltinsPlutusTx :: LV.PrintRead (H.CabalPackageName, H.ModuleName, H.ValueName) -lvEqBuiltinsPlutusTx = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("eq", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Eq", H.MkValueName "==")) - , ("and", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Bool", H.MkValueName "&&")) - , ("true", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Bool", H.MkValueName "True")) - , ("false", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Bool", H.MkValueName "False")) - ] - -printDeriveEqPlutusTx :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDeriveEqPlutusTx mn iTyDefs mkInstanceDoc ty = do - case deriveEqImpl mn iTyDefs ty of - Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Prelude.Eq LamVal implementation from a type failed with: " <> err ^. P.msg) - Right valE -> do - case LV.runPrint lvEqBuiltinsPlutusTx (printValueE valE) of - Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Interpreting LamVal into Haskell failed with: " <> err ^. P.msg) - Right (implDoc, imps) -> do - let instanceDoc = mkInstanceDoc (align $ printInlineable eqClassMethodName <> hardline <> printValueDef eqClassMethodName implDoc) - for_ imps Print.importValue - return instanceDoc - -printInlineable :: H.ValueName -> Doc ann -printInlineable valName = "{-# INLINABLE" <+> H.printHsValName valName <+> "#-}" - -lvPlutusDataBuiltins :: LV.PrintRead H.QValName -lvPlutusDataBuiltins = LV.MkPrintRead $ \(_ty, refName) -> +lvPlutusDataBuiltins :: Lv.Ref -> Maybe Haskell.QValName +lvPlutusDataBuiltins (_ty, refName) = Map.lookup refName $ Map.fromList [ ("toPlutusData", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkValueName "toBuiltinData")) @@ -119,15 +96,15 @@ lvPlutusDataBuiltins = LV.MkPrintRead $ \(_ty, refName) -> toPlutusDataClassMethodName :: H.ValueName toPlutusDataClassMethodName = H.MkValueName "toBuiltinData" -printDeriveToPlutusData :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDeriveToPlutusData :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) printDeriveToPlutusData mn iTyDefs mkInstanceDoc ty = do case deriveToPlutusDataImpl mn iTyDefs ty of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Plutus.V1.PlutusData LamVal implementation from a type failed with: " <> err ^. P.msg) Right valE -> do - case LV.runPrint lvPlutusDataBuiltins (printValueE valE) of + case printValue lvPlutusDataBuiltins valE of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Interpreting LamVal into Haskell failed with: " <> err ^. P.msg) Right (implDoc, imps) -> do - let instanceDoc = mkInstanceDoc (align $ printInlineable toPlutusDataClassMethodName <> hardline <> printValueDef toPlutusDataClassMethodName implDoc) + instanceDoc <- mkInstanceDoc (printValueDef toPlutusDataClassMethodName implDoc) for_ imps Print.importValue return instanceDoc @@ -140,22 +117,22 @@ fromPlutusDataClassMethodName = H.MkValueName "fromBuiltinData" builtinDataToDataRef :: H.QValName builtinDataToDataRef = (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkValueName "builtinDataToData") -printDeriveFromPlutusData :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDeriveFromPlutusData :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) printDeriveFromPlutusData mn iTyDefs mkInstanceDoc ty = do case deriveFromPlutusDataImpl mn iTyDefs ty of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Plutus.V1.PlutusData LamVal implementation from a type failed with: " <> err ^. P.msg) Right valE -> do - case LV.runPrint lvPlutusDataBuiltins (printValueE valE) of + case printValue lvPlutusDataBuiltins valE of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Interpreting LamVal into Haskell failed with: " <> err ^. P.msg) Right (implDoc, imps) -> do - let instanceDoc = mkInstanceDoc (align $ printInlineable fromPlutusDataClassMethodName <> hardline <> printValueDef fromPlutusDataClassMethodName implDoc) + instanceDoc <- mkInstanceDoc (printValueDef fromPlutusDataClassMethodName implDoc) Print.importValue builtinDataToDataRef for_ imps Print.importValue return instanceDoc -- | LambdaBuffers.Codegen.LamVal.Json specification printing -lvJsonBuiltins :: LV.PrintRead H.QValName -lvJsonBuiltins = LV.MkPrintRead $ \(_ty, refName) -> +lvJsonBuiltins :: Lv.Ref -> Maybe Haskell.QValName +lvJsonBuiltins (_ty, refName) = Map.lookup refName $ Map.fromList [ ("toJson", (H.MkCabalPackageName "lbr-prelude", H.MkModuleName "LambdaBuffers.Runtime.Prelude", H.MkValueName "toJson")) @@ -178,30 +155,28 @@ toJsonClassMethodName = H.MkValueName "toJson" fromJsonClassMethodName :: H.ValueName fromJsonClassMethodName = H.MkValueName "fromJson" -printDeriveJson :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDeriveJson :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) printDeriveJson mn iTyDefs mkInstanceDoc ty = do - case printDeriveJson' mn iTyDefs mkInstanceDoc ty of + let resOrErr = do + toJsonValE <- deriveToJsonImpl mn iTyDefs ty + (toJsonImplDoc, impsA) <- printValue lvJsonBuiltins toJsonValE + fromJsonValE <- deriveFromJsonImpl mn iTyDefs ty + (fromJsonImplDoc, impsB) <- printValue lvJsonBuiltins fromJsonValE + return (toJsonImplDoc, fromJsonImplDoc, impsA <> impsB) + + (toJsonImplDoc, fromJsonImplDoc, imps) <- case resOrErr of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Prelude.Json LamVal implementation from a type failed with: " <> err ^. P.msg) - Right (jsonInstDefDoc, imps) -> do - for_ imps Print.importValue - return jsonInstDefDoc - -printDeriveJson' :: PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> Either P.InternalError (Doc ann, Set H.QValName) -printDeriveJson' mn iTyDefs mkInstanceDoc ty = do - toJsonValE <- deriveToJsonImpl mn iTyDefs ty - (toJsonImplDoc, impsA) <- LV.runPrint lvJsonBuiltins (printValueE toJsonValE) - fromJsonValE <- deriveFromJsonImpl mn iTyDefs ty - (fromJsonImplDoc, impsB) <- LV.runPrint lvJsonBuiltins (printValueE fromJsonValE) - - let instanceDoc = - mkInstanceDoc - ( align $ - vsep - [ printValueDef toJsonClassMethodName toJsonImplDoc - , printValueDef fromJsonClassMethodName fromJsonImplDoc - ] - ) - return - ( instanceDoc - , impsA <> impsB - ) + Right res -> return res + + instanceDoc <- + mkInstanceDoc + ( align $ + vsep + [ printValueDef toJsonClassMethodName toJsonImplDoc + , printValueDef fromJsonClassMethodName fromJsonImplDoc + ] + ) + + for_ imps Print.importValue + + return instanceDoc diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native/LamVal.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native/LamVal.hs new file mode 100644 index 00000000..29eb4d1b --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Native/LamVal.hs @@ -0,0 +1,24 @@ +module LambdaBuffers.Codegen.Haskell.Backend.Native.LamVal (printCaseIntE, lamValContext) where + +import Data.Traversable (for) +import LambdaBuffers.Codegen.Haskell.Print.LamVal (HaskellLamValContext (HaskellLamValContext)) +import LambdaBuffers.Codegen.Haskell.Print.LamVal qualified as Haskell +import LambdaBuffers.Codegen.LamVal qualified as LV +import Prettyprinter (Doc, align, group, line, vsep, (<+>)) + +lamValContext :: HaskellLamValContext +lamValContext = HaskellLamValContext {ctx'printCaseIntE = printCaseIntE} + +printCaseIntE :: Haskell.HaskellLamValMonad m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printCaseIntE caseIntVal cases otherCase = do + caseValDoc <- Haskell.printValueE caseIntVal + caseDocs <- + for + cases + ( \(conditionVal, bodyVal) -> do + conditionDoc <- Haskell.printValueE conditionVal + bodyDoc <- Haskell.printValueE bodyVal + return $ group $ conditionDoc <+> "->" <+> bodyDoc + ) + otherDoc <- Haskell.printOtherCase otherCase + return $ "ca" <> align ("se" <+> caseValDoc <+> "of" <> line <> vsep (caseDocs <> [otherDoc])) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch.hs new file mode 100644 index 00000000..1798757a --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch.hs @@ -0,0 +1,34 @@ +module LambdaBuffers.Codegen.Haskell.Backend.Plutarch (PlutarchHaskellBackend) where + +import Control.Lens ((^.)) +import Data.Text qualified as Text +import LambdaBuffers.Codegen.Haskell.Backend (IsHaskellBackend (HaskellBackendContext, HaskellBackendState, filepathFromLbModuleName, fromLbModuleName, ghcOptions, languageExtensions, printImplementation, printModule, printTyDef)) +import LambdaBuffers.Codegen.Haskell.Backend.Plutarch.Derive qualified as PlutarchHaskellBackend +import LambdaBuffers.Codegen.Haskell.Backend.Plutarch.TyDef qualified as PlutarchHaskellBackend + +import LambdaBuffers.Codegen.Haskell.Print qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell + +data PlutarchHaskellBackend + +instance IsHaskellBackend PlutarchHaskellBackend where + type HaskellBackendContext PlutarchHaskellBackend = () + type HaskellBackendState PlutarchHaskellBackend = () + fromLbModuleName mn = Haskell.MkModuleName $ Text.intercalate "." ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) <> ".Plutarch" + filepathFromLbModuleName mn = Text.unpack $ Text.intercalate "/" ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) <> "/Plutarch.hs" + printImplementation = PlutarchHaskellBackend.hsClassImplPrinters + printModule = Haskell.printModule + printTyDef = PlutarchHaskellBackend.printTyDef + languageExtensions = + [ "KindSignatures" + , "DataKinds" + , "TypeFamilies" + , "MultiParamTypeClasses" + , "FlexibleContexts" + , "FlexibleInstances" + , "DerivingStrategies" + , "DeriveAnyClass" + , "DeriveGeneric" + , "UndecidableInstances" + ] + ghcOptions = [] diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/Derive.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/Derive.hs new file mode 100644 index 00000000..630d1a15 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/Derive.hs @@ -0,0 +1,396 @@ +module LambdaBuffers.Codegen.Haskell.Backend.Plutarch.Derive (hsClassImplPrinters) where + +import Control.Lens ((^.)) +import Data.Foldable (for_) +import Data.Map (Map) +import Data.Map qualified as Map +import Data.Set (Set) +import Data.Text (Text) +import Data.Text qualified as Text +import LambdaBuffers.Codegen.Haskell.Backend (MonadHaskellBackend) +import LambdaBuffers.Codegen.Haskell.Backend.Native.Derive qualified as Native +import LambdaBuffers.Codegen.Haskell.Backend.Plutarch.LamVal qualified as PlLamVal +import LambdaBuffers.Codegen.Haskell.Backend.Plutarch.Refs qualified as PlRefs +import LambdaBuffers.Codegen.Haskell.Print.InstanceDef qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.TyDef qualified as Haskell +import LambdaBuffers.Codegen.LamVal qualified as LV +import LambdaBuffers.Codegen.LamVal.MonadPrint qualified as LV +import LambdaBuffers.Codegen.LamVal.PlutusData (deriveFromPlutusDataImplPlutarch, deriveToPlutusDataImplPlutarch) +import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.ProtoCompat qualified as PC +import Prettyprinter (Doc, align, comma, defaultLayoutOptions, encloseSep, equals, group, hardline, layoutPretty, lparen, parens, pretty, rparen, space, vsep, (<+>)) +import Prettyprinter.Render.Text (renderStrict) +import Proto.Codegen_Fields qualified as P + +hsClassImplPrinters :: + MonadHaskellBackend t m => + Map + Haskell.QClassName + ( PC.ModuleName -> + PC.TyDefs -> + (Doc ann -> m (Doc ann)) -> + PC.Ty -> + m (Doc ann) + ) +hsClassImplPrinters = + Map.fromList + [ + ( PlRefs.peqQClassName + , printDerivePEq + ) + , + ( PlRefs.pisDataQClassName + , printDerivePIsData + ) + , + ( PlRefs.ptryFromQClassName + , printDerivePTryFrom + ) + , + ( PlRefs.plutusTypeQClassName + , printDerivePlutusType + ) + ] + +useVal :: MonadHaskellBackend t m => Haskell.QValName -> m (Doc ann) +useVal qvn = Print.importValue qvn >> return (Haskell.printHsQValName qvn) + +printValue :: (LV.Ref -> Maybe Haskell.QValName) -> LV.ValueE -> Either LV.PrintError (Doc ann, Set Haskell.QValName) +printValue builtins valE = LV.runPrint (LV.Context builtins ()) (PlLamVal.printValueE valE) + +{- | Deriving PEq. + +NOTE(bladyjoker): Doesn't derive the implementation but only uses the underlying PData representation for equality. + +``` +instance PEq (FooLessTrivial a) where + (#==) l r = pdata l #== pdata r +``` + +mkInstanceDoc "\\l r -> (Plutarch.Bool.#==) (Plutarch.Builtin.pdata l) (Plutarch.Builtin.pdata r)" +-} +printDerivePEq :: forall t m ann. MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) +printDerivePEq _mn _iTyDefs _mkInstanceDoc ty = do + pdataDoc <- useVal PlRefs.pdataQValName + peqDoc <- useVal PlRefs.peqQValName + let implDoc = "\\l r ->" <+> parens peqDoc <+> parens (pdataDoc <+> "l") <+> parens (pdataDoc <+> "r") + printPEqInstanceDef ty (printValueDef PlRefs.peqMethod implDoc) + +printPEqInstanceDef :: MonadHaskellBackend t m => PC.Ty -> Doc ann -> m (Doc ann) +printPEqInstanceDef ty implDefDoc = do + Print.importClass PlRefs.peqQClassName + Print.importClass PlRefs.pisDataQClassName + let freeVars = Haskell.collectTyVars ty + headDoc <- Haskell.printConstraint PlRefs.peqQClassName ty + case freeVars of + [] -> return $ "instance" <+> headDoc <+> "where" <> hardline <> space <> space <> implDefDoc + _other -> do + instanceCtxDoc <- Haskell.printInstanceContext PlRefs.pisDataQClassName freeVars + return $ + "instance" + <+> instanceCtxDoc + <+> "=>" + <+> headDoc + <+> "where" + <> hardline + <> space + <> space + <> implDefDoc + +{- | Deriving PIsData. + +NOTE(bladyjoker): Doesn't derive the implementation but only uses `punsafeCoerce`. + +``` +instance PIsData (FooLessTrivial a) where + pdataImpl = punsafeCoerce + pfromDataImpl = punsafeCoerce +``` +-} +printDerivePIsData :: forall t m ann. MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) +printDerivePIsData _mn _iTyDefs mkInstanceDoc _ty = do + punsafeCoerceDoc <- useVal PlRefs.punsafeCoerceQValName + let pdataImpl, pfromDataImpl :: Doc ann + pdataImpl = printValueDef (Haskell.MkValueName "pdataImpl") punsafeCoerceDoc + pfromDataImpl = printValueDef (Haskell.MkValueName "pfromDataImpl") punsafeCoerceDoc + mkInstanceDoc (align $ vsep [pdataImpl, pfromDataImpl]) + +lvPlutusDataBuiltinsForPlutusType :: LV.Ref -> Maybe Haskell.QValName +lvPlutusDataBuiltinsForPlutusType (_ty, refName) = + Map.lookup refName $ + Map.fromList + [ ("toPlutusData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "toPlutusData")) + , ("fromPlutusData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pfromPlutusDataPlutusType")) + , ("casePlutusData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pcasePlutusData")) + , ("integerData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "integerData")) + , ("constrData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "constrData")) + , ("listData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "listData")) + , ("succeedParse", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "psucceedParse")) + , ("failParse", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pfailParse")) + , ("bindParse", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pbindParse")) + ] + +printDerivePlutusType :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) +printDerivePlutusType mn iTyDefs _mkInstanceDoc ty = do + pappDoc <- useVal PlRefs.pappQValName + pconDoc <- useVal PlRefs.pconQValName + -- HACK(bladyjoker): The `fromData` implementation is trying to construct a term, which for Plutarch means `pcon`. However, this is 'pmatch' implementation which is NOT really exactly 'fromData', and has a different type signature for which we do this. I'm sorry. + let dirtyHack :: Doc ann -> Doc ann + dirtyHack = pretty . Text.replace (docToText pconDoc <> " ") "f " . docToText + + let resOrErr = + do + toDataE <- deriveToPlutusDataImplPlutarch mn iTyDefs ty + fromDataE <- deriveFromPlutusDataImplPlutarch mn iTyDefs ty + (pconImplDoc, imps) <- Native.printValue lvPlutusDataBuiltinsForPlutusType toDataE -- NOTE(bladyjoker): Yes this is printed as Native Haskell + (pmatchImplDoc, imps') <- printValue lvPlutusDataBuiltinsForPlutusType fromDataE + let implDoc = + align $ + vsep + [ printValueDef PlRefs.pconMethod pconImplDoc + , printValueDef PlRefs.pmatchMethod $ parens ("\\pd f -> " <+> parens pappDoc <+> parens (dirtyHack pmatchImplDoc) <+> "pd") + ] + + return (implDoc, imps' <> imps) + case resOrErr of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Printing an instance definition for PlutusType failed with: " <> err ^. P.msg) + Right (implDoc, imps) -> do + instanceDoc <- printPlutusTypeInstanceDef ty implDoc + for_ imps Print.importValue + return instanceDoc + where + docToText :: Doc ann -> Text + docToText = renderStrict . layoutPretty defaultLayoutOptions + +printPlutusTypeInstanceDef :: MonadHaskellBackend t m => PC.Ty -> Doc ann -> m (Doc ann) +printPlutusTypeInstanceDef ty implDefDoc = do + Print.importClass PlRefs.plutusTypeQClassName + Print.importClass PlRefs.pisDataQClassName + Print.importType PlRefs.pdataQTyName + headDoc <- Haskell.printConstraint PlRefs.plutusTypeQClassName ty + tyDoc <- Haskell.printTyInner ty + let freeVars = Haskell.collectTyVars ty + pinnerDefDoc = "type PInner" <+> tyDoc <+> "=" <+> Haskell.printHsQTyName PlRefs.pdataQTyName + case freeVars of + [] -> + return $ + "instance" + <+> headDoc + <+> "where" + <> hardline + <> space + <> space + <> pinnerDefDoc + <> hardline + <> space + <> space + <> implDefDoc + _other -> do + instanceCtxDoc <- Haskell.printInstanceContext PlRefs.pisDataQClassName freeVars + return $ + "instance" + <+> instanceCtxDoc + <+> "=>" + <+> headDoc + <+> "where" + <> hardline + <> space + <> space + <> pinnerDefDoc + <> hardline + <> space + <> space + <> implDefDoc + +printValueDef :: Haskell.ValueName -> Doc ann -> Doc ann +printValueDef valName valDoc = Haskell.printHsValName valName <+> equals <+> valDoc + +lvPlutusDataBuiltinsForPTryFrom :: LV.Ref -> Maybe Haskell.QValName +lvPlutusDataBuiltinsForPTryFrom (_ty, refName) = + Map.lookup refName $ + Map.fromList + [ ("toPlutusData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "toPlutusData")) + , ("fromPlutusData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pfromPlutusDataPTryFrom")) + , ("casePlutusData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pcasePlutusData")) + , ("integerData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "integerData")) + , ("constrData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "constrData")) + , ("listData", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "listData")) + , ("succeedParse", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "psucceedParse")) + , ("failParse", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pfailParse")) + , ("bindParse", (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", Haskell.MkValueName "pbindParse")) + ] + +{- | PTryFrom instance implementation. + +```haskell +instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PMaybe a) where + type PTryFromExcess PData (PMaybe a) = Const () + ptryFrom' = ptryFromPAsData + +instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PAsData (PMaybe a)) where + type PTryFromExcess PData (PAsData (PMaybe a)) = Const () + ptryFrom' pd f = ... +``` +-} +printDerivePTryFrom :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) +printDerivePTryFrom mn iTyDefs _mkInstanceDoc ty = do + pappDoc <- useVal PlRefs.pappQValName + let resOrErr = do + fromDataE <- deriveFromPlutusDataImplPlutarch mn iTyDefs ty + (ptryFromImplDoc, imps) <- printValue lvPlutusDataBuiltinsForPTryFrom fromDataE + return + ( align $ printValueDef PlRefs.ptryFromMethod (parens $ "\\pd f -> f" <+> parens (parens pappDoc <+> parens ptryFromImplDoc <+> "pd" <+> "," <+> "()")) + , imps + ) + case resOrErr of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Printing an instance definition for PTryFrom failed with: " <> err ^. P.msg) + Right (implDoc, imps) -> do + instancePAsDataDoc <- printPTryFromPAsDataInstanceDef ty implDoc + for_ imps Print.importValue + instanceDoc <- printPTryFromInstanceDef ty + return $ align $ vsep [instanceDoc, instancePAsDataDoc] + +{- | PTryFrom (PAsData a) + +```haskell +instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PAsData (PMaybe a)) where + type PTryFromExcess PData (PAsData (PMaybe a)) = Const () + ptryFrom' pd f = ... +``` +-} +printPTryFromPAsDataInstanceDef :: MonadHaskellBackend t m => PC.Ty -> Doc ann -> m (Doc ann) +printPTryFromPAsDataInstanceDef ty implDefDoc = do + Print.importClass PlRefs.ptryFromQClassName + Print.importClass PlRefs.pisDataQClassName + Print.importType PlRefs.pdataQTyName + Print.importType PlRefs.pasDataQTyName + Print.importType PlRefs.constQTyName + + tyDoc <- Haskell.printTyInner ty + let headDoc = + Haskell.printHsQClassName PlRefs.ptryFromQClassName + <+> Haskell.printHsQTyName PlRefs.pdataQTyName + <+> parens (Haskell.printHsQTyName PlRefs.pasDataQTyName <+> tyDoc) + freeVars = Haskell.collectTyVars ty + pinnerDefDoc = + "type PTryFromExcess" + <+> Haskell.printHsQTyName PlRefs.pdataQTyName + <+> parens (Haskell.printHsQTyName PlRefs.pasDataQTyName <+> tyDoc) + <+> "=" + <+> Haskell.printHsQTyName PlRefs.constQTyName + <+> "()" + in case freeVars of + [] -> + return $ + "instance" + <+> headDoc + <+> "where" + <> hardline + <> space + <> space + <> pinnerDefDoc + <> hardline + <> space + <> space + <> implDefDoc + _other -> do + ctxDoc <- printContext freeVars + return $ + "instance" + <+> ctxDoc + <+> "=>" + <+> headDoc + <+> "where" + <> hardline + <> space + <> space + <> pinnerDefDoc + <> hardline + <> space + <> space + <> implDefDoc + +{- | PTryFrom instance implementation. + +```haskell +instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PMaybe a) where + type PTryFromExcess PData (PMaybe a) = Const () + ptryFrom' = ptryFromPAsData +``` +-} +printPTryFromInstanceDef :: MonadHaskellBackend t m => PC.Ty -> m (Doc ann) +printPTryFromInstanceDef ty = do + ptryFromPAsDataDoc <- useVal PlRefs.ptryFromPAsDataQValName + Print.importClass PlRefs.ptryFromQClassName + Print.importClass PlRefs.pisDataQClassName + Print.importType PlRefs.pdataQTyName + Print.importType PlRefs.pasDataQTyName + Print.importType PlRefs.constQTyName + tyDoc <- Haskell.printTyInner ty + let headDoc = + Haskell.printHsQClassName PlRefs.ptryFromQClassName + <+> Haskell.printHsQTyName PlRefs.pdataQTyName + <+> tyDoc + freeVars = Haskell.collectTyVars ty + + pinnerDefDoc = + "type PTryFromExcess" + <+> Haskell.printHsQTyName PlRefs.pdataQTyName + <+> tyDoc + <+> "=" + <+> Haskell.printHsQTyName PlRefs.constQTyName + <+> "()" + + implDefDoc = printValueDef PlRefs.ptryFromMethod ptryFromPAsDataDoc + in case freeVars of + [] -> + return $ + "instance" + <+> headDoc + <+> "where" + <> hardline + <> space + <> space + <> pinnerDefDoc + <> hardline + <> space + <> space + <> implDefDoc + _other -> do + ctxDoc <- printContext freeVars + return $ + "instance" + <+> ctxDoc + <+> "=>" + <+> headDoc + <+> "where" + <> hardline + <> space + <> space + <> pinnerDefDoc + <> hardline + <> space + <> space + <> implDefDoc + +printContext :: MonadHaskellBackend t m => [PC.Ty] -> m (Doc ann) +printContext tys = do + ctxDocs <- + traverse + ( \t -> do + tyDoc <- Haskell.printTyInner t + return $ + Haskell.printHsQClassName PlRefs.ptryFromQClassName + <+> Haskell.printHsQTyName PlRefs.pdataQTyName + <+> parens (Haskell.printHsQTyName PlRefs.pasDataQTyName <+> tyDoc) + ) + tys + ctxDocs' <- traverse (Haskell.printConstraint PlRefs.pisDataQClassName) tys + return $ + align . group $ + encloseSep + lparen + rparen + comma + (ctxDocs <> ctxDocs') diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/LamVal.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/LamVal.hs similarity index 88% rename from lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/LamVal.hs rename to lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/LamVal.hs index 7158fb5b..82112091 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/LamVal.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/LamVal.hs @@ -1,4 +1,4 @@ -module LambdaBuffers.Codegen.Plutarch.Print.LamVal (printValueE) where +module LambdaBuffers.Codegen.Haskell.Backend.Plutarch.LamVal (printValueE) where import Control.Lens ((&), (.~)) import Control.Monad.Error.Class (MonadError (throwError)) @@ -15,10 +15,10 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), align, backslash, dquotes, group, hardline, hsep, line, parens, vsep, (<+>)) import Proto.Codegen_Fields qualified as P -throwInternalError :: MonadPrint m => String -> m a -throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Plutarch.Print.LamVal] " <> Text.pack msg +type PlutarchLamValMonad m = LV.MonadPrint m HsSyntax.QValName () -type MonadPrint m = LV.MonadPrint m HsSyntax.QValName +throwInternalError :: PlutarchLamValMonad m => String -> m a +throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Plutarch] " <> Text.pack msg withInfo :: PC.InfoLessC b => PC.InfoLess b -> b withInfo x = PC.withInfoLess x id @@ -66,7 +66,7 @@ translates to Plutarch plam (\x -> ) ``` -} -printLamE :: MonadPrint m => (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printLamE :: PlutarchLamValMonad m => (LV.ValueE -> LV.ValueE) -> m (Doc ann) printLamE lamVal = do arg <- LV.freshArg bodyDoc <- printValueE (lamVal arg) @@ -86,7 +86,7 @@ translates to Plutarch (#) (funVal) (argVal) ``` -} -printAppE :: MonadPrint m => LV.ValueE -> LV.ValueE -> m (Doc ann) +printAppE :: PlutarchLamValMonad m => LV.ValueE -> LV.ValueE -> m (Doc ann) printAppE funVal argVal = do funDoc <- printValueE funVal argDoc <- printValueE argVal @@ -111,7 +111,7 @@ pcon (Foo'Bar (x) (y)) TODO(bladyjoker): Add import for the `Foo'Bar` constructor value reference. -} -printCtorE :: MonadPrint m => LV.QCtor -> [LV.ValueE] -> m (Doc ann) +printCtorE :: PlutarchLamValMonad m => LV.QCtor -> [LV.ValueE] -> m (Doc ann) printCtorE _qctor@((_, tyN), (ctorN, _)) prodVals = do prodDocs <- for prodVals (fmap parens . printValueE) let ctorNDoc = HsSyntax.printCtorName (withInfo tyN) (withInfo ctorN) @@ -147,7 +147,7 @@ pmatch foo (\x -> case x of ) ``` -} -printCaseE :: MonadPrint m => LV.QSum -> LV.ValueE -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> m (Doc ann) +printCaseE :: PlutarchLamValMonad m => LV.QSum -> LV.ValueE -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> m (Doc ann) printCaseE _qsum@(qtyN, sumTy) caseVal ctorCont = do caseValDoc <- printValueE caseVal ctorCaseDocs <- @@ -156,14 +156,14 @@ printCaseE _qsum@(qtyN, sumTy) caseVal ctorCont = do (OMap.assocs sumTy) ( \(cn, ty) -> case ty of -- TODO(bladyjoker): Cleanup by refactoring LT.Ty. LT.TyProduct fields _ -> printCtorCase qtyN ctorCont (cn, fields) - _ -> throwInternalError "Got a non-product in Sum." + _other -> throwInternalError "Got a non-product in Sum." ) pmatchDoc <- HsSyntax.printHsQValName <$> LV.importValue pmatchRef pmatchContArgDoc <- LV.freshArg >>= printValueE let casesDoc = "ca" <> align ("se" <+> pmatchContArgDoc <+> "of" <> line <> ctorCaseDocs) return $ pmatchDoc <+> caseValDoc <+> parens (backslash <> pmatchContArgDoc <+> "->" <+> casesDoc) -printCtorCase :: MonadPrint m => PC.QTyName -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> LV.Ctor -> m (Doc ann) +printCtorCase :: PlutarchLamValMonad m => PC.QTyName -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> LV.Ctor -> m (Doc ann) printCtorCase (_, tyn) ctorCont ctor@(ctorN, fields) = do args <- for fields (const LV.freshArg) argDocs <- for args printValueE @@ -192,7 +192,7 @@ pcon (Foo (x) (y)) TODO(bladyjoker): Add Product constructor import. -} -printProductE :: MonadPrint m => LV.QProduct -> [LV.ValueE] -> m (Doc ann) +printProductE :: PlutarchLamValMonad m => LV.QProduct -> [LV.ValueE] -> m (Doc ann) printProductE ((_, tyN), _) vals = do fieldDocs <- for vals (fmap parens . printValueE) let ctorDoc = HsSyntax.printMkCtor (withInfo tyN) @@ -217,7 +217,7 @@ translates to Plutarch pmatch foo (\(Foo x y) -> ) ``` -} -printLetE :: MonadPrint m => LV.QProduct -> LV.ValueE -> ([LV.ValueE] -> LV.ValueE) -> m (Doc ann) +printLetE :: PlutarchLamValMonad m => LV.QProduct -> LV.ValueE -> ([LV.ValueE] -> LV.ValueE) -> m (Doc ann) printLetE ((_, tyN), fields) prodVal letCont = do prodValDoc <- printValueE prodVal args <- for fields (const LV.freshArg) @@ -240,7 +240,7 @@ translates to Plutarch pcon (PCons x (PCons y PNil)) ``` -} -printListE :: MonadPrint m => [LV.ValueE] -> m (Doc ann) +printListE :: PlutarchLamValMonad m => [LV.ValueE] -> m (Doc ann) printListE [] = do pconDoc <- HsSyntax.printHsQValName <$> LV.importValue pconRef pnilDoc <- HsSyntax.printHsQValName <$> LV.importValue pnilRef @@ -291,13 +291,13 @@ case xs of h4:t4 -> d xs -- OTHER ``` -} -printCaseListE :: MonadPrint m => LV.ValueE -> [(Int, [LV.ValueE] -> LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printCaseListE :: PlutarchLamValMonad m => LV.ValueE -> [(Int, [LV.ValueE] -> LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) printCaseListE xs cases otherCase = do let maxLength = maximum $ fst <$> cases otherCaseDoc <- printValueE (otherCase xs) printCaseListE' xs cases otherCaseDoc 0 maxLength [] -printCaseListE' :: MonadPrint m => LV.ValueE -> [(Int, [LV.ValueE] -> LV.ValueE)] -> Doc ann -> Int -> Int -> [LV.ValueE] -> m (Doc ann) +printCaseListE' :: PlutarchLamValMonad m => LV.ValueE -> [(Int, [LV.ValueE] -> LV.ValueE)] -> Doc ann -> Int -> Int -> [LV.ValueE] -> m (Doc ann) printCaseListE' _xs _cases otherCaseDoc currentLength maxLength _args | currentLength > maxLength = return otherCaseDoc printCaseListE' xs cases otherCaseDoc currentLength maxLength args = do pnilRefDoc <- HsSyntax.printHsQValName <$> LV.importValue pnilRef @@ -345,7 +345,7 @@ pconstant 1 pconstant (-1) ``` -} -printIntE :: MonadPrint m => Int -> m (Doc ann) +printIntE :: PlutarchLamValMonad m => Int -> m (Doc ann) printIntE i = do pconstantRefDoc <- HsSyntax.printHsQValName <$> LV.importValue pconstantRef return $ pconstantRefDoc <+> if i < 0 then parens (pretty i) else pretty i @@ -362,7 +362,7 @@ translates to Plutarch pif ((#==) (x) (pconstant 0)) (pif ((#==) (x) (pconstant 123)) ) ``` -} -printCaseIntE :: MonadPrint m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printCaseIntE :: PlutarchLamValMonad m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) printCaseIntE caseIntVal [] otherCase = printValueE (otherCase caseIntVal) -- TODO(bladyjoker): Why is this a function and not just a ValueE? printCaseIntE caseIntVal ((iVal, bodyVal) : cases) otherCase = do pifRefDoc <- HsSyntax.printHsQValName <$> LV.importValue pifRef @@ -385,7 +385,7 @@ translates to Plutarch pconstant "Dražen Popović" ``` -} -printTextE :: MonadPrint m => Text.Text -> m (Doc ann) +printTextE :: PlutarchLamValMonad m => Text.Text -> m (Doc ann) printTextE t = do pconstantRefDoc <- HsSyntax.printHsQValName <$> LV.importValue pconstantRef return $ pconstantRefDoc <+> dquotes (pretty t) @@ -402,7 +402,7 @@ translates to Plutarch pif ((#==) (x) (pconstant "a")) (pif ((#==) (x) (pconstant "b")) ) ``` -} -printCaseTextE :: MonadPrint m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printCaseTextE :: PlutarchLamValMonad m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) printCaseTextE caseTxtVal [] otherCase = printValueE (otherCase caseTxtVal) -- TODO(bladyjoker): Why is this a function and not just a ValueE? printCaseTextE caseTxtVal ((txtVal, bodyVal) : cases) otherCase = do pifRefDoc <- HsSyntax.printHsQValName <$> LV.importValue pifRef @@ -413,12 +413,12 @@ printCaseTextE caseTxtVal ((txtVal, bodyVal) : cases) otherCase = do elseDoc <- printCaseIntE caseTxtVal cases otherCase return $ pifRefDoc <+> parens (peqRefDoc <+> parens caseTxtValDoc <+> parens txtValDoc) <+> parens bodyValDoc <+> parens elseDoc -printRefE :: MonadPrint m => LV.Ref -> m (Doc ann) +printRefE :: PlutarchLamValMonad m => LV.Ref -> m (Doc ann) printRefE ref = do qvn <- LV.resolveRef ref HsSyntax.printHsQValName <$> LV.importValue qvn -printValueE :: MonadPrint m => LV.ValueE -> m (Doc ann) +printValueE :: PlutarchLamValMonad m => LV.ValueE -> m (Doc ann) printValueE (LV.VarE v) = return $ pretty v printValueE (LV.RefE ref) = printRefE ref printValueE (LV.LamE lamVal) = printLamE lamVal diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/Refs.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/Refs.hs new file mode 100644 index 00000000..80e357c5 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/Refs.hs @@ -0,0 +1,92 @@ +module LambdaBuffers.Codegen.Haskell.Backend.Plutarch.Refs ( + plutusTypeQClassName, + pconMethod, + pmatchMethod, + peqQClassName, + peqMethod, + pisDataQClassName, + ptryFromQClassName, + ptryFromMethod, + pconQValName, + pappQValName, + pdataQValName, + peqQValName, + punsafeCoerceQValName, + pdataQTyName, + constQTyName, + pasDataQTyName, + ptryFromPAsDataQValName, + termQTyName, + scopeQTyName, + ptypeQTyName, + showQClassName, + genericQClassName, +) where + +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell + +plutusTypeQClassName :: Haskell.QClassName +plutusTypeQClassName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Internal.PlutusType", Haskell.MkClassName "PlutusType") + +pconMethod :: Haskell.ValueName +pconMethod = Haskell.MkValueName "pcon'" + +pmatchMethod :: Haskell.ValueName +pmatchMethod = Haskell.MkValueName "pmatch'" + +peqQClassName :: Haskell.QClassName +peqQClassName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Bool", Haskell.MkClassName "PEq") + +peqMethod :: Haskell.ValueName +peqMethod = Haskell.MkValueName "#==" + +pisDataQClassName :: Haskell.QClassName +pisDataQClassName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Builtin", Haskell.MkClassName "PIsData") + +ptryFromQClassName :: Haskell.QClassName +ptryFromQClassName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.TryFrom", Haskell.MkClassName "PTryFrom") + +ptryFromMethod :: Haskell.ValueName +ptryFromMethod = Haskell.MkValueName "ptryFrom'" + +pconQValName :: Haskell.QValName +pconQValName = (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch", Haskell.MkValueName "pcon") + +pappQValName :: Haskell.QValName +pappQValName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Prelude", Haskell.MkValueName "#") + +pdataQValName :: Haskell.QValName +pdataQValName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Builtin", Haskell.MkValueName "pdata") + +peqQValName :: Haskell.QValName +peqQValName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Bool", Haskell.MkValueName "#==") + +punsafeCoerceQValName :: Haskell.QValName +punsafeCoerceQValName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Unsafe", Haskell.MkValueName "punsafeCoerce") + +pdataQTyName :: Haskell.QTyName +pdataQTyName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Builtin", Haskell.MkTyName "PData") + +constQTyName :: Haskell.QTyName +constQTyName = (Haskell.MkCabalPackageName "base", Haskell.MkModuleName "Data.Functor.Const", Haskell.MkTyName "Const") + +pasDataQTyName :: Haskell.QTyName +pasDataQTyName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Builtin", Haskell.MkTyName "PAsData") + +ptryFromPAsDataQValName :: Haskell.QValName +ptryFromPAsDataQValName = (Haskell.MkCabalPackageName "lbr-plutarch", Haskell.MkModuleName "LambdaBuffers.Runtime.Plutarch", Haskell.MkValueName "ptryFromPAsData") + +termQTyName :: Haskell.QTyName +termQTyName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch", Haskell.MkTyName "Term") + +scopeQTyName :: Haskell.QTyName +scopeQTyName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch", Haskell.MkTyName "S") + +ptypeQTyName :: Haskell.QTyName +ptypeQTyName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch", Haskell.MkTyName "PType") + +showQClassName :: Haskell.QClassName +showQClassName = (Haskell.MkCabalPackageName "plutarch", Haskell.MkModuleName "Plutarch.Show", Haskell.MkClassName "PShow") + +genericQClassName :: Haskell.QClassName +genericQClassName = (Haskell.MkCabalPackageName "base", Haskell.MkModuleName "GHC.Generics", Haskell.MkClassName "Generic") diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/TyDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/TyDef.hs similarity index 64% rename from lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/TyDef.hs rename to lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/TyDef.hs index df57b79b..c9518e2b 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/TyDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/Plutarch/TyDef.hs @@ -1,18 +1,17 @@ -module LambdaBuffers.Codegen.Plutarch.Print.TyDef (printTyDef, printTyInner) where +module LambdaBuffers.Codegen.Haskell.Backend.Plutarch.TyDef (printTyDef, printTyInner) where import Control.Lens (view) import Control.Monad.Reader.Class (asks) import Data.Foldable (Foldable (toList)) import Data.Map qualified as Map import LambdaBuffers.Codegen.Config (cfgOpaques) -import LambdaBuffers.Codegen.Haskell.Print.MonadPrint (MonadPrint) -import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsPrint -import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsSyntax -import LambdaBuffers.Codegen.Plutarch.Print.Refs qualified as PlRefs -import LambdaBuffers.Codegen.Plutarch.Print.Syntax qualified as PlSyntax +import LambdaBuffers.Codegen.Haskell.Backend (MonadHaskellBackend) +import LambdaBuffers.Codegen.Haskell.Backend.Plutarch.Refs qualified as PlRefs +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HaskellNative +import LambdaBuffers.Codegen.Haskell.Print.TyDef qualified as HaskellNative import LambdaBuffers.Codegen.Print qualified as Print import LambdaBuffers.ProtoCompat qualified as PC -import Prettyprinter (Doc, Pretty (pretty), align, dot, encloseSep, equals, group, hardline, hsep, parens, pipe, sep, space, vsep, (<+>)) +import Prettyprinter (Doc, align, encloseSep, equals, group, hardline, hsep, parens, pipe, sep, space, vsep, (<+>)) {- | Prints the type definition in Plutarch. @@ -80,7 +79,7 @@ import qualified Some.Configured.Opaque NOTE(bladyjoker): The full qualification is omitted in the following docstrings for brevity, as are deriving statements. -} -printTyDef :: MonadPrint m => PC.TyDef -> m (Doc ann) +printTyDef :: MonadHaskellBackend t m => PC.TyDef -> m (Doc ann) printTyDef (PC.TyDef tyN tyabs _) = do Print.importType PlRefs.termQTyName Print.importType PlRefs.scopeQTyName @@ -89,25 +88,25 @@ printTyDef (PC.TyDef tyN tyabs _) = do drvGenericDoc <- printDerivingGeneric drvShowDoc <- printDerivingShow (kw, absDoc) <- printTyAbs tyN tyabs - let tyDefDoc = group $ printTyDefKw kw <+> HsSyntax.printTyName tyN <+> absDoc - if kw == HsSyntax.SynonymTyDef + let tyDefDoc = group $ printTyDefKw kw <+> HaskellNative.printTyName tyN <+> absDoc + if kw == HaskellNative.SynonymTyDef then return tyDefDoc else return $ tyDefDoc <> hardline <> space <> space <> align (vsep [drvGenericDoc, drvShowDoc]) -printDerivingShow :: MonadPrint m => m (Doc ann) +printDerivingShow :: MonadHaskellBackend t m => m (Doc ann) printDerivingShow = do Print.importClass PlRefs.showQClassName - return $ "deriving anyclass" <+> HsSyntax.printHsQClassName PlRefs.showQClassName + return $ "deriving anyclass" <+> HaskellNative.printHsQClassName PlRefs.showQClassName -printDerivingGeneric :: MonadPrint m => m (Doc ann) +printDerivingGeneric :: MonadHaskellBackend t m => m (Doc ann) printDerivingGeneric = do Print.importClass PlRefs.genericQClassName - return $ "deriving stock" <+> HsSyntax.printHsQClassName PlRefs.genericQClassName + return $ "deriving stock" <+> HaskellNative.printHsQClassName PlRefs.genericQClassName -printTyDefKw :: HsSyntax.TyDefKw -> Doc ann -printTyDefKw HsSyntax.DataTyDef = "data" -printTyDefKw HsSyntax.NewtypeTyDef = "newtype" -printTyDefKw HsSyntax.SynonymTyDef = "type" +printTyDefKw :: HaskellNative.TyDefKw -> Doc ann +printTyDefKw HaskellNative.DataTyDef = "data" +printTyDefKw HaskellNative.NewtypeTyDef = "newtype" +printTyDefKw HaskellNative.SynonymTyDef = "type" {- | Prints the type abstraction. @@ -145,13 +144,13 @@ newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a NOTE(bladyjoker): We don't print the `s` Scope type argument/variable and others because `The type synonym ‘Prelude.Plutarch.Integer’ should have 1 argument, but has been given none` in `Term s Prelude.Plutarch.Integer`. We also don't print other args because it's either all args or none. -} -printTyAbs :: MonadPrint m => PC.TyName -> PC.TyAbs -> m (HsSyntax.TyDefKw, Doc ann) +printTyAbs :: MonadHaskellBackend t m => PC.TyName -> PC.TyAbs -> m (HaskellNative.TyDefKw, Doc ann) printTyAbs tyN (PC.TyAbs args body _) = do (kw, bodyDoc) <- printTyBody tyN (toList args) body let scopeArgDoc :: Doc ann - scopeArgDoc = parens ("s" <+> "::" <+> HsSyntax.printHsQTyName PlRefs.scopeQTyName) + scopeArgDoc = parens ("s" <+> "::" <+> HaskellNative.printHsQTyName PlRefs.scopeQTyName) argsDoc = - if kw == HsPrint.SynonymTyDef + if kw == HaskellNative.SynonymTyDef then mempty else hsep $ (printTyArg <$> toList args) <> [scopeArgDoc] return (kw, group $ argsDoc <+> equals <+> align bodyDoc) @@ -191,22 +190,30 @@ newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a TODO(bladyjoker): Revisit empty records and prods. -} -printTyBody :: MonadPrint m => PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (HsSyntax.TyDefKw, Doc ann) -printTyBody tyN _ (PC.SumI s) = (HsSyntax.DataTyDef,) <$> printSum tyN s +printTyBody :: MonadHaskellBackend t m => PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (HaskellNative.TyDefKw, Doc ann) +printTyBody tyN _ (PC.SumI s) = (HaskellNative.DataTyDef,) <$> printSum tyN s printTyBody tyN _ (PC.ProductI p@(PC.Product fields _)) = case toList fields of - [] -> return (HsSyntax.DataTyDef, HsSyntax.printMkCtor tyN) - [_] -> return (HsSyntax.NewtypeTyDef, HsSyntax.printMkCtor tyN <+> printProd p) - _ -> return (HsSyntax.DataTyDef, HsSyntax.printMkCtor tyN <+> printProd p) + [] -> return (HaskellNative.DataTyDef, HaskellNative.printMkCtor tyN) + [_] -> do + prodDoc <- printProd p + return (HaskellNative.NewtypeTyDef, HaskellNative.printMkCtor tyN <+> prodDoc) + _other -> do + prodDoc <- printProd p + return (HaskellNative.DataTyDef, HaskellNative.printMkCtor tyN <+> prodDoc) printTyBody tyN _ (PC.RecordI r@(PC.Record fields _)) = case toList fields of - [] -> return (HsSyntax.DataTyDef, HsSyntax.printMkCtor tyN) - [_] -> return (HsSyntax.NewtypeTyDef, HsSyntax.printMkCtor tyN <+> printRec r) - _ -> return (HsSyntax.DataTyDef, HsSyntax.printMkCtor tyN <+> printRec r) + [] -> return (HaskellNative.DataTyDef, HaskellNative.printMkCtor tyN) + [_] -> do + recDoc <- printRec r + return (HaskellNative.NewtypeTyDef, HaskellNative.printMkCtor tyN <+> recDoc) + _other -> do + recDoc <- printRec r + return (HaskellNative.DataTyDef, HaskellNative.printMkCtor tyN <+> recDoc) printTyBody tyN _args (PC.OpaqueI si) = do opqs <- asks (view $ Print.ctxConfig . cfgOpaques) mn <- asks (view $ Print.ctxModule . #moduleName) case Map.lookup (PC.mkInfoLess mn, PC.mkInfoLess tyN) opqs of Nothing -> Print.throwInternalError si ("Should have an Opaque configured for " <> show tyN) - Just hqtyn -> return (HsSyntax.SynonymTyDef, HsSyntax.printHsQTyName hqtyn) + Just hqtyn -> return (HaskellNative.SynonymTyDef, HaskellNative.printHsQTyName hqtyn) {- | Prints the type (abstraction) arguments. @@ -243,7 +250,7 @@ newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a ``` -} printTyArg :: PC.TyArg -> Doc ann -printTyArg (PC.TyArg vn _ _) = parens (HsSyntax.printVarName vn <+> "::" <+> HsSyntax.printHsQTyName PlRefs.ptypeQTyName) +printTyArg (PC.TyArg vn _ _) = parens (HaskellNative.printVarName vn <+> "::" <+> HaskellNative.printHsQTyName PlRefs.ptypeQTyName) {- | Prints the sum body. @@ -277,9 +284,9 @@ newtype FooProdUnit (a :: PType) (s :: S) = FooProdUnit (Term s (PAsData (PMaybe newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a))) ``` -} -printSum :: MonadPrint m => PC.TyName -> PC.Sum -> m (Doc ann) +printSum :: MonadHaskellBackend t m => PC.TyName -> PC.Sum -> m (Doc ann) printSum tyN (PC.Sum ctors _) = do - let ctorDocs = printCtor tyN <$> toList ctors + ctorDocs <- traverse (printCtor tyN) (toList ctors) return $ group $ if null ctors @@ -318,11 +325,11 @@ newtype FooProdUnit (a :: PType) (s :: S) = FooProdUnit (Term s (PAsData (PMaybe newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a))) ``` -} -printCtor :: PC.TyName -> PC.Constructor -> Doc ann -printCtor tyN (PC.Constructor ctorName prod) = - let ctorNDoc = HsSyntax.printCtorName tyN ctorName - prodDoc = printProd prod - in group $ ctorNDoc <+> prodDoc -- TODO(bladyjoker): Adds extra space when empty. +printCtor :: MonadHaskellBackend t m => PC.TyName -> PC.Constructor -> m (Doc ann) +printCtor tyN (PC.Constructor ctorName prod) = do + let ctorNDoc = HaskellNative.printCtorName tyN ctorName + prodDoc <- printProd prod + return $ group $ ctorNDoc <+> prodDoc -- TODO(bladyjoker): Adds extra space when empty. {- | Prints the record body. @@ -360,7 +367,7 @@ newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a ............................. ``` -} -printRec :: PC.Record -> Doc ann +printRec :: MonadHaskellBackend t m => PC.Record -> m (Doc ann) printRec (PC.Record fields si) = printProd (PC.Product (PC.fieldTy <$> toList fields) si) {- | Prints the product body. @@ -395,129 +402,19 @@ newtype FooProdUnit (a :: PType) (s :: S) = FooProdUnit (Term s (PAsData (PMaybe newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a))) ``` -} -printProd :: PC.Product -> Doc ann +printProd :: MonadHaskellBackend t m => PC.Product -> m (Doc ann) printProd (PC.Product fields _) = do - if null fields - then mempty - else align $ sep ((\f -> parens (HsSyntax.printHsQTyName PlRefs.termQTyName <+> "s" <+> parens (HsSyntax.printHsQTyName PlRefs.pasDataQTyName <+> printTyInner f))) <$> fields) - -printTyInner :: PC.Ty -> Doc ann -printTyInner (PC.TyVarI v) = printTyVar v -printTyInner (PC.TyRefI r) = printTyRef r -printTyInner (PC.TyAppI a) = printTyAppInner a - -{- | Prints the 'inner' type application. - -```lbf -sum FooSum a b = Foo (Maybe a) | Bar b - ....... -prod FooProd a b = (Maybe a) b - ....... -record FooRecord a b = { a: Maybe a, b: b } - ....... -opaque FooOpaque a b - -prod FooProdUnit a = (Maybe a) - ....... -record FooRecUnit a = { a: Maybe a } - ....... -``` - -translates to - -```haskell -data FooSum (a :: PType) (b :: PType) (s :: S) = FooSum'Foo (Term s (PAsData (PMaybe a))) | FooSum'Bar (Term s (PAsData b)) - .......... -data FooProd (a :: PType) (b :: PType) (s :: S) = FooProd (Term s (PAsData (PMaybe a))) (Term s (PAsData b)) - .......... -data FooRecord (a :: PType) (b :: PType) (s :: S) = FooRecord (Term s (PAsData (PMaybe a))) (Term s (PAsData b)) - .......... -type FooOpaque = Some.Configured.Opaque.FooOpaque - -newtype FooProdUnit (a :: PType) (s :: S) = FooProdUnit (Term s (PAsData (PMaybe a))) - .......... -newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a))) - .......... -``` --} -printTyAppInner :: PC.TyApp -> Doc ann -printTyAppInner (PC.TyApp f args _) = - let fDoc = printTyInner f - argsDoc = printTyInner <$> args - in group $ parens $ fDoc <+> align (sep argsDoc) - -{- | Prints the type reference. - -```lbf -sum FooSum a b = Foo (Maybe a) | Bar b - ..... -prod FooProd a b = (Maybe a) b - ..... -record FooRecord a b = { a: Maybe a, b: b } - ..... -opaque FooOpaque a b - -prod FooProdUnit a = (Maybe a) - ..... -record FooRecUnit a = { a: Maybe a } - ..... -``` - -translates to - -```haskell -data FooSum (a :: PType) (b :: PType) (s :: S) = FooSum'Foo (Term s (PAsData (PMaybe a))) | FooSum'Bar (Term s (PAsData b)) - ...... -data FooProd (a :: PType) (b :: PType) (s :: S) = FooProd (Term s (PAsData (PMaybe a))) (Term s (PAsData b)) - ...... -data FooRecord (a :: PType) (b :: PType) (s :: S) = FooRecord (Term s (PAsData (PMaybe a))) (Term s (PAsData b)) - ...... -type FooOpaque = Some.Configured.Opaque.FooOpaque - -newtype FooProdUnit (a :: PType) (s :: S) = FooProdUnit (Term s (PAsData (PMaybe a))) - ...... -newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a))) - ...... -``` --} -printTyRef :: PC.TyRef -> Doc ann -printTyRef (PC.LocalI (PC.LocalRef tn _)) = group $ HsSyntax.printTyName tn -printTyRef (PC.ForeignI fr) = let (_, HsSyntax.MkModuleName hmn, HsSyntax.MkTyName htn) = PlSyntax.fromLbForeignRef fr in pretty hmn <> dot <> pretty htn - -{- | Prints the type variable (remember args are different to vars). - -```lbf -sum FooSum a b = Foo (Maybe a) | Bar b - . . -prod FooProd a b = (Maybe a) b - . . -record FooRecord a b = { a: Maybe a, b: b } - . . -opaque FooOpaque a b - -prod FooProdUnit a = (Maybe a) - . -record FooRecUnit a = { a: Maybe a } - . -``` - -translates to - -```haskell -data FooSum (a :: PType) (b :: PType) (s :: S) = FooSum'Foo (Term s (PAsData (PMaybe a))) | FooSum'Bar (Term s (PAsData b)) - . . -data FooProd (a :: PType) (b :: PType) (s :: S) = FooProd (Term s (PAsData (PMaybe a))) (Term s (PAsData b)) - . . -data FooRecord (a :: PType) (b :: PType) (s :: S) = FooRecord (Term s (PAsData (PMaybe a))) (Term s (PAsData b)) - . . -type FooOpaque = Some.Configured.Opaque.FooOpaque - -newtype FooProdUnit (a :: PType) (s :: S) = FooProdUnit (Term s (PAsData (PMaybe a))) - . -newtype FooRecUnit (a :: PType) (s :: S) = FooRecUnit (Term s (PAsData (PMaybe a))) - . + fieldDocs <- + traverse + ( \f -> do + fieldDoc <- printTyInner f + return $ parens (HaskellNative.printHsQTyName PlRefs.termQTyName <+> "s" <+> parens (HaskellNative.printHsQTyName PlRefs.pasDataQTyName <+> fieldDoc)) + ) + fields + return $ + if null fields + then mempty + else align $ sep fieldDocs -``` --} -printTyVar :: PC.TyVar -> Doc ann -printTyVar (PC.TyVar vn) = HsSyntax.printVarName vn +printTyInner :: MonadHaskellBackend t m => PC.Ty -> m (Doc ann) +printTyInner = HaskellNative.printTyInner diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx.hs new file mode 100644 index 00000000..3dd79bb9 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx.hs @@ -0,0 +1,28 @@ +module LambdaBuffers.Codegen.Haskell.Backend.PlutusTx (PlutusTxHaskellBackend) where + +import Control.Lens ((^.)) +import Data.Text qualified as Text +import LambdaBuffers.Codegen.Haskell.Backend (IsHaskellBackend (HaskellBackendContext, HaskellBackendState, filepathFromLbModuleName, fromLbModuleName, ghcOptions, languageExtensions, printImplementation, printModule, printTyDef)) +import LambdaBuffers.Codegen.Haskell.Backend.PlutusTx.Derive qualified as PlutusTxHaskellBackend +import LambdaBuffers.Codegen.Haskell.Print qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.TyDef qualified as Haskell + +data PlutusTxHaskellBackend + +instance IsHaskellBackend PlutusTxHaskellBackend where + type HaskellBackendContext PlutusTxHaskellBackend = () + type HaskellBackendState PlutusTxHaskellBackend = () + fromLbModuleName mn = Haskell.MkModuleName $ Text.intercalate "." ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) <> ".PlutusTx" + filepathFromLbModuleName mn = Text.unpack $ Text.intercalate "/" ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) <> "/PlutusTx.hs" + printImplementation = PlutusTxHaskellBackend.instancePrinters + printModule = Haskell.printModule + printTyDef = Haskell.printTyDef + languageExtensions = ["NoImplicitPrelude", "NoPolyKinds"] -- NOTE(bladyjoker): NoPolyKinds is needed for PlutusTx compiler, quite safe. + ghcOptions = + [ "-fno-ignore-interface-pragmas" -- NOTE(bladyjoker): All this is necessary for PlutusTx compiler, apparently safe. + , "-fno-omit-interface-pragmas" + , "-fno-specialise" + , "-fno-strictness" + , "-fobject-code" + ] diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx/Derive.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx/Derive.hs new file mode 100644 index 00000000..db06be4f --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx/Derive.hs @@ -0,0 +1,129 @@ +module LambdaBuffers.Codegen.Haskell.Backend.PlutusTx.Derive (printDeriveEqPlutusTx, printDeriveToPlutusData, printDeriveFromPlutusData, instancePrinters) where + +import Control.Lens ((^.)) +import Data.Foldable (for_) +import Data.Map (Map) +import Data.Map qualified as Map +import Data.Set (Set) +import LambdaBuffers.Codegen.Haskell.Backend (MonadHaskellBackend) +import LambdaBuffers.Codegen.Haskell.Backend.PlutusTx.LamVal qualified as PlutusTx +import LambdaBuffers.Codegen.Haskell.Print.LamVal qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as H +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell +import LambdaBuffers.Codegen.LamVal qualified as LV +import LambdaBuffers.Codegen.LamVal.Eq (deriveEqImpl) +import LambdaBuffers.Codegen.LamVal.MonadPrint qualified as LV +import LambdaBuffers.Codegen.LamVal.PlutusData (deriveFromPlutusDataImpl, deriveToPlutusDataImpl) +import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.ProtoCompat qualified as PC +import Prettyprinter (Doc, align, equals, hardline, (<+>)) +import Proto.Codegen_Fields qualified as P + +instancePrinters :: + MonadHaskellBackend t m => + Map + H.QClassName + ( PC.ModuleName -> + PC.TyDefs -> + (Doc ann -> m (Doc ann)) -> + PC.Ty -> + m (Doc ann) + ) +instancePrinters = + Map.fromList + [ + ( (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Eq", H.MkClassName "Eq") + , printDeriveEqPlutusTx + ) + , + ( (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkClassName "ToData") + , printDeriveToPlutusData + ) + , + ( (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkClassName "FromData") + , printDeriveFromPlutusData + ) + ] + +printValue :: (LV.Ref -> Maybe Haskell.QValName) -> LV.ValueE -> Either LV.PrintError (Doc ann, Set Haskell.QValName) +printValue builtins valE = LV.runPrint (LV.Context builtins PlutusTx.lamValContext) (Haskell.printValueE valE) + +lvEqBuiltinsPlutusTx :: LV.Ref -> Maybe Haskell.QValName +lvEqBuiltinsPlutusTx (_ty, refName) = + Map.lookup refName $ + Map.fromList + [ ("eq", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Eq", H.MkValueName "==")) + , ("and", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Bool", H.MkValueName "&&")) + , ("true", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Bool", H.MkValueName "True")) + , ("false", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Bool", H.MkValueName "False")) + ] + +eqClassMethodName :: H.ValueName +eqClassMethodName = H.MkValueName "==" + +printDeriveEqPlutusTx :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) +printDeriveEqPlutusTx mn iTyDefs mkInstanceDoc ty = do + case deriveEqImpl mn iTyDefs ty of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Prelude.Eq LamVal implementation from a type failed with: " <> err ^. P.msg) + Right valE -> do + case printValue lvEqBuiltinsPlutusTx valE of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Interpreting LamVal into Haskell failed with: " <> err ^. P.msg) + Right (implDoc, imps) -> do + instanceDoc <- mkInstanceDoc (align $ printInlineable eqClassMethodName <> hardline <> printValueDef eqClassMethodName implDoc) + for_ imps Print.importValue + return instanceDoc + +printInlineable :: H.ValueName -> Doc ann +printInlineable valName = "{-# INLINABLE" <+> H.printHsValName valName <+> "#-}" + +lvPlutusDataBuiltins :: LV.Ref -> Maybe Haskell.QValName +lvPlutusDataBuiltins (_ty, refName) = + Map.lookup refName $ + Map.fromList + [ ("toPlutusData", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkValueName "toBuiltinData")) + , ("fromPlutusData", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkValueName "fromBuiltinData")) + , ("casePlutusData", (H.MkCabalPackageName "lbr-plutustx", H.MkModuleName "LambdaBuffers.Runtime.PlutusTx.LamVal", H.MkValueName "casePlutusData")) + , ("integerData", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Builtins", H.MkValueName "mkI")) + , ("constrData", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Builtins", H.MkValueName "mkConstr")) + , ("listData", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Builtins", H.MkValueName "mkList")) + , ("succeedParse", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Maybe", H.MkValueName "Just")) + , ("failParse", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Maybe", H.MkValueName "Nothing")) + , ("bindParse", (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx.Prelude", H.MkValueName ">>=")) + ] + +toPlutusDataClassMethodName :: H.ValueName +toPlutusDataClassMethodName = H.MkValueName "toBuiltinData" + +printDeriveToPlutusData :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) +printDeriveToPlutusData mn iTyDefs mkInstanceDoc ty = do + case deriveToPlutusDataImpl mn iTyDefs ty of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Plutus.V1.PlutusData LamVal implementation from a type failed with: " <> err ^. P.msg) + Right valE -> do + case printValue lvPlutusDataBuiltins valE of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Interpreting LamVal into Haskell failed with: " <> err ^. P.msg) + Right (implDoc, imps) -> do + instanceDoc <- mkInstanceDoc (align $ printInlineable toPlutusDataClassMethodName <> hardline <> printValueDef toPlutusDataClassMethodName implDoc) + for_ imps Print.importValue + return instanceDoc + +printValueDef :: H.ValueName -> Doc ann -> Doc ann +printValueDef valName valDoc = H.printHsValName valName <+> equals <+> valDoc + +fromPlutusDataClassMethodName :: H.ValueName +fromPlutusDataClassMethodName = H.MkValueName "fromBuiltinData" + +builtinDataToDataRef :: H.QValName +builtinDataToDataRef = (H.MkCabalPackageName "plutus-tx", H.MkModuleName "PlutusTx", H.MkValueName "builtinDataToData") + +printDeriveFromPlutusData :: MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> m (Doc ann)) -> PC.Ty -> m (Doc ann) +printDeriveFromPlutusData mn iTyDefs mkInstanceDoc ty = do + case deriveFromPlutusDataImpl mn iTyDefs ty of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Plutus.V1.PlutusData LamVal implementation from a type failed with: " <> err ^. P.msg) + Right valE -> do + case printValue lvPlutusDataBuiltins valE of + Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Interpreting LamVal into Haskell failed with: " <> err ^. P.msg) + Right (implDoc, imps) -> do + instanceDoc <- mkInstanceDoc (align $ printInlineable fromPlutusDataClassMethodName <> hardline <> printValueDef fromPlutusDataClassMethodName implDoc) + Print.importValue builtinDataToDataRef + for_ imps Print.importValue + return instanceDoc diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx/LamVal.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx/LamVal.hs new file mode 100644 index 00000000..c58bb716 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Backend/PlutusTx/LamVal.hs @@ -0,0 +1,32 @@ +module LambdaBuffers.Codegen.Haskell.Backend.PlutusTx.LamVal (lamValContext) where + +import Data.Traversable (for) +import LambdaBuffers.Codegen.Haskell.Print.LamVal (HaskellLamValContext (HaskellLamValContext), HaskellLamValMonad) +import LambdaBuffers.Codegen.Haskell.Print.LamVal qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as Haskell +import LambdaBuffers.Codegen.LamVal qualified as LV +import LambdaBuffers.Codegen.LamVal.MonadPrint qualified as LV +import Prettyprinter (Doc, align, comma, encloseSep, group, lbracket, parens, rbracket, (<+>)) + +lamValContext :: HaskellLamValContext +lamValContext = HaskellLamValContext {ctx'printCaseIntE = printCaseIntE} + +-- NOTE(bladyjoker): This is due to PlutusTx needing this to use the PlutusTx.Eq instances. +caseIntERef :: Haskell.QValName +caseIntERef = (Haskell.MkCabalPackageName "lbr-plutustx", Haskell.MkModuleName "LambdaBuffers.Runtime.PlutusTx.LamVal", Haskell.MkValueName "caseIntE") + +--- | `printCaseIntE i [(1, x), (2,y)] (\other -> z)` translates into `LambdaBuffers.Runtime.PlutusTx.LamVal.caseIntE i [(1,x), (2,y)] (\other -> z)` +printCaseIntE :: HaskellLamValMonad m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printCaseIntE caseIntVal cases otherCase = do + caseIntERefDoc <- Haskell.printHsQValName <$> LV.importValue caseIntERef + caseValDoc <- Haskell.printValueE caseIntVal + caseDocs <- + for + cases + ( \(conditionVal, bodyVal) -> do + conditionDoc <- Haskell.printValueE conditionVal + bodyDoc <- Haskell.printValueE bodyVal + return $ group $ parens (conditionDoc <+> "," <+> bodyDoc) + ) + otherDoc <- Haskell.printLamE otherCase + return $ group $ caseIntERefDoc <+> align (caseValDoc <+> align (encloseSep lbracket rbracket comma caseDocs) <+> otherDoc) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print.hs index 67a472d5..3134dfea 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print.hs @@ -6,21 +6,20 @@ Note that a single LambdaBuffers 'class' can be unpacked into several related Haskell classes and that's why it's a list of qualified Haskell class names. -} -module LambdaBuffers.Codegen.Haskell.Print (MonadPrint, printModule, PrintModuleEnv (..)) where +module LambdaBuffers.Codegen.Haskell.Print (printModule) where import Control.Lens (view, (^.)) import Control.Monad.Reader.Class (ask, asks) import Control.Monad.State.Class (MonadState (get)) import Data.Foldable (Foldable (toList), foldrM) -import Data.Map (Map) import Data.Map qualified as Map import Data.Set (Set) import Data.Set qualified as Set import Data.Text (Text) import Data.Traversable (for) import LambdaBuffers.Codegen.Config qualified as C +import LambdaBuffers.Codegen.Haskell.Backend (IsHaskellBackend (fromLbModuleName, ghcOptions, languageExtensions, printImplementation, printTyDef), MonadHaskellBackend) import LambdaBuffers.Codegen.Haskell.Print.InstanceDef (printInstanceDef) -import LambdaBuffers.Codegen.Haskell.Print.MonadPrint (MonadPrint) import LambdaBuffers.Codegen.Haskell.Print.Syntax ( cabalPackageNameToText, printTyName, @@ -31,70 +30,43 @@ import LambdaBuffers.Codegen.Print qualified as Print import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), align, comma, encloseSep, group, hsep, line, lparen, rparen, space, vsep, (<+>)) -data PrintModuleEnv m ann = PrintModuleEnv - { env'printModuleName :: PC.ModuleName -> Doc ann - , env'implementationPrinter :: - Map - H.QClassName - ( PC.ModuleName -> - PC.TyDefs -> - (Doc ann -> Doc ann) -> - PC.Ty -> - m (Doc ann) - ) - , env'printTyDef :: MonadPrint m => PC.TyDef -> m (Doc ann) - , env'languageExtensions :: [Text] - , env'ghcOptions :: [Text] - } - -printModule :: MonadPrint m => PrintModuleEnv m ann -> m (Doc ann, Set Text) -printModule env = do +printModule :: forall t m ann. MonadHaskellBackend t m => m (Doc ann, Set Text) +printModule = do ctx <- ask - tyDefDocs <- for (toList $ ctx ^. Print.ctxModule . #typeDefs) (env'printTyDef env) - instDocs <- printInstances env - st <- get + tyDefDocs <- for (toList $ ctx ^. Print.ctxModule . #typeDefs) (printTyDef @t) + instDocs <- printInstances + moduleHeaderDoc <- printModuleHeader (ctx ^. Print.ctxModule . #moduleName) (ctx ^. Print.ctxTyExports) + importsDoc <- printImports let modDoc = align . vsep $ - [ printLanguageExtensions (env'languageExtensions env) - , printGhcOptions (env'ghcOptions env) - , printModuleHeader env (ctx ^. Print.ctxModule . #moduleName) (ctx ^. Print.ctxTyExports) + [ printLanguageExtensions (languageExtensions @t) + , printGhcOptions (ghcOptions @t) + , moduleHeaderDoc , mempty - , printImports - env - (ctx ^. Print.ctxTyImports) - (ctx ^. Print.ctxOpaqueTyImports <> st ^. Print.stTypeImports) - (ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports) - (ctx ^. Print.ctxRuleImports) - (st ^. Print.stValueImports) + , importsDoc , mempty , vsep ((line <>) <$> tyDefDocs) , mempty , vsep ((line <>) <$> instDocs) ] - pkgDeps = - collectPackageDeps - (ctx ^. Print.ctxTyImports) - (ctx ^. Print.ctxOpaqueTyImports <> st ^. Print.stTypeImports) - (ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports) - (ctx ^. Print.ctxRuleImports) - (st ^. Print.stValueImports) + pkgDeps <- collectPackageDeps return (modDoc, pkgDeps) -printInstances :: MonadPrint m => PrintModuleEnv m ann -> m [Doc ann] -printInstances env = do +printInstances :: MonadHaskellBackend t m => m [Doc ann] +printInstances = do ci <- asks (view Print.ctxCompilerInput) m <- asks (view Print.ctxModule) let iTyDefs = PC.indexTyDefs ci foldrM ( \d instDocs -> do - instDocs' <- printDerive env iTyDefs d + instDocs' <- printDerive iTyDefs d return $ instDocs' <> instDocs ) mempty (toList $ m ^. #derives) -printDerive :: MonadPrint m => PrintModuleEnv m ann -> PC.TyDefs -> PC.Derive -> m [Doc ann] -printDerive env iTyDefs d = do +printDerive :: MonadHaskellBackend t m => PC.TyDefs -> PC.Derive -> m [Doc ann] +printDerive iTyDefs d = do mn <- asks (view $ Print.ctxModule . #moduleName) let qcn = PC.qualifyClassRef mn (d ^. #constraint . #classRef) classes <- asks (view $ Print.ctxConfig . C.cfgClasses) @@ -105,16 +77,16 @@ printDerive env iTyDefs d = do hsqcns ( \hsqcn -> do Print.importClass hsqcn - printHsQClassImpl env mn iTyDefs hsqcn d + printHsQClassImpl mn iTyDefs hsqcn d ) -printHsQClassImpl :: MonadPrint m => PrintModuleEnv m ann -> PC.ModuleName -> PC.TyDefs -> H.QClassName -> PC.Derive -> m (Doc ann) -printHsQClassImpl env mn iTyDefs hqcn d = - case Map.lookup hqcn (env'implementationPrinter env) of +printHsQClassImpl :: forall t m ann. MonadHaskellBackend t m => PC.ModuleName -> PC.TyDefs -> H.QClassName -> PC.Derive -> m (Doc ann) +printHsQClassImpl mn iTyDefs hqcn d = + case Map.lookup hqcn (printImplementation @t) of Nothing -> throwInternalError (d ^. #constraint . #sourceInfo) ("Missing capability to print the Haskell type class " <> show hqcn) -- TODO(bladyjoker): Fix hqcn printing Just implPrinter -> do let ty = d ^. #constraint . #argument - mkInstanceDoc = printInstanceDef hqcn ty + mkInstanceDoc <- printInstanceDef hqcn ty implPrinter mn iTyDefs mkInstanceDoc ty printLanguageExtensions :: Pretty a => [a] -> Doc ann @@ -125,8 +97,8 @@ printGhcOptions :: Pretty a => [a] -> Doc ann printGhcOptions [] = mempty printGhcOptions opts = "{-# OPTIONS_GHC" <+> align (hsep (pretty <$> opts)) <+> "#-}" -printModuleHeader :: PrintModuleEnv m ann -> PC.ModuleName -> Set (PC.InfoLess PC.TyName) -> Doc ann -printModuleHeader env mn exports = "module" <+> env'printModuleName env mn <+> printExports exports <+> "where" +printModuleHeader :: forall t m ann. MonadHaskellBackend t m => PC.ModuleName -> Set (PC.InfoLess PC.TyName) -> m (Doc ann) +printModuleHeader mn exports = return $ "module" <+> H.printModName (fromLbModuleName @t) mn <+> printExports exports <+> "where" printExports :: Set (PC.InfoLess PC.TyName) -> Doc ann printExports exports = align $ group $ encloseSep lparen rparen (comma <> space) ((`PC.withInfoLess` printTyExportWithCtors) <$> toList exports) @@ -134,12 +106,20 @@ printExports exports = align $ group $ encloseSep lparen rparen (comma <> space) printTyExportWithCtors :: PC.TyName -> Doc ann printTyExportWithCtors tyn = printTyName tyn <> "(..)" -printImports :: PrintModuleEnv m ann -> Set PC.QTyName -> Set H.QTyName -> Set H.QClassName -> Set (PC.InfoLess PC.ModuleName) -> Set H.QValName -> Doc ann -printImports env lbTyImports hsTyImports classImps ruleImps valImps = +printImports :: forall t m ann. MonadHaskellBackend t m => m (Doc ann) +printImports = do + ctx <- ask + st <- get + let lbTyImports = ctx ^. Print.ctxTyImports + hsTyImports = ctx ^. Print.ctxOpaqueTyImports <> st ^. Print.stTypeImports + classImps = ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports + ruleImps = ctx ^. Print.ctxRuleImports + valImps = st ^. Print.stValueImports + let groupedLbImports = Set.fromList [mn | (mn, _tn) <- toList lbTyImports] `Set.union` ruleImps - lbImportDocs = importQualified . env'printModuleName env . (`PC.withInfoLess` id) <$> toList groupedLbImports + lbImportDocs = importQualified . H.printModName (fromLbModuleName @t) . (`PC.withInfoLess` id) <$> toList groupedLbImports groupedHsImports = Set.fromList [mn | (_cbl, mn, _tn) <- toList hsTyImports] @@ -148,19 +128,27 @@ printImports env lbTyImports hsTyImports classImps ruleImps valImps = hsImportDocs = (\(H.MkModuleName mn) -> importQualified $ pretty mn) <$> toList groupedHsImports importsDoc = vsep $ lbImportDocs ++ hsImportDocs - in importsDoc + + return importsDoc where importQualified :: Doc ann -> Doc ann importQualified mnDoc = "import qualified" <+> mnDoc -{- | `collectPackageDeps lbTyImports hsTyImports classImps ruleImps valImps` collects all the package dependencies. +{- | `collectPackageDeps` collects all the package dependencies. Note that LB `lbTyImports` and `ruleImps` are wired by the user (as the user decides on the package name for their schemass). -} -collectPackageDeps :: Set PC.QTyName -> Set H.QTyName -> Set H.QClassName -> Set (PC.InfoLess PC.ModuleName) -> Set H.QValName -> Set Text -collectPackageDeps _lbTyImports hsTyImports classImps _ruleImps valImps = - let deps = +collectPackageDeps :: forall t m. MonadHaskellBackend t m => m (Set Text) +collectPackageDeps = do + ctx <- ask + st <- get + let hsTyImports = ctx ^. Print.ctxOpaqueTyImports <> st ^. Print.stTypeImports + classImps = ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports + valImps = st ^. Print.stValueImports + + deps = Set.singleton "base" `Set.union` Set.fromList [cabalPackageNameToText cbl | (cbl, _, _) <- toList hsTyImports] `Set.union` Set.fromList [cabalPackageNameToText cbl | (cbl, _, _) <- toList classImps] `Set.union` Set.fromList [cabalPackageNameToText cbl | (cbl, _, _) <- toList valImps] - in deps + + return deps diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/InstanceDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/InstanceDef.hs index 47094e64..69bb26c7 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/InstanceDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/InstanceDef.hs @@ -4,6 +4,7 @@ import Control.Lens (view) import Data.Foldable (Foldable (toList)) import Data.Set (Set) import Data.Set qualified as Set +import LambdaBuffers.Codegen.Haskell.Backend (MonadHaskellBackend) import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsSyntax import LambdaBuffers.Codegen.Haskell.Print.TyDef (printTyInner) import LambdaBuffers.ProtoCompat qualified as PC @@ -20,28 +21,32 @@ instance (SomeClass a, SomeClass b, SomeClass c) => SomeClass (SomeTy a b c) whe someMethod = ``` -} -printInstanceDef :: HsSyntax.QClassName -> PC.Ty -> (Doc ann -> Doc ann) -printInstanceDef hsQClassName ty = - let headDoc = printConstraint hsQClassName ty - freeVars = collectTyVars ty - in case freeVars of - [] -> \implDoc -> "instance" <+> headDoc <+> "where" <> hardline <> space <> space <> implDoc - _ -> \implDoc -> "instance" <+> printInstanceContext hsQClassName freeVars <+> "=>" <+> headDoc <+> "where" <> hardline <> space <> space <> implDoc - -printInstanceContext :: HsSyntax.QClassName -> [PC.Ty] -> Doc ann +printInstanceDef :: forall t m ann. MonadHaskellBackend t m => HsSyntax.QClassName -> PC.Ty -> m (Doc ann -> m (Doc ann)) +printInstanceDef hsQClassName ty = do + let freeVars = collectTyVars ty + headDoc <- printConstraint hsQClassName ty + return $ case freeVars of + [] -> \implDoc -> return $ "instance" <+> headDoc <+> "where" <> hardline <> space <> space <> implDoc + _r -> \implDoc -> do + instanceCtxDoc <- printInstanceContext hsQClassName freeVars + return $ "instance" <+> instanceCtxDoc <+> "=>" <+> headDoc <+> "where" <> hardline <> space <> space <> implDoc + +printInstanceContext :: forall t m ann. MonadHaskellBackend t m => HsSyntax.QClassName -> [PC.Ty] -> m (Doc ann) printInstanceContext hsQClassName = printInstanceContext' [hsQClassName] -printInstanceContext' :: [HsSyntax.QClassName] -> [PC.Ty] -> Doc ann -printInstanceContext' hsQClassNames tys = align . group $ encloseSep lparen rparen comma ([printConstraint hsQClassName ty | ty <- tys, hsQClassName <- hsQClassNames]) +printInstanceContext' :: forall t m ann. MonadHaskellBackend t m => [HsSyntax.QClassName] -> [PC.Ty] -> m (Doc ann) +printInstanceContext' hsQClassNames tys = do + constraintDocs <- traverse (uncurry printConstraint) [(hsQClassName, ty) | ty <- tys, hsQClassName <- hsQClassNames] + return $ align . group $ encloseSep lparen rparen comma constraintDocs -printConstraint :: HsSyntax.QClassName -> PC.Ty -> Doc ann +printConstraint :: forall t m ann. MonadHaskellBackend t m => HsSyntax.QClassName -> PC.Ty -> m (Doc ann) printConstraint qcn ty = printConstraint' qcn [ty] -printConstraint' :: HsSyntax.QClassName -> [PC.Ty] -> Doc ann -printConstraint' qcn tys = +printConstraint' :: forall t m ann. MonadHaskellBackend t m => HsSyntax.QClassName -> [PC.Ty] -> m (Doc ann) +printConstraint' qcn tys = do let crefDoc = HsSyntax.printHsQClassName qcn - tyDocs = printTyInner <$> tys - in crefDoc <+> hsep tyDocs + tyDocs <- traverse printTyInner tys + return $ crefDoc <+> hsep tyDocs collectTyVars :: PC.Ty -> [PC.Ty] collectTyVars = fmap (`PC.withInfoLess` (PC.TyVarI . PC.TyVar)) . toList . collectVars diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/LamVal.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/LamVal.hs index 23c0ff03..ed80fa6e 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/LamVal.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/LamVal.hs @@ -1,8 +1,9 @@ -module LambdaBuffers.Codegen.Haskell.Print.LamVal (printValueE) where +module LambdaBuffers.Codegen.Haskell.Print.LamVal (printValueE, printLamE, printOtherCase, HaskellLamValContext (..), HaskellLamValMonad) where import Control.Lens ((&), (.~)) import Control.Monad (replicateM) import Control.Monad.Error.Class (MonadError (throwError)) +import Control.Monad.RWS.Class (MonadReader (ask)) import Data.Map.Ordered qualified as OMap import Data.ProtoLens (Message (defMessage)) import Data.Text qualified as Text @@ -15,15 +16,19 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), align, comma, dquotes, encloseSep, equals, group, hsep, lbrace, lbracket, line, lparen, parens, rbrace, rbracket, rparen, space, vsep, (<+>)) import Proto.Codegen_Fields qualified as P -throwInternalError :: MonadPrint m => String -> m a -throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Haskell.Print.LamVal] " <> Text.pack msg +newtype HaskellLamValContext = HaskellLamValContext + { ctx'printCaseIntE :: forall m ann. HaskellLamValMonad m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) + } + +type HaskellLamValMonad m = LV.MonadPrint m HsSyntax.QValName HaskellLamValContext -type MonadPrint m = LV.MonadPrint m HsSyntax.QValName +throwInternalError :: HaskellLamValMonad m => String -> m a +throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Haskell.Print.LamVal] " <> Text.pack msg withInfo :: PC.InfoLessC b => PC.InfoLess b -> b withInfo x = PC.withInfoLess x id -printCtorCase :: MonadPrint m => PC.QTyName -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> LV.Ctor -> m (Doc ann) +printCtorCase :: HaskellLamValMonad m => PC.QTyName -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> LV.Ctor -> m (Doc ann) printCtorCase (_, tyn) ctorCont ctor@(ctorN, fields) = do args <- for fields (const LV.freshArg) argDocs <- for args printValueE @@ -34,7 +39,7 @@ printCtorCase (_, tyn) ctorCont ctor@(ctorN, fields) = do then return $ group $ ctorNameDoc <+> "->" <+> group bodyDoc else return $ group $ ctorNameDoc <+> hsep argDocs <+> "->" <+> group bodyDoc -printCaseE :: MonadPrint m => LV.QSum -> LV.ValueE -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> m (Doc ann) +printCaseE :: HaskellLamValMonad m => LV.QSum -> LV.ValueE -> ((LV.Ctor, [LV.ValueE]) -> LV.ValueE) -> m (Doc ann) printCaseE (qtyN, sumTy) caseVal ctorCont = do caseValDoc <- printValueE caseVal ctorCaseDocs <- @@ -43,18 +48,18 @@ printCaseE (qtyN, sumTy) caseVal ctorCont = do (OMap.assocs sumTy) ( \(cn, ty) -> case ty of -- TODO(bladyjoker): Cleanup by refactoring LT.Ty. LT.TyProduct fields _ -> printCtorCase qtyN ctorCont (cn, fields) - _ -> throwInternalError "Got a non-product in Sum." + _r -> throwInternalError "Got a non-product in Sum." ) return $ "ca" <> align ("se" <+> caseValDoc <+> "of" <> line <> ctorCaseDocs) -printLamE :: MonadPrint m => (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printLamE :: HaskellLamValMonad m => (LV.ValueE -> LV.ValueE) -> m (Doc ann) printLamE lamVal = do arg <- LV.freshArg bodyDoc <- printValueE (lamVal arg) argDoc <- printValueE arg return $ lparen <> "\\" <> argDoc <+> "->" <+> group bodyDoc <+> rparen -printAppE :: MonadPrint m => LV.ValueE -> LV.ValueE -> m (Doc ann) +printAppE :: HaskellLamValMonad m => LV.ValueE -> LV.ValueE -> m (Doc ann) printAppE funVal argVal = do funDoc <- printValueE funVal argDoc <- printValueE argVal @@ -71,7 +76,7 @@ printAppE funVal argVal = do foo'foo x -} -printFieldE :: MonadPrint m => LV.QField -> LV.ValueE -> m (Doc ann) +printFieldE :: HaskellLamValMonad m => LV.QField -> LV.ValueE -> m (Doc ann) printFieldE ((_, tyn), fieldN) recVal = do recDoc <- printValueE recVal let mayFnDoc = HsSyntax.printFieldName (withInfo tyn) (withInfo fieldN) @@ -90,7 +95,7 @@ printFieldE ((_, tyn), fieldN) recVal = do let MkFoo x1 x2 x3 = in -} -printLetE :: MonadPrint m => LV.QProduct -> LV.ValueE -> ([LV.ValueE] -> LV.ValueE) -> m (Doc ann) +printLetE :: HaskellLamValMonad m => LV.QProduct -> LV.ValueE -> ([LV.ValueE] -> LV.ValueE) -> m (Doc ann) printLetE ((_, tyN), fields) prodVal letCont = do letValDoc <- printValueE prodVal args <- for fields (const LV.freshArg) @@ -100,39 +105,19 @@ printLetE ((_, tyN), fields) prodVal letCont = do let prodCtorDoc = HsSyntax.printMkCtor (withInfo tyN) return $ "let" <+> prodCtorDoc <+> hsep argDocs <+> equals <+> letValDoc <+> "in" <+> bodyDoc -printOtherCase :: MonadPrint m => (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printOtherCase :: HaskellLamValMonad m => (LV.ValueE -> LV.ValueE) -> m (Doc ann) printOtherCase otherCase = do arg <- LV.freshArg argDoc <- printValueE arg bodyDoc <- printValueE $ otherCase arg return $ group $ argDoc <+> "->" <+> bodyDoc --- HACK(bladyjoker): This is an utter hack due to PlutusTx needing this to use the PlutusTx.Eq instances. -caseIntERef :: HsSyntax.QValName -caseIntERef = (HsSyntax.MkCabalPackageName "lbr-plutus", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutus.LamVal", HsSyntax.MkValueName "caseIntE") - ---- | `printCaseIntE i [(1, x), (2,y)] (\other -> z)` translates into `LambdaBuffers.Runtime.Plutus.LamValcaseIntE i [(1,x), (2,y)] (\other -> z)` -printCaseIntE :: MonadPrint m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) -printCaseIntE caseIntVal cases otherCase = do - caseIntERefDoc <- HsSyntax.printHsQValName <$> LV.importValue caseIntERef - caseValDoc <- printValueE caseIntVal - caseDocs <- - for - cases - ( \(conditionVal, bodyVal) -> do - conditionDoc <- printValueE conditionVal - bodyDoc <- printValueE bodyVal - return $ group $ parens (conditionDoc <+> "," <+> bodyDoc) - ) - otherDoc <- printLamE otherCase - return $ group $ caseIntERefDoc <+> align (caseValDoc <+> align (encloseSep lbracket rbracket comma caseDocs) <+> otherDoc) - -printListE :: MonadPrint m => [LV.ValueE] -> m (Doc ann) +printListE :: HaskellLamValMonad m => [LV.ValueE] -> m (Doc ann) printListE vals = do valDocs <- printValueE `traverse` vals return $ lbracket <> align (encloseSep mempty mempty (comma <> space) valDocs <> rbracket) -printCaseListE :: MonadPrint m => LV.ValueE -> [(Int, [LV.ValueE] -> LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printCaseListE :: HaskellLamValMonad m => LV.ValueE -> [(Int, [LV.ValueE] -> LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) printCaseListE caseListVal cases otherCase = do caseValDoc <- printValueE caseListVal caseDocs <- @@ -147,7 +132,7 @@ printCaseListE caseListVal cases otherCase = do otherDoc <- printOtherCase otherCase return $ "ca" <> align ("se" <+> caseValDoc <+> "of" <> line <> vsep (caseDocs <> [otherDoc])) -printCtorE :: MonadPrint m => LV.QCtor -> [LV.ValueE] -> m (Doc ann) +printCtorE :: HaskellLamValMonad m => LV.QCtor -> [LV.ValueE] -> m (Doc ann) printCtorE ((_, tyN), (ctorN, _)) prodVals = do prodDocs <- for prodVals printValueE let ctorNDoc = HsSyntax.printCtorName (withInfo tyN) (withInfo ctorN) @@ -155,7 +140,7 @@ printCtorE ((_, tyN), (ctorN, _)) prodVals = do then return ctorNDoc else return $ ctorNDoc <+> align (hsep prodDocs) -printRecordE :: MonadPrint m => LV.QRecord -> [(LV.Field, LV.ValueE)] -> m (Doc ann) +printRecordE :: HaskellLamValMonad m => LV.QRecord -> [(LV.Field, LV.ValueE)] -> m (Doc ann) printRecordE ((_, tyN), _) vals = do fieldDocs <- for vals $ \((fieldN, _), val) -> case HsSyntax.printFieldName (withInfo tyN) (withInfo fieldN) of @@ -166,22 +151,22 @@ printRecordE ((_, tyN), _) vals = do let ctorDoc = HsSyntax.printMkCtor (withInfo tyN) return $ ctorDoc <+> align (lbrace <+> encloseSep mempty mempty (comma <> space) fieldDocs <+> rbrace) -printProductE :: MonadPrint m => LV.QProduct -> [LV.ValueE] -> m (Doc ann) +printProductE :: HaskellLamValMonad m => LV.QProduct -> [LV.ValueE] -> m (Doc ann) printProductE ((_, tyN), _) vals = do fieldDocs <- for vals printValueE let ctorDoc = HsSyntax.printMkCtor (withInfo tyN) return $ ctorDoc <+> align (hsep fieldDocs) -printTupleE :: MonadPrint m => LV.ValueE -> LV.ValueE -> m (Doc ann) +printTupleE :: HaskellLamValMonad m => LV.ValueE -> LV.ValueE -> m (Doc ann) printTupleE l r = do lDoc <- printValueE l rDoc <- printValueE r return $ parens (lDoc <> comma <> rDoc) -printTextE :: MonadPrint m => Text.Text -> m (Doc ann) +printTextE :: HaskellLamValMonad m => Text.Text -> m (Doc ann) printTextE = return . dquotes . pretty -printCaseTextE :: MonadPrint m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) +printCaseTextE :: HaskellLamValMonad m => LV.ValueE -> [(LV.ValueE, LV.ValueE)] -> (LV.ValueE -> LV.ValueE) -> m (Doc ann) printCaseTextE txtVal cases otherCase = do caseValDoc <- printValueE txtVal caseDocs <- @@ -197,13 +182,19 @@ printCaseTextE txtVal cases otherCase = do otherDoc <- printOtherCase otherCase return $ "ca" <> align ("se" <+> caseValDoc <+> "of" <> line <> vsep (caseDocs <> [otherDoc])) -printRefE :: MonadPrint m => LV.Ref -> m (Doc ann) +printRefE :: HaskellLamValMonad m => LV.Ref -> m (Doc ann) printRefE ref = do qvn <- LV.resolveRef ref HsSyntax.printHsQValName <$> LV.importValue qvn -printValueE :: MonadPrint m => LV.ValueE -> m (Doc ann) -printValueE (LV.VarE v) = return $ pretty v +printVarE :: HaskellLamValMonad m => String -> m (Doc ann) +printVarE = return . pretty + +printErrorE :: HaskellLamValMonad m => String -> m (Doc ann) +printErrorE err = throwInternalError $ "LamVal error builtin was called " <> err + +printValueE :: HaskellLamValMonad m => LV.ValueE -> m (Doc ann) +printValueE (LV.VarE v) = printVarE v printValueE (LV.RefE ref) = printRefE ref printValueE (LV.LamE lamVal) = printLamE lamVal printValueE (LV.AppE funVal argVal) = printAppE funVal argVal @@ -214,10 +205,12 @@ printValueE (LV.FieldE fieldName recVal) = printFieldE fieldName recVal printValueE (LV.ProductE qprod vals) = printProductE qprod vals printValueE (LV.LetE prodTy prodVal letCont) = printLetE prodTy prodVal letCont printValueE (LV.IntE i) = return $ pretty i -printValueE (LV.CaseIntE intVal cases otherCase) = printCaseIntE intVal cases otherCase +printValueE (LV.CaseIntE intVal cases otherCase) = do + printCaseIntE <- ctx'printCaseIntE . LV.backendCtx <$> ask + printCaseIntE intVal cases otherCase printValueE (LV.ListE vals) = printListE vals printValueE (LV.CaseListE listVal cases otherCase) = printCaseListE listVal cases otherCase printValueE (LV.TextE txt) = printTextE txt printValueE (LV.CaseTextE txtVal cases otherCase) = printCaseTextE txtVal cases otherCase printValueE (LV.TupleE l r) = printTupleE l r -printValueE (LV.ErrorE err) = throwInternalError $ "LamVal error builtin was called " <> err +printValueE (LV.ErrorE err) = printErrorE err diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/MonadPrint.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/MonadPrint.hs deleted file mode 100644 index 9ddd62b7..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/MonadPrint.hs +++ /dev/null @@ -1,6 +0,0 @@ -module LambdaBuffers.Codegen.Haskell.Print.MonadPrint (MonadPrint) where - -import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as H -import LambdaBuffers.Codegen.Print qualified as Print - -type MonadPrint m = Print.MonadPrint H.QTyName H.QClassName H.QValName m diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/Syntax.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/Syntax.hs index 3b55123f..2175fc2e 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/Syntax.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/Syntax.hs @@ -1,4 +1,27 @@ -module LambdaBuffers.Codegen.Haskell.Print.Syntax (printHsQTyName, printCtorName, printFieldName, printVarName, printTyName, printMkCtor, printModName, printHsQValName, printHsClassMethodName, printHsQClassName, printHsValName, QTyName, QClassName, QValName, CabalPackageName (..), ModuleName (..), TyName (..), ClassName (..), ValueName (..), fromLbModuleName, cabalFromLbModuleName, fromLbTyName, fromLbForeignRef, filepathFromModuleName, TyDefKw (..), cabalPackageNameToText) where +module LambdaBuffers.Codegen.Haskell.Print.Syntax ( + printHsQTyName, + printCtorName, + printFieldName, + printVarName, + printTyName, + printMkCtor, + printModName, + printHsQValName, + printHsClassMethodName, + printHsQClassName, + printHsValName, + QTyName, + QClassName, + QValName, + CabalPackageName (..), + ModuleName (..), + TyName (..), + ClassName (..), + ValueName (..), + fromLbTyName, + TyDefKw (..), + cabalPackageNameToText, +) where import Control.Lens ((^.)) import Data.Char qualified as Char @@ -23,27 +46,11 @@ data TyDefKw = DataTyDef | NewtypeTyDef | SynonymTyDef deriving stock (Eq, Ord, fromLbTyName :: PC.TyName -> TyName fromLbTyName tn = MkTyName $ tn ^. #name -fromLbModuleName :: PC.ModuleName -> ModuleName -fromLbModuleName mn = MkModuleName $ Text.intercalate "." ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) - -cabalFromLbModuleName :: PC.ModuleName -> CabalPackageName -cabalFromLbModuleName mn = MkCabalPackageName $ Text.intercalate "-" ([Text.toLower $ p ^. #name | p <- mn ^. #parts] <> ["-lb"]) - cabalPackageNameToText :: CabalPackageName -> Text cabalPackageNameToText (MkCabalPackageName cpn) = cpn -fromLbForeignRef :: PC.ForeignRef -> QTyName -fromLbForeignRef fr = - ( cabalFromLbModuleName $ fr ^. #moduleName - , fromLbModuleName $ fr ^. #moduleName - , fromLbTyName $ fr ^. #tyName - ) - -filepathFromModuleName :: PC.ModuleName -> FilePath -filepathFromModuleName mn = Text.unpack (Text.replace "." "/" (let MkModuleName txt = fromLbModuleName mn in txt)) <> ".hs" - -printModName :: PC.ModuleName -> Doc ann -printModName mn = let MkModuleName hmn = fromLbModuleName mn in pretty hmn +printModName :: (PC.ModuleName -> ModuleName) -> PC.ModuleName -> Doc ann +printModName fromLbModuleName mn = let MkModuleName hmn = fromLbModuleName mn in pretty hmn printHsQTyName :: QTyName -> Doc ann printHsQTyName (_, MkModuleName hsModName, MkTyName hsTyName) = pretty hsModName <> dot <> pretty hsTyName @@ -55,13 +62,13 @@ printHsQValName :: QValName -> Doc ann printHsQValName (_, MkModuleName hsModName, MkValueName hsValName) = case Text.uncons hsValName of Nothing -> "TODO(bladyjoker): Got an empty Haskell value name" Just (c, _) | Char.isAlpha c -> pretty hsModName <> dot <> pretty hsValName - _ -> enclose lparen rparen $ pretty hsModName <> dot <> pretty hsValName + _r -> enclose lparen rparen $ pretty hsModName <> dot <> pretty hsValName printHsValName :: ValueName -> Doc ann printHsValName (MkValueName hsValName) = case Text.uncons hsValName of Nothing -> "TODO(bladyjoker): Got an empty Haskell value name" Just (c, _) | Char.isAlpha c -> pretty hsValName - _ -> enclose lparen rparen $ pretty hsValName + _r -> enclose lparen rparen $ pretty hsValName {- | Print the Haskell class method name (ie. (==), toJSON etc.). This doesn't require a qualified print as it's treated special, we just need to diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/TyDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/TyDef.hs index 6d3a7d68..309e4420 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/TyDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Haskell/Print/TyDef.hs @@ -7,7 +7,7 @@ import Data.Map qualified as Map import Data.Map.Ordered qualified as OMap import Data.Traversable (for) import LambdaBuffers.Codegen.Config (cfgOpaques) -import LambdaBuffers.Codegen.Haskell.Print.MonadPrint (MonadPrint) +import LambdaBuffers.Codegen.Haskell.Backend (IsHaskellBackend (fromLbModuleName), MonadHaskellBackend) import LambdaBuffers.Codegen.Haskell.Print.Syntax ( TyDefKw (DataTyDef, NewtypeTyDef, SynonymTyDef), printCtorName, @@ -22,7 +22,7 @@ import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as H import LambdaBuffers.Codegen.Print (importClass, throwInternalError) import LambdaBuffers.Codegen.Print qualified as Print import LambdaBuffers.ProtoCompat qualified as PC -import Prettyprinter (Doc, Pretty (pretty), align, colon, comma, dot, encloseSep, equals, group, lbrace, parens, pipe, rbrace, sep, space, (<+>)) +import Prettyprinter (Doc, align, colon, comma, dot, encloseSep, equals, group, lbrace, parens, pipe, rbrace, sep, space, (<+>)) {- | Prints the type definition. @@ -34,7 +34,7 @@ translates to data Foo a b = Foo'MkFoo a | Foo'MkBar b type Maybe a = Prelude.Maybe a -} -printTyDef :: MonadPrint m => PC.TyDef -> m (Doc ann) +printTyDef :: MonadHaskellBackend t m => PC.TyDef -> m (Doc ann) printTyDef (PC.TyDef tyN tyabs _) = do (kw, absDoc) <- printTyAbs tyN tyabs if kw /= SynonymTyDef @@ -51,7 +51,7 @@ printTyDefKw SynonymTyDef = "type" showClass :: H.QClassName showClass = (H.MkCabalPackageName "base", H.MkModuleName "Prelude", H.MkClassName "Show") -printDerivingShow :: MonadPrint m => m (Doc ann) +printDerivingShow :: MonadHaskellBackend t m => m (Doc ann) printDerivingShow = do importClass showClass return $ "deriving" <+> printHsQClassName showClass @@ -63,7 +63,7 @@ For the above examples it prints a b = Foo'MkFoo a | Foo'MkBar b a = Prelude.Maybe a -} -printTyAbs :: MonadPrint m => PC.TyName -> PC.TyAbs -> m (TyDefKw, Doc ann) +printTyAbs :: MonadHaskellBackend t m => PC.TyName -> PC.TyAbs -> m (TyDefKw, Doc ann) printTyAbs tyN (PC.TyAbs args body _) = do let argsDoc = if OMap.empty == args then mempty else encloseSep mempty space space (printTyArg <$> toList args) (kw, bodyDoc) <- printTyBody tyN (toList args) body @@ -78,16 +78,20 @@ Prelude.Maybe a TODO(bladyjoker): Revisit empty records and prods. -} -printTyBody :: MonadPrint m => PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (TyDefKw, Doc ann) +printTyBody :: MonadHaskellBackend t m => PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (TyDefKw, Doc ann) printTyBody tyN _ (PC.SumI s) = (DataTyDef,) <$> printSum tyN s printTyBody tyN _ (PC.ProductI p@(PC.Product fields _)) = case toList fields of [] -> return (DataTyDef, printMkCtor tyN) - [_] -> return (NewtypeTyDef, printMkCtor tyN <+> printProd p) - _ -> return (DataTyDef, printMkCtor tyN <+> printProd p) + [_] -> do + prodDoc <- printProd p + return (NewtypeTyDef, printMkCtor tyN <+> prodDoc) + _rest -> do + prodDoc <- printProd p + return (DataTyDef, printMkCtor tyN <+> prodDoc) printTyBody tyN _ (PC.RecordI r@(PC.Record fields _)) = case toList fields of [] -> return (DataTyDef, printMkCtor tyN) [_] -> printRec tyN r >>= \recDoc -> return (NewtypeTyDef, printMkCtor tyN <+> recDoc) - _ -> printRec tyN r >>= \recDoc -> return (DataTyDef, printMkCtor tyN <+> recDoc) + _rest -> printRec tyN r >>= \recDoc -> return (DataTyDef, printMkCtor tyN <+> recDoc) printTyBody tyN args (PC.OpaqueI si) = do opqs <- asks (view $ Print.ctxConfig . cfgOpaques) mn <- asks (view $ Print.ctxModule . #moduleName) @@ -98,22 +102,22 @@ printTyBody tyN args (PC.OpaqueI si) = do printTyArg :: PC.TyArg -> Doc ann printTyArg (PC.TyArg vn _ _) = printVarName vn -printSum :: MonadPrint m => PC.TyName -> PC.Sum -> m (Doc ann) +printSum :: MonadHaskellBackend t m => PC.TyName -> PC.Sum -> m (Doc ann) printSum tyN (PC.Sum ctors _) = do - let ctorDocs = printCtor tyN <$> toList ctors + ctorDocs <- traverse (printCtor tyN) (toList ctors) return $ group $ if null ctors then mempty else align $ encloseSep mempty mempty (space <> pipe <> space) ctorDocs -- TODO(bladyjoker): Make it align on the ConstrName. -printCtor :: PC.TyName -> PC.Constructor -> Doc ann -printCtor tyN (PC.Constructor ctorName prod) = +printCtor :: MonadHaskellBackend t m => PC.TyName -> PC.Constructor -> m (Doc ann) +printCtor tyN (PC.Constructor ctorName prod) = do let ctorNDoc = printCtorName tyN ctorName - prodDoc = printProd prod - in group $ ctorNDoc <+> prodDoc -- TODO(bladyjoker): Adds extra space when empty. + prodDoc <- printProd prod + return $ group $ ctorNDoc <+> prodDoc -- TODO(bladyjoker): Adds extra space when empty. -printRec :: MonadPrint m => PC.TyName -> PC.Record -> m (Doc ann) +printRec :: MonadHaskellBackend t m => PC.TyName -> PC.Record -> m (Doc ann) printRec tyN (PC.Record fields _) = do if null fields then return mempty @@ -121,45 +125,47 @@ printRec tyN (PC.Record fields _) = do fieldDocs <- for (toList fields) (printField tyN) return $ group $ align $ encloseSep (lbrace <> space) rbrace (comma <> space) fieldDocs -printProd :: PC.Product -> Doc ann +printProd :: MonadHaskellBackend t m => PC.Product -> m (Doc ann) printProd (PC.Product fields _) = do if null fields - then mempty - else align $ sep (printTyInner <$> fields) + then return mempty + else do + fieldDocs <- traverse printTyInner fields + return $ align $ sep fieldDocs -printField :: MonadPrint m => PC.TyName -> PC.Field -> m (Doc ann) +printField :: MonadHaskellBackend t m => PC.TyName -> PC.Field -> m (Doc ann) printField tyN f@(PC.Field fn ty) = do fnDoc <- case printFieldName tyN fn of Nothing -> throwInternalError (fn ^. #sourceInfo) ("Failed printing `FieldName` for field\n" <> show (tyN, f)) Just fnDoc -> return fnDoc - let tyDoc = printTyTopLevel ty + tyDoc <- printTyTopLevel ty return $ fnDoc <+> colon <> colon <+> tyDoc -printTyInner :: PC.Ty -> Doc ann -printTyInner (PC.TyVarI v) = printTyVar v +printTyInner :: MonadHaskellBackend t m => PC.Ty -> m (Doc ann) +printTyInner (PC.TyVarI v) = return $ printTyVar v printTyInner (PC.TyRefI r) = printTyRef r printTyInner (PC.TyAppI a) = printTyAppInner a -printTyAppInner :: PC.TyApp -> Doc ann -printTyAppInner (PC.TyApp f args _) = - let fDoc = printTyInner f - argsDoc = printTyInner <$> args - in group $ parens $ fDoc <+> align (sep argsDoc) +printTyAppInner :: MonadHaskellBackend t m => PC.TyApp -> m (Doc ann) +printTyAppInner (PC.TyApp f args _) = do + fDoc <- printTyInner f + argsDoc <- traverse printTyInner args + return $ group $ parens $ fDoc <+> align (sep argsDoc) -printTyTopLevel :: PC.Ty -> Doc ann -printTyTopLevel (PC.TyVarI v) = printTyVar v +printTyTopLevel :: MonadHaskellBackend t m => PC.Ty -> m (Doc ann) +printTyTopLevel (PC.TyVarI v) = return $ printTyVar v printTyTopLevel (PC.TyRefI r) = printTyRef r printTyTopLevel (PC.TyAppI a) = printTyAppTopLevel a -printTyAppTopLevel :: PC.TyApp -> Doc ann -printTyAppTopLevel (PC.TyApp f args _) = - let fDoc = printTyInner f - argsDoc = printTyInner <$> args - in group $ fDoc <+> align (sep argsDoc) +printTyAppTopLevel :: MonadHaskellBackend t m => PC.TyApp -> m (Doc ann) +printTyAppTopLevel (PC.TyApp f args _) = do + fDoc <- printTyInner f + argsDoc <- traverse printTyInner args + return $ group $ fDoc <+> align (sep argsDoc) -printTyRef :: PC.TyRef -> Doc ann -printTyRef (PC.LocalI (PC.LocalRef tn _)) = group $ printTyName tn -printTyRef (PC.ForeignI fr) = let (_, H.MkModuleName hmn, H.MkTyName htn) = H.fromLbForeignRef fr in pretty hmn <> dot <> pretty htn +printTyRef :: forall t m ann. MonadHaskellBackend t m => PC.TyRef -> m (Doc ann) +printTyRef (PC.LocalI (PC.LocalRef tn _)) = return $ group $ printTyName tn +printTyRef (PC.ForeignI fr) = return $ H.printModName (fromLbModuleName @t) (fr ^. #moduleName) <> dot <> printTyName (fr ^. #tyName) printTyVar :: PC.TyVar -> Doc ann printTyVar (PC.TyVar vn) = printVarName vn diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/LamVal/MonadPrint.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/LamVal/MonadPrint.hs index 916556ca..3fc409ba 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/LamVal/MonadPrint.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/LamVal/MonadPrint.hs @@ -1,4 +1,4 @@ -module LambdaBuffers.Codegen.LamVal.MonadPrint (MonadPrint, PrintRead (MkPrintRead), runPrint, freshArg, resolveRef, importValue) where +module LambdaBuffers.Codegen.LamVal.MonadPrint (MonadPrint, PrintError, Context (..), runPrint, freshArg, resolveRef, importValue) where import Control.Lens ((&), (.~)) import Control.Monad.Error.Class (MonadError (throwError)) @@ -14,40 +14,41 @@ import Prettyprinter (Doc) import Proto.Codegen qualified as P import Proto.Codegen_Fields qualified as P -newtype PrintRead qvn = MkPrintRead - { builtins :: Ref -> Maybe qvn +data Context qvn backend = Context + { builtins :: !(Ref -> Maybe qvn) + , backendCtx :: !backend } -data PrintState qvn = MkPrintState - { currentVar :: Int - , valueImports :: Set qvn +data State qvn = State + { currentVar :: !Int + , valueImports :: !(Set qvn) } deriving stock (Eq, Ord, Show) type PrintError = P.InternalError -throwInternalError :: MonadPrint m qvn => String -> m a +throwInternalError :: MonadPrint m qvn backend => String -> m a throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.LamVal.MonadPrint] " <> Text.pack msg -type MonadPrint m qvn = (MonadRWS (PrintRead qvn) () (PrintState qvn) m, MonadError PrintError m) +type MonadPrint m qvn backend = (MonadRWS (Context qvn backend) () (State qvn) m, MonadError PrintError m) -type PrintM qvn = RWST (PrintRead qvn) () (PrintState qvn) (Except PrintError) +type PrintM qvn backend = RWST (Context qvn backend) () (State qvn) (Except PrintError) -runPrint :: Ord qvn => PrintRead qvn -> PrintM qvn (Doc ann) -> Either PrintError (Doc ann, Set qvn) -runPrint lamValBuiltins printer = - let p = runExcept $ runRWST printer lamValBuiltins (MkPrintState 0 mempty) +runPrint :: Ord qvn => Context qvn backend -> PrintM qvn backend (Doc ann) -> Either PrintError (Doc ann, Set qvn) +runPrint ctx printer = + let p = runExcept $ runRWST printer ctx (State 0 mempty) in case p of Left err -> Left err Right (doc, st, _) -> Right (doc, valueImports st) -freshArg :: MonadPrint m qvn => m ValueE +freshArg :: MonadPrint m qvn backend => m ValueE freshArg = do i <- gets currentVar - modify (\(MkPrintState curr imps) -> MkPrintState (curr + 1) imps) + modify (\(State curr imps) -> State (curr + 1) imps) return $ VarE $ "x" <> show i -importValue :: (MonadPrint m qvn, Ord qvn) => qvn -> m qvn -importValue qvn = modify (\(MkPrintState curr imps) -> MkPrintState curr (Set.insert qvn imps)) >> return qvn +importValue :: (MonadPrint m qvn backend, Ord qvn) => qvn -> m qvn +importValue qvn = modify (\(State curr imps) -> State curr (Set.insert qvn imps)) >> return qvn {- | Resolves a `Ref` to a value reference in the target language. Resolves a `LV.Ref` which is a reference to a LamVal 'builtin', to the equivalent in the target language. @@ -57,7 +58,7 @@ importValue qvn = modify (\(MkPrintState curr imps) -> MkPrintState curr (Set.in NOTE(bladyjoker): Currently, this is assuming all the implementations are imported. TODO(bladyjoker): Output all necessary implementations from the Compiler and report on missing. -} -resolveRef :: MonadPrint m qvn => Ref -> m qvn +resolveRef :: MonadPrint m qvn backend => Ref -> m qvn resolveRef ref = do bs <- asks builtins case bs ref of diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch.hs index 453a9721..5e91b7eb 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch.hs @@ -1,53 +1,17 @@ module LambdaBuffers.Codegen.Plutarch ( - runPrint, + runBackend, ) where -import Control.Lens ((^.)) import Data.Set (Set) import Data.Text (Text) -import LambdaBuffers.Codegen.Check (runCheck) -import LambdaBuffers.Codegen.Haskell.Config qualified as HsConfig -import LambdaBuffers.Codegen.Haskell.Print qualified as HsPrint -import LambdaBuffers.Codegen.Haskell.Print.MonadPrint (MonadPrint) -import LambdaBuffers.Codegen.Plutarch.Print.Derive qualified as PlDerive -import LambdaBuffers.Codegen.Plutarch.Print.Syntax qualified as PlSyntax -import LambdaBuffers.Codegen.Plutarch.Print.TyDef qualified as PlPrint -import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Haskell.Backend qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Backend.Plutarch (PlutarchHaskellBackend) +import LambdaBuffers.Codegen.Haskell.Config qualified as Haskell import LambdaBuffers.ProtoCompat.Types qualified as PC -import Prettyprinter (defaultLayoutOptions, layoutPretty) -import Prettyprinter.Render.Text (renderStrict) import Proto.Codegen qualified as P -{- | `runPrint cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Plutarch configuration file in `cfg`. +{- | `runBackend cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Haskell configuration file in `cfg`. It either errors with an API error message or succeeds with a module filepath, code and package dependencies. -} -runPrint :: HsConfig.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) -runPrint cfg ci m = case runCheck cfg ci m of - Left err -> Left err - Right ctx -> case Print.runPrint ctx (HsPrint.printModule plutarchPrintModuleEnv) of - Left err -> Left err - Right (modDoc, deps) -> - Right - ( PlSyntax.filepathFromModuleName (m ^. #moduleName) - , renderStrict $ layoutPretty defaultLayoutOptions modDoc - , deps - ) - -plutarchPrintModuleEnv :: MonadPrint m => HsPrint.PrintModuleEnv m ann -plutarchPrintModuleEnv = - HsPrint.PrintModuleEnv - PlSyntax.printModName - PlDerive.hsClassImplPrinters - PlPrint.printTyDef - [ "KindSignatures" - , "DataKinds" - , "TypeFamilies" - , "MultiParamTypeClasses" - , "FlexibleContexts" - , "FlexibleInstances" - , "DerivingStrategies" - , "DeriveAnyClass" - , "DeriveGeneric" - , "UndecidableInstances" - ] - [] +runBackend :: Haskell.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) +runBackend = Haskell.runBackend @PlutarchHaskellBackend () () diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print.hs deleted file mode 100644 index bc4e0970..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print.hs +++ /dev/null @@ -1 +0,0 @@ -module LambdaBuffers.Codegen.Plutarch.Print () where diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Derive.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Derive.hs deleted file mode 100644 index e9d81e2e..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Derive.hs +++ /dev/null @@ -1,395 +0,0 @@ -module LambdaBuffers.Codegen.Plutarch.Print.Derive (hsClassImplPrinters) where - -import Control.Lens ((^.)) -import Data.Foldable (for_) -import Data.Map (Map) -import Data.Map qualified as Map -import Data.Text (Text) -import Data.Text qualified as Text -import LambdaBuffers.Codegen.Haskell.Print (MonadPrint) -import LambdaBuffers.Codegen.Haskell.Print.InstanceDef qualified as HsInstDef -import LambdaBuffers.Codegen.Haskell.Print.InstanceDef qualified as HsSyntax -import LambdaBuffers.Codegen.Haskell.Print.LamVal qualified as HsLamVal -import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsSyntax -import LambdaBuffers.Codegen.Haskell.Print.TyDef qualified as HsTyDef -import LambdaBuffers.Codegen.LamVal.MonadPrint qualified as LV -import LambdaBuffers.Codegen.LamVal.PlutusData (deriveFromPlutusDataImplPlutarch, deriveToPlutusDataImplPlutarch) -import LambdaBuffers.Codegen.Plutarch.Print.LamVal qualified as PlLamVal -import LambdaBuffers.Codegen.Plutarch.Print.Refs qualified as PlRefs -import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.ProtoCompat qualified as PC -import Prettyprinter (Doc, align, comma, defaultLayoutOptions, encloseSep, equals, group, hardline, layoutPretty, lparen, parens, pretty, rparen, space, vsep, (<+>)) -import Prettyprinter.Render.Text (renderStrict) -import Proto.Codegen_Fields qualified as P - -hsClassImplPrinters :: - MonadPrint m => - Map - HsSyntax.QClassName - ( PC.ModuleName -> - PC.TyDefs -> - (Doc ann -> Doc ann) -> - PC.Ty -> - m (Doc ann) - ) -hsClassImplPrinters = - Map.fromList - [ - ( PlRefs.peqQClassName - , printDerivePEq - ) - , - ( PlRefs.pisDataQClassName - , printDerivePIsData - ) - , - ( PlRefs.ptryFromQClassName - , printDerivePTryFrom - ) - , - ( PlRefs.plutusTypeQClassName - , printDerivePlutusType - ) - ] - -useVal :: MonadPrint m => HsSyntax.QValName -> m (Doc ann) -useVal qvn = Print.importValue qvn >> return (HsSyntax.printHsQValName qvn) - -{- | Deriving PEq. - -NOTE(bladyjoker): Doesn't derive the implementation but only uses the underlying PData representation for equality. - -``` -instance PEq (FooLessTrivial a) where - (#==) l r = pdata l #== pdata r -``` - -mkInstanceDoc "\\l r -> (Plutarch.Bool.#==) (Plutarch.Builtin.pdata l) (Plutarch.Builtin.pdata r)" --} -printDerivePEq :: forall ann m. MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDerivePEq _mn _iTyDefs _mkInstanceDoc ty = do - pdataDoc <- useVal PlRefs.pdataQValName - peqDoc <- useVal PlRefs.peqQValName - let implDoc = "\\l r ->" <+> parens peqDoc <+> parens (pdataDoc <+> "l") <+> parens (pdataDoc <+> "r") - printPEqInstanceDef ty (printValueDef PlRefs.peqMethod implDoc) - -printPEqInstanceDef :: MonadPrint m => PC.Ty -> Doc ann -> m (Doc ann) -printPEqInstanceDef ty implDefDoc = do - Print.importClass PlRefs.peqQClassName - Print.importClass PlRefs.pisDataQClassName - let headDoc = HsInstDef.printConstraint PlRefs.peqQClassName ty - freeVars = HsInstDef.collectTyVars ty - in case freeVars of - [] -> return $ "instance" <+> headDoc <+> "where" <> hardline <> space <> space <> implDefDoc - _ -> - return $ - "instance" - <+> HsInstDef.printInstanceContext PlRefs.pisDataQClassName freeVars - <+> "=>" - <+> headDoc - <+> "where" - <> hardline - <> space - <> space - <> implDefDoc - -{- | Deriving PIsData. - -NOTE(bladyjoker): Doesn't derive the implementation but only uses `punsafeCoerce`. - -``` -instance PIsData (FooLessTrivial a) where - pdataImpl = punsafeCoerce - pfromDataImpl = punsafeCoerce -``` --} -printDerivePIsData :: forall ann m. MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDerivePIsData _mn _iTyDefs mkInstanceDoc _ty = do - punsafeCoerceDoc <- useVal PlRefs.punsafeCoerceQValName - let pdataImpl, pfromDataImpl :: Doc ann - pdataImpl = printValueDef (HsSyntax.MkValueName "pdataImpl") punsafeCoerceDoc - pfromDataImpl = printValueDef (HsSyntax.MkValueName "pfromDataImpl") punsafeCoerceDoc - let instanceDoc = mkInstanceDoc (align $ vsep [pdataImpl, pfromDataImpl]) - return instanceDoc - -lvPlutusDataBuiltinsForPlutusType :: LV.PrintRead HsSyntax.QValName -lvPlutusDataBuiltinsForPlutusType = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("toPlutusData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "toPlutusData")) - , ("fromPlutusData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pfromPlutusDataPlutusType")) - , ("casePlutusData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pcasePlutusData")) - , ("integerData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "integerData")) - , ("constrData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "constrData")) - , ("listData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "listData")) - , ("succeedParse", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "psucceedParse")) - , ("failParse", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pfailParse")) - , ("bindParse", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pbindParse")) - ] - -printDerivePlutusType :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDerivePlutusType mn iTyDefs _mkInstanceDoc ty = do - pappDoc <- useVal PlRefs.pappQValName - pconDoc <- useVal PlRefs.pconQValName - -- HACK(bladyjoker): The `fromData` implementation is trying to construct a term, which for Plutarch means `pcon`. However, this is 'pmatch' implementation which is NOT really exactly 'fromData', and has a different type signature for which we do this. I'm sorry. - let dirtyHack :: Doc ann -> Doc ann - dirtyHack = pretty . Text.replace (docToText pconDoc <> " ") "f " . docToText - - let resOrErr = - do - toDataE <- deriveToPlutusDataImplPlutarch mn iTyDefs ty - fromDataE <- deriveFromPlutusDataImplPlutarch mn iTyDefs ty - (pconImplDoc, imps) <- LV.runPrint lvPlutusDataBuiltinsForPlutusType (HsLamVal.printValueE toDataE) - (pmatchImplDoc, imps') <- LV.runPrint lvPlutusDataBuiltinsForPlutusType (PlLamVal.printValueE fromDataE) - let implDoc = - align $ - vsep - [ printValueDef PlRefs.pconMethod pconImplDoc - , printValueDef PlRefs.pmatchMethod $ parens ("\\pd f -> " <+> parens pappDoc <+> parens (dirtyHack pmatchImplDoc) <+> "pd") - ] - - return (implDoc, imps' <> imps) - case resOrErr of - Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Printing an instance definition for PlutusType failed with: " <> err ^. P.msg) - Right (implDoc, imps) -> do - instanceDoc <- printPlutusTypeInstanceDef ty implDoc - for_ imps Print.importValue - return instanceDoc - where - docToText :: Doc ann -> Text - docToText = renderStrict . layoutPretty defaultLayoutOptions - -printPlutusTypeInstanceDef :: MonadPrint m => PC.Ty -> Doc ann -> m (Doc ann) -printPlutusTypeInstanceDef ty implDefDoc = do - Print.importClass PlRefs.plutusTypeQClassName - Print.importClass PlRefs.pisDataQClassName - Print.importType PlRefs.pdataQTyName - let headDoc = HsInstDef.printConstraint PlRefs.plutusTypeQClassName ty - freeVars = HsInstDef.collectTyVars ty - pinnerDefDoc = "type PInner" <+> HsTyDef.printTyInner ty <+> "=" <+> HsSyntax.printHsQTyName PlRefs.pdataQTyName - in case freeVars of - [] -> - return $ - "instance" - <+> headDoc - <+> "where" - <> hardline - <> space - <> space - <> pinnerDefDoc - <> hardline - <> space - <> space - <> implDefDoc - _ -> - return $ - "instance" - <+> HsInstDef.printInstanceContext PlRefs.pisDataQClassName freeVars - <+> "=>" - <+> headDoc - <+> "where" - <> hardline - <> space - <> space - <> pinnerDefDoc - <> hardline - <> space - <> space - <> implDefDoc - -printValueDef :: HsSyntax.ValueName -> Doc ann -> Doc ann -printValueDef valName valDoc = HsSyntax.printHsValName valName <+> equals <+> valDoc - -lvPlutusDataBuiltinsForPTryFrom :: LV.PrintRead HsSyntax.QValName -lvPlutusDataBuiltinsForPTryFrom = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("toPlutusData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "toPlutusData")) - , ("fromPlutusData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pfromPlutusDataPTryFrom")) - , ("casePlutusData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pcasePlutusData")) - , ("integerData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "integerData")) - , ("constrData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "constrData")) - , ("listData", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "listData")) - , ("succeedParse", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "psucceedParse")) - , ("failParse", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pfailParse")) - , ("bindParse", (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch.LamVal", HsSyntax.MkValueName "pbindParse")) - ] - -{- | PTryFrom instance implementation. - -```haskell -instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PMaybe a) where - type PTryFromExcess PData (PMaybe a) = Const () - ptryFrom' = ptryFromPAsData - -instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PAsData (PMaybe a)) where - type PTryFromExcess PData (PAsData (PMaybe a)) = Const () - ptryFrom' pd f = ... -``` --} -printDerivePTryFrom :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDerivePTryFrom mn iTyDefs _mkInstanceDoc ty = do - pappDoc <- useVal PlRefs.pappQValName - let resOrErr = do - fromDataE <- deriveFromPlutusDataImplPlutarch mn iTyDefs ty - (ptryFromImplDoc, imps) <- LV.runPrint lvPlutusDataBuiltinsForPTryFrom (PlLamVal.printValueE fromDataE) - return - ( align $ printValueDef PlRefs.ptryFromMethod (parens $ "\\pd f -> f" <+> parens (parens pappDoc <+> parens ptryFromImplDoc <+> "pd" <+> "," <+> "()")) - , imps - ) - case resOrErr of - Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Printing an instance definition for PTryFrom failed with: " <> err ^. P.msg) - Right (implDoc, imps) -> do - instancePAsDataDoc <- printPTryFromPAsDataInstanceDef ty implDoc - for_ imps Print.importValue - instanceDoc <- printPTryFromInstanceDef ty - return $ align $ vsep [instanceDoc, instancePAsDataDoc] - -{- | PTryFrom (PAsData a) - -```haskell -instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PAsData (PMaybe a)) where - type PTryFromExcess PData (PAsData (PMaybe a)) = Const () - ptryFrom' pd f = ... -``` --} -printPTryFromPAsDataInstanceDef :: MonadPrint m => PC.Ty -> Doc ann -> m (Doc ann) -printPTryFromPAsDataInstanceDef ty implDefDoc = do - Print.importClass PlRefs.ptryFromQClassName - Print.importClass PlRefs.pisDataQClassName - Print.importType PlRefs.pdataQTyName - Print.importType PlRefs.pasDataQTyName - Print.importType PlRefs.constQTyName - - let headDoc = - HsSyntax.printHsQClassName PlRefs.ptryFromQClassName - <+> HsSyntax.printHsQTyName PlRefs.pdataQTyName - <+> parens (HsSyntax.printHsQTyName PlRefs.pasDataQTyName <+> HsTyDef.printTyInner ty) - freeVars = HsInstDef.collectTyVars ty - pinnerDefDoc = - "type PTryFromExcess" - <+> HsSyntax.printHsQTyName PlRefs.pdataQTyName - <+> parens (HsSyntax.printHsQTyName PlRefs.pasDataQTyName <+> HsTyDef.printTyInner ty) - <+> "=" - <+> HsSyntax.printHsQTyName PlRefs.constQTyName - <+> "()" - in case freeVars of - [] -> - return $ - "instance" - <+> headDoc - <+> "where" - <> hardline - <> space - <> space - <> pinnerDefDoc - <> hardline - <> space - <> space - <> implDefDoc - _ -> - return $ - "instance" - <+> printContext freeVars - <+> "=>" - <+> headDoc - <+> "where" - <> hardline - <> space - <> space - <> pinnerDefDoc - <> hardline - <> space - <> space - <> implDefDoc - where - printContext :: [PC.Ty] -> Doc ann - printContext tys = - align . group $ - encloseSep - lparen - rparen - comma - ( [ HsSyntax.printHsQClassName PlRefs.ptryFromQClassName - <+> HsSyntax.printHsQTyName PlRefs.pdataQTyName - <+> parens (HsSyntax.printHsQTyName PlRefs.pasDataQTyName <+> HsTyDef.printTyInner t) - | t <- tys - ] - <> [HsSyntax.printConstraint PlRefs.pisDataQClassName t | t <- tys] - ) - -{- | PTryFrom instance implementation. - -```haskell -instance (PTryFrom PData (PAsData a)) => PTryFrom PData (PMaybe a) where - type PTryFromExcess PData (PMaybe a) = Const () - ptryFrom' = ptryFromPAsData -``` --} -printPTryFromInstanceDef :: MonadPrint m => PC.Ty -> m (Doc ann) -printPTryFromInstanceDef ty = do - ptryFromPAsDataDoc <- useVal PlRefs.ptryFromPAsDataQValName - Print.importClass PlRefs.ptryFromQClassName - Print.importClass PlRefs.pisDataQClassName - Print.importType PlRefs.pdataQTyName - Print.importType PlRefs.pasDataQTyName - Print.importType PlRefs.constQTyName - let headDoc = - HsSyntax.printHsQClassName PlRefs.ptryFromQClassName - <+> HsSyntax.printHsQTyName PlRefs.pdataQTyName - <+> HsTyDef.printTyInner ty - freeVars = HsInstDef.collectTyVars ty - - pinnerDefDoc = - "type PTryFromExcess" - <+> HsSyntax.printHsQTyName PlRefs.pdataQTyName - <+> HsTyDef.printTyInner ty - <+> "=" - <+> HsSyntax.printHsQTyName PlRefs.constQTyName - <+> "()" - - implDefDoc = printValueDef PlRefs.ptryFromMethod ptryFromPAsDataDoc - in case freeVars of - [] -> - return $ - "instance" - <+> headDoc - <+> "where" - <> hardline - <> space - <> space - <> pinnerDefDoc - <> hardline - <> space - <> space - <> implDefDoc - _ -> - return $ - "instance" - <+> printContext freeVars - <+> "=>" - <+> headDoc - <+> "where" - <> hardline - <> space - <> space - <> pinnerDefDoc - <> hardline - <> space - <> space - <> implDefDoc - where - printContext :: [PC.Ty] -> Doc ann - printContext tys = - align . group $ - encloseSep - lparen - rparen - comma - ( [ HsSyntax.printHsQClassName PlRefs.ptryFromQClassName - <+> HsSyntax.printHsQTyName PlRefs.pdataQTyName - <+> parens (HsSyntax.printHsQTyName PlRefs.pasDataQTyName <+> HsTyDef.printTyInner t) - | t <- tys - ] - <> [HsSyntax.printConstraint PlRefs.pisDataQClassName t | t <- tys] - ) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Refs.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Refs.hs deleted file mode 100644 index aebb25aa..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Refs.hs +++ /dev/null @@ -1,92 +0,0 @@ -module LambdaBuffers.Codegen.Plutarch.Print.Refs ( - plutusTypeQClassName, - pconMethod, - pmatchMethod, - peqQClassName, - peqMethod, - pisDataQClassName, - ptryFromQClassName, - ptryFromMethod, - pconQValName, - pappQValName, - pdataQValName, - peqQValName, - punsafeCoerceQValName, - pdataQTyName, - constQTyName, - pasDataQTyName, - ptryFromPAsDataQValName, - termQTyName, - scopeQTyName, - ptypeQTyName, - showQClassName, - genericQClassName, -) where - -import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsSyntax - -plutusTypeQClassName :: HsSyntax.QClassName -plutusTypeQClassName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Internal.PlutusType", HsSyntax.MkClassName "PlutusType") - -pconMethod :: HsSyntax.ValueName -pconMethod = HsSyntax.MkValueName "pcon'" - -pmatchMethod :: HsSyntax.ValueName -pmatchMethod = HsSyntax.MkValueName "pmatch'" - -peqQClassName :: HsSyntax.QClassName -peqQClassName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Bool", HsSyntax.MkClassName "PEq") - -peqMethod :: HsSyntax.ValueName -peqMethod = HsSyntax.MkValueName "#==" - -pisDataQClassName :: HsSyntax.QClassName -pisDataQClassName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Builtin", HsSyntax.MkClassName "PIsData") - -ptryFromQClassName :: HsSyntax.QClassName -ptryFromQClassName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.TryFrom", HsSyntax.MkClassName "PTryFrom") - -ptryFromMethod :: HsSyntax.ValueName -ptryFromMethod = HsSyntax.MkValueName "ptryFrom'" - -pconQValName :: HsSyntax.QValName -pconQValName = (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch", HsSyntax.MkValueName "pcon") - -pappQValName :: HsSyntax.QValName -pappQValName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Prelude", HsSyntax.MkValueName "#") - -pdataQValName :: HsSyntax.QValName -pdataQValName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Builtin", HsSyntax.MkValueName "pdata") - -peqQValName :: HsSyntax.QValName -peqQValName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Bool", HsSyntax.MkValueName "#==") - -punsafeCoerceQValName :: HsSyntax.QValName -punsafeCoerceQValName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Unsafe", HsSyntax.MkValueName "punsafeCoerce") - -pdataQTyName :: HsSyntax.QTyName -pdataQTyName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Builtin", HsSyntax.MkTyName "PData") - -constQTyName :: HsSyntax.QTyName -constQTyName = (HsSyntax.MkCabalPackageName "base", HsSyntax.MkModuleName "Data.Functor.Const", HsSyntax.MkTyName "Const") - -pasDataQTyName :: HsSyntax.QTyName -pasDataQTyName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Builtin", HsSyntax.MkTyName "PAsData") - -ptryFromPAsDataQValName :: HsSyntax.QValName -ptryFromPAsDataQValName = (HsSyntax.MkCabalPackageName "lbr-plutarch", HsSyntax.MkModuleName "LambdaBuffers.Runtime.Plutarch", HsSyntax.MkValueName "ptryFromPAsData") - -termQTyName :: HsSyntax.QTyName -termQTyName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch", HsSyntax.MkTyName "Term") - -scopeQTyName :: HsSyntax.QTyName -scopeQTyName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch", HsSyntax.MkTyName "S") - -ptypeQTyName :: HsSyntax.QTyName -ptypeQTyName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch", HsSyntax.MkTyName "PType") - -showQClassName :: HsSyntax.QClassName -showQClassName = (HsSyntax.MkCabalPackageName "plutarch", HsSyntax.MkModuleName "Plutarch.Show", HsSyntax.MkClassName "PShow") - -genericQClassName :: HsSyntax.QClassName -genericQClassName = (HsSyntax.MkCabalPackageName "base", HsSyntax.MkModuleName "GHC.Generics", HsSyntax.MkClassName "Generic") diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Syntax.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Syntax.hs deleted file mode 100644 index 5498241b..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Plutarch/Print/Syntax.hs +++ /dev/null @@ -1,26 +0,0 @@ -module LambdaBuffers.Codegen.Plutarch.Print.Syntax (filepathFromModuleName, printModName, cabalFromLbModuleName, fromLbForeignRef) where - -import Control.Lens ((^.)) -import Data.Text qualified as Text -import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsSyntax -import LambdaBuffers.ProtoCompat qualified as PC -import Prettyprinter (Doc, Pretty (pretty)) - -fromLbModuleName :: PC.ModuleName -> HsSyntax.ModuleName -fromLbModuleName mn = HsSyntax.MkModuleName $ Text.intercalate "." ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) <> ".Plutarch" - -cabalFromLbModuleName :: PC.ModuleName -> HsSyntax.CabalPackageName -cabalFromLbModuleName mn = HsSyntax.MkCabalPackageName $ Text.intercalate "-" ([Text.toLower $ p ^. #name | p <- mn ^. #parts] <> ["-plutarch-lb"]) - -fromLbForeignRef :: PC.ForeignRef -> HsSyntax.QTyName -fromLbForeignRef fr = - ( cabalFromLbModuleName $ fr ^. #moduleName - , fromLbModuleName $ fr ^. #moduleName - , HsSyntax.fromLbTyName $ fr ^. #tyName - ) - -printModName :: PC.ModuleName -> Doc ann -printModName mn = let HsSyntax.MkModuleName hmn = fromLbModuleName mn in pretty hmn - -filepathFromModuleName :: PC.ModuleName -> FilePath -filepathFromModuleName mn = Text.unpack $ Text.intercalate "/" ("LambdaBuffers" : [p ^. #name | p <- mn ^. #parts]) <> "/Plutarch.hs" diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/PlutusTx.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/PlutusTx.hs new file mode 100644 index 00000000..7696921c --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/PlutusTx.hs @@ -0,0 +1,17 @@ +module LambdaBuffers.Codegen.PlutusTx ( + runBackend, +) where + +import Data.Set (Set) +import Data.Text (Text) +import LambdaBuffers.Codegen.Haskell.Backend qualified as Haskell +import LambdaBuffers.Codegen.Haskell.Backend.PlutusTx (PlutusTxHaskellBackend) +import LambdaBuffers.Codegen.Haskell.Config qualified as Haskell +import LambdaBuffers.ProtoCompat.Types qualified as PC +import Proto.Codegen qualified as P + +{- | `runBackend cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Haskell configuration file in `cfg`. + It either errors with an API error message or succeeds with a module filepath, code and package dependencies. +-} +runBackend :: Haskell.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) +runBackend = Haskell.runBackend @PlutusTxHaskellBackend () () diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Print.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Print.hs index a05c3350..f091b0ff 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Print.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Print.hs @@ -1,7 +1,9 @@ module LambdaBuffers.Codegen.Print ( runPrint, + IsBackend (..), Context (..), MonadPrint, + PrintM, ctxTyImports, ctxOpaqueTyImports, ctxTyExports, @@ -10,21 +12,25 @@ module LambdaBuffers.Codegen.Print ( ctxConfig, ctxCompilerInput, ctxModule, + ctxBackend, importValue, importClass, stValueImports, stClassImports, stTypeImports, + stBackend, throwInternalError, importType, throwInternalError', + askBackend, + getBackend, ) where import Control.Lens (makeLenses, (&), (.~)) import Control.Monad.Error.Class (MonadError (throwError)) import Control.Monad.Except (Except, runExcept) import Control.Monad.RWS (RWST (runRWST)) -import Control.Monad.RWS.Class (MonadRWS, modify) +import Control.Monad.RWS.Class (MonadRWS, asks, gets, modify) import Data.ProtoLens (Message (defMessage)) import Data.Set (Set) import Data.Set qualified as Set @@ -38,42 +44,57 @@ import Proto.Codegen_Fields qualified as P type Error = P.InternalError -data Context qtn qcn = Context - { _ctxCompilerInput :: PC.CodegenInput - , _ctxModule :: PC.Module -- TODO(bladyjoker): Turn into a `ModuleName` and do a lookup on the CI. - , _ctxTyImports :: Set PC.QTyName - , _ctxOpaqueTyImports :: Set qtn - , _ctxClassImports :: Set qcn - , _ctxRuleImports :: Set (PC.InfoLess PC.ModuleName) - , _ctxTyExports :: Set (PC.InfoLess PC.TyName) - , _ctxConfig :: Config qtn qcn +-- TODO(bladyjoker): Add backend error +class + ( Ord (BackendQualifiedTyName backend) + , Ord (BackendQualifiedValueName backend) + , Ord (BackendQualifiedClassName backend) + ) => + IsBackend backend + where + type BackendContext backend + type BackendState backend + type BackendQualifiedTyName backend + type BackendQualifiedClassName backend + type BackendQualifiedValueName backend + +data Context backend = Context + { _ctxCompilerInput :: !PC.CodegenInput + , _ctxModule :: !PC.Module -- TODO(bladyjoker): Turn into a `ModuleName` and do a lookup on the CI. + , _ctxTyImports :: !(Set PC.QTyName) + , _ctxOpaqueTyImports :: !(Set (BackendQualifiedTyName backend)) + , _ctxClassImports :: !(Set (BackendQualifiedClassName backend)) + , _ctxRuleImports :: !(Set (PC.InfoLess PC.ModuleName)) + , _ctxTyExports :: !(Set (PC.InfoLess PC.TyName)) + , _ctxConfig :: !(Config (BackendQualifiedTyName backend) (BackendQualifiedClassName backend)) + , _ctxBackend :: !(BackendContext backend) } - deriving stock (Eq, Ord, Show) makeLenses 'Context -data State qcn qvn qtn = State - { _stValueImports :: Set qvn - , _stClassImports :: Set qcn - , _stTypeImports :: Set qtn +data State backend = State + { _stValueImports :: Set (BackendQualifiedValueName backend) + , _stClassImports :: Set (BackendQualifiedClassName backend) + , _stTypeImports :: Set (BackendQualifiedTyName backend) + , _stBackend :: BackendState backend } - deriving stock (Eq, Ord, Show) makeLenses 'State -type MonadPrint qtn qcn qvn m = (MonadError Error m, MonadRWS (Context qtn qcn) () (State qcn qvn qtn) m) +type MonadPrint backend m = (IsBackend backend, MonadError Error m, MonadRWS (Context backend) () (State backend) m) -type PrintM qtn qcn qvn = RWST (Context qtn qcn) () (State qcn qvn qtn) (Except Error) +type PrintM backend = RWST (Context backend) () (State backend) (Except Error) -- | `runPrint ctx printer` runs a printing workflow that yields a module document and a set of package dependencies. runPrint :: - forall qtn qcn qvn. - (Ord qvn, Ord qcn, Ord qtn) => - Context qtn qcn -> - PrintM qtn qcn qvn (Doc (), Set Text) -> + forall backend. + IsBackend backend => + BackendState backend -> + Context backend -> + PrintM backend (Doc (), Set Text) -> Either P.Error (Doc (), Set Text) -runPrint ctx modPrinter = - let p = runRWST modPrinter ctx (State mempty mempty mempty) +runPrint initSt ctx modPrinter = + let p = runRWST modPrinter ctx (State mempty mempty mempty initSt) in case runExcept p of Left err -> Left $ @@ -83,21 +104,27 @@ runPrint ctx modPrinter = ] Right (r, _, _) -> Right r -importValue :: (MonadPrint qtn qcn qvn m, Ord qvn) => qvn -> m () -importValue qvn = modify (\(State vimps cimps tyimps) -> State (Set.insert qvn vimps) cimps tyimps) +importValue :: MonadPrint backend m => BackendQualifiedValueName backend -> m () +importValue qvn = modify (\(State vimps cimps tyimps bstate) -> State (Set.insert qvn vimps) cimps tyimps bstate) -importClass :: (MonadPrint qtn qcn qvn m, Ord qcn) => qcn -> m () -importClass qcn = modify (\(State vimps cimps tyimps) -> State vimps (Set.insert qcn cimps) tyimps) +importClass :: MonadPrint backend m => BackendQualifiedClassName backend -> m () +importClass qcn = modify (\(State vimps cimps tyimps bstate) -> State vimps (Set.insert qcn cimps) tyimps bstate) -importType :: (MonadPrint qtn qcn qvn m, Ord qtn) => qtn -> m () -importType qtn = modify (\(State vimps cimps tyimps) -> State vimps cimps (Set.insert qtn tyimps)) +importType :: MonadPrint backend m => BackendQualifiedTyName backend -> m () +importType qtn = modify (\(State vimps cimps tyimps bstate) -> State vimps cimps (Set.insert qtn tyimps) bstate) -throwInternalError :: MonadPrint qtn qcn qvn m => PC.SourceInfo -> String -> m a +throwInternalError :: MonadPrint backend m => PC.SourceInfo -> String -> m a throwInternalError si = throwInternalError' si . Text.pack -throwInternalError' :: MonadPrint qtn qcn qvn m => PC.SourceInfo -> Text -> m a +throwInternalError' :: MonadPrint backend m => PC.SourceInfo -> Text -> m a throwInternalError' si msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Print] " <> msg & P.sourceInfo .~ PC.toProto si + +askBackend :: MonadPrint backend m => m (BackendContext backend) +askBackend = asks _ctxBackend + +getBackend :: MonadPrint backend m => m (BackendState backend) +getBackend = gets _stBackend diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript.hs index d3c22f83..11a6dd05 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript.hs @@ -1,31 +1,29 @@ module LambdaBuffers.Codegen.Purescript ( - runPrint, + runBackend, ) where import Control.Lens ((^.)) import Data.Set (Set) import Data.Text (Text) -import LambdaBuffers.Codegen.Check (runCheck) +import LambdaBuffers.Codegen.Check qualified as Check import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Purescript.Backend (PurescriptBackend) import LambdaBuffers.Codegen.Purescript.Config qualified as Purescript import LambdaBuffers.Codegen.Purescript.Print qualified as Purescript -import LambdaBuffers.Codegen.Purescript.Syntax (filepathFromModuleName) +import LambdaBuffers.Codegen.Purescript.Syntax qualified as Purescript import LambdaBuffers.ProtoCompat.Types qualified as PC import Prettyprinter (defaultLayoutOptions, layoutPretty) import Prettyprinter.Render.Text (renderStrict) import Proto.Codegen qualified as P -{- | `runPrint cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Purescript configuration file in `cfg`. - It either errors with an API error message or succeeds with a module filepath, code and package dependencies. --} -runPrint :: Purescript.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) -runPrint cfg ci m = case runCheck cfg ci m of +runBackend :: Purescript.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) +runBackend cfg ci m = case Check.runCheck @PurescriptBackend cfg () ci m of Left err -> Left err - Right ctx -> case Print.runPrint ctx Purescript.printModule of + Right ctx -> case Print.runPrint () ctx Purescript.printModule of Left err -> Left err Right (modDoc, deps) -> Right - ( filepathFromModuleName (m ^. #moduleName) + ( Purescript.filepathFromModuleName (m ^. #moduleName) , renderStrict $ layoutPretty defaultLayoutOptions modDoc , deps ) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Backend.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Backend.hs new file mode 100644 index 00000000..c6fcc842 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Backend.hs @@ -0,0 +1,20 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE UndecidableInstances #-} + +module LambdaBuffers.Codegen.Purescript.Backend (MonadPurescriptBackend, PurescriptBackendM, PurescriptBackend) where + +import LambdaBuffers.Codegen.Print (IsBackend) +import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Purescript.Syntax qualified as Purescript + +data PurescriptBackend + +instance IsBackend PurescriptBackend where + type BackendContext PurescriptBackend = () + type BackendState PurescriptBackend = () + type BackendQualifiedValueName PurescriptBackend = Purescript.QValName + type BackendQualifiedTyName PurescriptBackend = Purescript.QTyName + type BackendQualifiedClassName PurescriptBackend = Purescript.QClassName + +type MonadPurescriptBackend m = (Print.MonadPrint PurescriptBackend m) +type PurescriptBackendM = Print.PrintM PurescriptBackend diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print.hs index 6e78f5e1..e5f15735 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print.hs @@ -1,12 +1,4 @@ -{- | `Print.MonadPrint` implementation for the Purescript backend. - - The monad is instantiated with `Purs.QTyName` which are qualified Purescript type - names referring to `Opaque` type imports. It's also instantiated with - `[Purs.QClassName]` which denotes the qualified Purescript class names to import. - Note that a single LambdaBuffers 'class' can be unpacked into several related - Purescript classes and that's why it's a list of qualified Purescript class names. --} -module LambdaBuffers.Codegen.Purescript.Print (MonadPrint, printModule) where +module LambdaBuffers.Codegen.Purescript.Print (printModule) where import Control.Lens (view, (^.)) import Control.Monad.Reader.Class (ask, asks) @@ -21,9 +13,9 @@ import Data.Traversable (for) import LambdaBuffers.Codegen.Config qualified as C import LambdaBuffers.Codegen.Print (throwInternalError) import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Purescript.Backend (MonadPurescriptBackend) import LambdaBuffers.Codegen.Purescript.Print.Derive (printDeriveEq, printDeriveFromPlutusData, printDeriveJson, printDeriveToPlutusData) import LambdaBuffers.Codegen.Purescript.Print.InstanceDef (printInstanceDef) -import LambdaBuffers.Codegen.Purescript.Print.MonadPrint (MonadPrint) import LambdaBuffers.Codegen.Purescript.Print.Names (printModName, printModName', printTyName) import LambdaBuffers.Codegen.Purescript.Print.TyDef (printTyDef) import LambdaBuffers.Codegen.Purescript.Syntax qualified as Purs @@ -31,37 +23,27 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), align, comma, encloseSep, group, line, lparen, rparen, space, vsep, (<+>)) import Proto.Codegen qualified as P -printModule :: MonadPrint m => m (Doc ann, Set Text) +printModule :: MonadPurescriptBackend m => m (Doc ann, Set Text) printModule = do ctx <- ask + moduleHeaderDoc <- printModuleHeader tyDefDocs <- printTyDefs (ctx ^. Print.ctxModule) instDocs <- printInstances - st <- get + importsDoc <- printImports let modDoc = align . vsep $ - [ printModuleHeader (ctx ^. Print.ctxModule . #moduleName) (ctx ^. Print.ctxTyExports) + [ moduleHeaderDoc , mempty - , printImports - (ctx ^. Print.ctxTyImports) - (ctx ^. Print.ctxOpaqueTyImports) - (ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports) - (ctx ^. Print.ctxRuleImports) - (st ^. Print.stValueImports) + , importsDoc , mempty , vsep ((line <>) <$> tyDefDocs) , mempty , vsep ((line <>) <$> instDocs) ] - pkgDeps = - collectPackageDeps - (ctx ^. Print.ctxTyImports) - (ctx ^. Print.ctxOpaqueTyImports) - (ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports) - (ctx ^. Print.ctxRuleImports) - (st ^. Print.stValueImports) + pkgDeps <- collectPackageDeps return (modDoc, pkgDeps) -printTyDefs :: MonadPrint m => PC.Module -> m [Doc ann] +printTyDefs :: MonadPurescriptBackend m => PC.Module -> m [Doc ann] printTyDefs m = for (toList $ m ^. #typeDefs) printTyDef pursClassImplPrinters :: @@ -93,7 +75,7 @@ pursClassImplPrinters = ) ] -printInstances :: MonadPrint m => m [Doc ann] +printInstances :: MonadPurescriptBackend m => m [Doc ann] printInstances = do ci <- asks (view Print.ctxCompilerInput) m <- asks (view Print.ctxModule) @@ -106,7 +88,7 @@ printInstances = do mempty (toList $ m ^. #derives) -printDerive :: MonadPrint m => PC.TyDefs -> PC.Derive -> m [Doc ann] +printDerive :: MonadPurescriptBackend m => PC.TyDefs -> PC.Derive -> m [Doc ann] printDerive iTyDefs d = do mn <- asks (view $ Print.ctxModule . #moduleName) let qcn = PC.qualifyClassRef mn (d ^. #constraint . #classRef) @@ -121,7 +103,7 @@ printDerive iTyDefs d = do printPursQClassImpl mn iTyDefs pqcn d ) -printPursQClassImpl :: MonadPrint m => PC.ModuleName -> PC.TyDefs -> Purs.QClassName -> PC.Derive -> m (Doc ann) +printPursQClassImpl :: MonadPurescriptBackend m => PC.ModuleName -> PC.TyDefs -> Purs.QClassName -> PC.Derive -> m (Doc ann) printPursQClassImpl mn iTyDefs hqcn d = case Map.lookup hqcn pursClassImplPrinters of Nothing -> throwInternalError (d ^. #constraint . #sourceInfo) ("Missing capability to print the Purescript type class " <> show hqcn) @@ -134,8 +116,12 @@ printPursQClassImpl mn iTyDefs hqcn d = for_ (toList valImps) Print.importValue return instanceDefsDoc -printModuleHeader :: PC.ModuleName -> Set (PC.InfoLess PC.TyName) -> Doc ann -printModuleHeader mn exports = "module" <+> printModName mn <+> printExports exports <+> "where" +printModuleHeader :: MonadPurescriptBackend m => m (Doc ann) +printModuleHeader = do + ctx <- ask + let mn = ctx ^. Print.ctxModule . #moduleName + exports = ctx ^. Print.ctxTyExports + return $ "module" <+> printModName mn <+> printExports exports <+> "where" printExports :: Set (PC.InfoLess PC.TyName) -> Doc ann printExports exports = align $ group $ encloseSep lparen rparen (comma <> space) ((`PC.withInfoLess` printTyExportWithCtors) <$> toList exports) @@ -143,9 +129,17 @@ printExports exports = align $ group $ encloseSep lparen rparen (comma <> space) printTyExportWithCtors :: PC.TyName -> Doc ann printTyExportWithCtors tyn = printTyName tyn <> "(..)" -printImports :: Set PC.QTyName -> Set Purs.QTyName -> Set Purs.QClassName -> Set (PC.InfoLess PC.ModuleName) -> Set Purs.QValName -> Doc ann -printImports lbTyImports pursTyImports classImps ruleImps valImps = - let groupedLbImports = +printImports :: MonadPurescriptBackend m => m (Doc ann) +printImports = do + ctx <- ask + st <- get + let lbTyImports = ctx ^. Print.ctxTyImports + pursTyImports = ctx ^. Print.ctxOpaqueTyImports + classImps = ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports + ruleImps = ctx ^. Print.ctxRuleImports + valImps = st ^. Print.stValueImports + + groupedLbImports = Set.fromList [mn | (mn, _tn) <- toList lbTyImports] `Set.union` ruleImps lbImportDocs = importQualified . printModName' <$> toList groupedLbImports @@ -157,18 +151,26 @@ printImports lbTyImports pursTyImports classImps ruleImps valImps = pursImportDocs = (\(Purs.MkModuleName mn) -> importQualified $ pretty mn) <$> toList groupedPursImports importsDoc = vsep $ lbImportDocs ++ pursImportDocs - in importsDoc + + return importsDoc where importQualified :: Doc ann -> Doc ann importQualified mnDoc = "import" <+> mnDoc <+> "as" <+> mnDoc -{- | `collectPackageDeps lbTyImports hsTyImports classImps ruleImps valImps` collects all the package dependencies. +{- | `collectPackageDeps` collects all the package dependencies. Note that LB `lbTyImports` and `ruleImps` are wired by the user (as the user decides on the package name for their schemass). -} -collectPackageDeps :: Set PC.QTyName -> Set Purs.QTyName -> Set Purs.QClassName -> Set (PC.InfoLess PC.ModuleName) -> Set Purs.QValName -> Set Text -collectPackageDeps _lbTyImports hsTyImports classImps _ruleImps valImps = - let deps = - Set.fromList [Purs.pkgNameToText pkgName | (pkgName, _, _) <- toList hsTyImports] +collectPackageDeps :: MonadPurescriptBackend m => m (Set Text) +collectPackageDeps = do + ctx <- ask + st <- get + let pursTyImports = ctx ^. Print.ctxOpaqueTyImports <> st ^. Print.stTypeImports + classImps = ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports + valImps = st ^. Print.stValueImports + + deps = + Set.fromList [Purs.pkgNameToText pkgName | (pkgName, _, _) <- toList pursTyImports] `Set.union` Set.fromList [Purs.pkgNameToText pkgName | (pkgName, _, _) <- toList classImps] `Set.union` Set.fromList [Purs.pkgNameToText pkgName | (Just (pkgName, _), _) <- toList valImps] - in deps + + return deps diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Derive.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Derive.hs index 4072cb9a..3bb0f270 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Derive.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Derive.hs @@ -13,15 +13,19 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, align, equals, vsep, (<+>)) import Proto.Codegen qualified as P -lvEqBuiltins :: LV.PrintRead Purs.QValName -lvEqBuiltins = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("eq", Purs.normalValName "prelude" "Prelude" "==") - , ("and", Purs.normalValName "prelude" "Prelude" "&&") - , ("true", Purs.primValName "true") - , ("false", Purs.primValName "false") - ] +lvEqBuiltins :: LV.Context Purs.QValName () +lvEqBuiltins = + LV.Context + ( \(_ty, refName) -> + Map.lookup refName $ + Map.fromList + [ ("eq", Purs.normalValName "prelude" "Prelude" "==") + , ("and", Purs.normalValName "prelude" "Prelude" "&&") + , ("true", Purs.primValName "true") + , ("false", Purs.primValName "false") + ] + ) + () eqClassMethodName :: Purs.ValueName eqClassMethodName = Purs.MkValueName "eq" @@ -33,20 +37,24 @@ printDeriveEq mn iTyDefs mkInstanceDoc ty = do let instanceDoc = mkInstanceDoc (printValueDef eqClassMethodName implDoc) return (instanceDoc, imports) -lvPlutusDataBuiltins :: LV.PrintRead Purs.QValName -lvPlutusDataBuiltins = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("toPlutusData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.ToData" "toData") - , ("fromPlutusData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.FromData" "fromData") - , ("casePlutusData", Purs.normalValName "lbr-plutus" "LambdaBuffers.Runtime.Plutus" "casePlutusData") - , ("integerData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.Types.PlutusData" "Integer") - , ("constrData", Purs.normalValName "lbr-plutus" "LambdaBuffers.Runtime.Plutus" "pdConstr") - , ("listData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.Types.PlutusData" "List") - , ("succeedParse", Purs.normalValName "maybe" "Data.Maybe" "Just") - , ("failParse", Purs.normalValName "maybe" "Data.Maybe" "Nothing") - , ("bindParse", Purs.normalValName "prelude" "Prelude" ">>=") - ] +lvPlutusDataBuiltins :: LV.Context Purs.QValName () +lvPlutusDataBuiltins = + LV.Context + ( \(_ty, refName) -> + Map.lookup refName $ + Map.fromList + [ ("toPlutusData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.ToData" "toData") + , ("fromPlutusData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.FromData" "fromData") + , ("casePlutusData", Purs.normalValName "lbr-plutus" "LambdaBuffers.Runtime.Plutus" "casePlutusData") + , ("integerData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.Types.PlutusData" "Integer") + , ("constrData", Purs.normalValName "lbr-plutus" "LambdaBuffers.Runtime.Plutus" "pdConstr") + , ("listData", Purs.normalValName "cardano-transaction-lib" "Ctl.Internal.Types.PlutusData" "List") + , ("succeedParse", Purs.normalValName "maybe" "Data.Maybe" "Just") + , ("failParse", Purs.normalValName "maybe" "Data.Maybe" "Nothing") + , ("bindParse", Purs.normalValName "prelude" "Prelude" ">>=") + ] + ) + () toPlutusDataClassMethodName :: Purs.ValueName toPlutusDataClassMethodName = Purs.MkValueName "toData" @@ -78,23 +86,27 @@ printValueDef :: Purs.ValueName -> Doc ann -> Doc ann printValueDef valName valDoc = printPursValName valName <+> equals <+> valDoc -- | LambdaBuffers.Codegen.LamVal.Json specification printing -lvJsonBuiltins :: LV.PrintRead Purs.QValName -lvJsonBuiltins = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("toJson", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "toJson") - , ("fromJson", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "fromJson") - , ("jsonObject", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonObject") - , ("jsonConstructor", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonConstructor") - , ("jsonArray", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonArray") - , ("caseJsonConstructor", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "caseJsonConstructor") - , ("caseJsonArray", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "caseJsonArray") - , ("caseJsonObject", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "caseJsonObject") - , ("jsonField", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonField") - , ("succeedParse", Purs.normalValName "either" "Data.Either" "Right") - , ("failParse", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "fail") - , ("bindParse", Purs.normalValName "prelude" "Prelude" ">>=") - ] +lvJsonBuiltins :: LV.Context Purs.QValName () +lvJsonBuiltins = + LV.Context + ( \(_ty, refName) -> + Map.lookup refName $ + Map.fromList + [ ("toJson", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "toJson") + , ("fromJson", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "fromJson") + , ("jsonObject", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonObject") + , ("jsonConstructor", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonConstructor") + , ("jsonArray", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonArray") + , ("caseJsonConstructor", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "caseJsonConstructor") + , ("caseJsonArray", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "caseJsonArray") + , ("caseJsonObject", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "caseJsonObject") + , ("jsonField", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "jsonField") + , ("succeedParse", Purs.normalValName "either" "Data.Either" "Right") + , ("failParse", Purs.normalValName "lbr-prelude" "LambdaBuffers.Runtime.Prelude" "fail") + , ("bindParse", Purs.normalValName "prelude" "Prelude" ">>=") + ] + ) + () toJsonClassMethodName :: Purs.ValueName toJsonClassMethodName = Purs.MkValueName "toJson" diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/InstanceDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/InstanceDef.hs index c5cc9c16..0bd5ead9 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/InstanceDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/InstanceDef.hs @@ -7,7 +7,7 @@ import Data.Map.Ordered qualified as OMap import Data.Set (Set) import Data.Set qualified as Set import LambdaBuffers.Codegen.Print (importClass, importValue) -import LambdaBuffers.Codegen.Purescript.Print.MonadPrint (MonadPrint) +import LambdaBuffers.Codegen.Purescript.Backend (MonadPurescriptBackend) import LambdaBuffers.Codegen.Purescript.Print.Names (printPursQClassName, printPursQValName) import LambdaBuffers.Codegen.Purescript.Print.Ty (printTyInner) import LambdaBuffers.Codegen.Purescript.Syntax (className, normalValName) @@ -21,7 +21,7 @@ printInstanceDef pursQClassName ty = freeVars = collectTyVars ty in case freeVars of [] -> \implDoc -> "instance" <+> headDoc <+> "where" <> hardline <> space <> space <> implDoc - _ -> \implDoc -> "instance" <+> printInstanceContext pursQClassName freeVars <+> "=>" <+> headDoc <+> "where" <> hardline <> space <> space <> implDoc + _other -> \implDoc -> "instance" <+> printInstanceContext pursQClassName freeVars <+> "=>" <+> headDoc <+> "where" <> hardline <> space <> space <> implDoc printInstanceContext :: Purs.QClassName -> [PC.Ty] -> Doc ann printInstanceContext hsQClassName tys = align . group $ encloseSep lparen rparen comma (printConstraint hsQClassName <$> tys) @@ -55,13 +55,13 @@ genericClass = className "prelude" "Data.Generic.Rep" "Generic" showClass :: Purs.QClassName showClass = className "prelude" "Data.Show" "Show" -printNewtypeDerive :: MonadPrint m => PC.TyDef -> m (Doc ann) +printNewtypeDerive :: MonadPurescriptBackend m => PC.TyDef -> m (Doc ann) printNewtypeDerive = printDerive newtypeClass -printGenericDerive :: MonadPrint m => PC.TyDef -> m (Doc ann) +printGenericDerive :: MonadPurescriptBackend m => PC.TyDef -> m (Doc ann) printGenericDerive = printDerive genericClass -printShowInstance :: MonadPrint m => PC.TyDef -> m (Doc ann) +printShowInstance :: MonadPurescriptBackend m => PC.TyDef -> m (Doc ann) printShowInstance tyd = do importClass showClass importValue genericShow @@ -71,7 +71,7 @@ printShowInstance tyd = do For a `Show` type class on a `Maybe a` type definition it prints `derive instance Show (Maybe a) _` -} -printDerive :: MonadPrint m => Purs.QClassName -> PC.TyDef -> m (Doc ann) +printDerive :: MonadPurescriptBackend m => Purs.QClassName -> PC.TyDef -> m (Doc ann) printDerive qcn tyd = do importClass qcn return $ "derive instance" <+> printPursQClassName qcn <+> (printTyInner . toSaturatedTyApp $ tyd) <+> "_" diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/LamVal.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/LamVal.hs index df6abf80..a781d0ac 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/LamVal.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/LamVal.hs @@ -17,7 +17,7 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), align, colon, comma, dot, dquotes, encloseSep, equals, group, hardline, hsep, lbrace, lbracket, line, lparen, parens, rbrace, rbracket, rparen, space, vsep, (<+>)) import Proto.Codegen_Fields qualified as P -type MonadPrint m = LV.MonadPrint m Purs.QValName +type MonadPrint m = LV.MonadPrint m Purs.QValName () throwInternalError :: MonadPrint m => String -> m a throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Purescript.Print.LamVal] " <> Text.pack msg @@ -56,10 +56,10 @@ printCaseE (qtyN, sumTy) caseVal ctorCont = do <$> for (OMap.assocs sumTy) ( \(cn, ty) -> case ty of -- TODO(bladyjoker): Cleanup by refactoring LT.Ty. - LT.TyProduct fields _ -> do + LT.TyProduct fields _other -> do ctorCaseDoc <- printCtorCase qtyN ctorCont (cn, fields) return $ ctorCaseDoc <> hardline - _ -> throwInternalError "Got a non-product in Sum." + _other -> throwInternalError "Got a non-product in Sum." ) return $ align $ "case" <+> caseValDoc <+> "of" <> line <> ctorCaseDocs diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/MonadPrint.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/MonadPrint.hs deleted file mode 100644 index 98c92e80..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/MonadPrint.hs +++ /dev/null @@ -1,6 +0,0 @@ -module LambdaBuffers.Codegen.Purescript.Print.MonadPrint (MonadPrint) where - -import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Purescript.Syntax qualified as Purs - -type MonadPrint m = Print.MonadPrint Purs.QTyName Purs.QClassName Purs.QValName m diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Names.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Names.hs index 76a9a6b0..3ed964d7 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Names.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Names.hs @@ -22,17 +22,17 @@ printPursQValName :: Purs.QValName -> Doc ann printPursQValName (Just (_, Purs.MkModuleName pursModName), Purs.MkValueName pursValName) = case Text.uncons pursValName of Nothing -> "TODO(bladyjoker): Got an empty Purescript value name" Just (c, _) | Char.isAlpha c -> pretty pursModName <> dot <> pretty pursValName - _ -> pretty pursModName <> dot <> enclose lparen rparen (pretty pursValName) + _other -> pretty pursModName <> dot <> enclose lparen rparen (pretty pursValName) printPursQValName (Nothing, Purs.MkValueName pursValName) = case Text.uncons pursValName of Nothing -> "TODO(bladyjoker): Got an empty Purescript value name" Just (c, _) | Char.isAlpha c -> pretty pursValName - _ -> enclose lparen rparen (pretty pursValName) + _other -> enclose lparen rparen (pretty pursValName) printPursValName :: Purs.ValueName -> Doc ann printPursValName (Purs.MkValueName pursValName) = case Text.uncons pursValName of Nothing -> "TODO(bladyjoker): Got an empty Purescript value name" Just (c, _) | Char.isAlpha c -> pretty pursValName - _ -> enclose lparen rparen $ pretty pursValName + _other -> enclose lparen rparen $ pretty pursValName {- | Print the Purescript class method name (ie. (==), toJSON etc.). This doesn't require a qualified print as it's treated special, we just need to diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Ty.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Ty.hs index 7b676f16..e8b54190 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Ty.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/Ty.hs @@ -9,7 +9,7 @@ import Data.Traversable (for) import LambdaBuffers.Codegen.Config (cfgOpaques) import LambdaBuffers.Codegen.Print (throwInternalError) import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Purescript.Print.MonadPrint (MonadPrint) +import LambdaBuffers.Codegen.Purescript.Backend (MonadPurescriptBackend) import LambdaBuffers.Codegen.Purescript.Print.Names (printCtorName, printFieldName, printMkCtor, printPursQTyName, printTyName, printVarName) import LambdaBuffers.Codegen.Purescript.Syntax (TyDefKw (DataTyDef, NewtypeTyDef, SynonymTyDef)) import LambdaBuffers.Codegen.Purescript.Syntax qualified as Purs @@ -23,7 +23,7 @@ For the above examples it prints a b = Foo'MkFoo a | Foo'MkBar b a = Prelude.Maybe a -} -printTyAbs :: MonadPrint m => PC.TyName -> PC.TyAbs -> m (TyDefKw, Doc ann) +printTyAbs :: MonadPurescriptBackend m => PC.TyName -> PC.TyAbs -> m (TyDefKw, Doc ann) printTyAbs tyN (PC.TyAbs args body _) = do let argsDoc = if OMap.empty == args then mempty else encloseSep mempty space space (printTyArg <$> toList args) (kw, bodyDoc) <- printTyBody tyN (toList args) body @@ -38,15 +38,15 @@ Prelude.Maybe a TODO(bladyjoker): Revisit empty records and prods. -} -printTyBody :: MonadPrint m => PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (TyDefKw, Doc ann) +printTyBody :: MonadPurescriptBackend m => PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (TyDefKw, Doc ann) printTyBody tyN _ (PC.SumI s) = (DataTyDef,) <$> printSum tyN s printTyBody tyN _ (PC.ProductI p@(PC.Product fields _)) = case toList fields of [] -> return (DataTyDef, printMkCtor tyN) [_] -> return (NewtypeTyDef, printMkCtor tyN <+> printProd p) - _ -> return (DataTyDef, printMkCtor tyN <+> printProd p) + _other -> return (DataTyDef, printMkCtor tyN <+> printProd p) printTyBody tyN _ (PC.RecordI r@(PC.Record fields _)) = case toList fields of [] -> return (DataTyDef, printMkCtor tyN) - _ -> printRec tyN r >>= \recDoc -> return (NewtypeTyDef, printMkCtor tyN <+> recDoc) + _other -> printRec tyN r >>= \recDoc -> return (NewtypeTyDef, printMkCtor tyN <+> recDoc) printTyBody tyN args (PC.OpaqueI si) = do opqs <- asks (view $ Print.ctxConfig . cfgOpaques) mn <- asks (view $ Print.ctxModule . #moduleName) @@ -57,7 +57,7 @@ printTyBody tyN args (PC.OpaqueI si) = do printTyArg :: PC.TyArg -> Doc ann printTyArg (PC.TyArg vn _ _) = printVarName vn -printSum :: MonadPrint m => PC.TyName -> PC.Sum -> m (Doc ann) +printSum :: MonadPurescriptBackend m => PC.TyName -> PC.Sum -> m (Doc ann) printSum tyN (PC.Sum ctors _) = do let ctorDocs = printCtor tyN <$> toList ctors return $ @@ -72,7 +72,7 @@ printCtor tyN (PC.Constructor ctorName prod) = prodDoc = printProd prod in group $ ctorNDoc <+> prodDoc -- TODO(bladyjoker): Adds extra space when empty. -printRec :: MonadPrint m => PC.TyName -> PC.Record -> m (Doc ann) +printRec :: MonadPurescriptBackend m => PC.TyName -> PC.Record -> m (Doc ann) printRec tyN (PC.Record fields _) = do if null fields then return mempty @@ -86,7 +86,7 @@ printProd (PC.Product fields _) = do then mempty else align $ sep (printTyInner <$> fields) -printField :: MonadPrint m => PC.TyName -> PC.Field -> m (Doc ann) +printField :: MonadPurescriptBackend m => PC.TyName -> PC.Field -> m (Doc ann) printField tyN f@(PC.Field fn ty) = do fnDoc <- case printFieldName tyN fn of Nothing -> throwInternalError (fn ^. #sourceInfo) ("Failed printing `FieldName` for field\n" <> show (tyN, f)) @@ -118,7 +118,7 @@ printTyAppTopLevel (PC.TyApp f args _) = printTyRef :: PC.TyRef -> Doc ann printTyRef (PC.LocalI (PC.LocalRef tn _)) = group $ printTyName tn -printTyRef (PC.ForeignI fr) = let (_, Purs.MkModuleName hmn, Purs.MkTyName htn) = Purs.fromLbForeignRef fr in pretty hmn <> dot <> pretty htn +printTyRef (PC.ForeignI fr) = let (_, Purs.MkModuleName hmn, Purs.MkTyName htn) = Purs.fromLbForeignRef fr in pretty hmn <> dot <> pretty htn -- TODO(bladyjoker): This is not really correct but it works. Fix this with `resolveModuleToPackage` which gets the packages supplied via `--packages` printTyVar :: PC.TyVar -> Doc ann printTyVar (PC.TyVar vn) = printVarName vn diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/TyDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/TyDef.hs index 0d38fdf6..de93cc97 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/TyDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Print/TyDef.hs @@ -1,7 +1,7 @@ module LambdaBuffers.Codegen.Purescript.Print.TyDef (printTyDef) where +import LambdaBuffers.Codegen.Purescript.Backend (MonadPurescriptBackend) import LambdaBuffers.Codegen.Purescript.Print.InstanceDef (printGenericDerive, printNewtypeDerive, printShowInstance) -import LambdaBuffers.Codegen.Purescript.Print.MonadPrint (MonadPrint) import LambdaBuffers.Codegen.Purescript.Print.Names (printTyName) import LambdaBuffers.Codegen.Purescript.Print.Ty (printTyAbs) import LambdaBuffers.Codegen.Purescript.Syntax (TyDefKw (DataTyDef, NewtypeTyDef, SynonymTyDef)) @@ -54,7 +54,7 @@ instance (Data.Show.Show a) => Data.Show.Show (RecFoo a) where show = Data.Show.Generic.genericShow ``` -} -printTyDef :: MonadPrint m => PC.TyDef -> m (Doc ann) +printTyDef :: MonadPurescriptBackend m => PC.TyDef -> m (Doc ann) printTyDef tyd@(PC.TyDef tyN tyabs _) = do (kw, absDoc) <- printTyAbs tyN tyabs case kw of diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Syntax.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Syntax.hs index 0fea454c..7a9a8296 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Syntax.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Purescript/Syntax.hs @@ -55,6 +55,7 @@ fromLbModuleName mn = MkModuleName $ Text.intercalate "." ("LambdaBuffers" : [p pkgNameToText :: PackageName -> Text pkgNameToText (MkPackageName pkg) = pkg +-- TODO(bladyjoker): This is garbage fix with user supplied `--packages` pkgFromLbModuleName :: PC.ModuleName -> PackageName pkgFromLbModuleName mn = MkPackageName $ Text.intercalate "-" ([Text.toLower $ p ^. #name | p <- mn ^. #parts] <> ["-lb"]) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust.hs index 9fae8530..3d7fe82f 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust.hs @@ -1,42 +1,40 @@ module LambdaBuffers.Codegen.Rust ( - runPrint, + runBackend, ) where import Control.Lens ((^.)) import Data.Set (Set) import Data.Text (Text) -import LambdaBuffers.Codegen.Check (runCheck) +import LambdaBuffers.Codegen.Check qualified as Check import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Rust.Config qualified as RsConfig -import LambdaBuffers.Codegen.Rust.Print qualified as RsPrint -import LambdaBuffers.Codegen.Rust.Print.Derive qualified as RsDerive -import LambdaBuffers.Codegen.Rust.Print.MonadPrint (MonadPrint) -import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as RsSyntax -import LambdaBuffers.Codegen.Rust.Print.TyDef qualified as RsPrint +import LambdaBuffers.Codegen.Rust.Backend (RustBackend, RustBackendContext (RustBackendContext, rust'compilationCfgs, rust'packages)) +import LambdaBuffers.Codegen.Rust.Config qualified as Rust +import LambdaBuffers.Codegen.Rust.Print qualified as Rust +import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as Rust import LambdaBuffers.ProtoCompat.Types qualified as PC -import Prettyprinter (defaultLayoutOptions, layoutPretty) +import Prettyprinter ( + defaultLayoutOptions, + layoutPretty, + ) import Prettyprinter.Render.Text (renderStrict) import Proto.Codegen qualified as P -{- | `runPrint cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Rust configuration file in `cfg`. - It either errors with an API error message or succeeds with a module filepath, code and package dependencies. --} -runPrint :: RsConfig.Config -> RsSyntax.PkgMap -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) -runPrint cfg pkgs ci m = case runCheck cfg ci m of - Left err -> Left err - Right ctx -> case Print.runPrint ctx (RsPrint.printModule rsPrintModuleEnv pkgs) of - Left err -> Left err - Right (modDoc, deps) -> - Right - ( RsSyntax.filepathFromModuleName (m ^. #moduleName) - , renderStrict $ layoutPretty defaultLayoutOptions modDoc - , deps - ) - -rsPrintModuleEnv :: MonadPrint m => RsPrint.PrintModuleEnv m ann -rsPrintModuleEnv = - RsPrint.PrintModuleEnv - RsSyntax.printModName - RsDerive.rsTraitImplPrinters - RsPrint.printTyDef - ["no_implicit_prelude", "allow(warnings)"] +runBackend :: Rust.PkgMap -> Rust.Config -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) +runBackend pkgs cfg ci m = + let + rustCtx = + RustBackendContext + { rust'packages = pkgs + , rust'compilationCfgs = ["no_implicit_prelude", "allow(warnings)"] + } + in + case Check.runCheck @RustBackend cfg rustCtx ci m of + Left err -> Left err + Right ctx -> case Print.runPrint () ctx Rust.printModule of + Left err -> Left err + Right (modDoc, deps) -> + Right + ( Rust.filepathFromModuleName (m ^. #moduleName) + , renderStrict $ layoutPretty defaultLayoutOptions modDoc + , deps + ) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Backend.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Backend.hs new file mode 100644 index 00000000..532d4ec1 --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Backend.hs @@ -0,0 +1,26 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE UndecidableInstances #-} + +module LambdaBuffers.Codegen.Rust.Backend (MonadRustBackend, RustBackendM, RustBackend, RustBackendContext (..)) where + +import Data.Text (Text) +import LambdaBuffers.Codegen.Print (IsBackend) +import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as Rust + +data RustBackend + +instance IsBackend RustBackend where + type BackendContext RustBackend = RustBackendContext + type BackendState RustBackend = () + type BackendQualifiedValueName RustBackend = Rust.QValName + type BackendQualifiedTyName RustBackend = Rust.QTyName + type BackendQualifiedClassName RustBackend = Rust.QTraitName + +type MonadRustBackend m = (Print.MonadPrint RustBackend m) +type RustBackendM = Print.PrintM RustBackend + +data RustBackendContext = RustBackendContext + { rust'compilationCfgs :: ![Text] + , rust'packages :: !Rust.PkgMap + } diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print.hs index 4c39591e..c6207f6d 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print.hs @@ -1,18 +1,9 @@ -{- | `Print.MonadPrint` implementation for the Rust backend. - - The monad is instantiated with `R.QTyName` which are qualified Rust type - names referring to `Opaque` type imports. It's also instantiated with - `[R.QTraitName]` which denotes the qualified Rust trait names to import. - Note that a single LambdaBuffers 'trait' can be unpacked into several related - Rust traites and that's why it's a list of qualified Rust trait names. --} -module LambdaBuffers.Codegen.Rust.Print (MonadPrint, printModule, PrintModuleEnv (..)) where +module LambdaBuffers.Codegen.Rust.Print (printModule) where import Control.Lens (view, (^.)) import Control.Monad.Reader.Class (ask, asks) import Control.Monad.State.Class (MonadState (get)) import Data.Foldable (Foldable (toList), foldrM) -import Data.Map (Map) import Data.Map qualified as Map import Data.Maybe (mapMaybe) import Data.Set (Set) @@ -22,70 +13,51 @@ import Data.Traversable (for) import LambdaBuffers.Codegen.Config qualified as C import LambdaBuffers.Codegen.Print (throwInternalError) import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Rust.Backend (MonadRustBackend, RustBackendContext (rust'compilationCfgs, rust'packages)) +import LambdaBuffers.Codegen.Rust.Print.Derive qualified as Rust import LambdaBuffers.Codegen.Rust.Print.InstanceDef (printInstanceDef) -import LambdaBuffers.Codegen.Rust.Print.MonadPrint (MonadPrint) import LambdaBuffers.Codegen.Rust.Print.Syntax (crateNameToCargoText, crateNameToText) import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as R +import LambdaBuffers.Codegen.Rust.Print.TyDef qualified as Rust import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), align, brackets, line, semi, vsep, (<+>)) -data PrintModuleEnv m ann = PrintModuleEnv - { env'printModuleName :: PC.ModuleName -> Doc ann - , env'implementationPrinter :: - Map - R.QTraitName - ( PC.ModuleName -> - R.PkgMap -> - PC.TyDefs -> - (Doc ann -> Doc ann) -> - PC.Ty -> - m (Doc ann) - ) - , env'printTyDef :: MonadPrint m => R.PkgMap -> PC.TyDef -> m (Doc ann) - , env'compilationCfgs :: [Text] - } - -printModule :: MonadPrint m => PrintModuleEnv m ann -> R.PkgMap -> m (Doc ann, Set Text) -printModule env pkgs = do +printModule :: MonadRustBackend m => m (Doc ann, Set Text) +printModule = do ctx <- ask - tyDefDocs <- for (toList $ ctx ^. Print.ctxModule . #typeDefs) (env'printTyDef env pkgs) - instDocs <- printInstances env pkgs - st <- get + let rustCtx = ctx ^. Print.ctxBackend + tyDefDocs <- for (toList $ ctx ^. Print.ctxModule . #typeDefs) Rust.printTyDef + instDocs <- printInstances + let compCfgDoc = printCompilationCfgs (rust'compilationCfgs rustCtx) + imports <- collectPackageDeps + let importsDoc = printImports imports let modDoc = align . vsep $ - [ printCompilationCfgs (env'compilationCfgs env) - , printImports imports + [ compCfgDoc + , importsDoc , mempty , vsep ((line <>) <$> tyDefDocs) , mempty , vsep ((line <>) <$> instDocs) ] - imports = - collectPackageDeps - pkgs - (ctx ^. Print.ctxTyImports) - (ctx ^. Print.ctxOpaqueTyImports <> st ^. Print.stTypeImports) - (ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports) - (ctx ^. Print.ctxRuleImports) - (st ^. Print.stValueImports) return (modDoc, Set.map crateNameToCargoText imports) -printInstances :: MonadPrint m => PrintModuleEnv m ann -> R.PkgMap -> m [Doc ann] -printInstances env pkgs = do +printInstances :: MonadRustBackend m => m [Doc ann] +printInstances = do ci <- asks (view Print.ctxCompilerInput) m <- asks (view Print.ctxModule) let iTyDefs = PC.indexTyDefs ci foldrM ( \d instDocs -> do - instDocs' <- printDerive env pkgs iTyDefs d + instDocs' <- printDerive iTyDefs d return $ instDocs' <> instDocs ) mempty (toList $ m ^. #derives) -printDerive :: MonadPrint m => PrintModuleEnv m ann -> R.PkgMap -> PC.TyDefs -> PC.Derive -> m [Doc ann] -printDerive env pkgs iTyDefs d = do +printDerive :: MonadRustBackend m => PC.TyDefs -> PC.Derive -> m [Doc ann] +printDerive iTyDefs d = do mn <- asks (view $ Print.ctxModule . #moduleName) let qcn = PC.qualifyClassRef mn (d ^. #constraint . #classRef) classes <- asks (view $ Print.ctxConfig . C.cfgClasses) @@ -96,17 +68,17 @@ printDerive env pkgs iTyDefs d = do hsqcns ( \hsqcn -> do Print.importClass hsqcn - printRsQTraitImpl env mn pkgs iTyDefs hsqcn d + printRsQTraitImpl mn iTyDefs hsqcn d ) -printRsQTraitImpl :: MonadPrint m => PrintModuleEnv m ann -> PC.ModuleName -> R.PkgMap -> PC.TyDefs -> R.QTraitName -> PC.Derive -> m (Doc ann) -printRsQTraitImpl env mn pkgs iTyDefs hqcn d = - case Map.lookup hqcn (env'implementationPrinter env) of +printRsQTraitImpl :: MonadRustBackend m => PC.ModuleName -> PC.TyDefs -> R.QTraitName -> PC.Derive -> m (Doc ann) +printRsQTraitImpl mn iTyDefs hqcn d = + case Map.lookup hqcn Rust.rsTraitImplPrinters of Nothing -> throwInternalError (d ^. #constraint . #sourceInfo) ("Missing capability to print the Rust trait " <> show hqcn) -- TODO(bladyjoker): Fix hqcn printing Just implPrinter -> do let ty = d ^. #constraint . #argument - mkInstanceDoc = printInstanceDef pkgs hqcn ty - implPrinter mn pkgs iTyDefs mkInstanceDoc ty + mkInstanceDoc <- printInstanceDef hqcn ty + implPrinter mn iTyDefs mkInstanceDoc ty printCompilationCfgs :: Pretty a => [a] -> Doc ann printCompilationCfgs [] = mempty @@ -122,18 +94,28 @@ printImports crates = externCrate :: R.CrateName -> Doc ann externCrate crateName = "extern crate" <+> pretty (crateNameToText crateName) <> semi --- | `collectPackageDeps lbTyImports rsTyImports traitImps ruleImps valImps` collects all the package dependencies. -collectPackageDeps :: R.PkgMap -> Set PC.QTyName -> Set R.QTyName -> Set R.QTraitName -> Set (PC.InfoLess PC.ModuleName) -> Set R.QValName -> Set R.CrateName -collectPackageDeps packages lbTyImports rsTyImports traitImps ruleImps valImps = - Set.filter - (/= R.MkCrateName "crate") - ( Set.singleton (R.MkCrateName "std") - `Set.union` Set.fromList [R.crateFromLbModuleName packages $ withInfo mn | (mn, _tn) <- toList lbTyImports] - `Set.union` Set.fromList (mapMaybe R.qualifiedToCrate $ toList rsTyImports) - `Set.union` Set.fromList (mapMaybe R.qualifiedToCrate $ toList traitImps) - `Set.union` Set.fromList [R.crateFromLbModuleName packages $ withInfo mn | mn <- toList ruleImps] - `Set.union` Set.fromList (mapMaybe R.qualifiedToCrate $ toList valImps) - ) +-- | `collectPackageDeps` collects all the package dependencies. +collectPackageDeps :: MonadRustBackend m => m (Set R.CrateName) +collectPackageDeps = do + ctx <- ask + st <- get + let packages = rust'packages . view Print.ctxBackend $ ctx + lbTyImports = ctx ^. Print.ctxTyImports + rsTyImports = ctx ^. Print.ctxOpaqueTyImports <> st ^. Print.stTypeImports + traitImps = ctx ^. Print.ctxClassImports <> st ^. Print.stClassImports + ruleImps = ctx ^. Print.ctxRuleImports + valImps = st ^. Print.stValueImports + + return $ + Set.filter + (/= R.MkCrateName "crate") + ( Set.singleton (R.MkCrateName "std") + `Set.union` Set.fromList [R.crateFromLbModuleName packages $ withInfo mn | (mn, _tn) <- toList lbTyImports] + `Set.union` Set.fromList (mapMaybe R.qualifiedToCrate $ toList rsTyImports) + `Set.union` Set.fromList (mapMaybe R.qualifiedToCrate $ toList traitImps) + `Set.union` Set.fromList [R.crateFromLbModuleName packages $ withInfo mn | mn <- toList ruleImps] + `Set.union` Set.fromList (mapMaybe R.qualifiedToCrate $ toList valImps) + ) withInfo :: PC.InfoLessC b => PC.InfoLess b -> b withInfo x = PC.withInfoLess x id diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Derive.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Derive.hs index b948dc60..be35cc50 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Derive.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Derive.hs @@ -11,7 +11,7 @@ import LambdaBuffers.Codegen.LamVal.Json (deriveFromJsonImpl, deriveToJsonImpl) import LambdaBuffers.Codegen.LamVal.MonadPrint qualified as LV import LambdaBuffers.Codegen.LamVal.PlutusData (deriveFromPlutusDataImpl, deriveToPlutusDataImpl) import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Rust.Print (MonadPrint) +import LambdaBuffers.Codegen.Rust.Backend (MonadRustBackend, RustBackendContext (rust'packages)) import LambdaBuffers.Codegen.Rust.Print.LamVal (printInstance) import LambdaBuffers.Codegen.Rust.Print.Refs qualified as RR import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as R @@ -21,11 +21,10 @@ import Proto.Codegen qualified as P import Proto.Codegen_Fields qualified as P rsTraitImplPrinters :: - MonadPrint m => + MonadRustBackend m => Map R.QTraitName ( PC.ModuleName -> - R.PkgMap -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> @@ -47,18 +46,23 @@ eqTraitMethodArgs = [(R.MkValueName "self", R.qBuiltin R.MkTyName "Self"), (R.Mk eqTraitMethodReturns :: R.QTyName eqTraitMethodReturns = R.qBuiltin R.MkTyName "bool" -lvEqBuiltinsBase :: LV.PrintRead R.QValName -lvEqBuiltinsBase = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("eq", R.qForeignRef R.MkValueName "lbr-prelude" ["lamval"] "eq") - , ("and", R.qForeignRef R.MkValueName "lbr-prelude" ["lamval"] "and") - , ("true", R.qBuiltin R.MkValueName "true") - , ("false", R.qBuiltin R.MkValueName "false") - ] +lvEqBuiltinsBase :: LV.Context R.QValName () +lvEqBuiltinsBase = + LV.Context + ( \(_ty, refName) -> + Map.lookup refName $ + Map.fromList + [ ("eq", R.qForeignRef R.MkValueName "lbr-prelude" ["lamval"] "eq") + , ("and", R.qForeignRef R.MkValueName "lbr-prelude" ["lamval"] "and") + , ("true", R.qBuiltin R.MkValueName "true") + , ("false", R.qBuiltin R.MkValueName "false") + ] + ) + () -printDerivePartialEqBase :: MonadPrint m => PC.ModuleName -> R.PkgMap -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDerivePartialEqBase mn pkgs iTyDefs mkInstance ty = do +printDerivePartialEqBase :: MonadRustBackend m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDerivePartialEqBase mn iTyDefs mkInstance ty = do + pkgs <- rust'packages <$> Print.askBackend case deriveEqImpl mn iTyDefs ty of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Prelude.Eq LamVal implementation from a type failed with: " <> err ^. P.msg) Right valE -> do @@ -70,23 +74,27 @@ printDerivePartialEqBase mn pkgs iTyDefs mkInstance ty = do mkInstance $ printTraitMethod eqTraitMethodName eqTraitMethodArgs eqTraitMethodReturns implDoc -printDeriveEqBase :: MonadPrint m => PC.ModuleName -> R.PkgMap -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDeriveEqBase _ _ _ mkInstance _ = return $ mkInstance mempty +printDeriveEqBase :: MonadRustBackend m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDeriveEqBase _ _ mkInstance _ = return $ mkInstance mempty -lvPlutusDataBuiltins :: LV.PrintRead R.QValName -lvPlutusDataBuiltins = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("toPlutusData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data", "IsPlutusData"] "to_plutus_data") - , ("fromPlutusData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data", "IsPlutusData"] "from_plutus_data") - , ("casePlutusData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "case_plutus_data") - , ("integerData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data"] "PlutusData::integer") - , ("constrData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "constr") - , ("listData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data"] "PlutusData::list") - , ("succeedParse", R.qForeignRef R.MkValueName "std" ["result", "Result"] "Ok") - , ("failParse", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "fail_parse()") - , ("bindParse", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "bind_parse") - ] +lvPlutusDataBuiltins :: LV.Context R.QValName () +lvPlutusDataBuiltins = + LV.Context + ( \(_ty, refName) -> + Map.lookup refName $ + Map.fromList + [ ("toPlutusData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data", "IsPlutusData"] "to_plutus_data") + , ("fromPlutusData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data", "IsPlutusData"] "from_plutus_data") + , ("casePlutusData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "case_plutus_data") + , ("integerData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data"] "PlutusData::integer") + , ("constrData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "constr") + , ("listData", R.qForeignRef R.MkValueName "plutus-ledger-api" ["plutus_data"] "PlutusData::list") + , ("succeedParse", R.qForeignRef R.MkValueName "std" ["result", "Result"] "Ok") + , ("failParse", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "fail_parse()") + , ("bindParse", R.qForeignRef R.MkValueName "plutus-ledger-api" ["lamval"] "bind_parse") + ] + ) + () toPlutusDataTraitMethodName :: R.ValueName toPlutusDataTraitMethodName = R.MkValueName "to_plutus_data" @@ -121,8 +129,9 @@ fromPlutusDataTraitMethodReturns = ["result"] "Result" -printDeriveIsPlutusData :: MonadPrint m => PC.ModuleName -> R.PkgMap -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDeriveIsPlutusData mn pkgs iTyDefs mkInstanceDoc ty = do +printDeriveIsPlutusData :: MonadRustBackend m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDeriveIsPlutusData mn iTyDefs mkInstanceDoc ty = do + pkgs <- rust'packages <$> Print.askBackend case printDeriveIsPlutusData' mn pkgs iTyDefs mkInstanceDoc ty of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Prelude.IsPlutusData LamVal implementation from a type failed with: " <> err ^. P.msg) Right (plutusDataInstDefDoc, imps) -> do @@ -159,23 +168,27 @@ printDeriveIsPlutusData' mn pkgs iTyDefs mkInstanceDoc ty = do ) -- | LambdaBuffers.Codegen.LamVal.Json specification printing -lvJsonBuiltins :: LV.PrintRead R.QValName -lvJsonBuiltins = LV.MkPrintRead $ \(_ty, refName) -> - Map.lookup refName $ - Map.fromList - [ ("toJson", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "Json"] "to_json") - , ("fromJson", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "Json"] "from_json") - , ("jsonObject", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_object") - , ("jsonConstructor", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_constructor") - , ("jsonArray", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_array") - , ("caseJsonConstructor", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "case_json_constructor") - , ("caseJsonArray", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "case_json_array") - , ("caseJsonObject", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "case_json_object") - , ("jsonField", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_field") - , ("succeedParse", R.qForeignRef R.MkValueName "std" ["result", "Result"] "Ok") - , ("failParse", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "fail_parse") - , ("bindParse", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "bind_parse") - ] +lvJsonBuiltins :: LV.Context R.QValName () +lvJsonBuiltins = + LV.Context + ( \(_ty, refName) -> + Map.lookup refName $ + Map.fromList + [ ("toJson", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "Json"] "to_json") + , ("fromJson", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "Json"] "from_json") + , ("jsonObject", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_object") + , ("jsonConstructor", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_constructor") + , ("jsonArray", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_array") + , ("caseJsonConstructor", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "case_json_constructor") + , ("caseJsonArray", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "case_json_array") + , ("caseJsonObject", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "case_json_object") + , ("jsonField", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "json_field") + , ("succeedParse", R.qForeignRef R.MkValueName "std" ["result", "Result"] "Ok") + , ("failParse", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "fail_parse") + , ("bindParse", R.qForeignRef R.MkValueName "lbr-prelude" ["json", "lamval"] "bind_parse") + ] + ) + () toJsonTraitMethodName :: R.ValueName toJsonTraitMethodName = R.MkValueName "to_json" @@ -197,8 +210,9 @@ fromJsonTraitMethodReturns :: R.QTyName fromJsonTraitMethodReturns = R.qForeignRef R.MkTyName "std" ["result"] "Result" -- TODO(szg251): This is a hack -printDeriveJson :: MonadPrint m => PC.ModuleName -> R.PkgMap -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) -printDeriveJson mn pkgs iTyDefs mkInstanceDoc ty = do +printDeriveJson :: MonadRustBackend m => PC.ModuleName -> PC.TyDefs -> (Doc ann -> Doc ann) -> PC.Ty -> m (Doc ann) +printDeriveJson mn iTyDefs mkInstanceDoc ty = do + pkgs <- rust'packages <$> Print.askBackend case printDeriveJson' mn pkgs iTyDefs mkInstanceDoc ty of Left err -> Print.throwInternalError' (mn ^. #sourceInfo) ("Deriving Prelude.Json LamVal implementation from a type failed with: " <> err ^. P.msg) Right (jsonInstDefDoc, imps) -> do diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/InstanceDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/InstanceDef.hs index 2d014827..356f94f1 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/InstanceDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/InstanceDef.hs @@ -4,6 +4,7 @@ import Control.Lens (view) import Data.Foldable (Foldable (toList)) import Data.Set (Set) import Data.Set qualified as Set +import LambdaBuffers.Codegen.Rust.Backend (MonadRustBackend) import LambdaBuffers.Codegen.Rust.Print.Refs qualified as RR import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as R import LambdaBuffers.Codegen.Rust.Print.TyDef (printTyInner) @@ -22,33 +23,36 @@ impl SomeClass for SomeTy { } ``` -} -printInstanceDef :: R.PkgMap -> R.QTraitName -> PC.Ty -> (Doc ann -> Doc ann) -printInstanceDef pkgs rsQTraitName ty = - let headDoc = R.printRsQTraitName rsQTraitName <+> "for" <+> printTyInner pkgs ty +printInstanceDef :: MonadRustBackend m => R.QTraitName -> PC.Ty -> m (Doc ann -> Doc ann) +printInstanceDef rsQTraitName ty = do + tyDoc <- printTyInner ty + let headDoc = R.printRsQTraitName rsQTraitName <+> "for" <+> tyDoc freeVars = collectTyVars ty - in case freeVars of - [] -> \implDoc -> "impl" <+> headDoc <+> braces (line <> implDoc) - _ -> \implDoc -> - "impl" - <> printInstanceContext pkgs rsQTraitName freeVars - <+> headDoc - <+> braces (hardline <> space <> space <> implDoc) + instanceCtxDoc <- printInstanceContext rsQTraitName freeVars + return $ case freeVars of + [] -> \implDoc -> "impl" <+> headDoc <+> braces (line <> implDoc) + _other -> \implDoc -> + "impl" + <> instanceCtxDoc + <+> headDoc + <+> braces (hardline <> space <> space <> implDoc) -printInstanceContext :: R.PkgMap -> R.QTraitName -> [PC.Ty] -> Doc ann -printInstanceContext pkgs rsQTraitName = printInstanceContext' pkgs [rsQTraitName] +printInstanceContext :: MonadRustBackend m => R.QTraitName -> [PC.Ty] -> m (Doc ann) +printInstanceContext rsQTraitName = printInstanceContext' [rsQTraitName] defaultTraitBounds :: [R.QTraitName] defaultTraitBounds = [RR.cloneTrait] -printInstanceContext' :: R.PkgMap -> [R.QTraitName] -> [PC.Ty] -> Doc ann -printInstanceContext' pkgs rsQTraitNames tys = - align . group $ encloseSep langle rangle comma [printTraitBound pkgs (rsQTraitNames <> defaultTraitBounds) ty | ty <- tys] +printInstanceContext' :: MonadRustBackend m => [R.QTraitName] -> [PC.Ty] -> m (Doc ann) +printInstanceContext' rsQTraitNames tys = do + traitBoundDocs <- traverse (printTraitBound (rsQTraitNames <> defaultTraitBounds)) tys + return $ align . group $ encloseSep langle rangle comma traitBoundDocs -printTraitBound :: R.PkgMap -> [R.QTraitName] -> PC.Ty -> Doc ann -printTraitBound pkgs qcns ty = +printTraitBound :: MonadRustBackend m => [R.QTraitName] -> PC.Ty -> m (Doc ann) +printTraitBound qcns ty = do let crefDocs = R.printRsQTraitName <$> qcns - tyDoc = printTyInner pkgs ty - in tyDoc <> colon <+> encloseSep mempty mempty "+" crefDocs + tyDoc <- printTyInner ty + return $ tyDoc <> colon <+> encloseSep mempty mempty "+" crefDocs collectTyVars :: PC.Ty -> [PC.Ty] collectTyVars = fmap (`PC.withInfoLess` (PC.TyVarI . PC.TyVar)) . toList . collectVars diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/LamVal.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/LamVal.hs index 1eb0b073..e4134756 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/LamVal.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/LamVal.hs @@ -21,6 +21,8 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), align, angles, braces, brackets, colon, comma, dot, dquotes, encloseSep, equals, group, langle, lbracket, line, lparen, parens, pipe, punctuate, rangle, rbracket, rparen, semi, space, vsep, (<+>)) import Proto.Codegen_Fields qualified as P +type MonadPrint m = LV.MonadPrint m R.QValName () + toOwned :: Doc ann -> Doc ann toOwned = useTraitMethod RR.toOwnedTrait "to_owned" @@ -39,8 +41,6 @@ useTraitMethod trait method d = angles ("_" <+> "as" <+> R.printRsQTraitName tra throwInternalError :: MonadPrint m => String -> m a throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Rust.Print.LamVal] " <> Text.pack msg -type MonadPrint m = LV.MonadPrint m R.QValName - withInfo :: PC.InfoLessC b => PC.InfoLess b -> b withInfo x = PC.withInfoLess x id @@ -64,7 +64,7 @@ printCaseE pkgs iTyDefs (qtyN@(mn', tyN'), sumTy) caseVal ctorCont = do case Map.lookup qtyN iTyDefs of Just (PC.TyDef _ (PC.TyAbs tyArgs (PC.SumI (PC.Sum ctors _)) _) _) -> do return (toList tyArgs, TD.sumCtorTys ctors) - _ -> throwInternalError "Expected a SumE but got something else (TODO(szg251): Print got)" + _other -> throwInternalError "Expected a SumE but got something else (TODO(szg251): Print got)" let phantomFields = TD.collectPhantomTyArgs iTyDefs mn tyN fieldTys tyArgs phantomCaseDoc = @@ -82,8 +82,8 @@ printCaseE pkgs iTyDefs (qtyN@(mn', tyN'), sumTy) caseVal ctorCont = do for (OMap.assocs sumTy) ( \(cn, ty) -> case ty of - LT.TyProduct fields _ -> printCtorCase pkgs iTyDefs qtyN ctorCont (cn, fields) - _ -> throwInternalError "Got a non-product in Sum." + LT.TyProduct fields _other -> printCtorCase pkgs iTyDefs qtyN ctorCont (cn, fields) + _other -> throwInternalError "Got a non-product in Sum." ) return $ "ma" <> align ("tch" <+> caseValDoc <+> braces (line <> vsep (punctuate comma (ctorCases <> phantomCaseDoc)))) @@ -227,7 +227,7 @@ printCtorE pkgs iTyDefs (qtyN@(mn', tyN'), (ctorN, _)) prodVals = do case OMap.lookup ctorN ctors of Just (PC.Constructor _ (PC.Product tys _)) -> return tys Nothing -> throwInternalError "Couldn't find ConstrName in the TyDefs" - _ -> throwInternalError "Expected a SumE but got something else (TODO(szg251): Print got)" + _other -> throwInternalError "Expected a SumE but got something else (TODO(szg251): Print got)" let ctorNDoc = R.printQualifiedCtorName tyN (withInfo ctorN) mayBoxedFields = zip prodVals $ TD.isRecursive iTyDefs mn tyN <$> fieldTys @@ -246,7 +246,7 @@ printRecordE pkgs iTyDefs (qtyN@(mn', tyN'), _) vals = do (tyArgs, fieldTys) <- case Map.lookup qtyN iTyDefs of Just (PC.TyDef _ (PC.TyAbs tyArgs (PC.RecordI (PC.Record fields _)) _) _) -> return (toList tyArgs, TD.recFieldTys fields) - _ -> throwInternalError "Expected a RecordE but got something else (TODO(szg251): Print got)" + _other -> throwInternalError "Expected a RecordE but got something else (TODO(szg251): Print got)" let phantomFields = TD.collectPhantomTyArgs iTyDefs mn tyN fieldTys tyArgs phantomFieldDocs = @@ -277,7 +277,7 @@ printProductE pkgs iTyDefs (qtyN@(mn', tyN'), _) vals = do (tyArgs, fieldTys) <- case Map.lookup qtyN iTyDefs of Just (PC.TyDef _ (PC.TyAbs tyArgs (PC.ProductI (PC.Product fields _)) _) _) -> return (toList tyArgs, fields) - _ -> throwInternalError "Expected a ProductE but got something else (TODO(szg251): Print got)" + _other -> throwInternalError "Expected a ProductE but got something else (TODO(szg251): Print got)" let phantomFieldDocs = R.printRsQTyName RR.phantomData <$ TD.collectPhantomTyArgs iTyDefs mn tyN fieldTys tyArgs mayBoxedFields = zip vals $ TD.isRecursive iTyDefs mn tyN <$> fieldTys @@ -346,7 +346,7 @@ printRefE pkgs ref = do lamTyDoc <- printLamTy pkgs argTy methodDoc <- R.printRsQValName <$> LV.importValue qvn return $ methodDoc <> R.doubleColon <> langle <> lamTyDoc <> rangle - _ -> R.printRsQValName <$> LV.importValue qvn + _other -> R.printRsQValName <$> LV.importValue qvn printLamTy :: MonadPrint m => R.PkgMap -> LT.Ty -> m (Doc ann) printLamTy pkgs (LT.TyRef tyRef) = return $ R.printTyRef pkgs tyRef diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/MonadPrint.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/MonadPrint.hs deleted file mode 100644 index eb6b8570..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/MonadPrint.hs +++ /dev/null @@ -1,6 +0,0 @@ -module LambdaBuffers.Codegen.Rust.Print.MonadPrint (MonadPrint) where - -import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Rust.Print.Syntax qualified as R - -type MonadPrint m = Print.MonadPrint R.QTyName R.QTraitName R.QValName m diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Syntax.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Syntax.hs index 2529560b..3124ae5e 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Syntax.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/Syntax.hs @@ -12,8 +12,8 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), colon, comma, enclose, encloseSep, group, langle, lparen, rangle, rparen) data Qualified a - = Qualified'Builtin a - | Qualified'LibRef CrateName [ModuleName] a + = Qualified'Builtin !a + | Qualified'LibRef !CrateName ![ModuleName] !a deriving stock (Eq, Ord, Show) type QValName = Qualified ValueName @@ -96,7 +96,7 @@ printRsValName :: ValueName -> Doc ann printRsValName (MkValueName rsValName) = case Text.uncons rsValName of Nothing -> "TODO(bladyjoker): Got an empty Rust value name" Just (c, _) | Char.isAlpha c -> pretty rsValName - _ -> enclose lparen rparen $ pretty rsValName + _other -> enclose lparen rparen $ pretty rsValName printRsQTyName :: QTyName -> Doc ann printRsQTyName = printQualified printRsTyName diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/TyDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/TyDef.hs index 754691c0..0a9e890e 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/TyDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Rust/Print/TyDef.hs @@ -14,7 +14,7 @@ import Data.Traversable (for) import LambdaBuffers.Codegen.Config (cfgOpaques) import LambdaBuffers.Codegen.Print (throwInternalError) import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Rust.Print.MonadPrint (MonadPrint) +import LambdaBuffers.Codegen.Rust.Backend (MonadRustBackend, RustBackendContext (rust'packages)) import LambdaBuffers.Codegen.Rust.Print.Refs qualified as RR import LambdaBuffers.Codegen.Rust.Print.Syntax ( TyDefKw (EnumTyDef, StructTyDef, SynonymTyDef), @@ -48,9 +48,9 @@ enum Foo { type Maybe = lbf_prelude::prelude::maybe -} -printTyDef :: MonadPrint m => R.PkgMap -> PC.TyDef -> m (Doc ann) -printTyDef pkgs (PC.TyDef tyN tyabs _) = do - (kw, generics, absDoc) <- printTyAbs pkgs tyN tyabs +printTyDef :: MonadRustBackend m => PC.TyDef -> m (Doc ann) +printTyDef (PC.TyDef tyN tyabs _) = do + (kw, generics, absDoc) <- printTyAbs tyN tyabs if kw /= SynonymTyDef then return $ @@ -89,10 +89,10 @@ For the above examples it prints = lbf_prelude::prelude::maybe -} -printTyAbs :: MonadPrint m => R.PkgMap -> PC.TyName -> PC.TyAbs -> m (TyDefKw, Doc ann, Doc ann) -printTyAbs pkgs tyN (PC.TyAbs args body _) = do +printTyAbs :: MonadRustBackend m => PC.TyName -> PC.TyAbs -> m (TyDefKw, Doc ann, Doc ann) +printTyAbs tyN (PC.TyAbs args body _) = do let argsDoc = if OMap.empty == args then mempty else encloseGenerics (printTyArg <$> toList args) - (kw, bodyDoc) <- printTyBody pkgs tyN (toList args) body + (kw, bodyDoc) <- printTyBody tyN (toList args) body return (kw, argsDoc, group $ align bodyDoc) {- | Prints the type body. @@ -106,46 +106,46 @@ For the above examples it prints lbf_prelude::prelude::maybe -} -printTyBody :: MonadPrint m => R.PkgMap -> PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (TyDefKw, Doc ann) -printTyBody pkgs parentTyN tyArgs (PC.SumI s) = (EnumTyDef,) <$> printSum pkgs parentTyN tyArgs s -printTyBody pkgs parentTyN tyArgs (PC.ProductI p) = (StructTyDef,) <$> printProd pkgs parentTyN tyArgs p -printTyBody pkgs parentTyN tyArgs (PC.RecordI r) = printRec pkgs parentTyN tyArgs r >>= \recDoc -> return (StructTyDef, recDoc) -printTyBody _ tyN args (PC.OpaqueI si) = do +printTyBody :: MonadRustBackend m => PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (TyDefKw, Doc ann) +printTyBody parentTyN tyArgs (PC.SumI s) = (EnumTyDef,) <$> printSum parentTyN tyArgs s +printTyBody parentTyN tyArgs (PC.ProductI p) = (StructTyDef,) <$> printProd parentTyN tyArgs p +printTyBody parentTyN tyArgs (PC.RecordI r) = printRec parentTyN tyArgs r >>= \recDoc -> return (StructTyDef, recDoc) +printTyBody tyN args (PC.OpaqueI si) = do opqs <- asks (view $ Print.ctxConfig . cfgOpaques) mn <- asks (view $ Print.ctxModule . #moduleName) case Map.lookup (PC.mkInfoLess mn, PC.mkInfoLess tyN) opqs of Nothing -> throwInternalError si ("Should have an Opaque configured for " <> show tyN) Just hqtyn -> return (SynonymTyDef, printRsQTyName hqtyn <> encloseGenerics (printTyArg <$> args) <> semi) -printSum :: MonadPrint m => R.PkgMap -> PC.TyName -> [PC.TyArg] -> PC.Sum -> m (Doc ann) -printSum pkgs parentTyN tyArgs (PC.Sum ctors _) = do +printSum :: MonadRustBackend m => PC.TyName -> [PC.TyArg] -> PC.Sum -> m (Doc ann) +printSum parentTyN tyArgs (PC.Sum ctors _) = do ci <- asks (view Print.ctxCompilerInput) let iTyDefs = indexTyDefs ci mn <- asks (view $ Print.ctxModule . #moduleName) let phantomTyArgs = collectPhantomTyArgs iTyDefs mn parentTyN (sumCtorTys ctors) tyArgs phantomCtor = if null phantomTyArgs then mempty else [printPhantomDataCtor phantomTyArgs] - ctorDocs <- traverse (printCtor pkgs parentTyN) (toList ctors) + ctorDocs <- traverse (printCtor parentTyN) (toList ctors) if null ctors then return mempty else return $ align $ braces $ vsep $ punctuate comma (ctorDocs <> phantomCtor) -printCtor :: MonadPrint m => R.PkgMap -> PC.TyName -> PC.Constructor -> m (Doc ann) -printCtor pkgs parentTyN (PC.Constructor ctorName p@(PC.Product fields _)) = do +printCtor :: MonadRustBackend m => PC.TyName -> PC.Constructor -> m (Doc ann) +printCtor parentTyN (PC.Constructor ctorName p@(PC.Product fields _)) = do let ctorNDoc = printCtorName ctorName - prodDoc <- printCtorInner pkgs parentTyN p + prodDoc <- printCtorInner parentTyN p case fields of [] -> return $ group ctorNDoc - _ -> return $ group $ ctorNDoc <> prodDoc + _other -> return $ group $ ctorNDoc <> prodDoc -printCtorInner :: MonadPrint m => R.PkgMap -> PC.TyName -> PC.Product -> m (Doc ann) -printCtorInner pkgs parentTyN (PC.Product fields _) = do - tyDocs <- for fields (printTyTopLevel pkgs parentTyN) +printCtorInner :: MonadRustBackend m => PC.TyName -> PC.Product -> m (Doc ann) +printCtorInner parentTyN (PC.Product fields _) = do + tyDocs <- for fields (printTyTopLevel parentTyN) if null fields then return mempty else return $ encloseSep lparen rparen comma tyDocs -printRec :: MonadPrint m => R.PkgMap -> PC.TyName -> [PC.TyArg] -> PC.Record -> m (Doc ann) -printRec pkgs parentTyN tyArgs (PC.Record fields _) = do +printRec :: MonadRustBackend m => PC.TyName -> [PC.TyArg] -> PC.Record -> m (Doc ann) +printRec parentTyN tyArgs (PC.Record fields _) = do ci <- asks (view Print.ctxCompilerInput) let iTyDefs = indexTyDefs ci mn <- asks (view $ Print.ctxModule . #moduleName) @@ -154,15 +154,15 @@ printRec pkgs parentTyN tyArgs (PC.Record fields _) = do if null fields && null phantomTyArgs then return semi else do - fieldDocs <- for (toList fields) (printField pkgs parentTyN) + fieldDocs <- for (toList fields) (printField parentTyN) return $ group $ align $ braces $ vsep $ punctuate comma (fieldDocs <> phantomFields) -printProd :: MonadPrint m => R.PkgMap -> PC.TyName -> [PC.TyArg] -> PC.Product -> m (Doc ann) -printProd pkgs parentTyN tyArgs (PC.Product fields _) = do +printProd :: MonadRustBackend m => PC.TyName -> [PC.TyArg] -> PC.Product -> m (Doc ann) +printProd parentTyN tyArgs (PC.Product fields _) = do ci <- asks (view Print.ctxCompilerInput) let iTyDefs = indexTyDefs ci mn <- asks (view $ Print.ctxModule . #moduleName) - tyDocs <- for fields (printTyTopLevel pkgs parentTyN) + tyDocs <- for fields (printTyTopLevel parentTyN) let phantomTyArgs = collectPhantomTyArgs iTyDefs mn parentTyN fields tyArgs phantomFields = printPhantomData <$> phantomTyArgs if null fields && null phantomTyArgs @@ -194,7 +194,7 @@ collectPhantomTyArgs iTyDefs ownMn parentTyN tys tyArgs = foldr (go (Set.singlet let tyAbsArgs = fst <$> OMap.assocs omap resolvedArgs = Map.fromList $ zip tyAbsArgs tys' tyBodyTys = case tyBody of - PC.OpaqueI _ -> [] + PC.OpaqueI _other -> [] PC.SumI (PC.Sum ctors _) -> sumCtorTys ctors PC.ProductI (PC.Product fields _) -> fields PC.RecordI (PC.Record fields _) -> recFieldTys fields @@ -202,7 +202,7 @@ collectPhantomTyArgs iTyDefs ownMn parentTyN tys tyArgs = foldr (go (Set.singlet in if Set.member tyN seenTys then tyArgs' else foldr (go (Set.insert tyN seenTys)) tyArgs' resolvedChildrenTys - _ -> tyArgs' + _other -> tyArgs' go _ (PC.TyRefI _) tyArgs' = tyArgs' resolveTyVar :: Map (PC.InfoLess PC.VarName) PC.Ty -> PC.Ty -> PC.Ty @@ -222,10 +222,10 @@ sumCtorTys omap = concatMap go (OMap.assocs omap) go :: (PC.InfoLess PC.ConstrName, PC.Constructor) -> [PC.Ty] go (_, PC.Constructor _ (PC.Product fields _)) = fields -printField :: MonadPrint m => R.PkgMap -> PC.TyName -> PC.Field -> m (Doc ann) -printField pkgs parentTyN (PC.Field fn ty) = do +printField :: MonadRustBackend m => PC.TyName -> PC.Field -> m (Doc ann) +printField parentTyN (PC.Field fn ty) = do let fnDoc = printFieldName fn - tyDoc <- printTyTopLevel pkgs parentTyN ty + tyDoc <- printTyTopLevel parentTyN ty return $ pub fnDoc <> colon <+> tyDoc printPhantomData :: PC.TyArg -> Doc ann @@ -260,26 +260,29 @@ printPhantomDataCtor :: [PC.TyArg] -> Doc ann printPhantomDataCtor tyArgs = phantomDataCtorIdent <> encloseSep lparen rparen comma (printPhantomData <$> tyArgs) -printTyApp :: R.PkgMap -> PC.TyApp -> Doc ann -printTyApp pkgs (PC.TyApp f args _) = - let fDoc = printTyInner pkgs f - argsDoc = printTyInner pkgs <$> args - in group $ fDoc <> encloseGenerics argsDoc +printTyApp :: MonadRustBackend m => PC.TyApp -> m (Doc ann) +printTyApp (PC.TyApp f args _) = do + fDoc <- printTyInner f + argsDoc <- traverse printTyInner args + return $ group $ fDoc <> encloseGenerics argsDoc -printTyTopLevel :: MonadPrint m => R.PkgMap -> PC.TyName -> PC.Ty -> m (Doc ann) -printTyTopLevel pkgs parentTyN ty = do +printTyTopLevel :: MonadRustBackend m => PC.TyName -> PC.Ty -> m (Doc ann) +printTyTopLevel parentTyN ty = do ci <- asks (view Print.ctxCompilerInput) let iTyDefs = indexTyDefs ci mn <- asks (view $ Print.ctxModule . #moduleName) let recursive = isRecursive iTyDefs mn parentTyN ty + tyDoc <- printTyInner ty if recursive - then return $ boxed (printTyInner pkgs ty) - else return $ printTyInner pkgs ty + then return $ boxed tyDoc + else return tyDoc -printTyInner :: R.PkgMap -> PC.Ty -> Doc ann -printTyInner _ (PC.TyVarI v) = printTyVar v -printTyInner pkgs (PC.TyRefI r) = printTyRef pkgs r -printTyInner pkgs (PC.TyAppI a) = printTyApp pkgs a +printTyInner :: MonadRustBackend m => PC.Ty -> m (Doc ann) +printTyInner (PC.TyVarI v) = return $ printTyVar v +printTyInner (PC.TyRefI r) = do + pkgs <- rust'packages <$> Print.askBackend + return $ printTyRef pkgs r +printTyInner (PC.TyAppI a) = printTyApp a {- | Determines whether the field `Ty` of a data structure with name `TyName` is recursive This is done by resolving references, and searching for reoccurances of the parent type name @@ -308,7 +311,7 @@ findChildren iTyDefs qtyN = Nothing -> [] -- TODO(szg251): Gracefully failing, but this should be an error instead Just (PC.TyDef _ (PC.TyAbs _ tyBody _) _) -> case tyBody of - PC.OpaqueI _ -> [] + PC.OpaqueI _other -> [] PC.SumI (PC.Sum ctors _) -> sumCtorTys ctors PC.ProductI (PC.Product fields _) -> fields PC.RecordI (PC.Record fields _) -> recFieldTys fields diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript.hs index 2736fcd9..53e10c0c 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript.hs @@ -1,30 +1,27 @@ -module LambdaBuffers.Codegen.Typescript (runPrint) where +module LambdaBuffers.Codegen.Typescript (runBackend) where import Control.Lens ((^.)) import Data.Set (Set) import Data.Text (Text) -import LambdaBuffers.Codegen.Check (runCheck) +import LambdaBuffers.Codegen.Check qualified as Check import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Typescript.Backend (TypescriptBackend) import LambdaBuffers.Codegen.Typescript.Config qualified as Typescript import LambdaBuffers.Codegen.Typescript.Print qualified as Typescript -import LambdaBuffers.Codegen.Typescript.Syntax (filepathFromModuleName) import LambdaBuffers.Codegen.Typescript.Syntax qualified as Typescript import LambdaBuffers.ProtoCompat.Types qualified as PC import Prettyprinter (defaultLayoutOptions, layoutPretty) import Prettyprinter.Render.Text (renderStrict) import Proto.Codegen qualified as P -{- | `runPrint cfg inp mod` prints a LambdaBuffers checked module `mod`, given its entire compilation closure in `inp` and Typescript configuration file in `cfg`. - It either errors with an API error message or succeeds with a module filepath, code and package dependencies. --} -runPrint :: Typescript.Config -> Typescript.PkgMap -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) -runPrint cfg pkgMap ci m = case runCheck cfg ci m of +runBackend :: Typescript.Config -> Typescript.PkgMap -> PC.CodegenInput -> PC.Module -> Either P.Error (FilePath, Text, Set Text) +runBackend cfg pkgMap ci m = case Check.runCheck @TypescriptBackend cfg () ci m of Left err -> Left err - Right ctx -> case Print.runPrint ctx (Typescript.printModule pkgMap) of + Right ctx -> case Print.runPrint () ctx (Typescript.printModule pkgMap) of Left err -> Left err Right (modDoc, deps) -> Right - ( filepathFromModuleName (m ^. #moduleName) + ( Typescript.filepathFromModuleName (m ^. #moduleName) , renderStrict $ layoutPretty defaultLayoutOptions modDoc , deps ) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Backend.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Backend.hs new file mode 100644 index 00000000..7587c42f --- /dev/null +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Backend.hs @@ -0,0 +1,20 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE UndecidableInstances #-} + +module LambdaBuffers.Codegen.Typescript.Backend (MonadTypescriptBackend, TypescriptBackendM, TypescriptBackend) where + +import LambdaBuffers.Codegen.Print (IsBackend) +import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Typescript.Syntax qualified as Typescript + +data TypescriptBackend + +instance IsBackend TypescriptBackend where + type BackendContext TypescriptBackend = () + type BackendState TypescriptBackend = () + type BackendQualifiedValueName TypescriptBackend = Typescript.QValName + type BackendQualifiedTyName TypescriptBackend = Typescript.QTyName + type BackendQualifiedClassName TypescriptBackend = Typescript.QClassName + +type MonadTypescriptBackend m = (Print.MonadPrint TypescriptBackend m) +type TypescriptBackendM = Print.PrintM TypescriptBackend diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print.hs index 0066113c..353fddc0 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print.hs @@ -1,12 +1,4 @@ -{- | `Print.MonadPrint` implementation for the Typescript backend. - - The monad is instantiated with `Ts.QTyName` which are qualified Typescript type - names referring to `Opaque` type imports. It's also instantiated with - `[Ts.QClassName]` which denotes the qualified Typescript class names to import. - Note that a single LambdaBuffers 'class' can be unpacked into several related - Typescript classes and that's why it's a list of qualified Typescript class names. --} -module LambdaBuffers.Codegen.Typescript.Print (MonadPrint, printModule) where +module LambdaBuffers.Codegen.Typescript.Print (printModule) where import Control.Arrow ((***)) import Control.Lens (view, (^.), (^..)) @@ -24,9 +16,9 @@ import Data.Traversable (for) import LambdaBuffers.Codegen.Config qualified as C import LambdaBuffers.Codegen.Print (throwInternalError) import LambdaBuffers.Codegen.Print qualified as Print +import LambdaBuffers.Codegen.Typescript.Backend (MonadTypescriptBackend) import LambdaBuffers.Codegen.Typescript.Print.Derive (printDeriveEq, printDeriveIsPlutusData, printDeriveJson, tsEqClass, tsIsPlutusDataClass, tsJsonClass) import LambdaBuffers.Codegen.Typescript.Print.InstanceDef (printExportInstanceDecl) -import LambdaBuffers.Codegen.Typescript.Print.MonadPrint (MonadPrint) import LambdaBuffers.Codegen.Typescript.Print.Names (printModName, printModName') import LambdaBuffers.Codegen.Typescript.Print.TyDef (printTyDef) import LambdaBuffers.Codegen.Typescript.Syntax qualified as Ts @@ -34,7 +26,7 @@ import LambdaBuffers.ProtoCompat qualified as PC import Prettyprinter (Doc, Pretty (pretty), squotes, vsep, (<+>)) import Proto.Codegen qualified as P -printModule :: MonadPrint m => Ts.PkgMap -> m (Doc ann, Set Text) +printModule :: MonadTypescriptBackend m => Ts.PkgMap -> m (Doc ann, Set Text) printModule pkgMap = do ctx <- ask tyDefDocs <- printTyDefs pkgMap (ctx ^. Print.ctxModule) @@ -84,7 +76,7 @@ printModule pkgMap = do (st ^. Print.stValueImports) return (modDoc, pkgDeps) -printTyDefs :: MonadPrint m => Ts.PkgMap -> PC.Module -> m [Doc ann] +printTyDefs :: MonadTypescriptBackend m => Ts.PkgMap -> PC.Module -> m [Doc ann] printTyDefs pkgMap m = for (toList $ m ^. #typeDefs) $ printTyDef pkgMap tsClassImplPrinters :: @@ -113,7 +105,7 @@ tsClassImplPrinters pkgMap = ) ] -printInstances :: MonadPrint m => Ts.PkgMap -> m [Doc ann] +printInstances :: MonadTypescriptBackend m => Ts.PkgMap -> m [Doc ann] printInstances pkgMap = do ci <- asks (view Print.ctxCompilerInput) m <- asks (view Print.ctxModule) @@ -126,7 +118,7 @@ printInstances pkgMap = do mempty (toList $ m ^. #derives) -printDerive :: MonadPrint m => Ts.PkgMap -> PC.TyDefs -> PC.Derive -> m [Doc ann] +printDerive :: MonadTypescriptBackend m => Ts.PkgMap -> PC.TyDefs -> PC.Derive -> m [Doc ann] printDerive pkgMap iTyDefs d = do mn <- asks (view $ Print.ctxModule . #moduleName) let qcn = PC.qualifyClassRef mn (d ^. #constraint . #classRef) @@ -141,7 +133,7 @@ printDerive pkgMap iTyDefs d = do printTsQClassImpl pkgMap mn iTyDefs pqcn d ) -printTsQClassImpl :: MonadPrint m => Ts.PkgMap -> PC.ModuleName -> PC.TyDefs -> Ts.QClassName -> PC.Derive -> m (Doc ann) +printTsQClassImpl :: MonadTypescriptBackend m => Ts.PkgMap -> PC.ModuleName -> PC.TyDefs -> Ts.QClassName -> PC.Derive -> m (Doc ann) printTsQClassImpl pkgMap mn iTyDefs hqcn d = case Map.lookup hqcn (tsClassImplPrinters pkgMap) of Nothing -> throwInternalError (d ^. #constraint . #sourceInfo) ("Missing capability to print the Typescript type class " <> show hqcn) diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Derive.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Derive.hs index 62054616..69083841 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Derive.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Derive.hs @@ -39,7 +39,7 @@ lamTy2PCTy = \case LamTy.Types.TyVar var -> return $ PC.TyVarI var LamTy.Types.TyApp _f _args (Just tyApp) -> do return $ PC.TyAppI tyApp - _ -> + _other -> -- NOTE(jaredponn): hopefully this never happens... Nothing @@ -48,21 +48,25 @@ instanceDictIdent pkgMap className ty = Lens.view (dict . Lens.to (PrettyPrinter.Text.renderStrict . layoutPretty defaultLayoutOptions)) $ printInstanceDict pkgMap className ty -lvEqBuiltins :: Ts.PkgMap -> LV.PrintRead Builtin -lvEqBuiltins pkgMap = LV.MkPrintRead $ \(tys, refName) -> - case (refName, tys) of - ("eq", [ty]) -> do - ty' <- lamTy2PCTy ty - return $ - OverloadedBuiltin - (Ts.primValName $ instanceDictIdent pkgMap tsEqClass ty') - 0 -- index in the list of substitutions for the type we're overloading on - ".eq" - ("true", _) -> Just $ Builtin $ Ts.primValName "true" - ("false", _) -> Just $ Builtin $ Ts.primValName "false" - ("and", _) -> Just $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "and" - ("not", _) -> Just $ Builtin $ Ts.primValName "!" - _ -> Nothing +lvEqBuiltins :: Ts.PkgMap -> LV.Context Builtin () +lvEqBuiltins pkgMap = + LV.Context + ( \(tys, refName) -> + case (refName, tys) of + ("eq", [ty]) -> do + ty' <- lamTy2PCTy ty + return $ + OverloadedBuiltin + (Ts.primValName $ instanceDictIdent pkgMap tsEqClass ty') + 0 -- index in the list of substitutions for the type we're overloading on + ".eq" + ("true", _) -> Just $ Builtin $ Ts.primValName "true" + ("false", _) -> Just $ Builtin $ Ts.primValName "false" + ("and", _) -> Just $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "and" + ("not", _) -> Just $ Builtin $ Ts.primValName "!" + _other -> Nothing + ) + () eqClassMethodName :: Ts.ValueName eqClassMethodName = Ts.MkValueName "eq" @@ -90,31 +94,35 @@ printDeriveEq pkgMap mn iTyDefs mkExportInstanceDeclDoc ty = do , Set.map (Lens.view qualifiedValName) $ eqImports <> neqImports ) -lvPlutusDataBuiltins :: Ts.PkgMap -> LV.PrintRead Builtin -lvPlutusDataBuiltins pkgMap = LV.MkPrintRead $ \(tys, refName) -> - case (refName, tys) of - ("toPlutusData", [ty]) -> do - ty' <- lamTy2PCTy ty - return $ - OverloadedBuiltin - (Ts.primValName $ instanceDictIdent pkgMap tsIsPlutusDataClass ty') - 0 -- index in the list of substitutions for the type we're overloading on - ".toData" - ("fromPlutusData", [ty]) -> do - ty' <- lamTy2PCTy ty - return $ - OverloadedBuiltin - (Ts.primValName $ instanceDictIdent pkgMap tsIsPlutusDataClass ty') - 0 -- index in the list of substitutions for the type we're overloading on - ".fromData" - ("casePlutusData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "casePlutusData" - ("integerData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "integerData" - ("constrData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "constrData" - ("listData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "listData" - ("succeedParse", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "succeedParse" - ("failParse", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "failParse('PlutusData parse failed')" -- TODO(jaredponn): bit of a hack to call the function @failParse@ - ("bindParse", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "bindParse" - _ -> Nothing +lvPlutusDataBuiltins :: Ts.PkgMap -> LV.Context Builtin () +lvPlutusDataBuiltins pkgMap = + LV.Context + ( \(tys, refName) -> + case (refName, tys) of + ("toPlutusData", [ty]) -> do + ty' <- lamTy2PCTy ty + return $ + OverloadedBuiltin + (Ts.primValName $ instanceDictIdent pkgMap tsIsPlutusDataClass ty') + 0 -- index in the list of substitutions for the type we're overloading on + ".toData" + ("fromPlutusData", [ty]) -> do + ty' <- lamTy2PCTy ty + return $ + OverloadedBuiltin + (Ts.primValName $ instanceDictIdent pkgMap tsIsPlutusDataClass ty') + 0 -- index in the list of substitutions for the type we're overloading on + ".fromData" + ("casePlutusData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "casePlutusData" + ("integerData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "integerData" + ("constrData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "constrData" + ("listData", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "listData" + ("succeedParse", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "succeedParse" + ("failParse", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "failParse('PlutusData parse failed')" -- TODO(jaredponn): bit of a hack to call the function @failParse@ + ("bindParse", _) -> Just $ Builtin $ Ts.normalValName "lbr-plutus/Runtime.js" "LbrPlutusRuntime" "bindParse" + _other -> Nothing + ) + () toPlutusDataClassMethodName :: Ts.ValueName toPlutusDataClassMethodName = Ts.MkValueName "toData" @@ -148,43 +156,47 @@ tsJsonClass :: Ts.QClassName tsJsonClass = (Ts.MkPackageName "lbr-prelude", Ts.MkModuleName "LbrPrelude", Ts.MkClassName "Json") -- | LambdaBuffers.Codegen.LamVal.Json specification printing -lvJsonBuiltins :: Ts.PkgMap -> LV.PrintRead Builtin -lvJsonBuiltins pkgMap = LV.MkPrintRead $ \(tys, refName) -> - case (refName, tys) of - ("toJson", [ty]) -> do - ty' <- lamTy2PCTy ty - return $ - OverloadedBuiltin - (Ts.primValName $ instanceDictIdent pkgMap tsJsonClass ty') - 0 -- index in the list of substitutions for the type we're overloading on - ".toJson" - ("fromJson", [ty]) -> do - ty' <- lamTy2PCTy ty - return $ - OverloadedBuiltin - (Ts.primValName (instanceDictIdent pkgMap tsJsonClass ty')) - 0 -- index in the list of substitutions for the type we're overloading on - ".fromJson" - ("jsonObject", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonObject" - ("jsonConstructor", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonConstructor" - ("jsonArray", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonArray" - ("caseJsonConstructor", [ty]) -> do - ty' <- lamTy2PCTy ty - return $ - Builtin $ - Ts.normalValName - "lbr-prelude" - "LbrPrelude" - ( PrettyPrinter.Text.renderStrict . layoutPretty defaultLayoutOptions $ - "caseJsonConstructor" <> surround (Typescript.Print.Ty.printTyInner pkgMap ty') langle rangle - ) - ("caseJsonArray", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "caseJsonArray" - ("caseJsonObject", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "caseJsonObject" - ("jsonField", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonField" - ("succeedParse", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "succeedParse" - ("failParse", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "failParse" - ("bindParse", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "bindParse" - _ -> Nothing +lvJsonBuiltins :: Ts.PkgMap -> LV.Context Builtin () +lvJsonBuiltins pkgMap = + LV.Context + ( \(tys, refName) -> + case (refName, tys) of + ("toJson", [ty]) -> do + ty' <- lamTy2PCTy ty + return $ + OverloadedBuiltin + (Ts.primValName $ instanceDictIdent pkgMap tsJsonClass ty') + 0 -- index in the list of substitutions for the type we're overloading on + ".toJson" + ("fromJson", [ty]) -> do + ty' <- lamTy2PCTy ty + return $ + OverloadedBuiltin + (Ts.primValName (instanceDictIdent pkgMap tsJsonClass ty')) + 0 -- index in the list of substitutions for the type we're overloading on + ".fromJson" + ("jsonObject", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonObject" + ("jsonConstructor", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonConstructor" + ("jsonArray", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonArray" + ("caseJsonConstructor", [ty]) -> do + ty' <- lamTy2PCTy ty + return $ + Builtin $ + Ts.normalValName + "lbr-prelude" + "LbrPrelude" + ( PrettyPrinter.Text.renderStrict . layoutPretty defaultLayoutOptions $ + "caseJsonConstructor" <> surround (Typescript.Print.Ty.printTyInner pkgMap ty') langle rangle + ) + ("caseJsonArray", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "caseJsonArray" + ("caseJsonObject", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "caseJsonObject" + ("jsonField", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "jsonField" + ("succeedParse", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "succeedParse" + ("failParse", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "failParse" + ("bindParse", _) -> return $ Builtin $ Ts.normalValName "lbr-prelude" "LbrPrelude" "bindParse" + _other -> Nothing + ) + () toJsonClassMethodName :: Ts.ValueName toJsonClassMethodName = Ts.MkValueName "toJson" diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/InstanceDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/InstanceDef.hs index 380e870a..b7a42b6c 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/InstanceDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/InstanceDef.hs @@ -13,7 +13,7 @@ import Data.Default (Default (def)) import Data.Set (Set) import Data.Set qualified as Set import LambdaBuffers.Codegen.Print (throwInternalError) -import LambdaBuffers.Codegen.Typescript.Print.MonadPrint (MonadPrint) +import LambdaBuffers.Codegen.Typescript.Backend (MonadTypescriptBackend) import LambdaBuffers.Codegen.Typescript.Print.Names ( printTsQClassName, printTsQTyNameKey, @@ -49,15 +49,15 @@ import Prettyprinter ( -- | See 'printInstanceDict' data InstanceDict a = TopLevelInstanceDict - { _dict :: a + { _dict :: !a -- ^ name of the instance dictionary e.g. @Prelude.Eq[Prelude.Integer]@ - , _dictClassPart :: a + , _dictClassPart :: !a -- ^ the class part of the instance dictionary e.g. @Prelude.Eq@ - , _dictTypePart :: a + , _dictTypePart :: !a -- ^ the instance of the type e.g. @Prelude.Integer@ } | ArgumentInstanceDict - { _dict :: a + { _dict :: !a -- ^ name of the instance dictionary as an argument e.g. @dict$a@ } @@ -141,7 +141,7 @@ collectVars' collected (PC.TyAppI (PC.TyApp _ args _)) = collected `Set.union` ( collectVars' collected _ = collected -- See the INVARIANT note below -printExportInstanceDecl :: MonadPrint m => Ts.PkgMap -> Ts.QClassName -> PC.Ty -> m (Doc ann -> Doc ann) +printExportInstanceDecl :: MonadTypescriptBackend m => Ts.PkgMap -> Ts.QClassName -> PC.Ty -> m (Doc ann -> Doc ann) printExportInstanceDecl pkgMap tsQClassName ty = do let instanceType = printInstanceType pkgMap tsQClassName ty @@ -153,7 +153,7 @@ printExportInstanceDecl pkgMap tsQClassName ty = do (dictDoc, _classDoc, tyDoc) <- case lhsInstanceDecl of TopLevelInstanceDict dictDoc classDoc tyDoc -> return (dictDoc, classDoc, tyDoc) - _ -> + _other -> -- TODO(jaredponn): the 'def' is the default source info, but we really -- should put the proper source information in here. throwInternalError def "TODO(jaredponn): Invalid type class instance for TypeScript backend" @@ -201,7 +201,7 @@ printExportInstanceDecl pkgMap tsQClassName ty = do <+> colon <+> case instanceDeclTypeVars of [] -> instanceType - _ -> printInstanceContext pkgMap tsQClassName instanceDeclTypeVars <+> "=>" <+> instanceType + _other -> printInstanceContext pkgMap tsQClassName instanceDeclTypeVars <+> "=>" <+> instanceType ] , rbrace ] @@ -212,7 +212,7 @@ printExportInstanceDecl pkgMap tsQClassName ty = do vsep [ case instanceDeclTypeVars of [] -> dictDoc <+> equals <+> vsep [lbrace, indent 2 bodyDoc, rbrace] - _ -> + _other -> vsep [ dictDoc <+> equals <+> "function" <> printInstanceContext pkgMap tsQClassName instanceDeclTypeVars <+> colon <+> instanceType , indent 2 $ diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/LamVal.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/LamVal.hs index 6edb690c..6a60297f 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/LamVal.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/LamVal.hs @@ -30,9 +30,9 @@ import Proto.Codegen_Fields qualified as P -} data Builtin = OverloadedBuiltin - { _qualifiedValName :: Ts.QValName + { _qualifiedValName :: !Ts.QValName -- ^ the qualified name of the dictionary for the typeclass - , _instanceTyIx :: Int + , _instanceTyIx :: !Int -- ^ index (starting at 0) of the type in the 'LV.RefE' which is -- the instance type e.g. -- Given @@ -49,7 +49,7 @@ data Builtin -- -- Note(jaredponn): having a unique '_instanceTyIx' immediately implies -- that this only supports single parameter type classes. - , _dotMethodName :: Text + , _dotMethodName :: !Text -- ^ the method name of the dictionary prefixed with a dot. } | Builtin @@ -60,7 +60,7 @@ data Builtin $(makeLenses ''Builtin) -type MonadPrint m = LV.MonadPrint m Builtin +type MonadPrint m = LV.MonadPrint m Builtin () throwInternalError :: MonadPrint m => String -> m a throwInternalError msg = throwError $ defMessage & P.msg .~ "[LambdaBuffers.Codegen.Typescript.Print.LamVal] " <> Text.pack msg @@ -120,7 +120,7 @@ printCaseE (qtyN, sumTy) caseVal ctorCont = do -- 'LambdaBuffers.Codegen.Typescript.Print.Ty.printProd' -- for details. [singleField] -> ["let" <+> singleField <+> equals <+> caseOnArgDoc <> ".fields"] - _ -> + _other -> zipWith ( \i argDoc -> "let" <+> argDoc <+> equals <+> caseOnArgDoc <> ".fields" <> lbracket <> pretty (show i) <> rbracket @@ -132,7 +132,7 @@ printCaseE (qtyN, sumTy) caseVal ctorCont = do , rbrace ] ) - _ -> throwInternalError "Got a non-product in Sum." + _other -> throwInternalError "Got a non-product in Sum." casesDocs <- case OMap.assocs sumTy of t : ts -> do @@ -146,7 +146,7 @@ printCaseE (qtyN, sumTy) caseVal ctorCont = do "else" <+> "if" <+> parens (caseOnArgDoc <> dot <> "name" <+> "===" <+> cn) <> cnBody ) cnsCnBodies - _ -> throwInternalError "Empty case not supported" + _other -> throwInternalError "Empty case not supported" return $ -- Loosely, we @@ -258,7 +258,7 @@ printLetE ((_, _tyN), fields) prodVal letCont = do -- tuples", so it's wrong to access `.field` -- <> ".fields" ] - _ -> + _other -> zipWith ( \i argDoc -> "let" @@ -455,7 +455,7 @@ printCtorE ((_, tyN), (ctorN, _)) prodVals = do ] , rbrace ] - _ -> + _other -> return $ vsep [ lbrace @@ -530,7 +530,7 @@ printRefE ref@(refTys, _) = do -- ^~~~~~~~~~~~~~~~~~ this type instanceTy <- case refTys ^? ix instanceTyIndex of Just instanceTy -> return instanceTy - _ -> throwInternalError "Overloaded instance type doesn't exist" + _other -> throwInternalError "Overloaded instance type doesn't exist" -- Then, we do the type directed translation. -- @@ -579,7 +579,7 @@ printRefE ref@(refTys, _) = do OverloadedBuiltin d i _ | i == instanceTyIndex -> (printTsQValName d <>) <$> tdts tys | otherwise -> throwInternalError "Overloaded methods should be overloaded on the same type" - Builtin _ -> throwInternalError "Expected a an OverloadedBuiltin when resolving a type class" + Builtin _other -> throwInternalError "Expected a an OverloadedBuiltin when resolving a type class" tdt ty@(LT.TyRef _tyRef) = do -- essentially similar to the previous case, except we don't recurse builtin <- LV.resolveRef (ref & _1 . ix instanceTyIndex .~ ty) @@ -588,13 +588,13 @@ printRefE ref@(refTys, _) = do OverloadedBuiltin d i _ | i == instanceTyIndex -> return $ printTsQValName d | otherwise -> throwInternalError "Overloaded methods should be overloaded on the same type" - Builtin _ -> throwInternalError "Expected a an OverloadedBuiltin when resolving a type class" + Builtin _other -> throwInternalError "Expected a an OverloadedBuiltin when resolving a type class" tdt ty@(LT.TyVar _tyRef) = do -- duplicated code from the previous case builtin <- LV.resolveRef (ref & _1 . ix instanceTyIndex .~ ty) _ <- LV.importValue builtin case builtin of - Builtin _ -> throwInternalError "Expected a an OverloadedBuiltin when resolving a type class" + Builtin _other -> throwInternalError "Expected a an OverloadedBuiltin when resolving a type class" OverloadedBuiltin d i _ | i == instanceTyIndex -> return $ printTsQValName d | otherwise -> throwInternalError "Overloaded methods should be overloaded on the same type" diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/MonadPrint.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/MonadPrint.hs deleted file mode 100644 index 96c8a4b9..00000000 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/MonadPrint.hs +++ /dev/null @@ -1,6 +0,0 @@ -module LambdaBuffers.Codegen.Typescript.Print.MonadPrint (MonadPrint) where - -import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Typescript.Syntax qualified as Ts - -type MonadPrint m = Print.MonadPrint Ts.QTyName Ts.QClassName Ts.QValName m diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Names.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Names.hs index 581da5fc..ca7ba10c 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Names.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Names.hs @@ -42,17 +42,17 @@ printTsQValName :: Ts.QValName -> Doc ann printTsQValName (Just (_, Ts.MkModuleName tsModName), Ts.MkValueName pursValName) = case Text.uncons pursValName of Nothing -> "TODO(jaredponn): Got an empty Typescript value name" Just (c, _) | Char.isAlpha c -> pretty tsModName <> dot <> pretty pursValName - _ -> pretty tsModName <> dot <> pretty pursValName + _other -> pretty tsModName <> dot <> pretty pursValName printTsQValName (Nothing, Ts.MkValueName pursValName) = case Text.uncons pursValName of Nothing -> "TODO(jaredponn): Got an empty Typescript value name" Just (c, _) | Char.isAlpha c -> pretty pursValName - _ -> pretty pursValName + _other -> pretty pursValName printTsValName :: Ts.ValueName -> Doc ann printTsValName (Ts.MkValueName pursValName) = case Text.uncons pursValName of Nothing -> "TODO(jaredponn): Got an empty Typescript value name" Just (c, _) | Char.isAlpha c -> pretty pursValName - _ -> enclose lparen rparen $ pretty pursValName + _other -> enclose lparen rparen $ pretty pursValName {- | Translate LambdaBuffer sum constructor names into Typescript sum constructor names. diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Ty.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Ty.hs index e1940091..f62c92eb 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Ty.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/Ty.hs @@ -9,7 +9,7 @@ import Data.Traversable (for) import LambdaBuffers.Codegen.Config (cfgOpaques) import LambdaBuffers.Codegen.Print (throwInternalError) import LambdaBuffers.Codegen.Print qualified as Print -import LambdaBuffers.Codegen.Typescript.Print.MonadPrint (MonadPrint) +import LambdaBuffers.Codegen.Typescript.Backend (MonadTypescriptBackend) import LambdaBuffers.Codegen.Typescript.Print.Names (printCtorName, printFieldName, printTsQTyName, printTsQTyNameKey, printTyName, printVarName) import LambdaBuffers.Codegen.Typescript.Syntax qualified as Ts import LambdaBuffers.ProtoCompat qualified as PC @@ -22,7 +22,7 @@ Loosely, this will print things like \$a $b = { name: 'MkFoo', fields: $a } | { name: 'MkBar', fields: $b } \$a = Prelude.Maybe $a -} -printTyAbs :: MonadPrint m => Ts.PkgMap -> PC.TyName -> PC.TyAbs -> m (Doc ann, Doc ann) +printTyAbs :: MonadTypescriptBackend m => Ts.PkgMap -> PC.TyName -> PC.TyAbs -> m (Doc ann, Doc ann) printTyAbs pkgMap tyN (PC.TyAbs args body _) = do let argsDoc = if OMap.empty == args @@ -54,7 +54,7 @@ and type classes. Note: opaque types are _assumed_ to have such unique symbols already defined. -} -printTyBody :: MonadPrint m => Ts.PkgMap -> PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (Doc ann, Doc ann) +printTyBody :: MonadTypescriptBackend m => Ts.PkgMap -> PC.TyName -> [PC.TyArg] -> PC.TyBody -> m (Doc ann, Doc ann) printTyBody pkgMap tyN args tyBody = let -- E.g. @@ -83,7 +83,7 @@ printTyBody pkgMap tyN args tyBody = printTyArg :: PC.TyArg -> Doc ann printTyArg (PC.TyArg vn _ _) = printVarName vn -printSum :: MonadPrint m => Ts.PkgMap -> PC.TyName -> PC.Sum -> m (Doc ann) +printSum :: MonadTypescriptBackend m => Ts.PkgMap -> PC.TyName -> PC.Sum -> m (Doc ann) printSum pkgMap tyN (PC.Sum ctors _) = do let ctorDocs = printCtor pkgMap tyN <$> toList ctors return $ @@ -142,7 +142,7 @@ printCtor pkgMap tyN (PC.Constructor ctorName prod) = [flatAlt rbrace (space <> rbrace)] -- | Just prints out the same record as given in the .lbf file -printRec :: MonadPrint m => Ts.PkgMap -> PC.TyName -> PC.Record -> m (Doc ann) +printRec :: MonadTypescriptBackend m => Ts.PkgMap -> PC.TyName -> PC.Record -> m (Doc ann) printRec pkgMap tyN (PC.Record fields _) = do fieldsDoc <- for (toList fields) $ printField pkgMap tyN return $ group $ align $ case fieldsDoc of @@ -168,9 +168,9 @@ printProd pkgMap (PC.Product fields _) = align $ case fields of [ty] -> printTyInner pkgMap ty -- TODO(jaredponn): put spaces after the comma. Similar to Note [flatAlt -- rbrace] - _ -> encloseSep lbracket rbracket comma $ map (printTyInner pkgMap) fields + _other -> encloseSep lbracket rbracket comma $ map (printTyInner pkgMap) fields -printField :: MonadPrint m => Ts.PkgMap -> PC.TyName -> PC.Field -> m (Doc ann) +printField :: MonadTypescriptBackend m => Ts.PkgMap -> PC.TyName -> PC.Field -> m (Doc ann) printField pkgMap tyN f@(PC.Field fn ty) = do fnDoc <- maybe diff --git a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/TyDef.hs b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/TyDef.hs index c9d0a0cd..37e24dcd 100644 --- a/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/TyDef.hs +++ b/lambda-buffers-codegen/src/LambdaBuffers/Codegen/Typescript/Print/TyDef.hs @@ -1,6 +1,6 @@ module LambdaBuffers.Codegen.Typescript.Print.TyDef (printTyDef) where -import LambdaBuffers.Codegen.Typescript.Print.MonadPrint (MonadPrint) +import LambdaBuffers.Codegen.Typescript.Backend (MonadTypescriptBackend) import LambdaBuffers.Codegen.Typescript.Print.Names (printTyName) import LambdaBuffers.Codegen.Typescript.Print.Ty (printTyAbs) import LambdaBuffers.Codegen.Typescript.Syntax qualified as Ts @@ -43,7 +43,7 @@ export type RecBar<$a> = { bar : $a } export const RecBar: unique symbol = Symbol('RecBar'); ``` -} -printTyDef :: MonadPrint m => Ts.PkgMap -> PC.TyDef -> m (Doc ann) +printTyDef :: MonadTypescriptBackend m => Ts.PkgMap -> PC.TyDef -> m (Doc ann) printTyDef pkgMap (PC.TyDef tyN tyabs _) = do (absDoc, symbolDoc) <- printTyAbs pkgMap tyN tyabs return $ diff --git a/lambda-buffers-codegen/test/Test/LambdaBuffers/Codegen/Plutarch.hs b/lambda-buffers-codegen/test/Test/LambdaBuffers/Codegen/Plutarch.hs index 4ba36724..48320522 100644 --- a/lambda-buffers-codegen/test/Test/LambdaBuffers/Codegen/Plutarch.hs +++ b/lambda-buffers-codegen/test/Test/LambdaBuffers/Codegen/Plutarch.hs @@ -16,11 +16,11 @@ import Data.Set qualified as Set import Data.Text (Text) import Data.Text qualified as Text import Data.Text.IO qualified as Text +import LambdaBuffers.Codegen.Haskell.Backend.Plutarch.LamVal qualified as PlLamVal import LambdaBuffers.Codegen.Haskell.Config qualified as H import LambdaBuffers.Codegen.Haskell.Print.Syntax qualified as HsSyntax import LambdaBuffers.Codegen.LamVal qualified as LamVal import LambdaBuffers.Codegen.LamVal.MonadPrint qualified as LamVal -import LambdaBuffers.Codegen.Plutarch.Print.LamVal qualified as PlLamVal import LambdaBuffers.Compiler.LamTy qualified as LT import LambdaBuffers.ProtoCompat qualified as PC import Paths_lambda_buffers_codegen qualified as Path @@ -92,7 +92,7 @@ lamValCases = id , Right "lamval-cases/plutarch/CaseListE-1.hs" ) - , ("(x, y)", LamVal.TupleE (LamVal.VarE "x") (LamVal.VarE "y"), Left "[LambdaBuffers.Codegen.Plutarch.Print.LamVal] LamVal tuple literal expression is not supported for Plutarch (yet)") + , ("(x, y)", LamVal.TupleE (LamVal.VarE "x") (LamVal.VarE "y"), Left "[LambdaBuffers.Codegen.Plutarch] LamVal tuple literal expression is not supported for Plutarch (yet)") , ("x", LamVal.VarE "x", Right "lamval-cases/plutarch/VarE-1.hs") , ("fooRef", LamVal.RefE ([], "fooRef"), Right "lamval-cases/plutarch/RefE-1.hs") , ("\\x -> x", LamVal.LamE id, Right "lamval-cases/plutarch/LamE-1.hs") @@ -138,14 +138,14 @@ lamValCases = , LamVal.VarE "x" ) ] - , Left "[LambdaBuffers.Codegen.Plutarch.Print.LamVal] LamVal record literal expression is not supported for Plutarch" + , Left "[LambdaBuffers.Codegen.Plutarch] LamVal record literal expression is not supported for Plutarch" ) , ( "unitRecord.foo" , LamVal.FieldE ((PC.mkInfoLess (PC.ModuleName [] def), PC.mkInfoLess (PC.TyName "UnitProduct" def)), PC.mkInfoLess $ PC.FieldName "foo" def) (LamVal.VarE "unitRecord") - , Left "[LambdaBuffers.Codegen.Plutarch.Print.LamVal] LamVal record field accessor is not supported for Plutarch" + , Left "[LambdaBuffers.Codegen.Plutarch] LamVal record field accessor is not supported for Plutarch" ) , ( "Foo'Bar \"works\")" @@ -166,7 +166,7 @@ lamValCases = , ( "error \"some error\"'" , LamVal.ErrorE "some error" - , Left "[LambdaBuffers.Codegen.Plutarch.Print.LamVal] LamVal error builtin was called with: some error" + , Left "[LambdaBuffers.Codegen.Plutarch] LamVal error builtin was called with: some error" ) ] @@ -175,7 +175,10 @@ testLamValInterpretation = let interpret = LamVal.runPrint - (LamVal.MkPrintRead $ \(_ty, refName) -> Map.lookup refName $ Map.singleton "fooRef" (HsSyntax.MkCabalPackageName "foo-pkg", HsSyntax.MkModuleName "Foo", HsSyntax.MkValueName "fooRef")) + ( LamVal.Context + (\(_ty, refName) -> Map.lookup refName $ Map.singleton "fooRef" (HsSyntax.MkCabalPackageName "foo-pkg", HsSyntax.MkModuleName "Foo", HsSyntax.MkValueName "fooRef")) + () + ) . PlLamVal.printValueE tcs :: [TestTree] tcs = diff --git a/lambda-buffers-frontend/build.nix b/lambda-buffers-frontend/build.nix index 3b1a9140..f0a92ea8 100644 --- a/lambda-buffers-frontend/build.nix +++ b/lambda-buffers-frontend/build.nix @@ -121,6 +121,24 @@ }} "$@"; ''; + lbf-plutus-to-plutustx = pkgs.writeShellScriptBin "lbf-plutus-to-plutustx" '' + export LB_COMPILER=${config.packages.lbc}/bin/lbc; + mkdir autogen; + mkdir .work; + ${config.lbf-nix.lbfBuild.buildCall { + files = []; + import-paths = [ config.packages.lbf-prelude config.packages.lbf-plutus ]; + gen = "${config.packages.lbg-plutustx}/bin/lbg-plutustx"; + gen-classes = ["Prelude.Eq" "Plutus.V1.PlutusData" ]; + gen-dir = "autogen"; + gen-opts = [ + "--config=${config.packages.codegen-configs}/plutustx-prelude.json" + "--config=${config.packages.codegen-configs}/plutustx-plutus.json" + ]; + work-dir = ".work"; + }} "$@"; + ''; + lbf-prelude-to-purescript = pkgs.writeShellScriptBin "lbf-prelude-to-purescript" '' export LB_COMPILER=${config.packages.lbc}/bin/lbc; mkdir -p autogen; diff --git a/libs/build.nix b/libs/build.nix index b8f9b8d0..0ef8c855 100644 --- a/libs/build.nix +++ b/libs/build.nix @@ -1,8 +1,7 @@ # Foundational .lbf packages # TODO(bladyjoker): Make packages that actually try and compile. -{ inputs, ... }: { - perSystem = { pkgs, config, system, ... }: { + perSystem = { pkgs, config, ... }: { packages = { lbf-prelude = pkgs.stdenv.mkDerivation { @@ -40,7 +39,7 @@ ]; }; - lbf-prelude-plutarch = config.lbf-nix.lbfPlutarch' { + lbf-prelude-plutarch = config.lbf-nix.lbfPlutarchBase { name = "lbf-prelude-plutarch"; src = ./lbf-prelude; files = [ "Prelude.lbf" ]; @@ -48,6 +47,14 @@ configs = [ "${config.packages.codegen-configs}/plutarch-prelude.json" ]; }; + lbf-prelude-plutustx = config.lbf-nix.lbfPlutusTxBase { + name = "lbf-prelude-plutustx"; + src = ./lbf-prelude; + files = [ "Prelude.lbf" ]; + classes = [ "Prelude.Eq" ]; + configs = [ "${config.packages.codegen-configs}/plutustx-prelude.json" ]; + }; + lbf-prelude-rust = config.lbf-nix.lbfRust { name = "lbf-prelude"; src = ./lbf-prelude; @@ -67,7 +74,7 @@ name = "lbf-plutus"; src = ./lbf-plutus; imports = [ ./lbf-prelude ]; - files = [ "Plutus/V1.lbf" "Plutus/V1/Todo.lbf" "Plutus/V2.lbf" "Plutus/V2/Todo.lbf" ]; + files = [ "Plutus/V1.lbf" "Plutus/V2.lbf" ]; classes = [ "Prelude.Eq" "Prelude.Json" "Plutus.V1.PlutusData" ]; dependencies = [ @@ -95,7 +102,7 @@ ]; }; - lbf-plutus-plutarch = config.lbf-nix.lbfPlutarch' { + lbf-plutus-plutarch = config.lbf-nix.lbfPlutarchBase { name = "lbf-plutus-plutarch"; src = ./lbf-plutus; imports = [ ./lbf-prelude ]; @@ -108,6 +115,19 @@ ]; }; + lbf-plutus-plutustx = config.lbf-nix.lbfPlutusTxBase { + name = "lbf-plutus-plutustx"; + src = ./lbf-plutus; + imports = [ ./lbf-prelude ]; + files = [ "Plutus/V1.lbf" "Plutus/V2.lbf" ]; + classes = [ "Prelude.Eq" "Plutus.V1.PlutusData" ]; + dependencies = [ "lbf-prelude-plutustx" ]; + configs = [ + "${config.packages.codegen-configs}/plutustx-prelude.json" + "${config.packages.codegen-configs}/plutustx-plutus.json" + ]; + }; + lbf-plutus-typescript = config.lbf-nix.lbfTypescript { name = "lbf-plutus"; src = ./lbf-plutus; @@ -129,7 +149,7 @@ name = "lbf-plutus"; src = ./lbf-plutus; imports = { lbf-prelude = ./lbf-prelude; }; - files = [ "Plutus/V1.lbf" "Plutus/V1/Todo.lbf" "Plutus/V2.lbf" "Plutus/V2/Todo.lbf" ]; + files = [ "Plutus/V1.lbf" "Plutus/V2.lbf" ]; classes = [ "Prelude.Eq" "Prelude.Json" "Plutus.V1.PlutusData" ]; configs = [ "${config.packages.codegen-configs}/rust-prelude-base.json" @@ -137,130 +157,6 @@ ]; }; }; - - # The following devShells allow one to conveniently play with some of the - # above schemas - devShells = { - dev-prelude-haskell = - # Note: - # `lbf-prelude-haskell` (defined above - # `packages.lbf-prelude-haskell`) essentially generates a cabal - # project from the `./Prelude.lbf` schema; and the following uses - # `haskell.nix` to convert the `.cabal` project into a dev shell. - # This is a dev shell which provides - # - ghc with `lbf-prelude-haskell` package (and its dependencies) - # - the CLI application (`lbf-prelude-to-haskell`) to compile `.lbf` - # schemas - let - hsFlake = inputs.flake-lang.lib.${system}.haskellFlake { - src = config.packages.lbf-prelude-haskell; - - name = "dev-prelude-haskell"; - - inherit (config.settings.haskell) index-state compiler-nix-name; - - dependencies = [ - "${config.packages.lbr-prelude-haskell-src}" - "${config.packages.lbf-prelude-haskell}" - ]; - # Note: Add `lbf-prelude` Haskell package in the devShell environment. - # This *must* be the name of the autogenerated cabal package from - # `lbf-prelude-haskell` - devShellAdditionalPackages = ps: [ ps.lbf-prelude ]; - - devShellTools = config.settings.shell.tools ++ [ config.packages.lbf-prelude-to-haskell ]; - devShellHook = config.settings.shell.hook; - }; - in - hsFlake.devShell; - - dev-plutustx = - # Note: - # Similarly to `dev-prelude-haskell`, `packages.lbf-plutus-haskell` - # essentially generates a cabal project from the `*.lbf` schemas; and - # the following uses `haskell.nix` to convert the `.cabal` project into - # a dev shell. - # This is a dev shell which provides - # - ghc with `lbf-plutus-haskell` package (and its dependencies) - # - the CLI application (`lbf-plutus-to-haskell`) to compile `.lbf` - # schemas. - # - # Note: - # This is mostly duplicated code from `dev-prelude-haskell` - let - hsFlake = inputs.flake-lang.lib.${system}.haskellPlutusFlake { - src = config.packages.lbf-plutus-haskell; - - name = "dev-plutustx"; - - inherit (config.settings.haskell) index-state compiler-nix-name; - - dependencies = [ - "${config.packages.lbr-prelude-haskell-src}" - "${config.packages.lbf-prelude-haskell}" - "${config.packages.lbr-plutus-haskell-src}" - "${config.packages.lbf-plutus-haskell}" - ]; - # Note: Add `lbf-prelude` and `lbf-plutus` Haskell packages in the devShell environment. - # This *must* be the name of the autogenerated cabal package from - # `lbf-prelude-haskell` and `lbf-plutus-haskell` - devShellAdditionalPackages = ps: [ ps.lbf-prelude ps.lbf-plutus ]; - - devShellTools = config.settings.shell.tools ++ [ - # We include both the Prelude and Plutus - # frontend. Perhaps, we should _only_ include the - # Plutus frontend, but it doesn't hurt to include both. - config.packages.lbf-prelude-to-haskell - config.packages.lbf-plutus-to-haskell - ]; - - devShellHook = config.settings.shell.hook; - }; - in - hsFlake.devShell; - - dev-plutarch = - let - hsFlake = inputs.flake-lang.lib.${system}.haskellPlutusFlake { - src = config.packages.lbf-plutus-plutarch; - - name = "dev-plutarch"; - - inherit (config.settings.haskell) index-state compiler-nix-name; - - dependencies = [ - # Load Plutarch support (Prelude, Plutus) - "${config.packages.lbf-prelude-plutarch}" - "${config.packages.lbf-plutus-plutarch}" - "${config.packages.lbr-plutarch-src}" - # Load Haskell support (Prelude, Plutus) - "${config.packages.lbf-prelude-haskell}" - "${config.packages.lbf-plutus-haskell}" - "${config.packages.lbr-prelude-haskell-src}" - "${config.packages.lbr-plutus-haskell-src}" - # Plutarch itself - "${inputs.plutarch}" - "${inputs.plutarch}/plutarch-extra" - ]; - devShellAdditionalPackages = ps: [ - ps.lbf-prelude-plutarch - ps.lbf-plutus-plutarch - ps.lbr-plutarch - ps.plutus-tx - ps.plutus-ledger-api - ]; - - devShellTools = config.settings.shell.tools ++ [ - config.packages.lbf-plutus-to-plutarch - config.packages.lbf-prelude-to-haskell - config.packages.lbf-plutus-to-haskell - ]; - - devShellHook = config.settings.shell.hook; - }; - in - hsFlake.devShell; - }; }; } diff --git a/libs/lbf-plutus/Plutus/V1.lbf b/libs/lbf-plutus/Plutus/V1.lbf index 9c557c6f..aacbfb4a 100644 --- a/libs/lbf-plutus/Plutus/V1.lbf +++ b/libs/lbf-plutus/Plutus/V1.lbf @@ -171,3 +171,38 @@ instance PlutusData (Map k v) :- PlutusData k, PlutusData v instance Eq (Map k v) :- Eq k, Eq v instance Json (Map k v) :- Json k, Json v +-- PlutusLedgerApi.V1.Contexts +opaque TxInInfo + +instance PlutusData TxInInfo +instance Eq TxInInfo +instance Json TxInInfo + +-- PlutusLedgerApi.V1.Tx +opaque TxOut + +instance PlutusData TxOut +instance Eq TxOut +instance Json TxOut + +-- PlutusLedgerApi.V1.DCert +opaque DCert +instance PlutusData DCert +instance Eq DCert +instance Json DCert + +-- PlutusLedgerApi.V1.Contexts +opaque ScriptContext +instance PlutusData ScriptContext +instance Eq ScriptContext +instance Json ScriptContext + +opaque ScriptPurpose +instance PlutusData ScriptPurpose +instance Eq ScriptPurpose +instance Json ScriptPurpose + +opaque TxInfo +instance PlutusData TxInfo +instance Eq TxInfo +instance Json TxInfo diff --git a/libs/lbf-plutus/Plutus/V1/Todo.lbf b/libs/lbf-plutus/Plutus/V1/Todo.lbf deleted file mode 100644 index 784d5a24..00000000 --- a/libs/lbf-plutus/Plutus/V1/Todo.lbf +++ /dev/null @@ -1,26 +0,0 @@ -module Plutus.V1.Todo - -import Plutus.V1 (PlutusData) -import Prelude (Eq, Json) - --- PlutusLedgerApi.V1.DCert -opaque DCert -instance PlutusData DCert -instance Eq DCert -instance Json DCert - --- PlutusLedgerApi.V1.Contexts -opaque ScriptContext -instance PlutusData ScriptContext -instance Eq ScriptContext -instance Json ScriptContext - -opaque ScriptPurpose -instance PlutusData ScriptPurpose -instance Eq ScriptPurpose -instance Json ScriptPurpose - -opaque TxInfo -instance PlutusData TxInfo -instance Eq TxInfo -instance Json TxInfo diff --git a/libs/lbf-plutus/Plutus/V2.lbf b/libs/lbf-plutus/Plutus/V2.lbf index 22ffd8ea..acc9e2c4 100644 --- a/libs/lbf-plutus/Plutus/V2.lbf +++ b/libs/lbf-plutus/Plutus/V2.lbf @@ -22,3 +22,16 @@ opaque TxOut instance PlutusData TxOut instance Eq TxOut instance Json TxOut + +-- PlutusLedgerApi.V2.Contexts +opaque TxInfo + +instance PlutusData TxInfo +instance Eq TxInfo +instance Json TxInfo + +opaque ScriptContext + +instance PlutusData ScriptContext +instance Eq ScriptContext +instance Json ScriptContext diff --git a/libs/lbf-plutus/Plutus/V2/Todo.lbf b/libs/lbf-plutus/Plutus/V2/Todo.lbf deleted file mode 100644 index 2db85414..00000000 --- a/libs/lbf-plutus/Plutus/V2/Todo.lbf +++ /dev/null @@ -1,17 +0,0 @@ -module Plutus.V2.Todo - -import Prelude (Eq, Json) -import Plutus.V1 (PlutusData) - --- PlutusLedgerApi.V2.Contexts -opaque TxInfo - -instance PlutusData TxInfo -instance Eq TxInfo -instance Json TxInfo - -opaque ScriptContext - -instance PlutusData ScriptContext -instance Eq ScriptContext -instance Json ScriptContext diff --git a/runtimes/haskell/lbr-plutarch/src/LambdaBuffers/Runtime/Plutarch.hs b/runtimes/haskell/lbr-plutarch/src/LambdaBuffers/Runtime/Plutarch.hs index 6768ded9..7d2995a0 100644 --- a/runtimes/haskell/lbr-plutarch/src/LambdaBuffers/Runtime/Plutarch.hs +++ b/runtimes/haskell/lbr-plutarch/src/LambdaBuffers/Runtime/Plutarch.hs @@ -22,6 +22,7 @@ module LambdaBuffers.Runtime.Plutarch ( import Data.Functor.Const (Const) import GHC.Generics (Generic) import GHC.TypeLits qualified as GHC +import LambdaBuffers.Runtime.Plutarch.LamVal (pfromPlutusDataPTryFrom) import LambdaBuffers.Runtime.Plutarch.LamVal qualified as LamVal import Plutarch ( PType, @@ -40,7 +41,7 @@ import Plutarch.Api.V1 qualified import Plutarch.Api.V1.AssocMap qualified as AssocMap import Plutarch.Api.V1.Scripts (PScriptHash) import Plutarch.Api.V1.Scripts qualified -import Plutarch.Api.V2 qualified (POutputDatum (PNoOutputDatum, POutputDatum, POutputDatumHash), PTxInInfo (PTxInInfo), PTxOut (PTxOut)) +import Plutarch.Api.V2 qualified (POutputDatum (PNoOutputDatum, POutputDatum, POutputDatumHash), PScriptContext (PScriptContext), PTxInInfo (PTxInInfo), PTxInfo (PTxInfo), PTxOut (PTxOut)) import Plutarch.Builtin ( PBuiltinList (PCons, PNil), PData, @@ -48,6 +49,7 @@ import Plutarch.Builtin ( pasList, pdata, ) +import Plutarch.Builtin qualified as Plutarch import Plutarch.DataRepr.Internal () import Plutarch.Internal.PlutusType (PlutusType (pcon', pmatch')) import Plutarch.Prelude (PAsData, PBool (PFalse, PTrue), PByteString, PEq ((#==)), PInteger, PListLike, PTryFrom, pdcons, pdnil, pfromData, pif, ptryFrom) @@ -333,7 +335,7 @@ instance PTryFrom PData (PAsData a) => PTryFrom PData (PAsData (Plutarch.Api.V1. PNil -> perror PCons h' t' -> pmatch t' \case PNil -> pcon $ Plutarch.Api.V1.PInterval (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # (pdcons # (LamVal.pfromPlutusDataPTryFrom # h') # pdnil)) - _ -> perror + _other -> perror ) perror ) @@ -362,7 +364,7 @@ instance PTryFrom PData (PAsData a) => PTryFrom PData (PAsData (Plutarch.Api.V1. PNil -> perror PCons h' t' -> pmatch t' \case PNil -> pcon $ Plutarch.Api.V1.PLowerBound (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # (pdcons # (LamVal.pfromPlutusDataPTryFrom # h') # pdnil)) - _ -> perror + _other -> perror ) perror ) @@ -391,7 +393,7 @@ instance PTryFrom PData (PAsData a) => PTryFrom PData (PAsData (Plutarch.Api.V1. PNil -> perror PCons h' t' -> pmatch t' \case PNil -> pcon $ Plutarch.Api.V1.PUpperBound (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # (pdcons # (LamVal.pfromPlutusDataPTryFrom # h') # pdnil)) - _ -> perror + _other -> perror ) perror ) @@ -416,7 +418,7 @@ instance PTryFrom PData (PAsData a) => PTryFrom PData (PAsData (Plutarch.Api.V1. (ix #== 0) ( pmatch args \case PNil -> pcon $ Plutarch.Api.V1.PNegInf pdnil - _ -> perror + _other -> perror ) ( pif (ix #== 1) @@ -424,13 +426,13 @@ instance PTryFrom PData (PAsData a) => PTryFrom PData (PAsData (Plutarch.Api.V1. PNil -> perror PCons h t -> pmatch t \case PNil -> pcon $ Plutarch.Api.V1.PFinite (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # pdnil) - _ -> perror + _other -> perror ) ( pif (ix #== 2) ( pmatch args \case PNil -> pcon $ Plutarch.Api.V1.PPosInf pdnil - _ -> perror + _other -> perror ) perror ) @@ -457,7 +459,7 @@ instance PTryFrom PData (PAsData Plutarch.Api.V2.POutputDatum) where (ix #== 0) ( pmatch args \case PNil -> pcon $ Plutarch.Api.V2.PNoOutputDatum pdnil - _ -> perror + _other -> perror ) ( pif (ix #== 1) @@ -465,7 +467,7 @@ instance PTryFrom PData (PAsData Plutarch.Api.V2.POutputDatum) where PNil -> perror PCons h t -> pmatch t \case PNil -> pcon $ Plutarch.Api.V2.POutputDatumHash (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # pdnil) - _ -> perror + _other -> perror ) ( pif (ix #== 2) @@ -473,7 +475,7 @@ instance PTryFrom PData (PAsData Plutarch.Api.V2.POutputDatum) where PNil -> perror PCons h t -> pmatch t \case PNil -> pcon $ Plutarch.Api.V2.POutputDatum (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # pdnil) - _ -> perror + _other -> perror ) perror ) @@ -519,7 +521,46 @@ instance PTryFrom PData (PAsData Plutarch.Api.V2.PTxOut) where ) ) ) - _ -> perror + _other -> perror + ) + perror + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData Plutarch.Api.V1.PTxOut) where + type PTryFromExcess PData (PAsData Plutarch.Api.V1.PTxOut) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons address t -> pmatch t \case + PNil -> perror + PCons val t1 -> pmatch t1 \case + PNil -> perror + PCons mayDatumHash t2 -> pmatch t2 \case + PNil -> + pcon $ + Plutarch.Api.V1.PTxOut + ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # address) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # val) + # ( pdcons + # (maybeToMaybe # (LamVal.pfromPlutusDataPTryFrom # mayDatumHash)) + # pdnil + ) + ) + ) + _other -> perror ) perror ) @@ -540,6 +581,81 @@ maybeToMaybe = PNothing -> pcon $ PDNothing pdnil ) +instance PTryFrom PData (PAsData Plutarch.Api.V1.PScriptContext) where + type PTryFromExcess PData (PAsData Plutarch.Api.V1.PScriptContext) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons h t -> pmatch t \case + PNil -> perror + PCons h' t' -> pmatch t' \case + PNil -> pcon $ Plutarch.Api.V1.PScriptContext (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # (pdcons # (LamVal.pfromPlutusDataPTryFrom # h') # pdnil)) + _other -> perror + ) + perror + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData Plutarch.Api.V2.PScriptContext) where + type PTryFromExcess PData (PAsData Plutarch.Api.V2.PScriptContext) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons h t -> pmatch t \case + PNil -> perror + PCons h' t' -> pmatch t' \case + PNil -> pcon $ Plutarch.Api.V2.PScriptContext (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # (pdcons # (LamVal.pfromPlutusDataPTryFrom # h') # pdnil)) + _other -> perror + ) + perror + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData Plutarch.Api.V1.PTxInInfo) where + type PTryFromExcess PData (PAsData Plutarch.Api.V1.PTxInInfo) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons h t -> pmatch t \case + PNil -> perror + PCons h' t' -> pmatch t' \case + PNil -> pcon $ Plutarch.Api.V1.PTxInInfo (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # (pdcons # (LamVal.pfromPlutusDataPTryFrom # h') # pdnil)) + _other -> perror + ) + perror + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + instance PTryFrom PData (PAsData Plutarch.Api.V2.PTxInInfo) where type PTryFromExcess PData (PAsData Plutarch.Api.V2.PTxInInfo) = Const () ptryFrom' pd f = @@ -554,7 +670,391 @@ instance PTryFrom PData (PAsData Plutarch.Api.V2.PTxInInfo) where PNil -> perror PCons h' t' -> pmatch t' \case PNil -> pcon $ Plutarch.Api.V2.PTxInInfo (pdcons # (LamVal.pfromPlutusDataPTryFrom # h) # (pdcons # (LamVal.pfromPlutusDataPTryFrom # h') # pdnil)) - _ -> perror + _other -> perror + ) + perror + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V2.PTxInInfo)) where + type PTryFromExcess PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V2.PTxInInfo)) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + (const $ const perror) + ( \xs -> pdata $ Pl.pmap # plam (\xpd -> pfromData $ pfromPlutusDataPTryFrom @Plutarch.Api.V2.PTxInInfo # xpd) # xs + ) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V2.PTxOut)) where + type PTryFromExcess PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V2.PTxOut)) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + (const $ const perror) + ( \xs -> pdata $ Pl.pmap # plam (\xpd -> pfromData $ pfromPlutusDataPTryFrom @Plutarch.Api.V2.PTxOut # xpd) # xs + ) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V1.PTxInInfo)) where + type PTryFromExcess PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V1.PTxInInfo)) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + (const $ const perror) + ( \xs -> pdata $ Pl.pmap # plam (\xpd -> pfromData $ pfromPlutusDataPTryFrom @Plutarch.Api.V1.PTxInInfo # xpd) # xs + ) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V1.PTxOut)) where + type PTryFromExcess PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V1.PTxOut)) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + (const $ const perror) + ( \xs -> pdata $ Pl.pmap # plam (\xpd -> pfromData $ pfromPlutusDataPTryFrom @Plutarch.Api.V1.PTxOut # xpd) # xs + ) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData Plutarch.Api.V1.PDCert) where + type PTryFromExcess PData (PAsData Plutarch.Api.V1.PDCert) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons stakingCred args2 -> pmatch args2 \case + PNil -> pcon $ Plutarch.Api.V1.PDCertDelegRegKey (pdcons # (LamVal.pfromPlutusDataPTryFrom # stakingCred) # pdnil) + _other -> perror + ) + ( pif + (ix #== 1) + ( pmatch args \case + PNil -> perror + PCons stakingCred args2 -> pmatch args2 \case + PNil -> pcon $ Plutarch.Api.V1.PDCertDelegDeRegKey (pdcons # (LamVal.pfromPlutusDataPTryFrom # stakingCred) # pdnil) + _other -> perror + ) + ( pif + (ix #== 2) + ( pmatch args \case + PNil -> perror + PCons stakingCred args2 -> pmatch args2 \case + PNil -> perror + PCons pkh args3 -> pmatch args3 \case + PNil -> + pcon $ + Plutarch.Api.V1.PDCertDelegDelegate + ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # stakingCred) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # pkh) + # pdnil + ) + ) + _other -> perror + ) + ( pif + (ix #== 3) + ( pmatch args \case + PNil -> perror + PCons pkh1 args2 -> pmatch args2 \case + PNil -> perror + PCons pkh2 args3 -> pmatch args3 \case + PNil -> + pcon $ + Plutarch.Api.V1.PDCertPoolRegister + ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # pkh1) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # pkh2) + # pdnil + ) + ) + _other -> perror + ) + ( pif + (ix #== 4) + ( pmatch args \case + PNil -> perror + PCons pkh args2 -> pmatch args2 \case + PNil -> perror + PCons int args3 -> pmatch args3 \case + PNil -> + pcon $ + Plutarch.Api.V1.PDCertPoolRetire + ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # pkh) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # int) + # pdnil + ) + ) + _other -> perror + ) + ( pif + (ix #== 5) + ( pmatch args \case + PNil -> pcon $ Plutarch.Api.V1.PDCertGenesis pdnil + _other -> perror + ) + ( pif + (ix #== 6) + ( pmatch args \case + PNil -> pcon $ Plutarch.Api.V1.PDCertMir pdnil + _other -> perror + ) + perror + ) + ) + ) + ) + ) + ) + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData Plutarch.Api.V1.PScriptPurpose) where + type PTryFromExcess PData (PAsData Plutarch.Api.V1.PScriptPurpose) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons symbol args2 -> pmatch args2 \case + PNil -> pcon $ Plutarch.Api.V1.PMinting (pdcons # (LamVal.pfromPlutusDataPTryFrom # symbol) # pdnil) + _other -> perror + ) + ( pif + (ix #== 1) + ( pmatch args \case + PNil -> perror + PCons txOutRef args2 -> pmatch args2 \case + PNil -> pcon $ Plutarch.Api.V1.PSpending (pdcons # (LamVal.pfromPlutusDataPTryFrom # txOutRef) # pdnil) + _other -> perror + ) + ( pif + (ix #== 2) + ( pmatch args \case + PNil -> perror + PCons stakingCred args2 -> pmatch args2 \case + PNil -> pcon $ Plutarch.Api.V1.PRewarding (pdcons # (LamVal.pfromPlutusDataPTryFrom # stakingCred) # pdnil) + _other -> perror + ) + ( pif + (ix #== 3) + ( pmatch args \case + PNil -> perror + PCons dcert args2 -> pmatch args2 \case + PNil -> pcon $ Plutarch.Api.V1.PCertifying (pdcons # (LamVal.pfromPlutusDataPTryFrom # dcert) # pdnil) + _other -> perror + ) + perror + ) + ) + ) + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V1.PDCert)) where + type PTryFromExcess PData (PAsData (Plutarch.PBuiltinList Plutarch.Api.V1.PDCert)) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + (const $ const perror) + ( \xs -> pdata $ Pl.pmap # plam (\xpd -> pfromData $ pfromPlutusDataPTryFrom @Plutarch.Api.V1.PDCert # xpd) # xs + ) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData Plutarch.Api.V2.PTxInfo) where + type PTryFromExcess PData (PAsData Plutarch.Api.V2.PTxInfo) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons inputs t -> pmatch t \case + PNil -> perror + PCons references t1 -> pmatch t1 \case + PNil -> perror + PCons outputs t2 -> pmatch t2 \case + PNil -> perror + PCons fee t3 -> pmatch t3 \case + PNil -> perror + PCons mint t4 -> pmatch t4 \case + PNil -> perror + PCons dcert t5 -> pmatch t5 \case + PNil -> perror + PCons wdrl t6 -> pmatch t6 \case + PNil -> perror + PCons range t7 -> pmatch t7 \case + PNil -> perror + PCons sigs t8 -> pmatch t8 \case + PNil -> perror + PCons redeemers t9 -> pmatch t9 \case + PNil -> perror + PCons datums t10 -> pmatch t10 \case + PNil -> perror + PCons txId t11 -> pmatch t11 \case + PNil -> + pcon $ + Plutarch.Api.V2.PTxInfo + ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # inputs) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # references) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # outputs) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # fee) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # mint) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # dcert) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # wdrl) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # range) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # sigs) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # redeemers) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # datums) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # txId) + # pdnil + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + _other -> perror + ) + perror + ) + (const perror) + (const perror) + (const perror) + pd + , () + ) + +instance PTryFrom PData (PAsData Plutarch.Api.V1.PTxInfo) where + type PTryFromExcess PData (PAsData Plutarch.Api.V1.PTxInfo) = Const () + ptryFrom' pd f = + f + ( LamVal.casePlutusData + ( \ix args -> + pif + (ix #== 0) + ( pmatch args \case + PNil -> perror + PCons inputs t -> pmatch t \case + PNil -> perror + PCons outputs t1 -> pmatch t1 \case + PNil -> perror + PCons fee t2 -> pmatch t2 \case + PNil -> perror + PCons mint t3 -> pmatch t3 \case + PNil -> perror + PCons dcert t4 -> pmatch t4 \case + PNil -> perror + PCons wdrl t5 -> pmatch t5 \case + PNil -> perror + PCons range t6 -> pmatch t6 \case + PNil -> perror + PCons sigs t7 -> pmatch t7 \case + PNil -> perror + PCons datums t8 -> pmatch t8 \case + PNil -> perror + PCons txId t9 -> pmatch t9 \case + PNil -> + pcon $ + Plutarch.Api.V1.PTxInfo + ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # inputs) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # outputs) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # fee) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # mint) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # dcert) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # wdrl) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # range) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # sigs) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # datums) + # ( pdcons + # (LamVal.pfromPlutusDataPTryFrom # txId) + # pdnil + ) + ) + ) + ) + ) + ) + ) + ) + ) + ) + _other -> perror ) perror ) diff --git a/runtimes/haskell/lbr-plutus/lbr-plutus.cabal b/runtimes/haskell/lbr-plutus/lbr-plutus.cabal index ff748568..acb14154 100644 --- a/runtimes/haskell/lbr-plutus/lbr-plutus.cabal +++ b/runtimes/haskell/lbr-plutus/lbr-plutus.cabal @@ -98,7 +98,6 @@ library exposed-modules: LambdaBuffers.Runtime.Plutus LambdaBuffers.Runtime.Plutus.Json - LambdaBuffers.Runtime.Plutus.LamVal LambdaBuffers.Runtime.Plutus.PlutusData Test.LambdaBuffers.Plutus.Generators.Correct diff --git a/runtimes/haskell/lbr-plutus/src/LambdaBuffers/Runtime/Plutus/LamVal.hs b/runtimes/haskell/lbr-plutus/src/LambdaBuffers/Runtime/Plutus/LamVal.hs deleted file mode 100644 index feb871b8..00000000 --- a/runtimes/haskell/lbr-plutus/src/LambdaBuffers/Runtime/Plutus/LamVal.hs +++ /dev/null @@ -1,20 +0,0 @@ -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} -{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} -{-# OPTIONS_GHC -fno-specialise #-} -{-# OPTIONS_GHC -fno-strictness #-} -{-# OPTIONS_GHC -fobject-code #-} - -module LambdaBuffers.Runtime.Plutus.LamVal (caseIntE) where - -import PlutusTx.Eq (Eq ((==))) -import PlutusTx.Integer (Integer) - -{- | CaseIntE :: ValueE -> [(ValueE, ValueE)] -> (ValueE -> ValueE) -> ValueE - HACK(bladyjoker): This is stinky as base LamVal CaseIntE should be agnostic of PlutusTx ofc. However, PlutusTx is also like its own language and should be treated like Plutarch it seems, as an eDSL with its own setup. PlutusTx doesn't handle case expressions on Integer (see https://cardano.stackexchange.com/questions/8325/how-to-do-on-chain-integer-pattern-matching) as it tries the `base.Prelude` Integer's Eq instance rather than the PlutusTx one. --} -{-# INLINEABLE caseIntE #-} -caseIntE :: Integer -> [(Integer, a)] -> (Integer -> a) -> a -caseIntE i [] other = other i -caseIntE i ((i', val) : cases) other = if i == i' then val else caseIntE i cases other diff --git a/runtimes/haskell/lbr-plutustx/.envrc b/runtimes/haskell/lbr-plutustx/.envrc new file mode 100644 index 00000000..c62f94c2 --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/.envrc @@ -0,0 +1 @@ +use flake ../../..#dev-lbr-plutustx diff --git a/runtimes/haskell/lbr-plutustx/build.nix b/runtimes/haskell/lbr-plutustx/build.nix new file mode 100644 index 00000000..3d14e548 --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/build.nix @@ -0,0 +1,36 @@ +{ inputs, ... }: +{ + perSystem = { config, pkgs, system, ... }: + let + # TODO: plutusTxFlake + hsFlake = inputs.flake-lang.lib.${system}.haskellPlutusFlake { + src = ./.; + + name = "lbr-plutustx"; + + inherit (config.settings.haskell) index-state compiler-nix-name; + + devShellTools = config.settings.shell.tools; + devShellHook = config.settings.shell.hook; + }; + + in + { + devShells.dev-lbr-plutustx = hsFlake.devShell; + + packages = { + + lbr-plutustx-src = pkgs.stdenv.mkDerivation { + name = "lbr-plutustx-src"; + src = ./.; + phases = "installPhase"; + installPhase = "ln -s $src $out"; + }; + + lbr-plutustx-lib = hsFlake.packages."lbr-plutustx:lib:lbr-plutustx"; + }; + + inherit (hsFlake) checks; + + }; +} diff --git a/runtimes/haskell/lbr-plutustx/cabal.project b/runtimes/haskell/lbr-plutustx/cabal.project new file mode 100644 index 00000000..6b0c1f6a --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/cabal.project @@ -0,0 +1,3 @@ +packages: ./. + +tests: true \ No newline at end of file diff --git a/runtimes/haskell/lbr-plutustx/hie.yaml b/runtimes/haskell/lbr-plutustx/hie.yaml new file mode 100644 index 00000000..04cd2439 --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/hie.yaml @@ -0,0 +1,2 @@ +cradle: + cabal: diff --git a/runtimes/haskell/lbr-plutustx/lbr-plutustx.cabal b/runtimes/haskell/lbr-plutustx/lbr-plutustx.cabal new file mode 100644 index 00000000..2d89ea8b --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/lbr-plutustx.cabal @@ -0,0 +1,97 @@ +cabal-version: 3.0 +name: lbr-plutustx +version: 0.1.0.0 +synopsis: + Lambda Buffers Runtime library for the `lbf-plutus` package and the PlutusTx backend + +author: Drazen Popovic +maintainer: bladyjoker@gmail.com + +flag dev + description: Enable non-strict compilation for development + manual: True + +common common-language + ghc-options: + -Wall -Wcompat -fprint-explicit-foralls -fprint-explicit-kinds + -fwarn-missing-import-lists -Weverything -Wno-unsafe + -Wno-missing-safe-haskell-mode -Wno-implicit-prelude + -Wno-missing-kind-signatures -Wno-all-missed-specializations + + if !flag(dev) + ghc-options: -Werror + + default-extensions: + BangPatterns + BinaryLiterals + ConstrainedClassMethods + ConstraintKinds + DataKinds + DeriveAnyClass + DeriveDataTypeable + DeriveFoldable + DeriveFunctor + DeriveGeneric + DeriveLift + DeriveTraversable + DerivingStrategies + DerivingVia + DoAndIfThenElse + DuplicateRecordFields + EmptyCase + EmptyDataDecls + EmptyDataDeriving + ExistentialQuantification + ExplicitForAll + ExplicitNamespaces + FlexibleContexts + FlexibleInstances + ForeignFunctionInterface + GADTSyntax + GeneralizedNewtypeDeriving + HexFloatLiterals + ImportQualifiedPost + InstanceSigs + KindSignatures + LambdaCase + MonomorphismRestriction + MultiParamTypeClasses + NamedFieldPuns + NamedWildCards + NoStarIsType + NumericUnderscores + OverloadedLabels + OverloadedStrings + PartialTypeSignatures + PatternGuards + PolyKinds + PostfixOperators + RankNTypes + RecordWildCards + RelaxedPolyRec + ScopedTypeVariables + StandaloneDeriving + StandaloneKindSignatures + TemplateHaskell + TraditionalRecordSyntax + TupleSections + TypeApplications + TypeFamilies + TypeOperators + TypeSynonymInstances + ViewPatterns + + default-language: Haskell2010 + +library + import: common-language + build-depends: + , base >=4.18 + , plutus-tx + + hs-source-dirs: src + exposed-modules: + LambdaBuffers.Runtime.PlutusTx + LambdaBuffers.Runtime.PlutusTx.LamVal + LambdaBuffers.Runtime.PlutusTx.List + LambdaBuffers.Runtime.PlutusTx.NotImplemented diff --git a/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx.hs b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx.hs new file mode 100644 index 00000000..0b411e7b --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx.hs @@ -0,0 +1,14 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# OPTIONS_GHC -Wno-missing-import-lists #-} +{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} +{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} +{-# OPTIONS_GHC -fno-specialise #-} +{-# OPTIONS_GHC -fno-strictness #-} +{-# OPTIONS_GHC -fobject-code #-} + +module LambdaBuffers.Runtime.PlutusTx (module LamVal, module List, module NotImplemented) where + +import LambdaBuffers.Runtime.PlutusTx.LamVal as LamVal +import LambdaBuffers.Runtime.PlutusTx.LamVal as NotImplemented +import LambdaBuffers.Runtime.PlutusTx.List as List diff --git a/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/LamVal.hs b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/LamVal.hs new file mode 100644 index 00000000..23640723 --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/LamVal.hs @@ -0,0 +1,41 @@ +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} +{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} +{-# OPTIONS_GHC -fno-specialise #-} +{-# OPTIONS_GHC -fno-strictness #-} +{-# OPTIONS_GHC -fobject-code #-} + +module LambdaBuffers.Runtime.PlutusTx.LamVal (caseIntE, casePlutusData) where + +import PlutusTx (BuiltinData) +import PlutusTx.Base (const) +import PlutusTx.Builtins (matchData) +import PlutusTx.Eq (Eq ((==))) +import PlutusTx.Integer (Integer) + +-- | LamVal `casePlutusData` +{-# INLINEABLE casePlutusData #-} +casePlutusData :: + (PlutusTx.Integer.Integer -> [BuiltinData] -> r) -> + ([BuiltinData] -> r) -> + (PlutusTx.Integer.Integer -> r) -> + (BuiltinData -> r) -> + BuiltinData -> + r +casePlutusData ctorCase listCase intCase otherCase pd = + matchData + pd + ctorCase + (const (otherCase pd)) + listCase + intCase + (const (otherCase pd)) + +{- | CaseIntE :: ValueE -> [(ValueE, ValueE)] -> (ValueE -> ValueE) -> ValueE +NOTE(bladyjoker): PlutusTx doesn't handle case expressions on Integer (see https://cardano.stackexchange.com/questions/8325/how-to-do-on-chain-integer-pattern-matching) as it tries the `base.Prelude` Integer's Eq instance rather than the PlutusTx one. +-} +{-# INLINEABLE caseIntE #-} +caseIntE :: Integer -> [(Integer, a)] -> (Integer -> a) -> a +caseIntE i [] other = other i +caseIntE i ((i', val) : cases) other = if i == i' then val else caseIntE i cases other diff --git a/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/List.hs b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/List.hs new file mode 100644 index 00000000..65471cd2 --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/List.hs @@ -0,0 +1,3 @@ +module LambdaBuffers.Runtime.PlutusTx.List (List) where + +type List a = [a] diff --git a/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/NotImplemented.hs b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/NotImplemented.hs new file mode 100644 index 00000000..7f43bceb --- /dev/null +++ b/runtimes/haskell/lbr-plutustx/src/LambdaBuffers/Runtime/PlutusTx/NotImplemented.hs @@ -0,0 +1,16 @@ +module LambdaBuffers.Runtime.PlutusTx.NotImplemented (Set) where + +import GHC.TypeError qualified as GHC +import PlutusTx qualified +import PlutusTx.Eq qualified as PlutusTx + +data Set a + +instance GHC.TypeError ('GHC.Text "LambdaBuffers Prelude.Set not implemented for PlutusTx") => PlutusTx.FromData (Set a) where + fromBuiltinData _ = error "unreachable" + +instance GHC.TypeError ('GHC.Text "LambdaBuffers Prelude.Set not implemented for PlutusTx") => PlutusTx.ToData (Set a) where + toBuiltinData _ = error "unreachable" + +instance GHC.TypeError ('GHC.Text "LambdaBuffers Prelude.Set not implemented for PlutusTx") => PlutusTx.Eq (Set a) where + (==) _l _r = error "unreachable" diff --git a/runtimes/haskell/lbr-prelude/lbr-prelude.cabal b/runtimes/haskell/lbr-prelude/lbr-prelude.cabal index 8af885b4..58f631e8 100644 --- a/runtimes/haskell/lbr-prelude/lbr-prelude.cabal +++ b/runtimes/haskell/lbr-prelude/lbr-prelude.cabal @@ -101,7 +101,6 @@ library LambdaBuffers.Runtime.Prelude LambdaBuffers.Runtime.Prelude.Generators.Correct LambdaBuffers.Runtime.Prelude.Json - LambdaBuffers.Runtime.Prelude.LamVal test-suite tests import: common-language diff --git a/runtimes/haskell/lbr-prelude/src/LambdaBuffers/Runtime/Prelude/LamVal.hs b/runtimes/haskell/lbr-prelude/src/LambdaBuffers/Runtime/Prelude/LamVal.hs deleted file mode 100644 index 9148caf2..00000000 --- a/runtimes/haskell/lbr-prelude/src/LambdaBuffers/Runtime/Prelude/LamVal.hs +++ /dev/null @@ -1,8 +0,0 @@ -module LambdaBuffers.Runtime.Prelude.LamVal (caseIntE) where - -{- | CaseIntE :: ValueE -> [(ValueE, ValueE)] -> (ValueE -> ValueE) -> ValueE - HACK(bladyjoker): This one is not used, but the LambdaBuffers.Runtime.Plutus.LamVal one. We're just lucky that PlutusData encodings only use this functionality. --} -caseIntE :: Integer -> [(Integer, a)] -> (Integer -> a) -> a -caseIntE i [] other = other i -caseIntE i ((i', val) : cases) other = if i == i' then val else caseIntE i cases other diff --git a/runtimes/purescript/lbr-plutus/src/LambdaBuffers/Runtime/Plutus.purs b/runtimes/purescript/lbr-plutus/src/LambdaBuffers/Runtime/Plutus.purs index 7fe7ede5..6a86324a 100644 --- a/runtimes/purescript/lbr-plutus/src/LambdaBuffers/Runtime/Plutus.purs +++ b/runtimes/purescript/lbr-plutus/src/LambdaBuffers/Runtime/Plutus.purs @@ -3,6 +3,7 @@ module LambdaBuffers.Runtime.Plutus , TxInInfo(..) , casePlutusData , pdConstr + , NotImplemented ) where import Ctl.Internal.FromData (class FromData, fromData) @@ -44,6 +45,20 @@ casePlutusData ctorCase listCase intCase otherCase pd = case pd of Integer bi -> intCase bi other -> otherCase other +data NotImplemented + +instance eqNotImplemented :: Eq NotImplemented where + eq _ _ = false + +instance showNotImplement :: Show NotImplemented where + show _ = "not implemented" + +instance toDataNotImplemented :: ToData NotImplemented where + toData _ = List [] + +instance fromDataNotImplement :: FromData NotImplemented where + fromData _ = Nothing + -- | https://github.com/input-output-hk/plutus/blob/0f723bef8842d805f14e763fe15590cf3da622f7/plutus-ledger-api/src/PlutusLedgerApi/V2/Contexts.hs#L59 newtype TxInInfo = TxInInfo diff --git a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Instances.ts b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Instances.ts index f84d8eea..a90fe53c 100644 --- a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Instances.ts +++ b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Instances.ts @@ -635,3 +635,144 @@ declare module "../PlutusData.js" { } } PlutusData.IsPlutusData[Symbols.Map] = PlutusLedgerApiAssocMap.isPlutusDataMap; + +// DCert +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.DCert]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.DCert]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.DCert] = PlutusLedgerApiV1.eqDCert; +LbrPrelude.Json[Symbols.DCert] = PlutusLedgerApiV1.jsonDCert; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.DCert]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV1.DCert + >; + } +} +PlutusData.IsPlutusData[Symbols.DCert] = PlutusLedgerApiV1.isPlutusDataDCert; + +// TxOut +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.TxOut]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.TxOut]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.TxOut] = PlutusLedgerApiV1.eqTxOut; +LbrPrelude.Json[Symbols.TxOut] = PlutusLedgerApiV1.jsonTxOut; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.TxOut]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV1.TxOut + >; + } +} +PlutusData.IsPlutusData[Symbols.TxOut] = PlutusLedgerApiV1.isPlutusDataTxOut; + +// TxInInfo +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.TxInInfo]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.TxInInfo]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.TxInInfo] = PlutusLedgerApiV1.eqTxInInfo; +LbrPrelude.Json[Symbols.TxInInfo] = PlutusLedgerApiV1.jsonTxInInfo; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.TxInInfo]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV1.TxInInfo + >; + } +} +PlutusData.IsPlutusData[Symbols.TxInInfo] = + PlutusLedgerApiV1.isPlutusDataTxInInfo; + +// TxInfo +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.TxInfo]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.TxInfo]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.TxInfo] = PlutusLedgerApiV1.eqTxInfo; +LbrPrelude.Json[Symbols.TxInfo] = PlutusLedgerApiV1.jsonTxInfo; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.TxInfo]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV1.TxInfo + >; + } +} +PlutusData.IsPlutusData[Symbols.TxInfo] = PlutusLedgerApiV1.isPlutusDataTxInfo; + +// ScriptPurpose +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.ScriptPurpose]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.ScriptPurpose]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.ScriptPurpose] = PlutusLedgerApiV1.eqScriptPurpose; +LbrPrelude.Json[Symbols.ScriptPurpose] = PlutusLedgerApiV1.jsonScriptPurpose; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.ScriptPurpose]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV1.ScriptPurpose + >; + } +} +PlutusData.IsPlutusData[Symbols.ScriptPurpose] = + PlutusLedgerApiV1.isPlutusDataScriptPurpose; + +// ScriptContext +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.ScriptContext]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.ScriptContext]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.ScriptContext] = PlutusLedgerApiV1.eqScriptContext; +LbrPrelude.Json[Symbols.ScriptContext] = PlutusLedgerApiV1.jsonScriptContext; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.ScriptContext]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV1.ScriptContext + >; + } +} +PlutusData.IsPlutusData[Symbols.ScriptContext] = + PlutusLedgerApiV1.isPlutusDataScriptContext; diff --git a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Symbols.ts b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Symbols.ts index 58726f2f..adb61103 100644 --- a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Symbols.ts +++ b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V1/Symbols.ts @@ -27,6 +27,12 @@ export const AssetClass: unique symbol = Symbol("AssetClass"); export const Value: unique symbol = Symbol("Value"); export const PlutusData: unique symbol = Symbol("PlutusData"); export const Map: unique symbol = Symbol("Map"); +export const DCert: unique symbol = Symbol("DCert"); +export const TxOut: unique symbol = Symbol("TxOut"); +export const TxInInfo: unique symbol = Symbol("TxInInfo"); +export const TxInfo: unique symbol = Symbol("TxInfo"); +export const ScriptPurpose: unique symbol = Symbol("ScriptPurpose"); +export const ScriptContext: unique symbol = Symbol("ScriptContext"); export type Address = PlutusLedgerApiV1.Address; export type LedgerBytes = PlutusLedgerApiV1.LedgerBytes; @@ -53,3 +59,10 @@ export type AssetClass = PlutusLedgerApiV1.AssetClass; export type Value = PlutusLedgerApiV1.Value; export type PlutusData = PlutusLedgerApiPlutusData.PlutusData; export type Map = PlutusLedgerApiAssocMap.Map; + +export type DCert = PlutusLedgerApiV1.DCert; +export type TxOut = PlutusLedgerApiV1.TxOut; +export type TxInInfo = PlutusLedgerApiV1.TxInInfo; +export type TxInfo = PlutusLedgerApiV1.TxInfo; +export type ScriptPurpose = PlutusLedgerApiV1.ScriptPurpose; +export type ScriptContext = PlutusLedgerApiV1.ScriptContext; diff --git a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Instances.ts b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Instances.ts index 62b02512..0da5411e 100644 --- a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Instances.ts +++ b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Instances.ts @@ -75,3 +75,50 @@ declare module "../PlutusData.js" { } } PlutusData.IsPlutusData[Symbols.TxOut] = PlutusLedgerApiV2.isPlutusDataTxOut; + +// TxInfo +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.TxInfo]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.TxInfo]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.TxInfo] = PlutusLedgerApiV2.eqTxInfo; +LbrPrelude.Json[Symbols.TxInfo] = PlutusLedgerApiV2.jsonTxInfo; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.TxInfo]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV2.TxInfo + >; + } +} +PlutusData.IsPlutusData[Symbols.TxInfo] = PlutusLedgerApiV2.isPlutusDataTxInfo; + +// ScriptContext +declare module "lbr-prelude" { + export interface EqInstances { + [Symbols.ScriptContext]: Prelude.Eq; + } + + export interface JsonInstances { + [Symbols.ScriptContext]: Prelude.Json; + } +} + +LbrPrelude.Eq[Symbols.ScriptContext] = PlutusLedgerApiV2.eqScriptContext; +LbrPrelude.Json[Symbols.ScriptContext] = PlutusLedgerApiV2.jsonScriptContext; + +declare module "../PlutusData.js" { + export interface IsPlutusDataInstances { + [Symbols.ScriptContext]: PlutusLedgerApiPlutusData.IsPlutusData< + PlutusLedgerApiV2.ScriptContext + >; + } +} +PlutusData.IsPlutusData[Symbols.ScriptContext] = + PlutusLedgerApiV2.isPlutusDataScriptContext; diff --git a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Symbols.ts b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Symbols.ts index 9a875aa9..0987cc7e 100644 --- a/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Symbols.ts +++ b/runtimes/typescript/lbr-plutus/src/LambdaBuffers/V2/Symbols.ts @@ -3,7 +3,11 @@ import * as PlutusLedgerApiV2 from "plutus-ledger-api/V2.js"; export const TxInInfo: unique symbol = Symbol("TxInInfo"); export const OutputDatum: unique symbol = Symbol("OutputDatum"); export const TxOut: unique symbol = Symbol("TxOut"); +export const TxInfo: unique symbol = Symbol("TxInfo"); +export const ScriptContext: unique symbol = Symbol("ScriptContext"); export type TxInInfo = PlutusLedgerApiV2.TxInInfo; export type OutputDatum = PlutusLedgerApiV2.OutputDatum; export type TxOut = PlutusLedgerApiV2.TxOut; +export type TxInfo = PlutusLedgerApiV2.TxInfo; +export type ScriptContext = PlutusLedgerApiV2.ScriptContext; diff --git a/testsuites/lbt-plutus/api/build.nix b/testsuites/lbt-plutus/api/build.nix index 35242f41..e7650ef4 100644 --- a/testsuites/lbt-plutus/api/build.nix +++ b/testsuites/lbt-plutus/api/build.nix @@ -20,6 +20,12 @@ _: { files = [ "Foo.lbf" "Foo/Bar.lbf" "Days.lbf" ]; }; + lbf-plutus-golden-api-plutustx = config.lbf-nix.lbfPlutusTx { + name = "lbf-plutus-plutustx-golden-api"; + src = ./.; + files = [ "Foo.lbf" "Foo/Bar.lbf" "Days.lbf" ]; + }; + lbf-plutus-golden-api-rust = config.lbf-nix.lbfPlutusRust { name = "lbf-plutus-rust-golden-api"; src = ./.; diff --git a/testsuites/lbt-plutus/lbt-plutus-haskell/lbt-plutus-haskell.cabal b/testsuites/lbt-plutus/lbt-plutus-haskell/lbt-plutus-haskell.cabal index 41c9cd48..420a0b02 100644 --- a/testsuites/lbt-plutus/lbt-plutus-haskell/lbt-plutus-haskell.cabal +++ b/testsuites/lbt-plutus/lbt-plutus-haskell/lbt-plutus-haskell.cabal @@ -135,15 +135,10 @@ test-suite tests , lbt-plutus-golden-data , lbt-plutus-haskell , plutus-tx - , plutus-tx-plugin - , prettyprinter , tasty >=1.4 - , tasty-expected-failure , tasty-hedgehog >=1.4 - , tasty-hunit other-modules: Test.LambdaBuffers.Runtime.Plutus.Generators.Correct Test.LambdaBuffers.Runtime.Plutus.Json Test.LambdaBuffers.Runtime.Plutus.PlutusData - Test.LambdaBuffers.Runtime.Plutus.PlutusTx diff --git a/testsuites/lbt-plutus/lbt-plutus-haskell/test/Test.hs b/testsuites/lbt-plutus/lbt-plutus-haskell/test/Test.hs index c8f81f26..d0b534ef 100644 --- a/testsuites/lbt-plutus/lbt-plutus-haskell/test/Test.hs +++ b/testsuites/lbt-plutus/lbt-plutus-haskell/test/Test.hs @@ -2,7 +2,6 @@ module Main (main) where import Test.LambdaBuffers.Runtime.Plutus.Json qualified as PlutusJson import Test.LambdaBuffers.Runtime.Plutus.PlutusData qualified as PlutusPd -import Test.LambdaBuffers.Runtime.Plutus.PlutusTx qualified as PlutusTx import Test.Tasty (defaultMain, testGroup) main :: IO () @@ -14,5 +13,4 @@ main = do "LambdaBuffers Plutus package tests" [ plutusDataTests , jsonTests - , PlutusTx.tests ] diff --git a/testsuites/lbt-plutus/lbt-plutus-haskell/test/Test/LambdaBuffers/Runtime/Plutus/PlutusTx.hs b/testsuites/lbt-plutus/lbt-plutus-haskell/test/Test/LambdaBuffers/Runtime/Plutus/PlutusTx.hs deleted file mode 100644 index 5c206e95..00000000 --- a/testsuites/lbt-plutus/lbt-plutus-haskell/test/Test/LambdaBuffers/Runtime/Plutus/PlutusTx.hs +++ /dev/null @@ -1,93 +0,0 @@ -{-# LANGUAGE AllowAmbiguousTypes #-} -{-# LANGUAGE ScopedTypeVariables #-} -{-# LANGUAGE TemplateHaskellQuotes #-} -{-# LANGUAGE NoImplicitPrelude #-} -{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} -{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} -{-# OPTIONS_GHC -fno-specialise #-} -{-# OPTIONS_GHC -fno-strictness #-} -{-# OPTIONS_GHC -fobject-code #-} - --- TODO(bladyjoker): This module just tries to make sure things compile and it pprints the CompiledCode which is lame. Let's rather evaluate these scripts like proper people. -module Test.LambdaBuffers.Runtime.Plutus.PlutusTx (tests) where - -import LambdaBuffers.Days (Day, FreeDay, WorkDay) -import LambdaBuffers.Foo (A, B, C, D, E, FInt, GInt) -import PlutusTx (BuiltinData, CompiledCode, FromData (fromBuiltinData), ToData (toBuiltinData), compile, getPlc) -import PlutusTx.Maybe (fromMaybe) -import PlutusTx.Plugin () -import PlutusTx.Prelude (Bool, Eq ((==)), Integer, traceError, (&&)) -import Prettyprinter (Pretty (pretty)) -import Test.Tasty (TestTree, testGroup) -import Test.Tasty.ExpectedFailure (ignoreTestBecause) -import Test.Tasty.HUnit (testCase) -import Prelude (IO, String, print, ($), (.)) - -{-# INLINEABLE fromToDataAndEq #-} -fromToDataAndEq :: forall a. (PlutusTx.Prelude.Eq a, FromData a, ToData a) => BuiltinData -> Bool -fromToDataAndEq x = - let - x' = fromMaybe (traceError "Failed parsing x from PlutusData") (fromBuiltinData @a x) - x'' = toBuiltinData @a x' - in - x' == x' && x'' == x - -integerCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -integerCompiled = $$(PlutusTx.compile [||fromToDataAndEq @Integer||]) - -boolCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -boolCompiled = $$(PlutusTx.compile [||fromToDataAndEq @Bool||]) - -dayCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -dayCompiled = $$(PlutusTx.compile [||fromToDataAndEq @Day||]) - -freeDayCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -freeDayCompiled = $$(PlutusTx.compile [||fromToDataAndEq @FreeDay||]) - -workDayCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -workDayCompiled = $$(PlutusTx.compile [||fromToDataAndEq @WorkDay||]) - -fooACompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -fooACompiled = $$(PlutusTx.compile [||fromToDataAndEq @A||]) - -fooBCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -fooBCompiled = $$(PlutusTx.compile [||fromToDataAndEq @B||]) - -fooCCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -fooCCompiled = $$(PlutusTx.compile [||fromToDataAndEq @C||]) - -fooDCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -fooDCompiled = $$(PlutusTx.compile [||fromToDataAndEq @D||]) - -fooECompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -fooECompiled = $$(PlutusTx.compile [||fromToDataAndEq @(E Integer Bool)||]) - -fooFIntCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -fooFIntCompiled = $$(PlutusTx.compile [||fromToDataAndEq @FInt||]) - -fooGIntCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -fooGIntCompiled = $$(PlutusTx.compile [||fromToDataAndEq @GInt||]) - -tests :: TestTree -tests = - testGroup - "Just trying to compile with PlutusTx" - [ testGroup - "Compiling Prelude types" - [ testCase "Prelude.Integer" (pprint integerCompiled) - , testCase "Prelude.Bool" (pprint boolCompiled) - , testCase "Days.Day" (pprint dayCompiled) - , testCase "Days.FreeDay" (pprint freeDayCompiled) - , testCase "Days.WorkDay" (pprint workDayCompiled) - , testCase "Foo.A" (pprint fooACompiled) - , testCase "Foo.B" (pprint fooBCompiled) - , testCase "Foo.C" (pprint fooCCompiled) - , testCase "Foo.D" (pprint fooDCompiled) - , testCase "Foo.E" (pprint fooECompiled) - , ignoreTestBecause "GHC Core to PLC plugin: E003:Error: Error from the PIR compiler: E003: Unsupported construct: Mutually recursive datatypes ((recursive) let binding; from [ AnnOther ])" $ testCase "Foo.FInt" (print ("Not printing" :: String)) - , ignoreTestBecause "GHC Core to PLC plugin: E003:Error: Error from the PIR compiler: E003: Unsupported construct: Mutually recursive datatypes ((recursive) let binding; from [ AnnOther ])" $ testCase "Foo.GInt" (print ("Not printing" :: String)) - ] - ] - where - pprint :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -> IO () - pprint = print . pretty . getPlc diff --git a/testsuites/lbt-plutus/lbt-plutus-plutarch/lbt-plutus-plutarch.cabal b/testsuites/lbt-plutus/lbt-plutus-plutarch/lbt-plutus-plutarch.cabal index 14a18793..b7b54e39 100644 --- a/testsuites/lbt-plutus/lbt-plutus-plutarch/lbt-plutus-plutarch.cabal +++ b/testsuites/lbt-plutus/lbt-plutus-plutarch/lbt-plutus-plutarch.cabal @@ -96,7 +96,7 @@ library , plutus-tx >=1.1 hs-source-dirs: src - exposed-modules: Test.LambdaBuffers.Plutus.Plutarch.Golden + exposed-modules: Test.LambdaBuffers.Plutarch.Golden test-suite tests import: common-language @@ -120,4 +120,4 @@ test-suite tests , tasty-expected-failure , tasty-hunit >=0.10 - other-modules: Test.LambdaBuffers.Runtime.Plutus.PlutusData + other-modules: Test.LambdaBuffers.Runtime.Plutarch.PlutusData diff --git a/testsuites/lbt-plutus/lbt-plutus-plutarch/src/Test/LambdaBuffers/Plutus/Plutarch/Golden.hs b/testsuites/lbt-plutus/lbt-plutus-plutarch/src/Test/LambdaBuffers/Plutarch/Golden.hs similarity index 93% rename from testsuites/lbt-plutus/lbt-plutus-plutarch/src/Test/LambdaBuffers/Plutus/Plutarch/Golden.hs rename to testsuites/lbt-plutus/lbt-plutus-plutarch/src/Test/LambdaBuffers/Plutarch/Golden.hs index 9d75b8f1..e9a92537 100644 --- a/testsuites/lbt-plutus/lbt-plutus-plutarch/src/Test/LambdaBuffers/Plutus/Plutarch/Golden.hs +++ b/testsuites/lbt-plutus/lbt-plutus-plutarch/src/Test/LambdaBuffers/Plutarch/Golden.hs @@ -1,7 +1,7 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# OPTIONS_GHC -Wno-type-defaults #-} -module Test.LambdaBuffers.Plutus.Plutarch.Golden (readGoldenPdJson) where +module Test.LambdaBuffers.Plutarch.Golden (readGoldenPdJson) where import Data.ByteString qualified as B import LambdaBuffers.Runtime.Plutarch () diff --git a/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test.hs b/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test.hs index 5dc9e494..82100ac2 100644 --- a/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test.hs +++ b/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test.hs @@ -1,6 +1,6 @@ module Main (main) where -import Test.LambdaBuffers.Runtime.Plutus.PlutusData qualified as PlutusData +import Test.LambdaBuffers.Runtime.Plutarch.PlutusData qualified as PlutusData import Test.Tasty (defaultMain, testGroup) main :: IO () diff --git a/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test/LambdaBuffers/Runtime/Plutus/PlutusData.hs b/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test/LambdaBuffers/Runtime/Plutarch/PlutusData.hs similarity index 78% rename from testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test/LambdaBuffers/Runtime/Plutus/PlutusData.hs rename to testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test/LambdaBuffers/Runtime/Plutarch/PlutusData.hs index d73855a3..4f3d04b9 100644 --- a/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test/LambdaBuffers/Runtime/Plutus/PlutusData.hs +++ b/testsuites/lbt-plutus/lbt-plutus-plutarch/test/Test/LambdaBuffers/Runtime/Plutarch/PlutusData.hs @@ -1,7 +1,7 @@ {-# LANGUAGE AllowAmbiguousTypes #-} {-# OPTIONS_GHC -Wno-type-defaults #-} -module Test.LambdaBuffers.Runtime.Plutus.PlutusData (tests) where +module Test.LambdaBuffers.Runtime.Plutarch.PlutusData (tests) where import LambdaBuffers.Days qualified as HlDays import LambdaBuffers.Days.Plutarch qualified as PlDays @@ -20,11 +20,11 @@ import Plutarch (Config (Config), TracingMode (DoTracingAndBinds), pcon, perror, import Plutarch qualified import Plutarch.Bool (PBool, pif, (#==)) import Plutarch.Builtin (PData) -import Plutarch.Evaluate (evalScript) +import Plutarch.Evaluate (evalScriptHuge) import Plutarch.Prelude (PAsData, PIsData, PTryFrom, pconstant) import PlutusTx (Data, ToData) import PlutusTx.IsData (FromData, toData) -import Test.LambdaBuffers.Plutus.Plutarch.Golden (readGoldenPdJson) +import Test.LambdaBuffers.Plutarch.Golden (readGoldenPdJson) import Test.Tasty (TestTree, testGroup) import Test.Tasty.ExpectedFailure (ignoreTestBecause) import Test.Tasty.HUnit (Assertion, assertFailure, testCase) @@ -33,19 +33,40 @@ tests :: TestTree tests = testGroup "Round trip tests (from goldens and back)" + [ transparentGoldens + , preludeGoldens + , plutusV1Goldens + , plutusV2Goldens + ] + +transparentGoldens :: TestTree +transparentGoldens = + testGroup + "Transparent golden types" [ forallGoldens @HlDays.Day @PlDays.Day "Days.Day" 6 , forallGoldens @HlDays.FreeDay @PlDays.FreeDay "Days.FreeDay" 1 , forallGoldens @HlDays.WorkDay @PlDays.WorkDay "Days.WorkDay" 4 , forallGoldens @HlFoo.A @PlFoo.A "Foo.A" 9 , forallGoldens @HlFoo.B @PlFoo.B "Foo.B" 9 - , forallGoldens @HlFoo.B @PlFoo.B "Foo.B" 9 + , forallGoldens @HlFoo.C @PlFoo.C "Foo.C" 9 , forallGoldens @HlFoo.D @PlFoo.D "Foo.D" 7 , ignoreTestBecause "TODO(#131): Plutarch codegen: Recursive data type support" $ forallGoldens @HlFoo.FInt @PlFoo.FInt "Foo.FInt" 1 , ignoreTestBecause "TODO(#131): Plutarch codegen: Recursive data type support" $ forallGoldens @HlFoo.GInt @PlFoo.GInt "Foo.GInt" 1 - , forallGoldens @(HlPrelude.Maybe HlPrelude.Bool) @(PlPrelude.Maybe PlPrelude.Bool) "Prelude.Maybe" 2 + ] + +preludeGoldens :: TestTree +preludeGoldens = + testGroup + "LB Prelude golden types" + [ forallGoldens @(HlPrelude.Maybe HlPrelude.Bool) @(PlPrelude.Maybe PlPrelude.Bool) "Prelude.Maybe" 2 , forallGoldens @(HlPrelude.Either HlPrelude.Bool HlPrelude.Bool) @(PlPrelude.Either PlPrelude.Bool PlPrelude.Bool) "Prelude.Either" 2 , forallGoldens @(HlPrelude.List HlPrelude.Bool) @(PlPrelude.List PlPrelude.Bool) "Prelude.List" 3 - , forallGoldens @HlPlutus.Address @PlPlutus.Address "PlutusV1.Address" 7 + ] +plutusV1Goldens :: TestTree +plutusV1Goldens = + testGroup + "LB Plutus.V1. golden types" + [ forallGoldens @HlPlutus.Address @PlPlutus.Address "PlutusV1.Address" 7 , forallGoldens @HlPlutus.AssetClass @PlPlutus.AssetClass "PlutusV1.AssetClass" 3 , forallGoldens @HlPlutus.Bytes @PlPlutus.Bytes "PlutusV1.Bytes" 2 , forallGoldens @HlPlutus.Credential @PlPlutus.Credential "PlutusV1.Credential" 1 @@ -68,17 +89,31 @@ tests = , forallGoldens @HlPlutus.TxOutRef @PlPlutus.TxOutRef "PlutusV1.TxOutRef" 0 , forallGoldens @(HlPlutus.UpperBound HlPlutus.POSIXTime) @(PlPlutus.UpperBound PlPlutus.POSIXTime) "PlutusV1.UpperBound" 5 , forallGoldens @HlPlutus.Value @PlPlutus.Value "PlutusV1.Value" 2 - , forallGoldens @HlPlutusV2.OutputDatum @PlPlutusV2.OutputDatum "PlutusV2.OutputDatum" 2 + , forallGoldens @HlPlutus.DCert @PlPlutus.DCert "PlutusV1.DCert" 9 + , forallGoldens @HlPlutus.TxOut @PlPlutus.TxOut "PlutusV1.TxOut" 9 + , forallGoldens @HlPlutus.TxInInfo @PlPlutus.TxInInfo "PlutusV1.TxInInfo" 9 + , forallGoldens @HlPlutus.ScriptPurpose @PlPlutus.ScriptPurpose "PlutusV1.ScriptPurpose" 9 + , forallGoldens @HlPlutus.TxInfo @PlPlutus.TxInfo "PlutusV1.TxInfo" 9 + , forallGoldens @HlPlutus.ScriptContext @PlPlutus.ScriptContext "PlutusV1.ScriptContext" 9 + ] + +plutusV2Goldens :: TestTree +plutusV2Goldens = + testGroup + "LB Plutus.V2 golden types" + [ forallGoldens @HlPlutusV2.OutputDatum @PlPlutusV2.OutputDatum "PlutusV2.OutputDatum" 2 , forallGoldens @HlPlutusV2.TxInInfo @PlPlutusV2.TxInInfo "PlutusV2.TxInInfo" 9 , forallGoldens @HlPlutusV2.TxOut @PlPlutusV2.TxOut "PlutusV2.TxOut" 9 + , forallGoldens @HlPlutusV2.TxInfo @PlPlutusV2.TxInfo "PlutusV2.TxInfo" 9 + , forallGoldens @HlPlutusV2.ScriptContext @PlPlutusV2.ScriptContext "PlutusV2.ScriptContext" 9 ] evalRoundTrip :: forall a. (PIsData a, PTryFrom PData (PAsData a)) => Data -> Assertion evalRoundTrip pd = case Plutarch.compile (Config DoTracingAndBinds) (roundTripFunction @a # pconstant pd) of Left err -> assertFailure $ show ("Error while evaluating a Plutarch Term", err) - Right script -> case evalScript script of + Right script -> case evalScriptHuge script of (Left err, _, trace) -> assertFailure $ show ("Error while evaluating a Plutarch Term", err, trace) - _ -> return () + _other -> return () roundTripFunction :: forall a s. (PIsData a, PTryFrom PData (PAsData a)) => Plutarch.Term s (PData :--> PBool) roundTripFunction = diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/.envrc b/testsuites/lbt-plutus/lbt-plutus-plutustx/.envrc new file mode 100644 index 00000000..059e5bd6 --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/.envrc @@ -0,0 +1 @@ +use flake ../../..#dev-lbt-plutus-plutustx diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/build.nix b/testsuites/lbt-plutus/lbt-plutus-plutustx/build.nix new file mode 100644 index 00000000..9c6cf4e5 --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/build.nix @@ -0,0 +1,46 @@ +{ inputs, ... }: +{ + perSystem = { config, system, ... }: + let + hsFlake = inputs.flake-lang.lib.${system}.haskellPlutusFlake { + src = ./.; + + name = "lbt-plutus-plutustx"; + + inherit (config.settings.haskell) index-state compiler-nix-name; + + dependencies = [ + # LB PlutusTx backend imports + "${config.packages.lbf-prelude-plutustx}" + "${config.packages.lbf-plutus-plutustx}" + "${config.packages.lbf-plutus-golden-api-plutustx}" + "${config.packages.lbr-plutustx-src}" + + # LB Haskell backend imports (Prelude and Plutus) + "${config.packages.lbr-prelude-haskell-src}" + "${config.packages.lbf-prelude-haskell}" + "${config.packages.lbr-plutus-haskell-src}" + "${config.packages.lbf-plutus-haskell}" + "${config.packages.lbf-plutus-golden-api-haskell}" + "${config.packages.lbt-plutus-golden-haskell}" + + # Plutarch (just for script evaluation module) + "${inputs.plutarch}" + ]; + + devShellTools = config.settings.shell.tools; + devShellHook = config.settings.shell.hook; + }; + + in + + { + devShells.dev-lbt-plutus-plutustx = hsFlake.devShell; + + packages = { + lbt-plutus-plutustx-tests = hsFlake.packages."lbt-plutus-plutustx:test:tests"; + }; + + checks.check-lbt-plutus-plutustx = hsFlake.checks."lbt-plutus-plutustx:test:tests"; + }; +} diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/cabal.project b/testsuites/lbt-plutus/lbt-plutus-plutustx/cabal.project new file mode 100644 index 00000000..6b0c1f6a --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/cabal.project @@ -0,0 +1,3 @@ +packages: ./. + +tests: true \ No newline at end of file diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/hie.yaml b/testsuites/lbt-plutus/lbt-plutus-plutustx/hie.yaml new file mode 100644 index 00000000..04cd2439 --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/hie.yaml @@ -0,0 +1,2 @@ +cradle: + cabal: diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/lbt-plutus-plutustx.cabal b/testsuites/lbt-plutus/lbt-plutus-plutustx/lbt-plutus-plutustx.cabal new file mode 100644 index 00000000..b8948573 --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/lbt-plutus-plutustx.cabal @@ -0,0 +1,117 @@ +cabal-version: 3.0 +name: lbt-plutus-plutustx +version: 0.1.0.0 +synopsis: + Integration Test Suite for `lbf-plutus` and Haskell `lbr-plutustx` + +author: Drazen Popovic +maintainer: bladyjoker@gmail.com + +flag dev + description: Enable non-strict compilation for development + manual: True + +common common-language + ghc-options: + -Wall -Wcompat -fprint-explicit-foralls -fprint-explicit-kinds + -fwarn-missing-import-lists -Weverything -Wno-unsafe + -Wno-missing-safe-haskell-mode -Wno-implicit-prelude + -Wno-missing-kind-signatures -Wno-all-missed-specializations + + if !flag(dev) + ghc-options: -Werror + + default-extensions: + BangPatterns + BinaryLiterals + ConstrainedClassMethods + ConstraintKinds + DataKinds + DeriveAnyClass + DeriveDataTypeable + DeriveFoldable + DeriveFunctor + DeriveGeneric + DeriveLift + DeriveTraversable + DerivingStrategies + DerivingVia + DoAndIfThenElse + DuplicateRecordFields + EmptyCase + EmptyDataDecls + EmptyDataDeriving + ExistentialQuantification + ExplicitForAll + ExplicitNamespaces + FlexibleContexts + FlexibleInstances + ForeignFunctionInterface + GADTSyntax + GeneralizedNewtypeDeriving + HexFloatLiterals + ImportQualifiedPost + InstanceSigs + KindSignatures + LambdaCase + MonomorphismRestriction + MultiParamTypeClasses + NamedFieldPuns + NamedWildCards + NoStarIsType + NumericUnderscores + OverloadedLabels + OverloadedStrings + PartialTypeSignatures + PatternGuards + PolyKinds + PostfixOperators + RankNTypes + RecordWildCards + RelaxedPolyRec + ScopedTypeVariables + StandaloneDeriving + StandaloneKindSignatures + TemplateHaskell + TraditionalRecordSyntax + TupleSections + TypeApplications + TypeFamilies + TypeOperators + TypeSynonymInstances + ViewPatterns + + default-language: Haskell2010 + +test-suite tests + import: common-language + type: exitcode-stdio-1.0 + hs-source-dirs: test + main-is: Test.hs + build-depends: + , base >=4.16 + , bytestring >=0.11 + , filepath >=1.4 + , lbf-plutus >=0.1 + , lbf-plutus-golden-api + , lbf-plutus-plutustx + , lbf-plutus-plutustx-golden-api + , lbf-prelude + , lbf-prelude-plutustx + , lbr-plutus + , lbr-plutustx + , lbr-prelude + , lbt-plutus-golden-data + , plutarch + , plutus-core >=1.20 + , plutus-ledger-api >=1.20 + , plutus-tx + , plutus-tx-plugin + , tasty >=1.4 + , tasty-expected-failure + , tasty-hunit + + other-modules: + Test.LambdaBuffers.Runtime.PlutusTx.Evaluate + Test.LambdaBuffers.Runtime.PlutusTx.PlutusData + Test.LambdaBuffers.Runtime.PlutusTx.PlutusTx diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test.hs b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test.hs new file mode 100644 index 00000000..665ccfcc --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test.hs @@ -0,0 +1,12 @@ +module Main (main) where + +import Test.LambdaBuffers.Runtime.PlutusTx.PlutusData qualified as PlutusData +import Test.Tasty (defaultMain, testGroup) + +main :: IO () +main = do + defaultMain $ + testGroup + "LambdaBuffers Plutus package tests" + [ PlutusData.tests + ] diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/Evaluate.hs b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/Evaluate.hs new file mode 100644 index 00000000..ec7c5b0d --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/Evaluate.hs @@ -0,0 +1,17 @@ +module Test.LambdaBuffers.Runtime.PlutusTx.Evaluate (evalScript, evalScriptHuge, evalScript', EvalError, Script (..), fromCompiledCode, applyArg) where + +import Data.Functor (void) +import Plutarch (Script (Script)) +import Plutarch.Evaluate (EvalError, evalScript, evalScript', evalScriptHuge) +import PlutusCore qualified as PLC +import PlutusTx (CompiledCode, Lift, applyCode, getPlc, liftCode) +import UntypedPlutusCore ( + Program (Program), + ) +import UntypedPlutusCore qualified as UPLC + +fromCompiledCode :: CompiledCode a -> Script +fromCompiledCode cc = let (Program _x _y t) = getPlc cc in Script (Program () _y (UPLC.termMapNames UPLC.unNameDeBruijn (void t))) + +applyArg :: PlutusTx.Lift PLC.DefaultUni a => CompiledCode (a -> b) -> a -> Either String (CompiledCode b) +applyArg fun arg = let (Program _x version _t) = getPlc fun in PlutusTx.applyCode fun (PlutusTx.liftCode version arg) diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/PlutusData.hs b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/PlutusData.hs new file mode 100644 index 00000000..27d02423 --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/PlutusData.hs @@ -0,0 +1,173 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# OPTIONS_GHC -Wno-missing-import-lists #-} +{-# OPTIONS_GHC -Wno-unused-foralls #-} + +module Test.LambdaBuffers.Runtime.PlutusTx.PlutusData (tests) where + +import Data.ByteString qualified as B +import LambdaBuffers.Days qualified as HlDays +import LambdaBuffers.Days.PlutusTx qualified as PlDays +import LambdaBuffers.Foo qualified as HlFoo +import LambdaBuffers.Foo.PlutusTx qualified as PlFoo +import LambdaBuffers.Plutus.V1 qualified as HlPlutus +import LambdaBuffers.Plutus.V1.PlutusTx qualified as PlPlutus +import LambdaBuffers.Plutus.V2 qualified as HlPlutusV2 +import LambdaBuffers.Plutus.V2.PlutusTx qualified as PlPlutusV2 +import LambdaBuffers.Prelude qualified as HlPrelude +import LambdaBuffers.Prelude.PlutusTx qualified as PlPrelude +import LambdaBuffers.Runtime.Plutus () +import LambdaBuffers.Runtime.PlutusTx () +import LambdaBuffers.Runtime.Prelude.Json qualified as Lb +import Paths_lbt_plutus_golden_data qualified as Paths +import PlutusTx (BuiltinData, CompiledCode, ToData, dataToBuiltinData) +import PlutusTx.IsData (FromData, fromData, toData) +import PlutusTx.Prelude qualified as PlutusTx +import System.Exit (exitFailure) +import System.FilePath (()) +import Test.LambdaBuffers.Runtime.PlutusTx.Evaluate qualified as Evaluate +import Test.LambdaBuffers.Runtime.PlutusTx.PlutusTx qualified as PlutusTx +import Test.Tasty (TestTree, testGroup) +import Test.Tasty.ExpectedFailure (ignoreTestBecause) +import Test.Tasty.HUnit (Assertion, assertFailure, testCase) +import Prelude + +-- TODO(bladyjoker): Make the ``xyzCompiled` functions have `BuiltinData -> a` type so the `plutusType` type argument is actually used +tests :: TestTree +tests = + testGroup + "Round trip tests (from goldens and back)" + [ transparentGoldens + , preludeGoldens + , plutusV1Goldens + , plutusV2Goldens + ] + +transparentGoldens :: TestTree +transparentGoldens = + testGroup + "Transparent golden types" + [ forallGoldens @HlDays.Day @PlDays.Day PlutusTx.dayCompiled "Days.Day" 6 + , forallGoldens @HlDays.FreeDay @PlDays.FreeDay PlutusTx.freeDayCompiled "Days.FreeDay" 1 + , forallGoldens @HlDays.WorkDay @PlDays.WorkDay PlutusTx.workDayCompiled "Days.WorkDay" 4 + , forallGoldens @HlFoo.A @PlFoo.A PlutusTx.fooACompiled "Foo.A" 9 + , forallGoldens @HlFoo.B @PlFoo.B PlutusTx.fooBCompiled "Foo.B" 9 + , forallGoldens @HlFoo.C @PlFoo.C PlutusTx.fooCCompiled "Foo.C" 9 + , forallGoldens @HlFoo.D @PlFoo.D PlutusTx.fooDCompiled "Foo.D" 7 + , ignoreTestBecause "TODO(bladyjoker): What happened to Foo.E goldens? Install them!" $ forallGoldens @(HlFoo.E Integer Bool) @(PlFoo.E PlutusTx.Integer PlutusTx.Bool) PlutusTx.fooECompiled "Foo.E" 1 + , ignoreTestBecause "GHC Core to PLC plugin: E003:Error: Error from the PIR compiler: E003: Unsupported construct: Mutually recursive datatypes ((recursive) let binding; from [ AnnOther ])" $ testCase "Foo.FInt" (print ("Not compiling" :: String)) + , ignoreTestBecause "GHC Core to PLC plugin: E003:Error: Error from the PIR compiler: E003: Unsupported construct: Mutually recursive datatypes ((recursive) let binding; from [ AnnOther ])" $ testCase "Foo.GInt" (print ("Not compiling" :: String)) + ] + +preludeGoldens :: TestTree +preludeGoldens = + testGroup + "LB Prelude golden types" + [ forallGoldens @(HlPrelude.Maybe HlPrelude.Bool) @(PlPrelude.Maybe PlPrelude.Bool) PlutusTx.maybeCompiled "Prelude.Maybe" 2 + , forallGoldens @(HlPrelude.Either HlPrelude.Bool HlPrelude.Bool) @(PlPrelude.Either PlPrelude.Bool PlPrelude.Bool) PlutusTx.eitherCompiled "Prelude.Either" 2 + , forallGoldens @(HlPrelude.List HlPrelude.Bool) @(PlPrelude.List PlPrelude.Bool) PlutusTx.listCompiled "Prelude.List" 3 + , ignoreTestBecause "TODO(bladyjoker): Include Prelude.Integer in the goldens" $ forallGoldens @HlPrelude.Integer @PlPrelude.Integer PlutusTx.integerCompiled "Prelude.Integer" 1 + ] + +plutusV1Goldens :: TestTree +plutusV1Goldens = + testGroup + "LB Plutus.V1. golden types" + [ forallGoldens @HlPlutus.Address @PlPlutus.Address PlutusTx.addressCompiled "PlutusV1.Address" 7 + , forallGoldens @HlPlutus.AssetClass @PlPlutus.AssetClass PlutusTx.assetClassCompiled "PlutusV1.AssetClass" 3 + , forallGoldens @HlPlutus.Bytes @PlPlutus.Bytes PlutusTx.ledgerBytesCompiled "PlutusV1.Bytes" 2 + , forallGoldens @HlPlutus.Credential @PlPlutus.Credential PlutusTx.credentialCompiled "PlutusV1.Credential" 1 + , forallGoldens @HlPlutus.CurrencySymbol @PlPlutus.CurrencySymbol PlutusTx.currencySymbolCompiled "PlutusV1.CurrencySymbol" 1 + , forallGoldens @HlPlutus.Datum @PlPlutus.Datum PlutusTx.datumCompiled "PlutusV1.Datum" 0 + , forallGoldens @HlPlutus.DatumHash @PlPlutus.DatumHash PlutusTx.datumHashCompiled "PlutusV1.DatumHash" 0 + , forallGoldens @(HlPlutus.Extended HlPlutus.POSIXTime) @(PlPlutus.Extended PlPlutus.POSIXTime) PlutusTx.extendedCompiled "PlutusV1.Extended" 2 + , forallGoldens @(HlPlutus.Interval HlPlutus.POSIXTime) @(PlPlutus.Interval PlPlutus.POSIXTime) PlutusTx.intervalCompiled "PlutusV1.Interval" 9 + , forallGoldens @(HlPlutus.LowerBound HlPlutus.POSIXTime) @(PlPlutus.LowerBound PlPlutus.POSIXTime) PlutusTx.lowerBoundCompiled "PlutusV1.LowerBound" 5 + , forallGoldens @(HlPlutus.Map HlPlutus.CurrencySymbol (HlPlutus.Map HlPlutus.TokenName HlPrelude.Integer)) @(PlPlutus.Map PlPlutus.CurrencySymbol (PlPlutus.Map PlPlutus.TokenName PlPrelude.Integer)) PlutusTx.mapCompiled "PlutusV1.Map" 2 + , forallGoldens @HlPlutus.POSIXTime @PlPlutus.POSIXTime PlutusTx.posixTimeCompiled "PlutusV1.POSIXTime" 2 + , forallGoldens @HlPlutus.POSIXTimeRange @PlPlutus.POSIXTimeRange PlutusTx.posixTimeRangeCompiled "PlutusV1.POSIXTimeRange" 9 + , forallGoldens @HlPlutus.PlutusData @PlPlutus.PlutusData PlutusTx.plutusDataCompiled "PlutusV1.PlutusData" 12 + , forallGoldens @HlPlutus.Redeemer @PlPlutus.Redeemer PlutusTx.redeemerCompiled "PlutusV1.Redeemer" 0 + , forallGoldens @HlPlutus.RedeemerHash @PlPlutus.RedeemerHash PlutusTx.redeemerHashCompiled "PlutusV1.RedeemerHash" 0 + , forallGoldens @HlPlutus.ScriptHash @PlPlutus.ScriptHash PlutusTx.scriptHashCompiled "PlutusV1.ScriptHash" 0 + , forallGoldens @HlPlutus.StakingCredential @PlPlutus.StakingCredential PlutusTx.stakingCredentialCompiled "PlutusV1.StakingCredential" 2 + , forallGoldens @HlPlutus.TokenName @PlPlutus.TokenName PlutusTx.tokenNameCompiled "PlutusV1.TokenName" 2 + , forallGoldens @HlPlutus.TxId @PlPlutus.TxId PlutusTx.txIdCompiled "PlutusV1.TxId" 0 + , forallGoldens @HlPlutus.TxOutRef @PlPlutus.TxOutRef PlutusTx.txOutRefCompiled "PlutusV1.TxOutRef" 0 + , forallGoldens @(HlPlutus.UpperBound HlPlutus.POSIXTime) @(PlPlutus.UpperBound PlPlutus.POSIXTime) PlutusTx.upperBoundCompiled "PlutusV1.UpperBound" 5 + , forallGoldens @HlPlutus.Value @PlPlutus.Value PlutusTx.valueCompiled "PlutusV1.Value" 2 + , forallGoldens @HlPlutus.DCert @PlPlutus.DCert PlutusTx.dcertCompiled "PlutusV1.DCert" 9 + , forallGoldens @HlPlutus.TxOut @PlPlutus.TxOut PlutusTx.txOutCompiled "PlutusV1.TxOut" 9 + , forallGoldens @HlPlutus.TxInInfo @PlPlutus.TxInInfo PlutusTx.txInInfoCompiled "PlutusV1.TxInInfo" 9 + , forallGoldens @HlPlutus.ScriptPurpose @PlPlutus.ScriptPurpose PlutusTx.scriptPurposeCompiled "PlutusV1.ScriptPurpose" 9 + , forallGoldens @HlPlutus.TxInfo @PlPlutus.TxInfo PlutusTx.txInfoCompiled "PlutusV1.TxInfo" 9 + , forallGoldens @HlPlutus.ScriptContext @PlPlutus.ScriptContext PlutusTx.scriptContextCompiled "PlutusV1.ScriptContext" 9 + ] + +plutusV2Goldens :: TestTree +plutusV2Goldens = + testGroup + "LB Plutus.V2 golden types" + [ forallGoldens @HlPlutusV2.OutputDatum @PlPlutusV2.OutputDatum PlutusTx.outputDatumCompiled "PlutusV2.OutputDatum" 2 + , forallGoldens @HlPlutusV2.TxInInfo @PlPlutusV2.TxInInfo PlutusTx.txInInfo2Compiled "PlutusV2.TxInInfo" 9 + , forallGoldens @HlPlutusV2.TxOut @PlPlutusV2.TxOut PlutusTx.txOut2Compiled "PlutusV2.TxOut" 9 + , forallGoldens @HlPlutusV2.TxInfo @PlPlutusV2.TxInfo PlutusTx.txInfo2Compiled "PlutusV2.TxInfo" 9 + , forallGoldens @HlPlutusV2.ScriptContext @PlPlutusV2.ScriptContext PlutusTx.scriptContext2Compiled "PlutusV2.ScriptContext" 9 + ] + +forallGoldens :: + forall haskellType plutusTxType. + ( FromData haskellType + , ToData haskellType + ) => + PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -> + FilePath -> + Int -> + TestTree +forallGoldens plutusTxFunction prefix howMany = + testGroup prefix $ + fmap + ( \i -> + roundTripTestCase @haskellType + plutusTxFunction + (prefix <> "." <> show i <> ".pd.json") + ) + [0 .. howMany] + +roundTripTestCase :: + forall haskellType. + ( FromData haskellType + , ToData haskellType + ) => + PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -> + FilePath -> + TestTree +roundTripTestCase plutusTxFunction fp = testCase fp $ do + x <- readGoldenPdJson @haskellType fp + evalRoundTrip plutusTxFunction (dataToBuiltinData $ toData @haskellType x) + +evalRoundTrip :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) -> BuiltinData -> Assertion +evalRoundTrip plutusTxFunction pd = case Evaluate.applyArg plutusTxFunction pd of + Left err -> assertFailure $ show ("Error while applying a PlutusData value to a PlutusTx Term" :: String, err) + Right cc -> case Evaluate.evalScriptHuge . Evaluate.fromCompiledCode $ cc of + (Left err, _, trace) -> assertFailure $ show ("Error while evaluating a PlutusTx script" :: String, err, trace) + _ -> return () + +-- | Golden utilities +readPdJson :: FromData b => FilePath -> IO b +readPdJson fp = do + content <- B.readFile fp + case Lb.fromJsonBytes content of + Left err -> do + print ("Error while parsing LambdaBuffers .pd.json file" :: String, fp, err) + exitFailure + Right pd -> do + case fromData pd of + Nothing -> do + print ("Error while parsing LambdaBuffers PlutusData" :: String, fp) + exitFailure + Just x -> return x + +readGoldenPdJson :: FromData b => FilePath -> IO b +readGoldenPdJson fp = do + dataDir <- Paths.getDataDir + readPdJson (dataDir "data" fp) diff --git a/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/PlutusTx.hs b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/PlutusTx.hs new file mode 100644 index 00000000..2c5596ce --- /dev/null +++ b/testsuites/lbt-plutus/lbt-plutus-plutustx/test/Test/LambdaBuffers/Runtime/PlutusTx/PlutusTx.hs @@ -0,0 +1,233 @@ +{-# LANGUAGE AllowAmbiguousTypes #-} +{-# LANGUAGE ScopedTypeVariables #-} +{-# LANGUAGE TemplateHaskellQuotes #-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# OPTIONS_GHC -fno-ignore-interface-pragmas #-} +{-# OPTIONS_GHC -fno-omit-interface-pragmas #-} +{-# OPTIONS_GHC -fno-specialise #-} +{-# OPTIONS_GHC -fno-strictness #-} +{-# OPTIONS_GHC -fobject-code #-} + +module Test.LambdaBuffers.Runtime.PlutusTx.PlutusTx ( + dayCompiled, + integerCompiled, + boolCompiled, + workDayCompiled, + freeDayCompiled, + fooACompiled, + fooBCompiled, + fooCCompiled, + fooDCompiled, + fooECompiled, + maybeCompiled, + eitherCompiled, + listCompiled, + addressCompiled, + assetClassCompiled, + currencySymbolCompiled, + credentialCompiled, + mapCompiled, + intervalCompiled, + extendedCompiled, + lowerBoundCompiled, + datumCompiled, + datumHashCompiled, + ledgerBytesCompiled, + posixTimeCompiled, + posixTimeRangeCompiled, + plutusDataCompiled, + redeemerCompiled, + redeemerHashCompiled, + scriptHashCompiled, + stakingCredentialCompiled, + tokenNameCompiled, + txIdCompiled, + txOutRefCompiled, + upperBoundCompiled, + valueCompiled, + dcertCompiled, + txInInfoCompiled, + txOutCompiled, + scriptPurposeCompiled, + txInfoCompiled, + scriptContextCompiled, + outputDatumCompiled, + txInInfo2Compiled, + txOut2Compiled, + txInfo2Compiled, + scriptContext2Compiled, +) where + +import LambdaBuffers.Days.PlutusTx (Day, FreeDay, WorkDay) +import LambdaBuffers.Foo.PlutusTx (A, B, C, D, E, FInt, GInt) +import LambdaBuffers.Plutus.V2.PlutusTx qualified as PlutusV2 +import PlutusLedgerApi.V1 qualified as PlutusV1 +import PlutusLedgerApi.V1.Value qualified as PlutusV1 +import PlutusTx (BuiltinData, CompiledCode, FromData (fromBuiltinData), ToData (toBuiltinData), compile) +import PlutusTx.AssocMap qualified as PlutusTx +import PlutusTx.Maybe (Maybe (Just, Nothing)) +import PlutusTx.Plugin () +import PlutusTx.Prelude (Bool, Either, Eq ((==)), Integer, error, trace, (&&)) + +{-# INLINEABLE fromToDataAndEq #-} +fromToDataAndEq :: forall a. (PlutusTx.Prelude.Eq a, FromData a, ToData a) => BuiltinData -> Bool +fromToDataAndEq x'data = + let + may'x = fromBuiltinData @a x'data + in + case may'x of + Nothing -> trace "Failed FromData" (error ()) + Just x -> x == x && toBuiltinData x == x'data + +integerCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +integerCompiled = $$(PlutusTx.compile [||fromToDataAndEq @Integer||]) + +boolCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +boolCompiled = $$(PlutusTx.compile [||fromToDataAndEq @Bool||]) + +dayCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +dayCompiled = $$(PlutusTx.compile [||fromToDataAndEq @Day||]) + +freeDayCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +freeDayCompiled = $$(PlutusTx.compile [||fromToDataAndEq @FreeDay||]) + +workDayCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +workDayCompiled = $$(PlutusTx.compile [||fromToDataAndEq @WorkDay||]) + +fooACompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +fooACompiled = $$(PlutusTx.compile [||fromToDataAndEq @A||]) + +fooBCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +fooBCompiled = $$(PlutusTx.compile [||fromToDataAndEq @B||]) + +fooCCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +fooCCompiled = $$(PlutusTx.compile [||fromToDataAndEq @C||]) + +fooDCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +fooDCompiled = $$(PlutusTx.compile [||fromToDataAndEq @D||]) + +fooECompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +fooECompiled = $$(PlutusTx.compile [||fromToDataAndEq @(E Integer Bool)||]) + +-- NOTE(bladyjoker): Recursive types are not supported by PlutusTx +fooFIntCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +fooFIntCompiled = $$(PlutusTx.compile [||fromToDataAndEq @FInt||]) + +-- NOTE(bladyjoker): Recursive types are not supported by PlutusTx +fooGIntCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +fooGIntCompiled = $$(PlutusTx.compile [||fromToDataAndEq @GInt||]) + +-- * Prelude + +maybeCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +maybeCompiled = $$(PlutusTx.compile [||fromToDataAndEq @(Maybe Bool)||]) + +eitherCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +eitherCompiled = $$(PlutusTx.compile [||fromToDataAndEq @(Either Bool Bool)||]) + +listCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +listCompiled = $$(PlutusTx.compile [||fromToDataAndEq @[Bool]||]) + +-- * Plutus V1 +addressCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +addressCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.Address||]) + +assetClassCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +assetClassCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.AssetClass||]) + +ledgerBytesCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +ledgerBytesCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.LedgerBytes||]) + +credentialCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +credentialCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.Credential||]) + +currencySymbolCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +currencySymbolCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.CurrencySymbol||]) + +datumCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +datumCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.Datum||]) + +datumHashCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +datumHashCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.DatumHash||]) + +extendedCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +extendedCompiled = $$(PlutusTx.compile [||fromToDataAndEq @(PlutusV1.Extended PlutusV1.POSIXTime)||]) + +intervalCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +intervalCompiled = $$(PlutusTx.compile [||fromToDataAndEq @(PlutusV1.Interval PlutusV1.POSIXTime)||]) + +lowerBoundCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +lowerBoundCompiled = $$(PlutusTx.compile [||fromToDataAndEq @(PlutusV1.LowerBound PlutusV1.POSIXTime)||]) + +mapCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +mapCompiled = $$(PlutusTx.compile [||fromToDataAndEq @(PlutusTx.Map PlutusV1.CurrencySymbol (PlutusTx.Map PlutusV1.TokenName Integer))||]) + +posixTimeCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +posixTimeCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.POSIXTime||]) + +posixTimeRangeCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +posixTimeRangeCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.POSIXTimeRange||]) + +plutusDataCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +plutusDataCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.BuiltinData||]) + +redeemerCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +redeemerCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.Redeemer||]) + +redeemerHashCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +redeemerHashCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.RedeemerHash||]) + +scriptHashCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +scriptHashCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.ScriptHash||]) + +stakingCredentialCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +stakingCredentialCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.StakingCredential||]) + +tokenNameCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +tokenNameCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.TokenName||]) + +txIdCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txIdCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.TxId||]) + +txOutRefCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txOutRefCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.TxOutRef||]) + +upperBoundCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +upperBoundCompiled = $$(PlutusTx.compile [||fromToDataAndEq @(PlutusV1.UpperBound PlutusV1.POSIXTime)||]) + +valueCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +valueCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.Value||]) + +dcertCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +dcertCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.DCert||]) + +scriptPurposeCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +scriptPurposeCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.ScriptPurpose||]) + +txInInfoCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txInInfoCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.TxInInfo||]) + +txOutCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txOutCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.TxOut||]) + +txInfoCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txInfoCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.TxInfo||]) + +scriptContextCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +scriptContextCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV1.ScriptContext||]) + +-- * Plutus V2 +outputDatumCompiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +outputDatumCompiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV2.OutputDatum||]) + +txInInfo2Compiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txInInfo2Compiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV2.TxInInfo||]) + +txOut2Compiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txOut2Compiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV2.TxOut||]) + +txInfo2Compiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +txInfo2Compiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV2.TxInfo||]) + +scriptContext2Compiled :: PlutusTx.CompiledCode (PlutusTx.BuiltinData -> Bool) +scriptContext2Compiled = $$(PlutusTx.compile [||fromToDataAndEq @PlutusV2.ScriptContext||]) diff --git a/testsuites/lbt-plutus/lbt-plutus-typescript/src/Goldens.ts b/testsuites/lbt-plutus/lbt-plutus-typescript/src/Goldens.ts index a80db459..1e83e3e2 100644 --- a/testsuites/lbt-plutus/lbt-plutus-typescript/src/Goldens.ts +++ b/testsuites/lbt-plutus/lbt-plutus-typescript/src/Goldens.ts @@ -66,10 +66,13 @@ export function plutusDataGoldens(): LbrPrelude.List { { name: "Constr", - fields: [1n, [ - { name: "Integer", fields: 1n }, - { name: "Bytes", fields: someBytes() }, - ]], + fields: [ + 1n, + [ + { name: "Integer", fields: 1n }, + { name: "Bytes", fields: someBytes() }, + ], + ], }, { name: "List", fields: [] }, @@ -90,13 +93,22 @@ export function plutusDataGoldens(): LbrPrelude.List { { name: "Map", fields: PlaMap.fromList([]) }, { name: "Map", - fields: PlaMap.fromList([[{ name: "Integer", fields: 1n }, { - name: "Bytes", - fields: someBytes(), - }], [{ name: "Integer", fields: 2n }, { - name: "Bytes", - fields: someMoreBytes(), - }]]), + fields: PlaMap.fromList([ + [ + { name: "Integer", fields: 1n }, + { + name: "Bytes", + fields: someBytes(), + }, + ], + [ + { name: "Integer", fields: 2n }, + { + name: "Bytes", + fields: someMoreBytes(), + }, + ], + ]), }, { name: "Integer", fields: 0n }, { name: "Integer", fields: 1n }, @@ -340,22 +352,26 @@ export function adaCurrencySymbolGolden(): LbrPlutusV1.CurrencySymbol { */ export function tokenNameGoldens(): LbrPrelude.List { const tn1 = unsafeFromJust(PlaV1.tokenNameFromBytes(emptyBytes())); - const tn2 = unsafeFromJust(PlaV1.tokenNameFromBytes( - ((arr: LbrPrelude.List) => { - for (let i = 1; i < 16; ++i) { - arr.push(i); - } - return Uint8Array.from(arr); - })([]), - )); - const tn3 = unsafeFromJust(PlaV1.tokenNameFromBytes( - ((arr: LbrPrelude.List) => { - for (let i = 1; i < 32; ++i) { - arr.push(i); - } - return Uint8Array.from(arr); - })([]), - )); + const tn2 = unsafeFromJust( + PlaV1.tokenNameFromBytes( + ((arr: LbrPrelude.List) => { + for (let i = 1; i < 16; ++i) { + arr.push(i); + } + return Uint8Array.from(arr); + })([]), + ), + ); + const tn3 = unsafeFromJust( + PlaV1.tokenNameFromBytes( + ((arr: LbrPrelude.List) => { + for (let i = 1; i < 32; ++i) { + arr.push(i); + } + return Uint8Array.from(arr); + })([]), + ), + ); return [tn1, tn2, tn3]; } @@ -404,61 +420,58 @@ export function mapGoldens(): LbrPrelude.List< PlaMap.fromList< LbrPlutusV1.CurrencySymbol, LbrPlutusV1.Map - >( + >([ [ - [ - PlaV1.adaSymbol, - PlaMap.fromList( - [[PlaV1.adaToken, 1337n]], - ), - ], + PlaV1.adaSymbol, + PlaMap.fromList([ + [PlaV1.adaToken, 1337n], + ]), ], - ), + ]), PlaMap.fromList< LbrPlutusV1.CurrencySymbol, LbrPlutusV1.Map - >( + >([ [ - [ - PlaV1.adaSymbol, - PlaMap.fromList([[ - PlaV1.adaToken, - 1337n, - ]]), - ], + PlaV1.adaSymbol, + PlaMap.fromList([ + [PlaV1.adaToken, 1337n], + ]), + ], - [ - unsafeFromJust(PlaV1.currencySymbolFromBytes(blake2b_224Hash())), - PlaMap.fromList( - [ - [unsafeFromJust(PlaV1.tokenNameFromBytes(emptyBytes())), 1337n], - [ - unsafeFromJust(PlaV1.tokenNameFromBytes( - ((arr: LbrPrelude.List) => { - for (let i = 1; i < 16; ++i) { - arr.push(i); - } - return Uint8Array.from(arr); - })([]), - )), - 16n, - ], - [ - unsafeFromJust(PlaV1.tokenNameFromBytes( - ((arr: LbrPrelude.List) => { - for (let i = 1; i < 32; ++i) { - arr.push(i); - } - return Uint8Array.from(arr); - })([]), - )), - 32n, - ], - ], - ), - ], + [ + unsafeFromJust(PlaV1.currencySymbolFromBytes(blake2b_224Hash())), + PlaMap.fromList([ + [unsafeFromJust(PlaV1.tokenNameFromBytes(emptyBytes())), 1337n], + [ + unsafeFromJust( + PlaV1.tokenNameFromBytes( + ((arr: LbrPrelude.List) => { + for (let i = 1; i < 16; ++i) { + arr.push(i); + } + return Uint8Array.from(arr); + })([]), + ), + ), + 16n, + ], + [ + unsafeFromJust( + PlaV1.tokenNameFromBytes( + ((arr: LbrPrelude.List) => { + for (let i = 1; i < 32; ++i) { + arr.push(i); + } + return Uint8Array.from(arr); + })([]), + ), + ), + 32n, + ], + ]), ], - ), + ]), ]; } @@ -466,18 +479,14 @@ export function mapGoldens(): LbrPrelude.List< * Hard coded {@link Redeemer} tests */ export function redeemerGoldens(): LbrPrelude.List { - return [ - { name: "Integer", fields: 1337n }, - ]; + return [{ name: "Integer", fields: 1337n }]; } /** * Hard coded {@link Datum} tests */ export function datumGoldens(): LbrPrelude.List { - return [ - { name: "Integer", fields: 1337n }, - ]; + return [{ name: "Integer", fields: 1337n }]; } /** @@ -486,27 +495,21 @@ export function datumGoldens(): LbrPrelude.List { export function redeemerHashGoldens(): LbrPrelude.List< LbrPlutusV1.RedeemerHash > { - return [ - unsafeFromJust(PlaV1.redeemerHashFromBytes(blake2b_256Hash())), - ]; + return [unsafeFromJust(PlaV1.redeemerHashFromBytes(blake2b_256Hash()))]; } /** * Hard coded {@link DatumHash} tests */ export function datumHashGoldens(): LbrPrelude.List { - return [ - unsafeFromJust(PlaV1.datumHashFromBytes(blake2b_256Hash())), - ]; + return [unsafeFromJust(PlaV1.datumHashFromBytes(blake2b_256Hash()))]; } /** * Hard coded {@link TxId} tests */ export function txIdGoldens(): LbrPrelude.List { - return [ - unsafeFromJust(PlaV1.txIdFromBytes(blake2b_256Hash())), - ]; + return [unsafeFromJust(PlaV1.txIdFromBytes(blake2b_256Hash()))]; } /** @@ -524,25 +527,211 @@ export function txOutRefGoldens(): LbrPrelude.List { return res; } -// /* -// * Hard coded {@link TxInInfo} tests -// * TODO(jaredponn): this is borked -- this type doesn't actually exist in the .lbf file -// */ -// export function txInInfoGoldensV1() : LbrPrelude.List { -// const res : LbrPrelude.List = []; -// -// for (const txOutRef of txOutRefGoldens()) { -// for (const txOut of txOutGoldensV1()) { -// } -// } -// return res -// } - -// /* -// * Hard coded {@link TxOut} tests -// * TODO(jaredponn): this is borked -- this type doesn't actually exist in the .lbf file -// */ -// +/** + * Hard coded {@link TxInInfo} tests + */ +export function txInInfoGoldensV1(): LbrPrelude.List { + const res: LbrPrelude.List = []; + + for (const txOutRef of txOutRefGoldens()) { + for (const txOut of txOutGoldensV1()) { + res.push({ txInInfoOutRef: txOutRef, txInInfoResolved: txOut }); + } + } + return res; +} + +/** + * Hard coded {@link TxOut} tests + */ +export function txOutGoldensV1(): LbrPrelude.List { + const res: LbrPrelude.List = []; + + for (const address of addressGoldens()) { + for (const value of valueGoldens()) { + for (const datumHash of datumHashGoldens()) { + const datumHash1: LbrPrelude.Maybe = { + fields: datumHash, + name: "Just", + }; + const txOut1 = { + txOutAddress: address, + txOutValue: value, + txOutDatumHash: datumHash1, + }; + + res.push(txOut1); + } + const datumHash2: LbrPrelude.Maybe = { + name: "Nothing", + }; + const txOut2 = { + txOutAddress: address, + txOutValue: value, + txOutDatumHash: datumHash2, + }; + res.push(txOut2); + } + } + return res; +} + +/** + * Hard coded {@link DCert} tests + */ +export function dCertGoldens(): LbrPrelude.List { + const res: LbrPrelude.List = []; + + res.push({ name: "Mir" }); + res.push({ name: "Genesis" }); + + for (const pubKeyHash of pubKeyHashGoldens()) { + res.push({ + fields: [pubKeyHash, 1337n], + name: "PoolRetire", + }); + } + + for (const stakingCredential of stakingCredentialGoldens()) { + res.push({ + fields: stakingCredential, + name: "DelegRegKey", + }); + } + + for (const pubKeyHash1 of pubKeyHashGoldens()) { + for (const pubKeyHash2 of pubKeyHashGoldens()) { + res.push({ + fields: [pubKeyHash1, pubKeyHash2], + name: "PoolRegister", + }); + } + } + + for (const stakingCredential of stakingCredentialGoldens()) { + res.push({ + fields: stakingCredential, + name: "DelegDeRegKey", + }); + } + + for (const stakingCredential of stakingCredentialGoldens()) { + for (const pubKeyHash of pubKeyHashGoldens()) { + res.push({ + fields: [stakingCredential, pubKeyHash], + name: "DelegDelegate", + }); + } + } + + return res; +} + +/** + * Hard coded {@link ScriptPurpose} tests + */ +export function scriptPurposeGoldens(): LbrPrelude.List< + LbrPlutusV1.ScriptPurpose +> { + const res: LbrPrelude.List = []; + + for (const currencySymbol of currencySymbolGoldens()) { + res.push({ + fields: currencySymbol, + name: "Minting", + }); + } + + for (const txOutRef of txOutRefGoldens()) { + res.push({ + fields: txOutRef, + name: "Spending", + }); + } + + for (const stakingCredential of stakingCredentialGoldens()) { + res.push({ + fields: stakingCredential, + name: "Rewarding", + }); + } + + for (const dCert of dCertGoldens()) { + res.push({ + fields: dCert, + name: "Certifying", + }); + } + + return res; +} + +/** + * Hard coded {@link TxInfo} tests + */ +export function txInfoGoldensV1(): LbrPrelude.List { + const res: LbrPrelude.List = []; + + const wdrls: LbrPrelude.List< + [LbrPlutusV1.StakingCredential, LbrPrelude.Integer] + > = []; + + for (const stakingCredential of stakingCredentialGoldens()) { + wdrls.push([stakingCredential, 1234n]); + } + + const datums: LbrPrelude.List<[LbrPlutusV1.DatumHash, LbrPlutusV1.Datum]> = + []; + + for (const datumHash of datumHashGoldens()) { + for (const datum of datumGoldens()) { + datums.push([datumHash, datum]); + } + } + + for (const fee of valueGoldens()) { + for (const mint of valueGoldens()) { + for (const validRange of posixTimeRangeGoldens()) { + for (const id of txIdGoldens()) { + res.push({ + txInfoInputs: txInInfoGoldensV1(), + txInfoOutputs: txOutGoldensV1(), + txInfoFee: fee, + txInfoMint: mint, + txInfoDCert: dCertGoldens(), + txInfoWdrl: wdrls, + txInfoValidRange: validRange, + txInfoSignatories: pubKeyHashGoldens(), + txInfoData: datums, + txInfoId: id, + }); + } + } + } + } + + return res; +} + +/** + * Hard coded {@link ScriptContext} tests + */ +export function scriptContextGoldensV1(): LbrPrelude.List< + LbrPlutusV1.ScriptContext +> { + const res: LbrPrelude.List = []; + + for (const scriptPurpose of scriptPurposeGoldens()) { + for (const txInfo of txInfoGoldensV1()) { + res.push({ + scriptContextPurpose: scriptPurpose, + scriptContextTxInfo: txInfo, + }); + } + } + + return res; +} /* * Plutus.V2 goldens @@ -583,14 +772,12 @@ export function txOutGoldensV2(): LbrPrelude.List { ); for (const mScriptHash of mScriptHashes) { - res.push( - { - txOutAddress: address, - txOutValue: value, - txOutDatum: outDatums[outDatumIx]!, - txOutReferenceScript: mScriptHash, - }, - ); + res.push({ + txOutAddress: address, + txOutValue: value, + txOutDatum: outDatums[outDatumIx]!, + txOutReferenceScript: mScriptHash, + }); } } } @@ -618,6 +805,83 @@ export function outDatumGoldens(): LbrPrelude.List { return res; } +/** + * Hard coded {@link TxInfo} tests + */ +export function txInfoGoldensV2(): LbrPrelude.List { + const res: LbrPrelude.List = []; + + const wdrls: PlaMap.Map = + PlaMap.empty(); + + for (const stakingCredential of stakingCredentialGoldens()) { + PlaMap.insert(PlaV1.eqStakingCredential, stakingCredential, 1234n, wdrls); + } + + const datums: PlaMap.Map = PlaMap + .empty(); + + for (const datumHash of datumHashGoldens()) { + for (const datum of datumGoldens()) { + PlaMap.insert(PlaV1.eqDatumHash, datumHash, datum, datums); + } + } + + const redeemers: PlaMap.Map = + PlaMap.empty(); + + for (const scriptPurpose of scriptPurposeGoldens()) { + for (const redeemer of redeemerGoldens()) { + PlaMap.insert(PlaV1.eqScriptPurpose, scriptPurpose, redeemer, redeemers); + } + } + + for (const fee of valueGoldens()) { + for (const mint of valueGoldens()) { + for (const validRange of posixTimeRangeGoldens()) { + for (const id of txIdGoldens()) { + res.push({ + txInfoInputs: txInInfoGoldensV2(), + txInfoReferenceInputs: txInInfoGoldensV2(), + txInfoOutputs: txOutGoldensV2(), + txInfoFee: fee, + txInfoMint: mint, + txInfoDCert: dCertGoldens(), + txInfoWdrl: wdrls, + txInfoValidRange: validRange, + txInfoSignatories: pubKeyHashGoldens(), + txInfoRedeemers: redeemers, + txInfoData: datums, + txInfoId: id, + }); + } + } + } + } + + return res; +} + +/** + * Hard coded {@link ScriptContext} tests + */ +export function scriptContextGoldensV2(): LbrPrelude.List< + LbrPlutusV2.ScriptContext +> { + const res: LbrPrelude.List = []; + + for (const scriptPurpose of scriptPurposeGoldens()) { + for (const txInfo of txInfoGoldensV2()) { + res.push({ + scriptContextPurpose: scriptPurpose, + scriptContextTxInfo: txInfo, + }); + } + } + + return res; +} + /* * Foo.Bar goldens */ @@ -658,9 +922,7 @@ export function fooRecGoldens( y: B, z: C, ): LbfFooBar.FooRec[] { - return [ - { fooA: x, fooB: y, fooC: z, fooInt: 1337n }, - ]; + return [{ fooA: x, fooB: y, fooC: z, fooInt: 1337n }]; } /* @@ -777,9 +1039,7 @@ export function dGoldens(): LbrPrelude.List { for (const fooSum of fooSums) { for (const fooProd of fooProds) { for (const fooRec of fooRecs) { - fooComplicateds.push( - { sum: fooSum, prod: fooProd, rec: fooRec }, - ); + fooComplicateds.push({ sum: fooSum, prod: fooProd, rec: fooRec }); } } } @@ -830,9 +1090,15 @@ export function dayGoldens(): LbfDays.Day[] { * Hard coded {@link WorkDay} tests */ export function workDayGoldens(): LbfDays.WorkDay[] { - return [{ name: "Monday" }, { name: "Tuesday" }, { name: "Wednesday" }, { - name: "Thursday", - }, { name: "Friday" }]; + return [ + { name: "Monday" }, + { name: "Tuesday" }, + { name: "Wednesday" }, + { + name: "Thursday", + }, + { name: "Friday" }, + ]; } /** @@ -857,10 +1123,14 @@ export function boolGoldens(): LbrPrelude.Bool[] { * Hard coded {@link Maybe} tests */ export function maybeGoldens(): LbrPrelude.Maybe[] { - return [{ name: "Nothing" }, { name: "Just", fields: true }, { - name: "Just", - fields: false, - }]; + return [ + { name: "Nothing" }, + { name: "Just", fields: true }, + { + name: "Just", + fields: false, + }, + ]; } /** @@ -870,10 +1140,14 @@ export function eitherGoldens(): LbrPrelude.Either< LbrPrelude.Bool, LbrPrelude.Bool >[] { - return [{ name: "Left", fields: true }, { name: "Left", fields: false }, { - name: "Right", - fields: true, - }]; + return [ + { name: "Left", fields: true }, + { name: "Left", fields: false }, + { + name: "Right", + fields: true, + }, + ]; } /** diff --git a/testsuites/lbt-plutus/lbt-plutus-typescript/src/Json-test.ts b/testsuites/lbt-plutus/lbt-plutus-typescript/src/Json-test.ts index 29031606..346f3eff 100644 --- a/testsuites/lbt-plutus/lbt-plutus-typescript/src/Json-test.ts +++ b/testsuites/lbt-plutus/lbt-plutus-typescript/src/Json-test.ts @@ -16,9 +16,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.PlutusData from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.PlutusData\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.PlutusData\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson, @@ -32,9 +30,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Address from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Address\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Address\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Address].fromJson, @@ -48,9 +44,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Credential from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Credential\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Credential\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Credential].fromJson, @@ -80,9 +74,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.PubKeyHash from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.PubKeyHash\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.PubKeyHash\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.PubKeyHash].fromJson, @@ -96,9 +88,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Bytes from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Bytes\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Bytes\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.LedgerBytes].fromJson, @@ -112,9 +102,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Interval from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Interval\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Interval\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Interval]( @@ -132,9 +120,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Extended from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Extended\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Extended\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Extended]( @@ -152,9 +138,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.LowerBound from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.LowerBound\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.LowerBound\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.LowerBound]( @@ -172,9 +156,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.UpperBound from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.UpperBound\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.UpperBound\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.UpperBound]( @@ -192,9 +174,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.POSIXTime from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.POSIXTime\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.POSIXTime\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.POSIXTime].fromJson, @@ -208,9 +188,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.POSIXTimeRange from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.POSIXTimeRange\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.POSIXTimeRange\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.POSIXTimeRange].fromJson, @@ -224,9 +202,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.CurrencySymbol from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.CurrencySymbol\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.CurrencySymbol\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.CurrencySymbol].fromJson, @@ -242,9 +218,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.TokenName from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.TokenName\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.TokenName\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.TokenName].fromJson, @@ -258,9 +232,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.AssetClass from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.AssetClass\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.AssetClass\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.AssetClass].fromJson, @@ -274,9 +246,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Value from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Value\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Value\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Value].fromJson, @@ -290,9 +260,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Redeemer from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Redeemer\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Redeemer\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Redeemer].fromJson, @@ -306,9 +274,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Datum from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Datum\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Datum\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Datum].fromJson, @@ -322,9 +288,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.RedeemerHash from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.RedeemerHash\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.RedeemerHash\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.RedeemerHash].fromJson, @@ -338,9 +302,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.DatumHash from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.DatumHash\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.DatumHash\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.DatumHash].fromJson, @@ -354,9 +316,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.ScriptHash from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.ScriptHash\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.ScriptHash\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.ScriptHash].fromJson, @@ -370,9 +330,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.TxId from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.TxId\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.TxId\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.TxId].fromJson, @@ -386,9 +344,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.TxOutRef from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.TxOutRef\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.TxOutRef\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.TxOutRef].fromJson, @@ -402,9 +358,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV1.Map from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Map\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Map\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV1.Map]( @@ -427,15 +381,94 @@ describe("JSON tests (toJson . fromJson)", () => { ); }); - // TODO(jaredponn): TxInInfo V1 doesn't exist yet - // TODO(jaredponn): TxOut V1 doesn't exist yet + it(`PlutusV1.TxInInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.TxInInfo\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV1.TxInInfo].fromJson, + LbrPrelude.Json[LbrPlutusV1.TxInInfo].toJson, + PreludeJson.stringify, + ), + Goldens.txInInfoGoldensV1(), + ); + }); - it(`PlutusV2.TxInInfo from to golden tests`, async () => { + it(`PlutusV1.TxOut from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV2\.TxInInfo\.[0-9]*\.json$/g, + new Utils.RegExpFileFilter(/^PlutusV1\.TxOut\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV1.TxOut].fromJson, + LbrPrelude.Json[LbrPlutusV1.TxOut].toJson, + PreludeJson.stringify, ), + Goldens.txOutGoldensV1(), + ); + }); + + it(`PlutusV1.DCert from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.DCert\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV1.DCert].fromJson, + LbrPrelude.Json[LbrPlutusV1.DCert].toJson, + PreludeJson.stringify, + ), + Goldens.dCertGoldens(), + ); + }); + + it(`PlutusV1.ScriptPurpose from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.ScriptPurpose\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV1.ScriptPurpose].fromJson, + LbrPrelude.Json[LbrPlutusV1.ScriptPurpose].toJson, + PreludeJson.stringify, + ), + Goldens.scriptPurposeGoldens(), + ); + }); + + it(`PlutusV1.TxInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.TxInfo\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV1.TxInfo].fromJson, + LbrPrelude.Json[LbrPlutusV1.TxInfo].toJson, + PreludeJson.stringify, + ), + Goldens.txInfoGoldensV1(), + ); + }); + + it(`PlutusV1.ScriptContext from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.ScriptContext\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV1.ScriptContext].fromJson, + LbrPrelude.Json[LbrPlutusV1.ScriptContext].toJson, + PreludeJson.stringify, + ), + Goldens.scriptContextGoldensV1(), + ); + }); + + it(`PlutusV2.TxInInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV2\.TxInInfo\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV2.TxInInfo].fromJson, @@ -449,9 +482,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV2.OutputDatum from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV2\.OutputDatum\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV2\.OutputDatum\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV2.OutputDatum].fromJson, @@ -465,9 +496,7 @@ describe("JSON tests (toJson . fromJson)", () => { it(`PlutusV2.TxOut from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV2\.TxOut\.[0-9]*\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV2\.TxOut\.[0-9]*\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, LbrPrelude.Json[LbrPlutusV2.TxOut].fromJson, @@ -477,4 +506,32 @@ describe("JSON tests (toJson . fromJson)", () => { Goldens.txOutGoldensV2(), ); }); + + it(`PlutusV2.TxInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV2\.TxInfo\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV2.TxInfo].fromJson, + LbrPrelude.Json[LbrPlutusV2.TxInfo].toJson, + PreludeJson.stringify, + ), + Goldens.txInfoGoldensV2(), + ); + }); + + it(`PlutusV2.ScriptContext from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV2\.ScriptPurpose\.[0-9]*\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + LbrPrelude.Json[LbrPlutusV2.ScriptContext].fromJson, + LbrPrelude.Json[LbrPlutusV2.ScriptContext].toJson, + PreludeJson.stringify, + ), + Goldens.scriptContextGoldensV2(), + ); + }); }); diff --git a/testsuites/lbt-plutus/lbt-plutus-typescript/src/PlutusData-test.ts b/testsuites/lbt-plutus/lbt-plutus-typescript/src/PlutusData-test.ts index 4a71ae3c..0350c8ee 100644 --- a/testsuites/lbt-plutus/lbt-plutus-typescript/src/PlutusData-test.ts +++ b/testsuites/lbt-plutus/lbt-plutus-typescript/src/PlutusData-test.ts @@ -26,21 +26,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Foo.A from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Foo\.A\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Foo\.A\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfFoo.A] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfFoo.A].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfFoo.A] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfFoo.A].toData(v), ), PreludeJson.stringify, ), @@ -51,21 +46,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Foo.B from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Foo\.B\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Foo\.B\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfFoo.B] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfFoo.B].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfFoo.B] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfFoo.B].toData(v), ), PreludeJson.stringify, ), @@ -76,21 +66,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Foo.C from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Foo\.C\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Foo\.C\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfFoo.C] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfFoo.C].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfFoo.C] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfFoo.C].toData(v), ), PreludeJson.stringify, ), @@ -101,21 +86,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Foo.D from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Foo\.D\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Foo\.D\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfFoo.D] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfFoo.D].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfFoo.D] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfFoo.D].toData(v), ), PreludeJson.stringify, ), @@ -126,21 +106,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Foo.FInt from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Foo\.FInt\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Foo\.FInt\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfFoo.FInt] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfFoo.FInt].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfFoo.FInt] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfFoo.FInt].toData(v), ), PreludeJson.stringify, ), @@ -151,21 +126,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Foo.GInt from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Foo\.GInt\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Foo\.GInt\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfFoo.GInt] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfFoo.GInt].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfFoo.GInt] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfFoo.GInt].toData(v), ), PreludeJson.stringify, ), @@ -178,21 +148,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Days.Day from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Days\.Day\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Days\.Day\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfDays.Day] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfDays.Day].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfDays.Day] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfDays.Day].toData(v), ), PreludeJson.stringify, ), @@ -203,21 +168,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Days.WorkDay from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Days\.WorkDay\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Days\.WorkDay\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfDays.WorkDay] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfDays.WorkDay].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfDays.WorkDay] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfDays.WorkDay].toData(v), ), PreludeJson.stringify, ), @@ -228,21 +188,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Days.FreeDay from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Days\.FreeDay\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Days\.FreeDay\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbfDays.FreeDay] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbfDays.FreeDay].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbfDays.FreeDay] - .toData(v), + LbrPlutusV1.IsPlutusData[LbfDays.FreeDay].toData(v), ), PreludeJson.stringify, ), @@ -255,21 +210,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.PlutusData from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.PlutusData\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.PlutusData\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.PlutusData] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.PlutusData].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.PlutusData] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.PlutusData].toData(v), ), PreludeJson.stringify, ), @@ -280,20 +230,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Address from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Address\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Address\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Address] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Address].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Address] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Address].toData(v), ), PreludeJson.stringify, ), @@ -304,20 +250,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Credential from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Credential\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Credential\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Credential] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Credential].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Credential] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Credential].toData(v), ), PreludeJson.stringify, ), @@ -334,14 +276,12 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.StakingCredential] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.StakingCredential].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.StakingCredential] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.StakingCredential].toData(v), ), PreludeJson.stringify, ), @@ -352,20 +292,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.PubKeyHash from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.PubKeyHash\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.PubKeyHash\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.PubKeyHash] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.PubKeyHash].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.PubKeyHash] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.PubKeyHash].toData(v), ), PreludeJson.stringify, ), @@ -376,20 +312,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Bytes from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Bytes\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Bytes\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.LedgerBytes] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.LedgerBytes].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.LedgerBytes] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.LedgerBytes].toData(v), ), PreludeJson.stringify, ), @@ -400,24 +332,18 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Interval from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Interval\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Interval\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Interval]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Interval]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Interval]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Interval]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).toData(v), ), PreludeJson.stringify, ), @@ -428,24 +354,18 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Extended from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Extended\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Extended\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Extended]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Extended]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Extended]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Extended]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).toData(v), ), PreludeJson.stringify, ), @@ -456,24 +376,18 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.LowerBound from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.LowerBound\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.LowerBound\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.LowerBound]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.LowerBound]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.LowerBound]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.LowerBound]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).toData(v), ), PreludeJson.stringify, ), @@ -484,24 +398,18 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.UpperBound from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.UpperBound\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.UpperBound\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.UpperBound]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.UpperBound]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.UpperBound]( - LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], - ) - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.UpperBound]( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime], + ).toData(v), ), PreludeJson.stringify, ), @@ -512,20 +420,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.POSIXTime from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.POSIXTime\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.POSIXTime\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.POSIXTime] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.POSIXTime] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTime].toData(v), ), PreludeJson.stringify, ), @@ -542,14 +446,12 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.POSIXTimeRange] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTimeRange].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.POSIXTimeRange] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.POSIXTimeRange].toData(v), ), PreludeJson.stringify, ), @@ -566,14 +468,12 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.CurrencySymbol] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.CurrencySymbol].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.CurrencySymbol] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.CurrencySymbol].toData(v), ), PreludeJson.stringify, ), @@ -586,20 +486,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.TokenName from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.TokenName\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.TokenName\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.TokenName] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TokenName].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.TokenName] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TokenName].toData(v), ), PreludeJson.stringify, ), @@ -610,20 +506,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.AssetClass from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.AssetClass\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.AssetClass\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.AssetClass] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.AssetClass].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.AssetClass] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.AssetClass].toData(v), ), PreludeJson.stringify, ), @@ -634,20 +526,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Value from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Value\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Value\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Value] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Value].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Value] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Value].toData(v), ), PreludeJson.stringify, ), @@ -658,20 +546,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Redeemer from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Redeemer\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Redeemer\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Redeemer] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Redeemer].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Redeemer] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Redeemer].toData(v), ), PreludeJson.stringify, ), @@ -682,20 +566,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Datum from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Datum\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Datum\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Datum] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Datum].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.Datum] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.Datum].toData(v), ), PreludeJson.stringify, ), @@ -712,14 +592,12 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.RedeemerHash] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.RedeemerHash].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.RedeemerHash] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.RedeemerHash].toData(v), ), PreludeJson.stringify, ), @@ -730,20 +608,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.DatumHash from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.DatumHash\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.DatumHash\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.DatumHash] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.DatumHash].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.DatumHash] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.DatumHash].toData(v), ), PreludeJson.stringify, ), @@ -754,20 +628,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.ScriptHash from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.ScriptHash\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.ScriptHash\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.ScriptHash] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.ScriptHash].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.ScriptHash] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.ScriptHash].toData(v), ), PreludeJson.stringify, ), @@ -778,20 +648,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.TxId from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.TxId\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.TxId\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.TxId] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxId].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.TxId] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxId].toData(v), ), PreludeJson.stringify, ), @@ -802,20 +668,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.TxOutRef from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.TxOutRef\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.TxOutRef\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.TxOutRef] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxOutRef].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV1.TxOutRef] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxOutRef].toData(v), ), PreludeJson.stringify, ), @@ -826,9 +688,7 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV1.Map from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV1\.Map\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV1\.Map\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => @@ -838,8 +698,7 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", LbrPlutusV1.IsPlutusData[LbrPlutusV1.TokenName], LbrPlutusV1.IsPlutusData[LbrPrelude.Integer], ), - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( LbrPlutusV1.IsPlutusData[LbrPlutusV1.Map]( @@ -848,8 +707,7 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", LbrPlutusV1.IsPlutusData[LbrPlutusV1.TokenName], LbrPlutusV1.IsPlutusData[LbrPrelude.Integer], ), - ) - .toData(v), + ).toData(v), ), PreludeJson.stringify, ), @@ -857,26 +715,143 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", ); }); - // TODO(jaredponn) TxInInfo V1 missing - // TODO(jaredponn) TxOut V1 missing + it(`PlutusV1.TxInInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.TxInInfo\.[0-9]*\.pd\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxInInfo].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxInInfo].toData(v), + ), + PreludeJson.stringify, + ), + Goldens.txInInfoGoldensV1(), + ); + }); - it(`PlutusV2.TxInInfo from to golden tests`, async () => { + it(`PlutusV1.TxOut from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.TxOut\.[0-9]*\.pd\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxOut].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxOut].toData(v), + ), + PreludeJson.stringify, + ), + Goldens.txOutGoldensV1(), + ); + }); + + it(`PlutusV1.DCert from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.DCert\.[0-9]*\.pd\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV1.DCert].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.DCert].toData(v), + ), + PreludeJson.stringify, + ), + Goldens.dCertGoldens(), + ); + }); + + it(`PlutusV1.ScriptPurpose from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, new Utils.RegExpFileFilter( - /^PlutusV2\.TxInInfo\.[0-9]*\.pd\.json$/g, + /^PlutusV1\.ScriptPurpose\.[0-9]*\.pd\.json$/g, + ), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV1.ScriptPurpose].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.ScriptPurpose].toData(v), + ), + PreludeJson.stringify, ), + Goldens.scriptPurposeGoldens(), + ); + }); + + it(`PlutusV1.TxInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV1\.TxInfo\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV2.TxInInfo] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxInfo].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV2.TxInInfo] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV1.TxInfo].toData(v), + ), + PreludeJson.stringify, + ), + Goldens.txInfoGoldensV1(), + ); + }); + + it(`PlutusV1.ScriptContext from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter( + /^PlutusV1\.ScriptContext\.[0-9]*\.pd\.json$/g, + ), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV1.ScriptContext].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV1.ScriptContext].toData(v), + ), + PreludeJson.stringify, + ), + Goldens.scriptContextGoldensV1(), + ); + }); + + it(`PlutusV2.TxInInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV2\.TxInInfo\.[0-9]*\.pd\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV2.TxInInfo].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV2.TxInInfo].toData(v), ), PreludeJson.stringify, ), @@ -893,14 +868,12 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV2.OutputDatum] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV2.OutputDatum].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV2.OutputDatum] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV2.OutputDatum].toData(v), ), PreludeJson.stringify, ), @@ -911,20 +884,16 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`PlutusV2.TxOut from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^PlutusV2\.TxOut\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^PlutusV2\.TxOut\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPlutusV2.TxOut] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPlutusV2.TxOut].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPlutusV2.TxOut] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPlutusV2.TxOut].toData(v), ), PreludeJson.stringify, ), @@ -933,25 +902,62 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", }); }); + it(`PlutusV2.TxInfo from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter(/^PlutusV2\.TxInfo\.[0-9]*\.pd\.json$/g), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV2.TxInfo].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV2.TxInfo].toData(v), + ), + PreludeJson.stringify, + ), + Goldens.txInfoGoldensV2(), + ); + }); + + it(`PlutusV2.ScriptContext from to golden tests`, async () => { + await Utils.fromToGoldenTest( + goldenDir, + new Utils.RegExpFileFilter( + /^PlutusV2\.ScriptContext\.[0-9]*\.pd\.json$/g, + ), + Utils.mkFromToAssertGolden( + PreludeJson.parseJson, + (v) => + LbrPlutusV1.IsPlutusData[LbrPlutusV2.ScriptContext].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), + (v) => + LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( + LbrPlutusV1.IsPlutusData[LbrPlutusV2.ScriptContext].toData(v), + ), + PreludeJson.stringify, + ), + Goldens.scriptContextGoldensV2(), + ); + }); + describe("Prelude tests", () => { it(`Prelude.Bool from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Prelude\.Bool\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Prelude\.Bool\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPrelude.Bool] - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool].fromData( + LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v), + ), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPrelude.Bool] - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool].toData(v), ), PreludeJson.stringify, ), @@ -962,25 +968,18 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Prelude.Maybe from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Prelude\.Maybe\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Prelude\.Maybe\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPrelude.Maybe]( - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPrelude.Maybe]( + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPrelude.Maybe]( - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - ) - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPrelude.Maybe]( + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + ).toData(v), ), PreludeJson.stringify, ), @@ -991,27 +990,20 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Prelude.Either from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Prelude\.Either\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Prelude\.Either\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPrelude.Either]( - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPrelude.Either]( + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPrelude.Either]( - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - ) - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPrelude.Either]( + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + ).toData(v), ), PreludeJson.stringify, ), @@ -1022,25 +1014,18 @@ describe("PlutusData tests (toJson . toPlutusData . fromPlutusData . fromJson)", it(`Prelude.List from to golden tests`, async () => { await Utils.fromToGoldenTest( goldenDir, - new Utils.RegExpFileFilter( - /^Prelude\.List\.[0-9]*\.pd\.json$/g, - ), + new Utils.RegExpFileFilter(/^Prelude\.List\.[0-9]*\.pd\.json$/g), Utils.mkFromToAssertGolden( PreludeJson.parseJson, (v) => - LbrPlutusV1 - .IsPlutusData[LbrPrelude.List]( - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - ) - .fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData] - .fromJson(v)), + LbrPlutusV1.IsPlutusData[LbrPrelude.List]( + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + ).fromData(LbrPrelude.Json[LbrPlutusV1.PlutusData].fromJson(v)), (v) => LbrPrelude.Json[LbrPlutusV1.PlutusData].toJson( - LbrPlutusV1 - .IsPlutusData[LbrPrelude.List]( - LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], - ) - .toData(v), + LbrPlutusV1.IsPlutusData[LbrPrelude.List]( + LbrPlutusV1.IsPlutusData[LbrPrelude.Bool], + ).toData(v), ), PreludeJson.stringify, ),