Skip to content

Commit 8198f27

Browse files
committed
added weakest precondition of assignment and fixed domain
1 parent 77dc499 commit 8198f27

File tree

2 files changed

+68
-26
lines changed

2 files changed

+68
-26
lines changed

Prover/LanguageServices/Wybe/Semantics.fs

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,25 @@ let rec checkChildrenFixedType
8282
| _ -> None)
8383
|> List.choose id
8484
|> function
85-
| [] -> ST((Typed resultType, e), xs)
85+
| [] ->
86+
let childrenDomains = xs |> List.choose (fun x -> x.SemanticResult.Domain)
87+
88+
match childrenDomains with
89+
| [] -> ST((Typed resultType, e), xs)
90+
| _ -> ST((TypedDomain(resultType, childrenDomains), e), xs)
91+
8692
| rs -> ST((Expecting rs, e), xs)
8793

8894
and checkChildrenEqualType (vars: Map<string, Type>) (e: Expr, resultType: Type) (children: Expr list) =
8995
let xs = children |> List.map (extractTypeAndDomain vars)
9096
let types = xs |> List.choose _.SemanticResult.Type |> Set
9197

9298
if Set.count types = 1 then
93-
ST((Typed resultType, e), xs)
99+
let childrenDomains = xs |> List.choose (fun x -> x.SemanticResult.Domain)
100+
101+
match childrenDomains with
102+
| [] -> ST((Typed resultType, e), xs)
103+
| _ -> ST((TypedDomain(resultType, childrenDomains), e), xs)
94104
else
95105
ST((ExpectingSameType(Set.toList types), e), xs)
96106

@@ -106,8 +116,12 @@ and extractTypeAndDomain (vars: Map<string, Type>) (e: Expr) : SemanticTree =
106116
let r =
107117
checkChildrenFixedType vars (e, Type.Integer) (Type.Integer, [ left; right ])
108118

109-
let divDomain = Binary(right, Op.Differs, Lit(Int 0)) |> extractTypeAndDomain vars
110-
r.AddDomain divDomain
119+
let zero = Lit(Int 0)
120+
let diffZero = Binary(right, Op.Differs, zero)
121+
let typedZero = ST((Typed Type.Integer, zero), [])
122+
123+
let domain = ST((Typed Type.Boolean, diffZero), [ r.Children[1]; typedZero ])
124+
r.AddDomain domain
111125
| Op.Equals
112126
| Op.Differs -> checkChildrenEqualType vars (e, Type.Boolean) [ left; right ]
113127
| Op.AtMost
@@ -400,7 +414,7 @@ let semanticExprToWExpr (e: SemanticTree) : DomainWExpr option =
400414
| None -> None
401415
| Lit(Bool b), [] -> Some(if b then True else False)
402416
| Expr.Var name, [] -> Some(mkBoolVar name)
403-
| _ -> failwith $"not implemented: {exprToTree e.Expr}"
417+
| _ -> failwith $"unexpected boolean expression: {exprToTree e.Expr}"
404418
| Some Type.Integer ->
405419
match e.Expr, e.Children with
406420
| Lit(Int i), [] -> Some(Integer i)
@@ -475,3 +489,28 @@ let semanticExprToWExpr (e: SemanticTree) : DomainWExpr option =
475489

476490
let domain = e.SemanticResult.Domain |> Option.bind typedToWExpr
477491
typedToWExpr e |> Option.map (fun r -> DomainWExpr(domain, r))
492+
493+
// weakest precondition of assignemt
494+
let wpAssignment (vars: Map<string, Type>, var: string, expr: Expr, postcondition: Expr) =
495+
let rec loop (target: Expr) =
496+
match target with
497+
| Expr.Var name when name.Equals var -> expr
498+
| Binary(l, op, r) -> Binary(loop l, op, loop r)
499+
| Unary(op, r) -> Unary(op, loop r)
500+
| Array xs -> Array(xs |> List.map loop)
501+
| ArrayElem(name, index) -> ArrayElem(name, loop index)
502+
| _ -> target
503+
504+
match extractTypeAndDomain vars postcondition with
505+
| postconditionST when postconditionST.SemanticResult.Type.Equals(Some Type.Boolean) ->
506+
let exprSubstituted = loop postcondition
507+
508+
match extractTypeAndDomain vars exprSubstituted with
509+
| substituted when substituted.SemanticResult.Type.Equals(Some Type.Boolean) ->
510+
511+
match semanticExprToWExpr substituted with
512+
| Some wexpr when wexpr.Domain.IsSome -> Some(wexpr.Domain.Value <&&> wexpr.Expr)
513+
| Some wexpr -> Some(wexpr.Expr :?> Proposition)
514+
| _ -> None
515+
| _ -> None
516+
| _ -> None

Test/WybeLangTest.fs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -74,34 +74,23 @@ let ``domain conjunction`` () =
7474
[ "xs", Type.Array Type.Integer; "i", Type.Integer; "j", Type.Integer ]
7575
|> Map.ofList
7676

77-
let indexExpr = Binary(Var "i", Op.Div, Var "j")
78-
let r = extractTypeAndDomain vars (ArrayElem("xs", indexExpr))
79-
shouldEqual "xs[ i ÷ j ]" (r.Expr |> exprToTree |> string)
80-
shouldEqual (Some Type.Integer) r.SemanticResult.Type
81-
82-
let arrayDomain =
83-
Binary(Binary(Lit(Int 0), Op.AtMost, indexExpr), Op.And, Binary(indexExpr, Op.LessThan, Unary(Op.Length, Var "xs")))
84-
85-
let divDomain = Binary(Var "j", Op.Differs, Lit(Int 0))
86-
87-
let expectedDomain =
88-
Binary(divDomain, Op.And, arrayDomain)
89-
|> extractTypeAndDomain vars
90-
|> _.Expr
91-
|> exprToTree
92-
|> string
77+
let iDivJ = Binary(Var "i", Op.Div, Var "j")
9378

94-
shouldEqual "j ≠ 0 ∧ 0 ≤ i ÷ j ∧ i ÷ j < #xs" expectedDomain
95-
let actualDomain = exprToTree (r.SemanticResult.Domain.Value.Expr) |> string
79+
[ ArrayElem("xs", iDivJ), (Some Type.Integer), "xs[ i ÷ j ]", "j ≠ 0 ∧ 0 ≤ i ÷ j ∧ i ÷ j < #xs"
80+
Binary(iDivJ, Op.Exceeds, Lit(Int 0)), (Some Type.Boolean), "i ÷ j > 0", "j ≠ 0" ]
81+
|> List.iter (fun (expr, expectedType, representation, domain) ->
82+
let r = extractTypeAndDomain vars expr
83+
shouldEqual representation (r.Expr |> exprToTree |> string)
84+
shouldEqual expectedType r.SemanticResult.Type
85+
Assert.True(r.SemanticResult.Domain.IsSome, $"No domain at {representation}")
86+
let actualDomain = exprToTree (r.SemanticResult.Domain.Value.Expr) |> string
9687

97-
shouldEqual expectedDomain actualDomain
88+
shouldEqual domain actualDomain)
9889

9990
open GriesSchneider
10091

10192
[<Fact>]
10293
let ``Expr to WExpr`` () =
103-
let x, y = mkBoolVar "x", mkBoolVar "y"
104-
let n, m = mkIntVar "n", mkIntVar "m"
10594

10695
let vars =
10796
[ "n", Type.Integer; "m", Type.Integer; "x", Type.Boolean; "y", Type.Boolean ]
@@ -114,3 +103,17 @@ let ``Expr to WExpr`` () =
114103
let r = semanticExprToWExpr e
115104
Assert.True(r.IsSome, $"{collectSemanticTreeInfo e}")
116105
shouldEqual expected r.Value.Expr)
106+
107+
[<Fact>]
108+
let ``weakest precondition assignment`` () =
109+
let vars =
110+
[ "n", Type.Integer; "m", Type.Integer; "x", Type.Boolean; "y", Type.Boolean ]
111+
|> Map.ofList
112+
113+
let nExceeds0 = Binary(Expr.Var "n", Op.Exceeds, Lit(Int 0))
114+
115+
[ "n", Binary(Expr.Var "n", Op.Plus, Lit(Int 1)), nExceeds0, Some(n + 1 > zero)
116+
"n", Binary(Expr.Var "n", Op.Div, Expr.Var "m"), nExceeds0, Some(m != zero <&&> (n / m > zero)) ]
117+
|> List.iter (fun (var, expr, postcondition, wp) ->
118+
let r = wpAssignment (vars, var, expr, postcondition)
119+
shouldEqual wp r)

0 commit comments

Comments
 (0)