diff --git a/AVM/Class/Label.lean b/AVM/Class/Label.lean index 4e710da4..3fb4233c 100644 --- a/AVM/Class/Label.lean +++ b/AVM/Class/Label.lean @@ -69,6 +69,9 @@ def Label.dummy : Label where methodsRepr := inferInstanceAs (Repr PUnit) methodsBEq := inferInstanceAs (BEq PUnit) +def Label.logicRef (lab : Label) : Anoma.LogicRef := + ⟨"class-logic-" ++ lab.name⟩ + inductive Label.MemberId (lab : Class.Label) where | constructorId (constrId : lab.ConstructorId) : MemberId lab | destructorId (destructorId : lab.DestructorId) : MemberId lab diff --git a/AVM/Class/Translation/Logics.lean b/AVM/Class/Translation/Logics.lean index ba399d16..b990b7c0 100644 --- a/AVM/Class/Translation/Logics.lean +++ b/AVM/Class/Translation/Logics.lean @@ -85,14 +85,14 @@ private def Upgrade.Message.logicFun && selfRes.isPersistent && upgradedRes.isPersistent -/-- The class logic checks if all consumed messages in the action correspond to - class members, the single consumed object is the receiver, and there is - at least one message. -/ +/-- The class logic checks if the message consumed in the action is associated + with the same ecosystem, the `self` object is among the message recipients + and the number of recipients is equal to the number of consumed object + resources. The class logic also checks the class invariant for `self`. -/ private def logicFun {lab : Ecosystem.Label} {classId : lab.ClassId} (cl : Class classId) - (consumedMessageResources consumedObjectResources : List Anoma.Resource) (args : Logic.Args) : Bool := let try self : Object classId := Object.fromResource args.self @@ -100,16 +100,29 @@ private def logicFun match args.status with | Created => true | Consumed => - let nMessages := consumedMessageResources.length - let! [consumedObjectResource] : List Anoma.Resource := consumedObjectResources - let try consumedObject : Object classId := Object.fromResource consumedObjectResource - -- NOTE: consumedObject == self by definition of Logic.Args; we only check - -- that there are no other consumed objects - nMessages + 1 == (Logic.filterOutDummy args.consumed).length - && consumedMessageResources.all fun res => - let try msg : Message lab := Message.fromResource res - let! [recipient] := msg.recipients.toList - consumedObject.uid == recipient + let consumedObjectResources : List Anoma.Resource := Logic.selectObjectResources args.consumed + let! [consumedMessageResource] := Logic.selectMessageResources args.consumed + let try msg : Message lab := Message.fromResource consumedMessageResource + let recipients := msg.recipients.toList + self.uid ∈ recipients + && recipients.length == consumedObjectResources.length + -- Note that the message logics already check if the consumed object + -- resources have the right form, i.e., correspond to the self / selves. We + -- only need to check that the number of recipients is equal to the number + -- of consumed object resources, i.e., there are no extra recipients. The + -- class logic will be run for each consumed object, with `self` set to that + -- object, so it will be checked if every consumed object is among the + -- recipients. + +/-- The class logic that is the Resource Logic of each resource corresponding to + an object of this class. -/ +def logic + {lab : Ecosystem.Label} + {classId : lab.ClassId} + (cl : Class classId) + : Anoma.Logic := + { reference := classId.label.logicRef, + function := logicFun cl } def Constructor.Message.logic {lab : Ecosystem.Label} @@ -207,32 +220,4 @@ def MultiMethod.Message.logic { reference := ⟨s!"AVM.MultiMethod.{@repr _ lab.multiMethodsRepr multiId}"⟩, function args := MultiMethod.Message.logicFun method args data } -/-- The multiMethod logic checks that all consumed messages in the action correspond - to members in the ecosystem and the consumed objects are the receivers. -/ -private def logicFun - {lab : Ecosystem.Label} - (eco : Ecosystem lab) - (args : Logic.Args) - : Bool := - match args.status with - | Created => true - | Consumed => - let consumedMessageResources : List Anoma.Resource := Logic.selectMessageResources args.consumed - let nMessages := consumedMessageResources.length - let consumedObjectResources : List Anoma.Resource := Logic.selectObjectResources args.consumed - nMessages >= 1 - && consumedMessageResources.all fun res => - let try msg : Message lab := Message.fromResource res - match msg.id with - | .classMember (classId := cl) _ => AVM.Class.logicFun (eco.classes cl) consumedMessageResources consumedObjectResources args - | .multiMethodId multiId => - let try selves : multiId.Selves := multiId.ConsumedToSelves consumedObjectResources - nMessages + multiId.numObjectArgs == (Logic.filterOutDummy args.consumed).length - && Label.MultiMethodId.SelvesToVector selves (fun o => o.uid) ≍? msg.recipients - -def logic - {lab : Ecosystem.Label} - (eco : Ecosystem lab) - : Anoma.Logic := - { reference := lab.logicRef, - function := logicFun eco } +end AVM.Ecosystem diff --git a/AVM/Ecosystem/Label/Base.lean b/AVM/Ecosystem/Label/Base.lean index 7dcc7609..10c5fd8e 100644 --- a/AVM/Ecosystem/Label/Base.lean +++ b/AVM/Ecosystem/Label/Base.lean @@ -43,9 +43,6 @@ def Fin.classId namespace AVM.Ecosystem.Label -def logicRef (lab : Label) : Anoma.LogicRef := - ⟨"logic-of-ecosystem-" ++ lab.name⟩ - /-- Singleton ecosystem: An ecosystem with a single class, no multiMethods and no intents -/ def singleton (l : Class.Label) : Ecosystem.Label where name := l.name @@ -101,6 +98,7 @@ def ObjectArgNames {lab : Ecosystem.Label} (multiId : lab.MultiMethodId) : Type def ObjectArgNamesEnum {lab : Ecosystem.Label} (multiId : lab.MultiMethodId) : FinEnum (lab.MultiMethodObjectArgNames multiId) := lab.ObjectArgNamesEnum multiId +/-- The number of selves in a multi-method. -/ def numObjectArgs {lab : Ecosystem.Label} {multiId : lab.MultiMethodId} : Nat := (lab.ObjectArgNamesEnum multiId).card diff --git a/AVM/Logic.lean b/AVM/Logic.lean index 3b464b50..c5d84a13 100644 --- a/AVM/Logic.lean +++ b/AVM/Logic.lean @@ -21,7 +21,7 @@ def checkResourceValues (objectValues : List ObjectValue) (resources : List Anom where resourceValueEq (sdata : ObjectValue) (res : Anoma.Resource) : Bool := sdata.label === res.label && - sdata.label.logicRef == res.logicRef && + sdata.classId.label.logicRef == res.logicRef && sdata.data.quantity == res.quantity && let try resVal : Object.Resource.Value sdata.classId := tryCast res.value resVal.privateFields == sdata.data.privateFields && diff --git a/AVM/Object.lean b/AVM/Object.lean index d2776703..2d32c9bd 100644 --- a/AVM/Object.lean +++ b/AVM/Object.lean @@ -106,7 +106,7 @@ def SomeObject.toResource { label classId dynamicLabel := clab.DynamicLabel.mkDynamicLabel obj.data.privateFields } - logicRef := label.logicRef, + logicRef := classId.label.logicRef, quantity := obj.data.quantity, Val := ⟨Object.Resource.Value classId⟩, value := ⟨obj.uid, obj.data.privateFields⟩, @@ -126,7 +126,7 @@ def Object.fromResource let try resLab : AVM.Resource.Label := tryCast res.label let try objLab := Resource.Label.getObjectResourceLabel resLab check (objLab.label == lab) - check (res.logicRef == lab.logicRef) + check (res.logicRef == c.label.logicRef) let try value : Object.Resource.Value c := tryCast res.value some { uid := value.uid, data := ⟨res.quantity, value.privateFields⟩,