korken89 / smlang-rs

A State Machine Language DSL procedual macro for Rust
Apache License 2.0
202 stars 28 forks source link

Feature: Pattern matching on input states #29

Closed dzimmanck closed 2 years ago

dzimmanck commented 2 years ago

Imagine if you have a simple state machine representing a battery charger.

statemachine! {
    transitions: {
        *Idle + Charge= Charging,
        Idle+ Discharge= Discharging,
        Charging + ChargeComplete= Charged,
        Discharging+ DischargeComplete= Discharged,
        Charged + Discharge = Discharging,
        Discharged + Charge = Charging
    }
}

Now, lets say we want to add a Fault state to handle any faults that might be detected. We would then need to add 5 new transitions to model the entrance into a faulted state. It would be great if we could use Rust pattern matching syntax to do something like this.

statemachine! {
    transitions: {
        *Idle + Charge= Charging,
        Idle+ Discharge= Discharging,
        Charging + ChargeComplete= Charged,
        Discharging+ DischargeComplete= Discharged,
        Charged + Discharge = Discharging,
        Discharged + Charge = Charging,
        _ + FaultDetected = Fault
    }
}

In this case, the procedural macro would interpret _ to mean add this transition for every state except "Fault". I could also see applications where supporting State1 | State2 | State3 + Event = NextState logic.

dzimmanck commented 2 years ago

My planned test example.

statemachine! {
    transitions: {
        *Idle + Charge = Charging,
        Idle + Discharge = Discharging,
        Charging + ChargeComplete = Charged,
        Discharging + DischargeComplete = Discharged,
        Charged + Discharge = Discharging,
        Dischaged + Charge = Charging,
        Charging + Discharge = Discharging,
        Discharging + Charge = Charging,
        Idle + FaultDetected = Fault,
        Charging + FaultDetected = Fault,
        Discharging + FaultDetected = Fault,
        Charged + FaultDetected = Fault,
        Discharged + FaultDetected = Fault,
        Fault + FaultCleard = Idle,
    },
}
statemachine! {
    transitions: {
        *Idle | Discharging | Discharged + Charge = Charging,
        Idle | Charging | Charged + Discharge = Discharging,
        Charging + ChargeComplete = Charged,
        Discharging + DischargeComplete = Discharged,
        _ + FaultDetected = Fault,
        Fault + FaultCleard = Idle,
    },
}
korken89 commented 2 years ago

Looks good!

Just one nit-pick: I think _ should keep the meaning as in Rust. So it should match any state, even the output state IMO.

dzimmanck commented 2 years ago

I have a working branch here.

I was able to isolate all changes to the parser file. The code works well, but I am not happy with the readability. I think it makes sense to break the parsing code into a few different files with some well defined unit tests to make it easier to maintain.

dzimmanck commented 2 years ago

Closed by PR #32