-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathz3.rkt
124 lines (106 loc) · 3.75 KB
/
z3.rkt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#lang racket
(require racket/runtime-path racket/path)
(require "common.rkt" "smt.rkt")
(provide call-with-z3 z3-send z3-check-sat z3-solve)
(define (z3-process #:flags [flags '("-st")])
(define-values (process z3-out z3-in z3-err)
(apply subprocess #f #f #f z3-path "-smt2" "-in" flags))
(define side-channel
(if (and (*debug*) (directory-exists? "/tmp"))
(open-output-file "/tmp/out.z3" #:exists 'replace)
#f))
(define soft? false)
(define (kill)
(close-output-port z3-in)
(close-input-port z3-out)
(close-input-port z3-err)
(when side-channel (close-output-port side-channel))
(subprocess-kill process true))
(define (ffprintf port fmt . vs)
(apply fprintf port fmt vs)
(when side-channel (apply fprintf side-channel fmt vs))
(flush-output port))
(define (send cmd)
(parameterize ([read-decimal-as-inexact #f])
(with-handlers
([exn:break? (λ (e) (kill) (raise e))]
[exn:fail:syntax? (λ (e) (raise-syntax-error 'Z3 (exn-message e) cmd))])
(define out
(match cmd
[(list 'kill)
(kill)
'success]
[(list 'echo s)
(ffprintf z3-in "; ~a\n" s)
'success]
[(list 'assert-soft _ ...)
(ffprintf z3-in "~a\n" cmd)
(set! soft? true)
'success]
[_
(ffprintf z3-in "~a\n" cmd)
(parse-output (read z3-out) cmd)]))
(if (and (equal? out 'sat) soft?)
(parse-output (read z3-out) cmd)
out))))
(send '(set-option :print-success true))
send)
(define (make-z3 #:flags [flags '("-st")] . cmdss)
(define proc (z3-process #:flags flags))
(for-each (curry z3-send proc) cmdss)
proc)
(define (parse-output msg input)
(match msg
[`(error ,description)
(match-define (list line/col parts ...) (string-split description ": "))
(define text (string-join parts ": "))
(match-define (list "line" (app string->number line) "column" (app string->number column))
(string-split line/col))
(raise-cassius-error (format "~a (~a:~a)" text line column))]
['unsupported
(error "Z3 unsupported:" input)]
[(? eof-object?)
(error "Z3 error: premature EOF received")]
[_
(match input
['(get-model)
(for/hash ([entry msg]
#:when (equal? (first entry) 'define-fun)
#:when (null? (third entry)))
(match-define `(define-fun ,const ,_ ,_ ,val) entry)
(values const (deserialize val)))]
[_ msg])]))
(define (call-with-z3 fn)
(let ([proc (z3-process)])
(with-handlers ([(const true) (λ (e) (z3-kill proc) (raise e))])
(begin0 (fn proc)
(z3-kill proc)))))
(define (z3-solve encoding #:check [check '(check-sat)])
(call-with-z3
(λ (z3)
(z3-send z3 encoding)
(z3-check-sat z3 (z3 check)))))
(define (z3-send process cmds)
(for ([line cmds])
(define out (process line))
(unless (equal? 'success out)
(raise (make-exn:fail (format "~a;\n ~a" out line) (current-continuation-marks))))))
(define (z3-check-sat process result)
(match result
['unsat `(core ,(process '(get-unsat-core)))]
[(or 'sat (list 'objectives _)) `(model ,(process '(get-model)))]
['unknown (error "Z3 returned 'unknown'")]))
(define (z3-kill process)
(z3-send process '((kill)))
(void))
(define (deserialize v)
(match v
[(== 'true) #t]
[(== 'false) #f]
[`(to_real ,n) n]
[`(- ,n) (- (deserialize n))]
[`(/ ,n ,d) (exact->inexact (/ (deserialize n) (deserialize d)))]
[`(let ((,names ,values) ...) ,body)
(deserialize (smt-replace-terms body (map cons names values)))]
[(list args ...) (map deserialize args)]
[else v]))