From 5043dd13fd63d5328e0843bb616a7e2a878ad5a8 Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Mon, 19 Jan 2026 12:56:11 +0100 Subject: [PATCH 1/8] feat: add chameneos example --- chameneos/chameneos.pkl | 53 +++++++++++++++++++++++++++++++++++++++++ chameneos/main.pkl | 14 +++++++++++ chameneos/mall.pkl | 53 +++++++++++++++++++++++++++++++++++++++++ chameneos/services.pkl | 4 ++++ 4 files changed, 124 insertions(+) create mode 100644 chameneos/chameneos.pkl create mode 100644 chameneos/main.pkl create mode 100644 chameneos/mall.pkl create mode 100644 chameneos/services.pkl diff --git a/chameneos/chameneos.pkl b/chameneos/chameneos.pkl new file mode 100644 index 0000000..8c4e0e2 --- /dev/null +++ b/chameneos/chameneos.pkl @@ -0,0 +1,53 @@ +import + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + +sm = new csml.StateMachine { + transient { + ["chameneosId"] = "std:getUniqueId()" + ["color"] = "std:getRandomColor()" + ["individualMeetingCounter"] = "0" + } + states { + ["requestingPartner"] = new csml.Initial { + entry { + new csml.Raise { + event = new csml.Global { + topic = "requestingPartner" + data { ["chameneosId"] = "chameneosId"; ["chameneosColor"] = "color" } + } + } + } + on { + ["matchMade"] = new csml.Transition { + to = "matchFound" + iif = "$chameneos == chameneosId" + } + ["change"] = new csml.Transition { + to = "requestingPartner" + iif = "$partner == chameneosId" + do { + new csml.Eval { expression = "color = std:complement(color, $color)" } + new csml.Eval { expression = "individualMeetingCounter = individualMeetingCounter + 1" } + } + } + ["done"] = new csml.Transition { + to = "done" + } + } + } + ["matchFound"] = new csml.State { + entry { + new csml.Eval { expression = "color = std:complement(color, $color)" } + new csml.Eval { expression = "individualMeetingCounter = individualMeetingCounter + 1" } + new csml.Raise { + event = new csml.Global { + topic = "change" + data { ["partner"] = "$partner"; ["color"] = "color" } + } + } + } + always { new csml.Transition { to = "requestingPartner" } } + } + ["done"] = new csml.Terminal {} + } +} diff --git a/chameneos/main.pkl b/chameneos/main.pkl new file mode 100644 index 0000000..cf5bda8 --- /dev/null +++ b/chameneos/main.pkl @@ -0,0 +1,14 @@ +amends + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + +import "chameneos.pkl" +import "defs.pkl" +import "mall.pkl" + +version = "4.0.0" +stateMachines { + ["mall"] = mall.sm + for (_def in defs.chameneos) { + [_def] = chameneos.sm + } +} diff --git a/chameneos/mall.pkl b/chameneos/mall.pkl new file mode 100644 index 0000000..283863b --- /dev/null +++ b/chameneos/mall.pkl @@ -0,0 +1,53 @@ +import + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + +sm = new csml.StateMachine { + transient { + ["waitingList"] = "[...]" + ["meetingCounter"] = "0" + } + states { + ["waitingForChameneos"] = new csml.Initial { + on { + ["requestingPartner"] = new csml.Transition { + to = "waitingForChameneos" + iif = "waitingList.isEmpty() && meetingCounter < 1000000" + do { + new csml.Eval { + expression = "waitingList = std:addToList(\("waitingList"), $chameneosId)" + } + } + or = "scheduleMeeting" + } + } + } + ["scheduleMeeting"] = new csml.State { + always { + new csml.Transition { + to = "waitingForChameneos" + iif = "!waitingList.isEmpty() && meetingCounter < 1000000" + do { + new csml.Eval { expression = "meetingCounter = meetingCounter + 1" } + new csml.Raise { + event = new csml.Global { + topic = "matchMade" + data { + ["chameneos"] = "waitingList.get(0)" + ["partner"] = "$chameneosId" + ["color"] = "$chameneosColor" + } + } + } + new csml.Eval { expression = "waitingList = std:removeFirst(\("waitingList"))" } + } + or = "done" + } + } + } + ["done"] = new csml.Terminal { + entry { + new csml.Raise { event = new csml.Global { topic = "done" } } + } + } + } +} diff --git a/chameneos/services.pkl b/chameneos/services.pkl new file mode 100644 index 0000000..07c151f --- /dev/null +++ b/chameneos/services.pkl @@ -0,0 +1,4 @@ +amends + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/bindings.pkl" + +bindings {} From 9eb063ba8f3326ed4a5241da2e727ccf9001fcfa Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Wed, 28 Jan 2026 11:00:35 +0100 Subject: [PATCH 2/8] fix: remove use of std functions from chameneos example --- chameneos/chameneos.pkl | 23 +++++++++++++++++------ chameneos/defs.pkl | 8 ++++++++ chameneos/main.pkl | 4 ++-- chameneos/mall.pkl | 8 ++++---- 4 files changed, 31 insertions(+), 12 deletions(-) create mode 100644 chameneos/defs.pkl diff --git a/chameneos/chameneos.pkl b/chameneos/chameneos.pkl index 8c4e0e2..3559263 100644 --- a/chameneos/chameneos.pkl +++ b/chameneos/chameneos.pkl @@ -1,10 +1,15 @@ import "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" -sm = new csml.StateMachine { +import "defs.pkl" + +function complement(myColor: String, otherColor: String): String = + defs.colorComplementMap[myColor][otherColor] + +function createChameneos(id: Int) = new csml.StateMachine { transient { - ["chameneosId"] = "std:getUniqueId()" - ["color"] = "std:getRandomColor()" + ["chameneosId"] = "\(id)" + ["color"] = "std:takeRandom([1,2,3,...])" ["individualMeetingCounter"] = "0" } states { @@ -26,7 +31,10 @@ sm = new csml.StateMachine { to = "requestingPartner" iif = "$partner == chameneosId" do { - new csml.Eval { expression = "color = std:complement(color, $color)" } + new csml.Eval { + expression = + "color = (function (x,y) { if (x == y) {x} else {x ^ y} })(color, $color)" + } new csml.Eval { expression = "individualMeetingCounter = individualMeetingCounter + 1" } } } @@ -37,7 +45,6 @@ sm = new csml.StateMachine { } ["matchFound"] = new csml.State { entry { - new csml.Eval { expression = "color = std:complement(color, $color)" } new csml.Eval { expression = "individualMeetingCounter = individualMeetingCounter + 1" } new csml.Raise { event = new csml.Global { @@ -45,8 +52,12 @@ sm = new csml.StateMachine { data { ["partner"] = "$partner"; ["color"] = "color" } } } + + new csml.Eval { + expression = "color = (function (x,y) { if (x == y) {x} else {x ^ y} })(color, $color)" + } } - always { new csml.Transition { to = "requestingPartner" } } + always { new csml.Transition { to = "requestingPartner"; iif = "color < 4"; or = "done" } } } ["done"] = new csml.Terminal {} } diff --git a/chameneos/defs.pkl b/chameneos/defs.pkl new file mode 100644 index 0000000..65d735c --- /dev/null +++ b/chameneos/defs.pkl @@ -0,0 +1,8 @@ +chameneos = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) + +colorComplementMap = + Map( + "RED", Map("RED", "RED", "YELLOW", "BLUE", "BLUE", "YELLOW"), + "YELLOW", Map("RED", "BLUE", "YELLOW", "YELLOW", "BLUE", "RED"), + "BLUE", Map("RED", "YELLOW", "YELLOW", "RED", "BLUE", "RED") + ) diff --git a/chameneos/main.pkl b/chameneos/main.pkl index cf5bda8..01777ba 100644 --- a/chameneos/main.pkl +++ b/chameneos/main.pkl @@ -8,7 +8,7 @@ import "mall.pkl" version = "4.0.0" stateMachines { ["mall"] = mall.sm - for (_def in defs.chameneos) { - [_def] = chameneos.sm + for (c in defs.chameneos) { + [c.toString()] = chameneos.createChameneos(c) } } diff --git a/chameneos/mall.pkl b/chameneos/mall.pkl index 283863b..b22c650 100644 --- a/chameneos/mall.pkl +++ b/chameneos/mall.pkl @@ -11,10 +11,10 @@ sm = new csml.StateMachine { on { ["requestingPartner"] = new csml.Transition { to = "waitingForChameneos" - iif = "waitingList.isEmpty() && meetingCounter < 1000000" + iif = "waitingList.isEmpty() && meetingCounter < 20000" do { new csml.Eval { - expression = "waitingList = std:addToList(\("waitingList"), $chameneosId)" + expression = "waitingList = waitingList + [$chameneosId]" } } or = "scheduleMeeting" @@ -25,7 +25,7 @@ sm = new csml.StateMachine { always { new csml.Transition { to = "waitingForChameneos" - iif = "!waitingList.isEmpty() && meetingCounter < 1000000" + iif = "!waitingList.isEmpty() && meetingCounter < 20000" do { new csml.Eval { expression = "meetingCounter = meetingCounter + 1" } new csml.Raise { @@ -38,7 +38,7 @@ sm = new csml.StateMachine { } } } - new csml.Eval { expression = "waitingList = std:removeFirst(\("waitingList"))" } + new csml.Eval { expression = "waitingList = waitingList - [waitingList.get(0)]" } } or = "done" } From 1a5d9a07829489fc76ee4c6b4b55d80ea731e59c Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Wed, 21 Jan 2026 13:26:51 +0100 Subject: [PATCH 3/8] feat: add big example --- big/big.pkl | 92 +++++++++++++++++++++++++++++++ big/defs.pkl | 1 + big/main.pkl | 14 +++++ big/services.pkl | 4 ++ big/sink.pkl | 59 ++++++++++++++++++++ pingpong/benchmark/Akka.txt | 31 ----------- pingpong/benchmark/AkkaRemote.txt | 30 ---------- 7 files changed, 170 insertions(+), 61 deletions(-) create mode 100644 big/big.pkl create mode 100644 big/defs.pkl create mode 100644 big/main.pkl create mode 100644 big/services.pkl create mode 100644 big/sink.pkl delete mode 100644 pingpong/benchmark/Akka.txt delete mode 100644 pingpong/benchmark/AkkaRemote.txt diff --git a/big/big.pkl b/big/big.pkl new file mode 100644 index 0000000..3ac9522 --- /dev/null +++ b/big/big.pkl @@ -0,0 +1,92 @@ +import + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + +sm = new csml.StateMachine { + transient { + ["bigId"] = "std:getSequentialId()" + ["target"] = "''" + ["otherBigs"] = "[...]" + ["pingCounter"] = "0" + ["pongCounter"] = "0" + } + states { + ["registerBig"] = new csml.Initial { + entry { + new csml.Raise { + event = new csml.Global { topic = "registerBig"; data { ["bigId"] = "bigId" } } + } + } + on { + ["allBigsRegistered"] = new csml.Transition { + to = "sendPing" + do { + new csml.Eval { expression = "otherBigs = std:getAllStateMachines()" } + new csml.Eval { + expression = "otherBigs = std:removeFromList(\("otherBigs"), \("bigId"))" + } + } + } + } + } + ["sendPing"] = new csml.State { + always { + new csml.Transition { + to = "waitForPingOrPong" + iif = "pingCounter < 20000" + do { + new csml.Eval { expression = "pingCounter = pingCounter + 1" } + new csml.Eval { expression = "target = std:takeRandom(\("otherBigs"))" } + new csml.Raise { + event = new csml.Global { + topic = "ping" + data { ["sender"] = "bigId"; ["receiver"] = "target" } + } + } + } + or = "receiveRemaining" + } + } + } + ["waitForPingOrPong"] = new csml.State { + on { + ["ping"] = new csml.Transition { + iif = "$sender != bigId && $receiver == bigId" + do { + new csml.Raise { + event = new csml.Global { + topic = "pong" + data { ["sender"] = "bigId"; ["receiver"] = "$sender" } + } + } + } + } + ["pong"] = new csml.Transition { + iif = "$receiver == bigId && $sender == target" + to = "sendPing" + } + } + } + ["receiveRemaining"] = new csml.State { + entry { + new csml.Raise { event = new csml.Global { topic = "donePinging" } } + } + on { + ["ping"] = new csml.Transition { + iif = "$sender != bigId && $receiver == bigId" + do { + new csml.Raise { + event = new csml.Global { + topic = "pong" + data { ["sender"] = "bigId"; ["receiver"] = "$sender" } + } + } + } + } + ["shutdown"] = new csml.Transition { + to = "done" + } + } + } + ["done"] = new csml.Terminal {} + } +} diff --git a/big/defs.pkl b/big/defs.pkl new file mode 100644 index 0000000..b9bdb2c --- /dev/null +++ b/big/defs.pkl @@ -0,0 +1 @@ +bigs = List("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11") diff --git a/big/main.pkl b/big/main.pkl new file mode 100644 index 0000000..fc70794 --- /dev/null +++ b/big/main.pkl @@ -0,0 +1,14 @@ +amends + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + +import "big.pkl" +import "defs.pkl" +import "sink.pkl" + +version = "4.0.0" +stateMachines { + ["sink"] = sink.sm + for (_def in defs.bigs) { + [_def] = big.sm + } +} diff --git a/big/services.pkl b/big/services.pkl new file mode 100644 index 0000000..07c151f --- /dev/null +++ b/big/services.pkl @@ -0,0 +1,4 @@ +amends + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/bindings.pkl" + +bindings {} diff --git a/big/sink.pkl b/big/sink.pkl new file mode 100644 index 0000000..f1f64e2 --- /dev/null +++ b/big/sink.pkl @@ -0,0 +1,59 @@ +import + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + +sm = new csml.StateMachine { + transient { + ["registered"] = "''" + ["registeredCounter"] = "0" + ["doneCounter"] = "0" + ["cumulatedPongCounter"] = "0" + } + states { + ["registerBigs"] = new csml.Initial { + on { + ["registerBig"] = new csml.Transition { + to = "evaluateAllBigsReceived" + do { + new csml.Eval { expression = "registeredCounter = registeredCounter + 1" } + new csml.Eval { expression = "registered = std:registerStateMachine(\("$bigId"))" } + } + } + } + } + ["evaluateAllBigsReceived"] = new csml.State { + always { + new csml.Transition { + to = "waitingForBigs" + iif = "registeredCounter == 12" + do { + new csml.Raise { event = new csml.Global { topic = "allBigsRegistered" } } + } + or = "registerBigs" + } + } + } + ["waitingForBigs"] = new csml.State { + on { + ["donePinging"] = new csml.Transition { + to = "isFinal" + do { + new csml.Eval { expression = "doneCounter = doneCounter + 1" } + } + } + } + } + ["isFinal"] = new csml.State { + always { + new csml.Transition { + to = "done" + iif = "doneCounter == 12" + do { + new csml.Raise { event = new csml.Global { topic = "shutdown" } } + } + or = "waitingForBigs" + } + } + } + ["done"] = new csml.Terminal {} + } +} diff --git a/pingpong/benchmark/Akka.txt b/pingpong/benchmark/Akka.txt deleted file mode 100644 index f8f6882..0000000 --- a/pingpong/benchmark/Akka.txt +++ /dev/null @@ -1,31 +0,0 @@ -Number of pings: 50.000 -Execution - Iterations: -PingPongAkkaActorBenchmark Iteration-0: 316.151 ms -PingPongAkkaActorBenchmark Iteration-1: 118.366 ms -PingPongAkkaActorBenchmark Iteration-2: 77.245 ms -PingPongAkkaActorBenchmark Iteration-3: 84.737 ms -PingPongAkkaActorBenchmark Iteration-4: 70.632 ms -PingPongAkkaActorBenchmark Iteration-5: 76.096 ms -PingPongAkkaActorBenchmark Iteration-6: 72.107 ms -PingPongAkkaActorBenchmark Iteration-7: 67.815 ms -PingPongAkkaActorBenchmark Iteration-8: 64.724 ms -PingPongAkkaActorBenchmark Iteration-9: 65.730 ms -PingPongAkkaActorBenchmark Iteration-10: 68.262 ms -PingPongAkkaActorBenchmark Iteration-11: 64.844 ms - - -Execution - Summary: - Total executions = 12 - Filtered executions = 10 -PingPongAkkaActorBenchmark Best Time: 64.724 ms -PingPongAkkaActorBenchmark Worst Time: 84.737 ms -PingPongAkkaActorBenchmark Median: 69.447 ms -PingPongAkkaActorBenchmark Arith. Mean Time: 71.219 ms -PingPongAkkaActorBenchmark Geo. Mean Time: 70.966 ms -PingPongAkkaActorBenchmark Harmonic Mean Time: 70.724 ms -PingPongAkkaActorBenchmark Std. Dev Time: 6.142 ms -PingPongAkkaActorBenchmark Lower Confidence: 67.412 ms -PingPongAkkaActorBenchmark Higher Confidence: 75.026 ms -PingPongAkkaActorBenchmark Error Window: 3.807 ms (5.345 percent) -PingPongAkkaActorBenchmark Coeff. of Variation: 0.086 -PingPongAkkaActorBenchmark Skewness: 0.979 \ No newline at end of file diff --git a/pingpong/benchmark/AkkaRemote.txt b/pingpong/benchmark/AkkaRemote.txt deleted file mode 100644 index 8f63738..0000000 --- a/pingpong/benchmark/AkkaRemote.txt +++ /dev/null @@ -1,30 +0,0 @@ -Number of pings: 50.000 -Execution - Iterations: -PingPongAkkaActorBenchmark Iteration-0: 30511.704 ms -PingPongAkkaActorBenchmark Iteration-1: 25736.073 ms -PingPongAkkaActorBenchmark Iteration-2: 30145.372 ms -PingPongAkkaActorBenchmark Iteration-3: 31287.985 ms -PingPongAkkaActorBenchmark Iteration-4: 33002.205 ms -PingPongAkkaActorBenchmark Iteration-5: 30022.782 ms -PingPongAkkaActorBenchmark Iteration-6: 31745.709 ms -PingPongAkkaActorBenchmark Iteration-7: 32723.041 ms -PingPongAkkaActorBenchmark Iteration-8: 32083.870 ms -PingPongAkkaActorBenchmark Iteration-9: 29523.999 ms -PingPongAkkaActorBenchmark Iteration-10: 24884.690 ms -PingPongAkkaActorBenchmark Iteration-11: 28197.974 ms - -Execution - Summary: - Total executions = 12 - Filtered executions = 12 -PingPongAkkaActorBenchmark Best Time: 24884.690 ms -PingPongAkkaActorBenchmark Worst Time: 33002.205 ms -PingPongAkkaActorBenchmark Median: 30328.538 ms -PingPongAkkaActorBenchmark Arith. Mean Time: 29988.784 ms -PingPongAkkaActorBenchmark Geo. Mean Time: 29881.058 ms -PingPongAkkaActorBenchmark Harmonic Mean Time: 29767.749 ms -PingPongAkkaActorBenchmark Std. Dev Time: 2476.228 ms -PingPongAkkaActorBenchmark Lower Confidence: 28587.726 ms -PingPongAkkaActorBenchmark Higher Confidence: 31389.841 ms -PingPongAkkaActorBenchmark Error Window: 1401.058 ms (4.672 percent) -PingPongAkkaActorBenchmark Coeff. of Variation: 0.083 -PingPongAkkaActorBenchmark Skewness: -0.904 \ No newline at end of file From 77d4fa352af1838ad002c8d3574802e7dd95a79b Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Thu, 22 Jan 2026 09:25:57 +0100 Subject: [PATCH 4/8] fix: fix registration logic --- big/sink.pkl | 3 +-- pingpong/benchmark/CSM.txt | 20 -------------------- 2 files changed, 1 insertion(+), 22 deletions(-) delete mode 100644 pingpong/benchmark/CSM.txt diff --git a/big/sink.pkl b/big/sink.pkl index f1f64e2..641d113 100644 --- a/big/sink.pkl +++ b/big/sink.pkl @@ -3,7 +3,6 @@ import sm = new csml.StateMachine { transient { - ["registered"] = "''" ["registeredCounter"] = "0" ["doneCounter"] = "0" ["cumulatedPongCounter"] = "0" @@ -13,9 +12,9 @@ sm = new csml.StateMachine { on { ["registerBig"] = new csml.Transition { to = "evaluateAllBigsReceived" + iif = "std:registerStateMachine(\("$bigId"))" do { new csml.Eval { expression = "registeredCounter = registeredCounter + 1" } - new csml.Eval { expression = "registered = std:registerStateMachine(\("$bigId"))" } } } } diff --git a/pingpong/benchmark/CSM.txt b/pingpong/benchmark/CSM.txt deleted file mode 100644 index f334d1e..0000000 --- a/pingpong/benchmark/CSM.txt +++ /dev/null @@ -1,20 +0,0 @@ -Number of pings: 50.000 -Execution - Iterations: -CsmPingPong Iteration-0: 37631.159 ms -CsmPingPong Iteration-1: 41742.721 ms -CsmPingPong Iteration-2: 41878.055 ms -CsmPingPong Iteration-3: 41937.863 ms -CsmPingPong Iteration-4: 38841.834 ms -CsmPingPong Iteration-5: 38506.544 ms -CsmPingPong Iteration-6: 43645.336 ms -CsmPingPong Iteration-7: 41605.493 ms -CsmPingPong Iteration-8: 41993.211 ms -CsmPingPong Iteration-9: 41589.462 ms -CsmPingPong Iteration-10: 42283.925 ms -CsmPingPong Iteration-11: 41893.918 ms - -Execution - Summary: - Total executions = 12 - Filtered executions = 12 -PingPongAkkaActorBenchmark Best Time: 37631.159 ms -PingPongAkkaActorBenchmark Worst Time: 43645.336 ms \ No newline at end of file From a2e8c4c2e810a9f1e9d5e1b7bc4de087eea37488 Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Thu, 22 Jan 2026 13:11:51 +0100 Subject: [PATCH 5/8] feat: add sleepingBarber example --- sleepingBarber/barber.pkl | 62 ++++----- sleepingBarber/customer.pkl | 138 ++++++------------- sleepingBarber/main.pkl | 12 +- sleepingBarber/services.pkl | 3 +- sleepingBarber/waitingRoom.pkl | 245 +++++++++++---------------------- 5 files changed, 156 insertions(+), 304 deletions(-) diff --git a/sleepingBarber/barber.pkl b/sleepingBarber/barber.pkl index 3282012..0e10749 100644 --- a/sleepingBarber/barber.pkl +++ b/sleepingBarber/barber.pkl @@ -1,59 +1,45 @@ import - "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/Csml.pkl" + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" -class StateMachine extends Csml.StateMachineDescription { - name = "barber" +sm = new csml.StateMachine { states { - new { - name = "sleeping" - initial = true + ["sleeping"] = new csml.Initial { entry { - new Csml.RaiseActionDescription { - event { - name = "statusSleeping" - channel = "global" - } - } + new csml.Raise { event = new csml.Global { topic = "statusSleeping" } } } on { - new { - event = "enter" - target = "cutting" + ["ready"] = new csml.Transition { + do {} + } + ["enter"] = new csml.Transition { + to = "cutting" + } + ["stopCutting"] = new csml.Transition { + to = "stop" } } } - new { - name = "cutting" + ["cutting"] = new csml.State { always { - new { - guards { - new { - expression = "utility:busyWait(1000) == 1000" - } - } - actions { - new Csml.RaiseActionDescription { - event { - name = "done" + new csml.Transition { + to = "sleeping" + iif = "std:busyWait(1000)" + do { + new csml.Raise { + event = new csml.Global { + topic = "done" data { - new { - name = "customer" - value = "$customer" - } + ["customer"] = "$customer" } - channel = "global" } } - new Csml.RaiseActionDescription { - event { - name = "getNext" - channel = "global" - } + new csml.Raise { + event = new csml.Global { topic = "getNext" } } } - target = "sleeping" } } } + ["stop"] = new csml.Terminal {} } } diff --git a/sleepingBarber/customer.pkl b/sleepingBarber/customer.pkl index 2d99b51..01fdd60 100644 --- a/sleepingBarber/customer.pkl +++ b/sleepingBarber/customer.pkl @@ -1,127 +1,77 @@ -import "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/Csml.pkl" +import + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" -class StateMachine extends Csml.StateMachineDescription { - name = "customer" - local self = this - localContext { - variables { - new { - name = "counter" - value = "0" - } - } +sm = new csml.StateMachine { + transient { + ["counter"] = "0" + ["customerId"] = "std:getSequentialId()" } states { - new { - name = "init" - initial = true + ["init"] = new csml.Initial { on { - new { - event = "ready" - target = "requestHaircut" + ["ready"] = new csml.Transition { + to = "requestHaircut" } } } - new { - name = "requestHaircut" + ["requestHaircut"] = new csml.State { entry { - new Csml.RaiseActionDescription { - event { - name = "customerEnter" + new csml.Raise { + event = new csml.Global { + topic = "customerEnter" data { - new { - name = "customer" - value = self.name - } + ["customer"] = "customerId" } - channel = "global" } } } on { - new { - event = "full" - guards { - new { - expression = "$customer == \(self.name)" - } - } - target = "requestHaircut" + ["full"] = new csml.Transition { + to = "requestHaircut" + iif = "$customer == customerId" } - new { - event = "enter" - guards { - new { - expression = "$customer == \(self.name)" - } - } - target = "gettingHaircut" + ["enter"] = new csml.Transition { + to = "gettingHaircut" + iif = "$customer == customerId" } - new { - event = "waiting" - guards { - new { - expression = "$customer == \(self.name)" - } - } - target = "waiting" + ["waiting"] = new csml.Transition { + to = "waiting" + iif = "$customer == customerId" } } } - new { - name = "gettingHaircut" + ["gettingHaircut"] = new csml.State { entry { - new Csml.AssignActionDescription { - variable = new { - name = "counter" - value = "counter + 1" - } - } + new csml.Eval { expression = "counter = counter + 1" } } on { - new { - event = "done" - guards { - new { - expression = "$customer == \(self.name)" - } - new { - expression = "counter < 333" - } - } - target = "requestHaircut" + ["done"] = new csml.Transition { + to = "evaluateCounter" + iif = "$customer == customerId" } - new { - event = "done" - guards { - new { - expression = "$customer == \(self.name)" - } - new { - expression = "counter >= 333" - } - } - target = "leave" + } + } + ["evaluateCounter"] = new csml.State { + always { + new csml.Transition { + to = "requestHaircut" + iif = "counter < 2000" + or = "leave" } } } - new { - name = "waiting" + ["waiting"] = new csml.State { on { - new { - event = "enter" - guards { - new { - expression = "$customer == \(self.name)" - } - } - target = "gettingHaircut" + ["enter"] = new csml.Transition { + to = "gettingHaircut" + iif = "$customer == customerId" } } } - new { - name = "leave" - terminal = true + ["leave"] = new csml.Terminal { + entry { + new csml.Raise { event = new csml.Global { topic = "finished" } } + } } } } diff --git a/sleepingBarber/main.pkl b/sleepingBarber/main.pkl index 86655d0..192f51e 100644 --- a/sleepingBarber/main.pkl +++ b/sleepingBarber/main.pkl @@ -1,16 +1,16 @@ -amends "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/Csml.pkl" +amends + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" import "barber.pkl" import "customer.pkl" import "defs.pkl" import "waitingRoom.pkl" -name = "benchmark" -version = "3.0.0" +version = "4.0.0" stateMachines { - new barber.StateMachine {} + ["barber"] = barber.sm for (_def in defs.customers) { - new customer.StateMachine { name = _def } + [_def] = customer.sm } - new waitingRoom.StateMachine {} + ["waitingRoom"] = waitingRoom.sm } diff --git a/sleepingBarber/services.pkl b/sleepingBarber/services.pkl index 48fc97f..07c151f 100644 --- a/sleepingBarber/services.pkl +++ b/sleepingBarber/services.pkl @@ -1,3 +1,4 @@ -amends "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/ServiceImplementationBindings.pkl" +amends + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/bindings.pkl" bindings {} diff --git a/sleepingBarber/waitingRoom.pkl b/sleepingBarber/waitingRoom.pkl index 94f49ba..7a838a0 100644 --- a/sleepingBarber/waitingRoom.pkl +++ b/sleepingBarber/waitingRoom.pkl @@ -1,193 +1,108 @@ -import "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/Csml.pkl" +import + "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" -class StateMachine extends Csml.StateMachineDescription { - name = "waitingRoom" - localContext { - variables { - new { - name = "waitingCustomers" - value = "[...]" - } - new { - name = "barberStatus" - value = "''" - } - } +sm = new csml.StateMachine { + transient { + ["waitingCustomers"] = "[...]" + ["barberStatus"] = "''" + ["finishedCounter"] = "0" } states { - new { - name = "process" - initial = true + ["init"] = new csml.Initial { entry { - new Csml.RaiseActionDescription { - event { - name = "ready" - channel = "global" - } + new csml.Raise { event = new csml.Global { topic = "ready" } } + } + always { + new csml.Transition { + to = "process" } } + } + ["process"] = new csml.State { on { - new { - event = "customerEnter" - guards { - new { - expression = "waitingCustomers.size() == 3" - } - } - actions { - new Csml.RaiseActionDescription { - event { - name = "full" - data { - new { - name = "customer" - value = "$customer" - } - } - channel = "global" - } + ["customerEnter"] = new csml.Transition { + to = "process" + iif = "waitingCustomers.size() == 3" + do { + new csml.Raise { + event = new csml.Global { topic = "full"; data { ["customer"] = "$customer" } } } } + or = "checkWaitingRoom" } - new { - event = "customerEnter" - guards { - new { - expression = "waitingCustomers.isEmpty()" - } - new { - expression = "barberStatus == 'sleeping'" - } - } - actions { - new Csml.RaiseActionDescription { - event { - name = "enter" - data { - new { - name = "customer" - value = "$customer" - } - } - channel = "global" + ["getNext"] = new csml.Transition { + iif = "!waitingCustomers.isEmpty()" + do { + new csml.Raise { + event = new csml.Global { + topic = "enter" + data { ["customer"] = "waitingCustomers.get(0)" } } } - new Csml.AssignActionDescription { - variable = new { - name = "barberStatus" - value = "'busy'" - } + new csml.Eval { + expression = "waitingCustomers = std:removeFirst(\("waitingCustomers"))" } + new csml.Eval { expression = "barberStatus = 'busy'" } } } - new { - event = "customerEnter" - guards { - new { - expression = "waitingCustomers.isEmpty()" - } - new Csml.GuardDescription { - expression = "barberStatus == 'busy'" - } - } - actions { - new Csml.AssignActionDescription { - variable = new { - name = "waitingCustomers" - value = "utility:addToList(\("waitingCustomers"), $customer)" - } - } - new Csml.RaiseActionDescription { - event { - name = "waiting" - data { - new { - name = "customer" - value = "$customer" - } - } - channel = "global" - } - } + ["statusSleeping"] = new csml.Transition { + do { + new csml.Eval { expression = "barberStatus = 'sleeping'" } } } - new { - event = "customerEnter" - guards { - new { - expression = "waitingCustomers.size() != 3" - } - new { - expression = "!waitingCustomers.isEmpty()" - } - } - actions { - new Csml.AssignActionDescription { - variable = new { - name = "waitingCustomers" - value = "utility:addToList(\("waitingCustomers"), $customer)" - } - } - new Csml.RaiseActionDescription { - event { - name = "waiting" - data { - new { - name = "customer" - value = "$customer" - } - } - channel = "global" - } - } + ["finished"] = new csml.Transition { + to = "process" + iif = "finishedCounter < 14" + do { + new csml.Eval { expression = "finishedCounter = finishedCounter + 1" } } + or = "stop" } - new { - event = "getNext" - guards { - new { - expression = "!waitingCustomers.isEmpty()" - } - } - actions { - new Csml.RaiseActionDescription { - event { - name = "enter" - data { - new { - name = "customer" - value = "waitingCustomers.get(0)" - } - } - channel = "global" - } - } - new Csml.AssignActionDescription { - variable = new { - name = "waitingCustomers" - value = "utility:removeFirst(\("waitingCustomers"))" - } - } - new Csml.AssignActionDescription { - variable = new { - name = "barberStatus" - value = "'busy'" - } - } + } + } + ["checkWaitingRoom"] = new csml.State { + always { + new csml.Transition { + to = "checkBarberStatus" + iif = "waitingCustomers.isEmpty()" + or = "addToWaitingRoom" + } + } + } + ["checkBarberStatus"] = new csml.State { + always { + new csml.Transition { + to = "process" + iif = "barberStatus == 'sleeping'" + do { + new csml.Raise { + event = new csml.Global { topic = "enter"; data { ["customer"] = "$customer" } } + } + new csml.Eval { expression = "barberStatus = 'busy'" } } + or = "addToWaitingRoom" } - new { - event = "statusSleeping" - actions { - new Csml.AssignActionDescription { - variable = new { - name = "barberStatus" - value = "'sleeping'" - } + } + } + ["addToWaitingRoom"] = new csml.State { + always { + new csml.Transition { + to = "process" + do { + new csml.Eval { + expression = "waitingCustomers = std:addToList(\("waitingCustomers"), $customer)" + } + new csml.Raise { + event = new csml.Global { topic = "waiting"; data { ["customer"] = "$customer" } } } } } } } + ["stop"] = new csml.Terminal { + entry { + new csml.Raise { event = new csml.Global { topic = "stopCutting" } } + } + } } } From b5770a5e6c52cdb3e45484359204c618b46e58cd Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Tue, 27 Jan 2026 15:03:42 +0100 Subject: [PATCH 6/8] fix: remove use of non-essential std functions --- big/big.pkl | 28 +++++----------------------- big/defs.pkl | 2 +- big/main.pkl | 4 ++-- big/sink.pkl | 26 +------------------------- 4 files changed, 9 insertions(+), 51 deletions(-) diff --git a/big/big.pkl b/big/big.pkl index 3ac9522..e13b997 100644 --- a/big/big.pkl +++ b/big/big.pkl @@ -1,41 +1,23 @@ import "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" -sm = new csml.StateMachine { +function createBig(id: Int) = new csml.StateMachine { transient { - ["bigId"] = "std:getSequentialId()" + ["bigId"] = "\(id)" ["target"] = "''" - ["otherBigs"] = "[...]" + ["otherBigs"] = "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...] - [\(id)]" ["pingCounter"] = "0" ["pongCounter"] = "0" } states { - ["registerBig"] = new csml.Initial { - entry { - new csml.Raise { - event = new csml.Global { topic = "registerBig"; data { ["bigId"] = "bigId" } } - } - } - on { - ["allBigsRegistered"] = new csml.Transition { - to = "sendPing" - do { - new csml.Eval { expression = "otherBigs = std:getAllStateMachines()" } - new csml.Eval { - expression = "otherBigs = std:removeFromList(\("otherBigs"), \("bigId"))" - } - } - } - } - } - ["sendPing"] = new csml.State { + ["sendPing"] = new csml.Initial { always { new csml.Transition { to = "waitForPingOrPong" iif = "pingCounter < 20000" do { new csml.Eval { expression = "pingCounter = pingCounter + 1" } - new csml.Eval { expression = "target = std:takeRandom(\("otherBigs"))" } + new csml.Eval { expression = "target = std:rand(otherBigs)" } new csml.Raise { event = new csml.Global { topic = "ping" diff --git a/big/defs.pkl b/big/defs.pkl index b9bdb2c..c0362ad 100644 --- a/big/defs.pkl +++ b/big/defs.pkl @@ -1 +1 @@ -bigs = List("0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11") +bigs = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) diff --git a/big/main.pkl b/big/main.pkl index fc70794..36b3ed3 100644 --- a/big/main.pkl +++ b/big/main.pkl @@ -8,7 +8,7 @@ import "sink.pkl" version = "4.0.0" stateMachines { ["sink"] = sink.sm - for (_def in defs.bigs) { - [_def] = big.sm + for (b in defs.bigs) { + [b.toString()] = big.createBig(b) } } diff --git a/big/sink.pkl b/big/sink.pkl index 641d113..2d2e17c 100644 --- a/big/sink.pkl +++ b/big/sink.pkl @@ -3,35 +3,11 @@ import sm = new csml.StateMachine { transient { - ["registeredCounter"] = "0" ["doneCounter"] = "0" ["cumulatedPongCounter"] = "0" } states { - ["registerBigs"] = new csml.Initial { - on { - ["registerBig"] = new csml.Transition { - to = "evaluateAllBigsReceived" - iif = "std:registerStateMachine(\("$bigId"))" - do { - new csml.Eval { expression = "registeredCounter = registeredCounter + 1" } - } - } - } - } - ["evaluateAllBigsReceived"] = new csml.State { - always { - new csml.Transition { - to = "waitingForBigs" - iif = "registeredCounter == 12" - do { - new csml.Raise { event = new csml.Global { topic = "allBigsRegistered" } } - } - or = "registerBigs" - } - } - } - ["waitingForBigs"] = new csml.State { + ["waitingForBigs"] = new csml.Initial { on { ["donePinging"] = new csml.Transition { to = "isFinal" From adbc3b04da8b29c1be10fd0393ad791579fabea2 Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Thu, 29 Jan 2026 09:18:04 +0100 Subject: [PATCH 7/8] fix: optimize evals in big example --- big/big.pkl | 4 ++-- big/sink.pkl | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/big/big.pkl b/big/big.pkl index e13b997..53b9a29 100644 --- a/big/big.pkl +++ b/big/big.pkl @@ -16,8 +16,8 @@ function createBig(id: Int) = new csml.StateMachine { to = "waitForPingOrPong" iif = "pingCounter < 20000" do { - new csml.Eval { expression = "pingCounter = pingCounter + 1" } - new csml.Eval { expression = "target = std:rand(otherBigs)" } + new csml.Eval { expression = "++pingCounter" } + new csml.Eval { expression = "target = std:takeRandom(otherBigs)" } new csml.Raise { event = new csml.Global { topic = "ping" diff --git a/big/sink.pkl b/big/sink.pkl index 2d2e17c..0d51abf 100644 --- a/big/sink.pkl +++ b/big/sink.pkl @@ -12,7 +12,7 @@ sm = new csml.StateMachine { ["donePinging"] = new csml.Transition { to = "isFinal" do { - new csml.Eval { expression = "doneCounter = doneCounter + 1" } + new csml.Eval { expression = "++doneCounter" } } } } From 79d1a7ffe9fed3b29416c8b183af99d8c80a6b90 Mon Sep 17 00:00:00 2001 From: AlexZangerle Date: Fri, 30 Jan 2026 14:31:15 +0100 Subject: [PATCH 8/8] feat: add targeting logic to big example --- big/big.pkl | 20 +++++++++----------- big/defs.pkl | 2 +- big/main.pkl | 24 ++++++++++++++++++++---- big/services.pkl | 2 +- big/sink.pkl | 2 +- 5 files changed, 32 insertions(+), 18 deletions(-) diff --git a/big/big.pkl b/big/big.pkl index 53b9a29..91d64a3 100644 --- a/big/big.pkl +++ b/big/big.pkl @@ -1,11 +1,9 @@ import - "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + "https://raw.githubusercontent.com/Frnd-me/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" -function createBig(id: Int) = new csml.StateMachine { +sm = new csml.StateMachine { transient { - ["bigId"] = "\(id)" ["target"] = "''" - ["otherBigs"] = "[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...] - [\(id)]" ["pingCounter"] = "0" ["pongCounter"] = "0" } @@ -14,15 +12,16 @@ function createBig(id: Int) = new csml.StateMachine { always { new csml.Transition { to = "waitForPingOrPong" - iif = "pingCounter < 20000" + iif = "pingCounter < 100" do { new csml.Eval { expression = "++pingCounter" } new csml.Eval { expression = "target = std:takeRandom(otherBigs)" } new csml.Raise { event = new csml.Global { topic = "ping" - data { ["sender"] = "bigId"; ["receiver"] = "target" } + data { ["sender"] = "bigId" } } + target = "target" } } or = "receiveRemaining" @@ -32,18 +31,18 @@ function createBig(id: Int) = new csml.StateMachine { ["waitForPingOrPong"] = new csml.State { on { ["ping"] = new csml.Transition { - iif = "$sender != bigId && $receiver == bigId" do { new csml.Raise { event = new csml.Global { topic = "pong" - data { ["sender"] = "bigId"; ["receiver"] = "$sender" } + data { ["sender"] = "bigId" } } + target = "$sender" } } } ["pong"] = new csml.Transition { - iif = "$receiver == bigId && $sender == target" + iif = "$sender == target" to = "sendPing" } } @@ -54,12 +53,11 @@ function createBig(id: Int) = new csml.StateMachine { } on { ["ping"] = new csml.Transition { - iif = "$sender != bigId && $receiver == bigId" do { new csml.Raise { event = new csml.Global { topic = "pong" - data { ["sender"] = "bigId"; ["receiver"] = "$sender" } + data { ["sender"] = "bigId" } } } } diff --git a/big/defs.pkl b/big/defs.pkl index c0362ad..8cbbffc 100644 --- a/big/defs.pkl +++ b/big/defs.pkl @@ -1 +1 @@ -bigs = List(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11) +bigs = List("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten", "eleven") diff --git a/big/main.pkl b/big/main.pkl index 36b3ed3..358ac2a 100644 --- a/big/main.pkl +++ b/big/main.pkl @@ -1,14 +1,30 @@ amends - "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + "https://raw.githubusercontent.com/Frnd-me/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" import "big.pkl" import "defs.pkl" import "sink.pkl" version = "4.0.0" -stateMachines { - ["sink"] = sink.sm +collaborativeStateMachine { + stateMachines { + ["sink"] = sink.sm + ["big"] = big.sm + } +} + +instantiate { + ["sink"] = "sink" + for (b in defs.bigs) { + [b] = "big" + } +} +instanceData { for (b in defs.bigs) { - [b.toString()] = big.createBig(b) + [b] { + ["bigId"] = "'\(b)'" + ["otherBigs"] = "['zero', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine', 'ten', 'eleven', ...] - ['\(b)']" + } } } +instanceSubscriptions {} diff --git a/big/services.pkl b/big/services.pkl index 07c151f..7459387 100644 --- a/big/services.pkl +++ b/big/services.pkl @@ -1,4 +1,4 @@ amends - "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/bindings.pkl" + "https://raw.githubusercontent.com/Frnd-me/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/bindings.pkl" bindings {} diff --git a/big/sink.pkl b/big/sink.pkl index 0d51abf..08092fb 100644 --- a/big/sink.pkl +++ b/big/sink.pkl @@ -1,5 +1,5 @@ import - "https://raw.githubusercontent.com/CollaborativeStateMachines/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" + "https://raw.githubusercontent.com/Frnd-me/Cirrina/refs/heads/develop/src/main/resources/pkl/csm/csml.pkl" sm = new csml.StateMachine { transient {