Runner
This module provides the execution harness for the Ping-Pong example using the AVM.Interpreter.
{-# OPTIONS --type-in-type --guardedness #-} module examples.PingPong.Runner where open import Background.BasicTypes open import Background.InteractionTrees as IT hiding (_>>=_) open import examples.PingPong.Main as PP open import examples.RunnerUtilities hiding (initialState) open import examples.Common.Equality
Display Functions
showOid : PP.ObjectId → String showOid (_ , id) = id {-# TERMINATING #-} showValAgda : PP.Val → String showValAgda (PP.VInt n) = "(VInt " ++ˢ showNat n ++ˢ ")" showValAgda (PP.VString s) = "\"" ++ˢ s ++ˢ "\"" showValAgda (PP.VList []) = "[]" showValAgda (PP.VList (x ∷ xs)) = showValAgda x ++ˢ " :: " ++ˢ showValAgda (PP.VList xs) showValAgda (PP.VPingPongMsg record { msgType = PP.Ping ; counter = c }) = "(VPingPongMsg Ping " ++ˢ showNat c ++ˢ ")" showValAgda (PP.VPingPongMsg record { msgType = PP.Pong ; counter = c }) = "(VPingPongMsg Pong " ++ˢ showNat c ++ˢ ")"
-- Fresh ID generators freshObjectId : ℕ → PP.ObjectId freshObjectId n = ("node1" , "obj-" ++ˢ showNat n) freshTxId : ℕ → PP.TxId freshTxId n = n -- Import AVM Interpreter with our types and generators -- We'll instantiate Object with ObjectImpl after we define it below module InterpreterImport where open import AVM.Interpreter PP.Val PP.ObjectId freshObjectId PP.MachineId PP.ControllerId PP.TxId freshTxId public
Interpreter Parameterization
-- Equality for ObjectId (pairs of strings) eqObjectId : PP.ObjectId → PP.ObjectId → Bool eqObjectId (node1 , id1) (node2 , id2) = caseMaybe (node1 ≟-string node2) (λ _ → caseMaybe (id1 ≟-string id2) (λ _ → true) false) false -- Equality for TxId (natural numbers) eqTxId : PP.TxId → PP.TxId → Bool eqTxId = _==ℕ_ -- Concrete implementation of ObjectBehaviour type -- ObjectBehaviour is concretely defined as AVMProgram (List Val) -- We use a named reference approach: String names map to concrete AVMProgram values data ObjectBehaviourImpl : Set where namedBehaviour : String → ObjectBehaviourImpl -- Now open the AVM.Interpreter module with ObjectBehaviourImpl to get AVMProgram types open import AVM.Interpreter PP.Val PP.ObjectId freshObjectId PP.MachineId PP.ControllerId PP.TxId freshTxId ObjectBehaviourImpl open import examples.Common.StateInit PP.Val PP.ObjectId PP.MachineId PP.ControllerId PP.TxId ObjectBehaviourImpl open import examples.Common.Display PP.Val PP.ObjectId PP.TxId PP.ControllerId PP.MachineId ObjectBehaviourImpl showValAgda showOid showNat (λ s → s) (λ s → s) hiding (showNat) -- Reachability predicates eqControllerId : PP.ControllerId → PP.ControllerId → Bool eqControllerId = eqString -- Use message type from Main module open PP using (MessageType; Ping; Pong)
-- Helper to extract PingPongMsg from Val extractMsg : PP.Val → Maybe PP.PingPongMsg extractMsg (PP.VPingPongMsg msg) = just msg extractMsg _ = nothing
-- Helper to construct next message mkNextMsg : MessageType → PP.PingPongMsg → PP.ObjectId → PP.Val mkNextMsg msgType msg myId = PP.VPingPongMsg (PP.mkMsg msgType (suc (PP.PingPongMsg.counter msg)) myId (PP.PingPongMsg.maxCount msg)) -- Generic ping-pong behavior implementation genericPingPongBehavior : MessageType → String → AVMProgram (List PP.Val) genericPingPongBehavior responseType role = IT._>>=_ (trigger (Introspect input)) λ inp → IT._>>=_ (trigger (Introspect self)) λ myId → caseMaybe (extractMsg inp) (λ msg → (if PP.PingPongMsg.counter msg <? PP.PingPongMsg.maxCount msg then (IT._>>=_ (trigger (Obj (call (PP.PingPongMsg.partnerId msg) (mkNextMsg responseType msg myId)))) λ _ → ret (PP.VString (role ++ˢ "-continue") ∷ [])) else ret (PP.VString (role ++ˢ "-done") ∷ []))) (ret (PP.VString (role ++ˢ "-decode-failed") ∷ [])) -- Ping object behavioral specification: processes incoming messages and generates Pong responses pingBehaviorImpl : AVMProgram (List PP.Val) pingBehaviorImpl = genericPingPongBehavior Pong "ping" -- Pong object behavioral specification: processes incoming messages and generates Ping responses pongBehaviorImpl : AVMProgram (List PP.Val) pongBehaviorImpl = genericPingPongBehavior Ping "pong" -- Interpret behavior name to ObjectBehaviourImpl (used by createObj instruction) -- This maps behavior names to our named reference type interpretBehaviorName : String → ObjectBehaviourImpl interpretBehaviorName s = namedBehaviour s -- Extract all object IDs from the state -- For this simple example, we collect IDs from observed objects and pending creates -- A more complete implementation would maintain a global registry allObjectIds : State → List PP.ObjectId allObjectIds st = State.observed st ++ map (λ { (oid , _ , _) → oid }) (State.creates st) -- Convert ObjectBehaviour to AVMProgram -- Maps behavior names to their concrete implementations getBehavior : ObjectBehaviourImpl → AVMProgram (List PP.Val) getBehavior (namedBehaviour "ping") = pingBehaviorImpl getBehavior (namedBehaviour "pong") = pongBehaviorImpl getBehavior (namedBehaviour _) = ret [] -- Default: empty behavior mkControllerId : String → PP.ControllerId mkControllerId s = s -- Instantiate the interpreter with type-specific equality functions -- This replaces the broken generic equality with proper implementations module RunnerInterpreter where {-# TERMINATING #-} mutual -- Forward reference to the full interpreter interpretAVMProgramRec : ∀ {A} → AVMProgram A → State → AVMResult A interpretAVMProgramRec = interp.interpretAVMProgram where module interp = Interpreter eqObjectId eqTxId eqControllerId allObjectIds interpretBehaviorName getBehavior (isReachableController {PP.ControllerId}) (isReachableMachine {PP.MachineId}) mkControllerId interpretAVMProgramRec -- Now open the interpreter with the recursive reference open Interpreter eqObjectId eqTxId eqControllerId allObjectIds interpretBehaviorName getBehavior (isReachableController {PP.ControllerId}) (isReachableMachine {PP.MachineId}) mkControllerId interpretAVMProgramRec public open RunnerInterpreter public
Initial State
initialState : State initialState = mkInitialState "node1" ("root", "orchestrator") (VString "")
Test Programs
testSimple : AVMProgram PP.Val testSimple = IT._>>=_ (trigger (obj-create "pong" nothing)) λ pongId → let msg = PP.VPingPongMsg (PP.mkMsg PP.Ping 0 pongId 1) in IT._>>=_ (trigger (obj-call pongId msg)) λ mResult → caseMaybe mResult (λ result → ret result) (ret (PP.VString "call-failed")) test : AVMProgram PP.Val test = IT._>>=_ (trigger (Tx (beginTx nothing))) λ txid → IT._>>=_ (trigger (obj-create "pong" nothing)) λ pongId → IT._>>=_ (trigger (obj-create "ping" nothing)) λ pingId → IT._>>=_ (trigger (Tx (commitTx txid))) λ _ → let initialMsg = PP.VPingPongMsg (PP.mkMsg PP.Ping 0 pongId 5) in IT._>>=_ (trigger (obj-call pingId initialMsg)) λ mResult → caseMaybe mResult (λ result → ret (PP.VList (PP.VString "complete" ∷ result ∷ []))) (ret (PP.VString "call-failed")) runExample : String → AVMProgram PP.Val → PrimIO ⊤ runExample title prog = do putStrLn ("=== " ++ˢ title ++ˢ " ===") putStrLn "" let result = interpretAVMProgram prog initialState putStrLn (showResult showValAgda result) putStrLn "" main : PrimIO ⊤ main = do runExample "Simple Pong Test" testSimple putStrLn "" runExample "Ping-Pong Example" test putStrLn "Done!"
Module References
References
This module references:
- AVM.Context
- AVM.Instruction
- Imports: AVMProgram, obj-call, obj-create
- AVM.Interpreter
- Imports: Interpreter
- Background.BasicTypes
- Background.InteractionTrees
- examples.Battleship.Game
- Imports: GameState, gameWithRollback, playFullGame, playGameWithPlayerType
- examples.Battleship.PlayerBoard
- Imports: VCoord, VShip, boardBehavior
- examples.Common.Display
- Imports: showResult
- examples.Common.Equality
- Imports: eqString, isReachableController, isReachableMachine
- examples.Common.StateInit
- Imports: mkInitialState