mirror of
https://github.com/priyanshujain/sanderling.git
synced 2026-10-02 11:07:10 +00:00
Supports Always over Pure/Thunk leaves; eventually/next/bounds deferred. Once a thunk returns false under an Always, the verdict latches to violated so the runner can surface the offending step without later observations masking it.
61 lines
1.3 KiB
Go
61 lines
1.3 KiB
Go
package ltl
|
|
|
|
import "fmt"
|
|
|
|
type Verdict int
|
|
|
|
const (
|
|
VerdictHolds Verdict = iota
|
|
VerdictViolated
|
|
)
|
|
|
|
func (v Verdict) String() string {
|
|
switch v {
|
|
case VerdictHolds:
|
|
return "holds"
|
|
case VerdictViolated:
|
|
return "violated"
|
|
default:
|
|
return fmt.Sprintf("verdict(%d)", int(v))
|
|
}
|
|
}
|
|
|
|
// Evaluator folds a formula across observed steps. v0.1 semantics:
|
|
// Always(P) is satisfied if P held at every observed step; once P is false,
|
|
// the verdict latches to Violated.
|
|
type Evaluator struct {
|
|
formula Formula
|
|
violated bool
|
|
}
|
|
|
|
func NewEvaluator(formula Formula) *Evaluator {
|
|
return &Evaluator{formula: formula}
|
|
}
|
|
|
|
// Observe evaluates the formula against the current state and returns the
|
|
// running verdict. Once Violated, subsequent calls keep returning Violated
|
|
// regardless of what later observations look like.
|
|
func (e *Evaluator) Observe() Verdict {
|
|
if e.violated {
|
|
return VerdictViolated
|
|
}
|
|
if !holdsAtCurrentStep(e.formula) {
|
|
e.violated = true
|
|
return VerdictViolated
|
|
}
|
|
return VerdictHolds
|
|
}
|
|
|
|
func holdsAtCurrentStep(formula Formula) bool {
|
|
switch concrete := formula.(type) {
|
|
case AlwaysFormula:
|
|
return holdsAtCurrentStep(concrete.Inner)
|
|
case PureFormula:
|
|
return concrete.Value
|
|
case ThunkFormula:
|
|
return concrete.Func()
|
|
default:
|
|
panic(fmt.Sprintf("ltl: unsupported formula type %T", formula))
|
|
}
|
|
}
|