LF: Utility to enrich interface views (#14520)

CHANGELOG_BEGIN
CHANGELOG_END

* fix

* Add test
This commit is contained in:
Remy 2022-07-25 19:36:40 +02:00 committed by GitHub
parent 3a33b3bcde
commit 6caedfb0ca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 13 deletions

View File

@ -27,17 +27,15 @@ final class ValueEnricher(
loadPackage: (PackageId, language.Reference) => Result[Unit],
) {
def this(engine: Engine) = {
def this(engine: Engine) =
this(
engine.compiledPackages(),
engine.preprocessor.translateValue,
engine.loadPackage,
)
}
def enrichValue(typ: Ast.Type, value: Value): Result[Value] = {
def enrichValue(typ: Ast.Type, value: Value): Result[Value] =
translateValue(typ, value).map(_.toUnnormalizedValue)
}
def enrichVersionedValue(
typ: Ast.Type,
@ -61,6 +59,29 @@ final class ValueEnricher(
arg <- enrichValue(Ast.TTyCon(contract.unversioned.template), contract.unversioned.arg)
} yield contract.map(_.copy(arg = arg))
def enrichView(
interfaceId: Identifier,
viewValue: Value,
): Result[Value] = for {
// TODO: https://github.com/digital-asset/daml/issues/14112
// Switch to builtin views once those are implemented.
method <- handleLookup(
compiledPackages.pkgInterface.lookupInterfaceMethod(
interfaceId,
Name.assertFromString("_view"),
)
)
viewType = method.returnType
r <- enrichValue(viewType, viewValue)
} yield r
def enrichVersionedView(
interfaceId: Identifier,
viewValue: VersionedValue,
): Result[VersionedValue] = for {
view <- enrichView(interfaceId, viewValue.unversioned)
} yield viewValue.copy(unversioned = view)
def enrichContract(tyCon: Identifier, value: Value): Result[Value] =
enrichValue(Ast.TTyCon(tyCon), value)

View File

@ -52,6 +52,21 @@ class ValueEnricherSpec extends AnyWordSpec with Matchers with TableDrivenProper
\(contract: Mod:Contract) ->
Mod:keyParties (Mod:Contract {key} contract);
record @serializable View = {
signatory: List Party,
cids: List (ContractId Mod:Contract)
};
interface (this: I) = {
precondition True;
method _view : Mod:View;
};
interface (this: J) = {
precondition True;
method _view : Int64;
};
template (this : Contract) = {
precondition True;
signatories Mod:contractParties this;
@ -62,6 +77,12 @@ class ValueEnricherSpec extends AnyWordSpec with Matchers with TableDrivenProper
Mod:contractParties this
to
upure @Mod:Record r;
implements Mod:I {
method _view = Mod:View { signatory = Mod:contractParties this, cids = Mod:Contract {cids} this } ;
};
implements Mod:J {
method _view = 42;
};
key @Mod:Key (Mod:Contract {key} this) Mod:keyParties;
};
}
@ -69,9 +90,12 @@ class ValueEnricherSpec extends AnyWordSpec with Matchers with TableDrivenProper
"""
private[this] val engine = Engine.DevEngine()
engine
.preloadPackage(defaultPackageId, pkg)
.consume(_ => None, _ => None, _ => None)
.left
.foreach(err => sys.error(err.message))
private[this] val enricher = new ValueEnricher(engine)
@ -125,12 +149,43 @@ class ValueEnricherSpec extends AnyWordSpec with Matchers with TableDrivenProper
)
"enrich values as expected" in {
forAll(testCases) { (typ, input, output) =>
forEvery(testCases) { (typ, input, output) =>
enricher.enrichValue(typ, input) shouldBe ResultDone(output)
}
}
}
"enrichValue" should {
val alice = Ref.Party.assertFromString("alice")
val view = Value.ValueRecord(
None,
ImmArray(
None -> ValueList(FrontStack(ValueParty(alice))),
None -> ValueList(FrontStack(ValueContractId(cid("#contractId").coid))),
),
)
val enrichedView = Value.ValueRecord(
Some("Mod:View": Ref.Identifier),
ImmArray(
Some("signatory": Ref.Name) -> ValueList(FrontStack(ValueParty(alice))),
Some("cids": Ref.Name) -> ValueList(FrontStack(ValueContractId(cid("#contractId").coid))),
),
)
val testCases = Table[Ref.Identifier, Value, Value](
("interfaceId", "contract input", "expected output"),
("Mod:I", view, enrichedView),
("Mod:J", ValueInt64(42L), ValueInt64(42L)),
)
"enrich views as expected" in {
forEvery(testCases) { (ifaceId, input, output) =>
enricher.enrichView(ifaceId, input) shouldBe ResultDone(output)
}
}
}
"enrichTransaction" should {
def buildTransaction(

View File

@ -186,11 +186,11 @@ private[parser] class ExprParser[P](parserParameters: ParserParameters[P]) {
rep1sep(binding(`<-`), `;`) <~! `in` ^^ (_.to(ImmArray))
private def binding(sep: Token): Parser[Binding] =
id ~ (`:` ~> typ) ~ (sep ~> expr) ^^ { case vName ~ t ~ value =>
Binding(Some(vName), t, value)
Id("_") ~> (`:` ~> typ) ~ (sep ~> expr) ^^ { case t ~ value =>
Binding(None, t, value)
} |
`_` ~> (`:` ~> typ) ~ (sep ~> expr) ^^ { case t ~ value =>
Binding(None, t, value)
id ~ (`:` ~> typ) ~ (sep ~> expr) ^^ { case vName ~ t ~ value =>
Binding(Some(vName), t, value)
}
private lazy val eLet: Parser[Expr] =
@ -278,7 +278,8 @@ private[parser] class ExprParser[P](parserParameters: ParserParameters[P]) {
}
private lazy val pattern: Parser[CasePat] =
primCon ^^ CPPrimCon |
Id("_") ^^^ CPDefault |
primCon ^^ CPPrimCon |
(`nil` ^^^ CPNil) |
(`cons` ~>! id ~ id ^^ { case x1 ~ x2 => CPCons(x1, x2) }) |
(`none` ^^^ CPNone) |
@ -288,8 +289,7 @@ private[parser] class ExprParser[P](parserParameters: ParserParameters[P]) {
CPVariant(tyCon, vName, x)
case tyCon ~ vName ~ None =>
CPEnum(tyCon, vName)
} |
Token.`_` ^^^ CPDefault
}
private lazy val alternative: Parser[CaseAlt] =
pattern ~! (`->` ~>! expr) ^^ { case p ~ e =>

View File

@ -75,7 +75,6 @@ private[parser] object Lexer extends RegexParsers {
"]" ^^^ `]` |
"*" ^^^ `*` |
"=" ^^^ `=` |
"_" ^^^ Token.`_` |
"|" ^^^ `|` |
"""[a-zA-Z_\$][\w\$]*""".r ^^ (s => keywords.getOrElse(s, Id(s))) |
"""#\w+""".r ^^ ContractId |