z3.scm.in
| 1 | ;; Guile-Z3 |
| 2 | ;; Copyright (C) 2020 Julien Lepiller <julien@lepiller.eu> |
| 3 | |
| 4 | ;; This library is free software; you can redistribute it and/or modify |
| 5 | ;; it under the terms of the GNU Lesser General Public License as |
| 6 | ;; published by the Free Software Foundation; either version 3 of the |
| 7 | ;; License, or (at your option) any later version. |
| 8 | ;; |
| 9 | ;; This library is distributed in the hope that it will be useful, but |
| 10 | ;; WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | ;; Lesser General Public License for more details. |
| 13 | ;; |
| 14 | ;; You should have received a copy of the GNU Lesser General Public |
| 15 | ;; License along with this program; if not, contact: |
| 16 | ;; |
| 17 | ;; Free Software Foundation Voice: +1-617-542-5942 |
| 18 | ;; 59 Temple Place - Suite 330 Fax: +1-617-542-2652 |
| 19 | ;; Boston, MA 02111-1307, USA gnu@gnu.org |
| 20 | |
| 21 | ;;; Commentary: |
| 22 | ;; |
| 23 | ;; A Guile binding for the Z3 Theorem Prover. |
| 24 | ;; |
| 25 | ;;; Code: |
| 26 | |
| 27 | (define-module (z3) |
| 28 | #:use-module (system foreign) |
| 29 | #:use-module (rnrs bytevectors) |
| 30 | #:use-module (srfi srfi-9) |
| 31 | #:use-module (system base language) |
| 32 | #:use-module (system repl command) |
| 33 | #:use-module (system repl common) |
| 34 | #:use-module (system repl repl) |
| 35 | #:export (z3-eval |
| 36 | run-with-z3)) |
| 37 | |
| 38 | ;;; Dynamic linking to foreign functions |
| 39 | (define libz3 (dynamic-link "@Z3_LIBDIR@/libz3")) |
| 40 | |
| 41 | (define z3-mk-config |
| 42 | (pointer->procedure '* (dynamic-func "Z3_mk_config" libz3) '())) |
| 43 | (define z3-del-config |
| 44 | (pointer->procedure void (dynamic-func "Z3_del_config" libz3) (list '*))) |
| 45 | |
| 46 | (define z3-mk-context |
| 47 | (pointer->procedure '* (dynamic-func "Z3_mk_context" libz3) (list '*))) |
| 48 | (define z3-del-context |
| 49 | (pointer->procedure void (dynamic-func "Z3_del_context" libz3) (list '*))) |
| 50 | |
| 51 | (define z3-eval-smtlib2-string |
| 52 | (pointer->procedure '* (dynamic-func "Z3_eval_smtlib2_string" libz3) (list '* '*))) |
| 53 | |
| 54 | (define z3-set-error-handler |
| 55 | (pointer->procedure void (dynamic-func "Z3_set_error_handler" libz3) (list '* '*))) |
| 56 | (define get-error |
| 57 | (dynamic-func "Z3_get_error_msg" libz3)) |
| 58 | |
| 59 | ;;; Utility function |
| 60 | |
| 61 | (define (sexp->string sexp) |
| 62 | "Converts an s-expression to a string, to be passed to eval-smtlib2" |
| 63 | (with-output-to-string |
| 64 | (lambda _ |
| 65 | (write sexp)))) |
| 66 | |
| 67 | ;;; Interface |
| 68 | |
| 69 | (define (z3-eval context query) |
| 70 | "Runs a query as an SMT-LIB2 s-expression in the Z3 context. See the Z3 |
| 71 | manual for more information on the expected format." |
| 72 | (let* ((query (sexp->string query)) |
| 73 | (ans (z3-eval-smtlib2-string |
| 74 | context |
| 75 | (string->pointer |
| 76 | (substring query 1 (- (string-length query) 1)))))) |
| 77 | (call-with-input-string (pointer->string ans) read))) |
| 78 | |
| 79 | (define (run-with-z3 thunk) |
| 80 | "Runs a one-argument procedure in a new Z3 context. The only argument to that |
| 81 | procedure is the newly-created Z3 context." |
| 82 | (let* ((conf (z3-mk-config)) |
| 83 | (ctx (z3-mk-context conf)) |
| 84 | (_ (z3-set-error-handler ctx get-error))) |
| 85 | (dynamic-wind |
| 86 | (lambda () #t) |
| 87 | (lambda () (thunk ctx)) |
| 88 | (lambda () |
| 89 | (z3-del-context ctx) |
| 90 | (z3-del-config conf))))) |
| 91 | |
| 92 | (define-meta-command ((z3 exp) repl) |
| 93 | "Run exp in custom repl." |
| 94 | (run-with-z3 |
| 95 | (lambda (context) |
| 96 | (let* ((scheme (lookup-language 'scheme)) |
| 97 | (new (make-repl |
| 98 | (make-language #:name "z3" |
| 99 | #:title "z3" |
| 100 | #:reader (language-reader scheme) |
| 101 | #:evaluator (lambda (exp env) |
| 102 | (z3-eval context (list exp))) |
| 103 | #:printer (language-printer scheme) |
| 104 | #:make-default-environment |
| 105 | (language-make-default-environment scheme))))) |
| 106 | (repl-option-set! new 'interp #t) |
| 107 | (run-repl new))))) |
| 108 |