mirror of
https://github.com/Z3Prover/z3
synced 2026-05-25 11:26:21 +00:00
simplify Go bindings: extract CGo slice conversion helpers
Add three package-internal helper functions in z3.go to eliminate repeated boilerplate for converting Go slices to CGo arrays: - exprsToASTs([]*Expr) ([]C.Z3_ast, *C.Z3_ast) - sortsToCSorts([]*Sort) ([]C.Z3_sort, *C.Z3_sort) - intsToCs([]int) ([]C.int, *C.int) Each helper returns both the slice (to keep the backing array alive during CGo calls) and a pointer to its first element (or nil if empty). This replaces 13 instances of 4-9 line slice construction patterns. Also simplify the verbose C.bool assignment pattern in MkQuantifier and MkQuantifierConst from 5-line if/else blocks to single-line C.bool(isForall) conversions. Net: -66 lines in z3.go with no functional changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
1c6943c2cb
commit
0759e2fdde
1 changed files with 61 additions and 127 deletions
188
src/api/go/z3.go
188
src/api/go/z3.go
|
|
@ -240,6 +240,45 @@ func newExpr(ctx *Context, ptr C.Z3_ast) *Expr {
|
||||||
return expr
|
return expr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// intsToCs converts a []int slice to []C.int, returning the slice and
|
||||||
|
// a pointer to its first element (nil if empty).
|
||||||
|
func intsToCs(ints []int) ([]C.int, *C.int) {
|
||||||
|
if len(ints) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
cInts := make([]C.int, len(ints))
|
||||||
|
for i, v := range ints {
|
||||||
|
cInts[i] = C.int(v)
|
||||||
|
}
|
||||||
|
return cInts, &cInts[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// exprsToASTs converts a []*Expr slice to []C.Z3_ast, returning the slice and
|
||||||
|
// a pointer to its first element (nil if empty).
|
||||||
|
func exprsToASTs(exprs []*Expr) ([]C.Z3_ast, *C.Z3_ast) {
|
||||||
|
if len(exprs) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
cExprs := make([]C.Z3_ast, len(exprs))
|
||||||
|
for i, e := range exprs {
|
||||||
|
cExprs[i] = e.ptr
|
||||||
|
}
|
||||||
|
return cExprs, &cExprs[0]
|
||||||
|
}
|
||||||
|
|
||||||
|
// sortsToCSorts converts a []*Sort slice to []C.Z3_sort, returning the slice and
|
||||||
|
// a pointer to its first element (nil if empty).
|
||||||
|
func sortsToCSorts(sorts []*Sort) ([]C.Z3_sort, *C.Z3_sort) {
|
||||||
|
if len(sorts) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
cSorts := make([]C.Z3_sort, len(sorts))
|
||||||
|
for i, s := range sorts {
|
||||||
|
cSorts[i] = s.ptr
|
||||||
|
}
|
||||||
|
return cSorts, &cSorts[0]
|
||||||
|
}
|
||||||
|
|
||||||
// String returns the string representation of the expression.
|
// String returns the string representation of the expression.
|
||||||
func (e *Expr) String() string {
|
func (e *Expr) String() string {
|
||||||
return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr))
|
return C.GoString(C.Z3_ast_to_string(e.ctx.ptr, e.ptr))
|
||||||
|
|
@ -368,11 +407,8 @@ func (c *Context) MkAnd(exprs ...*Expr) *Expr {
|
||||||
if len(exprs) == 1 {
|
if len(exprs) == 1 {
|
||||||
return exprs[0]
|
return exprs[0]
|
||||||
}
|
}
|
||||||
cExprs := make([]C.Z3_ast, len(exprs))
|
_, cExprsPtr := exprsToASTs(exprs)
|
||||||
for i, e := range exprs {
|
return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||||
cExprs[i] = e.ptr
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_and(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkOr creates a disjunction.
|
// MkOr creates a disjunction.
|
||||||
|
|
@ -383,11 +419,8 @@ func (c *Context) MkOr(exprs ...*Expr) *Expr {
|
||||||
if len(exprs) == 1 {
|
if len(exprs) == 1 {
|
||||||
return exprs[0]
|
return exprs[0]
|
||||||
}
|
}
|
||||||
cExprs := make([]C.Z3_ast, len(exprs))
|
_, cExprsPtr := exprsToASTs(exprs)
|
||||||
for i, e := range exprs {
|
return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||||
cExprs[i] = e.ptr
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_or(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkNot creates a negation.
|
// MkNot creates a negation.
|
||||||
|
|
@ -422,38 +455,21 @@ func (c *Context) MkDistinct(exprs ...*Expr) *Expr {
|
||||||
if len(exprs) <= 1 {
|
if len(exprs) <= 1 {
|
||||||
return c.MkTrue()
|
return c.MkTrue()
|
||||||
}
|
}
|
||||||
cExprs := make([]C.Z3_ast, len(exprs))
|
_, cExprsPtr := exprsToASTs(exprs)
|
||||||
for i, e := range exprs {
|
return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), cExprsPtr))
|
||||||
cExprs[i] = e.ptr
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_distinct(c.ptr, C.uint(len(exprs)), &cExprs[0]))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pseudo-Boolean / cardinality constraints
|
// Pseudo-Boolean / cardinality constraints
|
||||||
|
|
||||||
// MkAtMost encodes p1 + p2 + ... + pn <= k.
|
// MkAtMost encodes p1 + p2 + ... + pn <= k.
|
||||||
func (c *Context) MkAtMost(args []*Expr, k uint) *Expr {
|
func (c *Context) MkAtMost(args []*Expr, k uint) *Expr {
|
||||||
cArgs := make([]C.Z3_ast, len(args))
|
_, cArgsPtr := exprsToASTs(args)
|
||||||
for i, a := range args {
|
|
||||||
cArgs[i] = a.ptr
|
|
||||||
}
|
|
||||||
var cArgsPtr *C.Z3_ast
|
|
||||||
if len(cArgs) > 0 {
|
|
||||||
cArgsPtr = &cArgs[0]
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_atmost(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
return newExpr(c, C.Z3_mk_atmost(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkAtLeast encodes p1 + p2 + ... + pn >= k.
|
// MkAtLeast encodes p1 + p2 + ... + pn >= k.
|
||||||
func (c *Context) MkAtLeast(args []*Expr, k uint) *Expr {
|
func (c *Context) MkAtLeast(args []*Expr, k uint) *Expr {
|
||||||
cArgs := make([]C.Z3_ast, len(args))
|
_, cArgsPtr := exprsToASTs(args)
|
||||||
for i, a := range args {
|
|
||||||
cArgs[i] = a.ptr
|
|
||||||
}
|
|
||||||
var cArgsPtr *C.Z3_ast
|
|
||||||
if len(cArgs) > 0 {
|
|
||||||
cArgsPtr = &cArgs[0]
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_atleast(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
return newExpr(c, C.Z3_mk_atleast(c.ptr, C.uint(len(args)), cArgsPtr, C.uint(k)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -462,20 +478,8 @@ func (c *Context) MkPBLe(args []*Expr, coeffs []int, k int) *Expr {
|
||||||
if len(args) != len(coeffs) {
|
if len(args) != len(coeffs) {
|
||||||
panic("MkPBLe: args and coeffs must have the same length")
|
panic("MkPBLe: args and coeffs must have the same length")
|
||||||
}
|
}
|
||||||
cArgs := make([]C.Z3_ast, len(args))
|
_, cArgsPtr := exprsToASTs(args)
|
||||||
for i, a := range args {
|
_, cCoeffsPtr := intsToCs(coeffs)
|
||||||
cArgs[i] = a.ptr
|
|
||||||
}
|
|
||||||
cCoeffs := make([]C.int, len(coeffs))
|
|
||||||
for i, v := range coeffs {
|
|
||||||
cCoeffs[i] = C.int(v)
|
|
||||||
}
|
|
||||||
var cArgsPtr *C.Z3_ast
|
|
||||||
var cCoeffsPtr *C.int
|
|
||||||
if len(cArgs) > 0 {
|
|
||||||
cArgsPtr = &cArgs[0]
|
|
||||||
cCoeffsPtr = &cCoeffs[0]
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_pble(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
return newExpr(c, C.Z3_mk_pble(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -484,20 +488,8 @@ func (c *Context) MkPBGe(args []*Expr, coeffs []int, k int) *Expr {
|
||||||
if len(args) != len(coeffs) {
|
if len(args) != len(coeffs) {
|
||||||
panic("MkPBGe: args and coeffs must have the same length")
|
panic("MkPBGe: args and coeffs must have the same length")
|
||||||
}
|
}
|
||||||
cArgs := make([]C.Z3_ast, len(args))
|
_, cArgsPtr := exprsToASTs(args)
|
||||||
for i, a := range args {
|
_, cCoeffsPtr := intsToCs(coeffs)
|
||||||
cArgs[i] = a.ptr
|
|
||||||
}
|
|
||||||
cCoeffs := make([]C.int, len(coeffs))
|
|
||||||
for i, v := range coeffs {
|
|
||||||
cCoeffs[i] = C.int(v)
|
|
||||||
}
|
|
||||||
var cArgsPtr *C.Z3_ast
|
|
||||||
var cCoeffsPtr *C.int
|
|
||||||
if len(cArgs) > 0 {
|
|
||||||
cArgsPtr = &cArgs[0]
|
|
||||||
cCoeffsPtr = &cCoeffs[0]
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_pbge(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
return newExpr(c, C.Z3_mk_pbge(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -506,20 +498,8 @@ func (c *Context) MkPBEq(args []*Expr, coeffs []int, k int) *Expr {
|
||||||
if len(args) != len(coeffs) {
|
if len(args) != len(coeffs) {
|
||||||
panic("MkPBEq: args and coeffs must have the same length")
|
panic("MkPBEq: args and coeffs must have the same length")
|
||||||
}
|
}
|
||||||
cArgs := make([]C.Z3_ast, len(args))
|
_, cArgsPtr := exprsToASTs(args)
|
||||||
for i, a := range args {
|
_, cCoeffsPtr := intsToCs(coeffs)
|
||||||
cArgs[i] = a.ptr
|
|
||||||
}
|
|
||||||
cCoeffs := make([]C.int, len(coeffs))
|
|
||||||
for i, v := range coeffs {
|
|
||||||
cCoeffs[i] = C.int(v)
|
|
||||||
}
|
|
||||||
var cArgsPtr *C.Z3_ast
|
|
||||||
var cCoeffsPtr *C.int
|
|
||||||
if len(cArgs) > 0 {
|
|
||||||
cArgsPtr = &cArgs[0]
|
|
||||||
cCoeffsPtr = &cCoeffs[0]
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_pbeq(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
return newExpr(c, C.Z3_mk_pbeq(c.ptr, C.uint(len(args)), cArgsPtr, cCoeffsPtr, C.int(k)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -569,54 +549,26 @@ func (f *FuncDecl) GetRange() *Sort {
|
||||||
|
|
||||||
// MkFuncDecl creates a function declaration.
|
// MkFuncDecl creates a function declaration.
|
||||||
func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
func (c *Context) MkFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
||||||
cDomain := make([]C.Z3_sort, len(domain))
|
_, domainPtr := sortsToCSorts(domain)
|
||||||
for i, s := range domain {
|
|
||||||
cDomain[i] = s.ptr
|
|
||||||
}
|
|
||||||
var domainPtr *C.Z3_sort
|
|
||||||
if len(domain) > 0 {
|
|
||||||
domainPtr = &cDomain[0]
|
|
||||||
}
|
|
||||||
return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
return newFuncDecl(c, C.Z3_mk_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkRecFuncDecl creates a recursive function declaration.
|
// MkRecFuncDecl creates a recursive function declaration.
|
||||||
// After creating, use AddRecDef to provide the function body.
|
// After creating, use AddRecDef to provide the function body.
|
||||||
func (c *Context) MkRecFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
func (c *Context) MkRecFuncDecl(name *Symbol, domain []*Sort, range_ *Sort) *FuncDecl {
|
||||||
cDomain := make([]C.Z3_sort, len(domain))
|
_, domainPtr := sortsToCSorts(domain)
|
||||||
for i, s := range domain {
|
|
||||||
cDomain[i] = s.ptr
|
|
||||||
}
|
|
||||||
var domainPtr *C.Z3_sort
|
|
||||||
if len(domain) > 0 {
|
|
||||||
domainPtr = &cDomain[0]
|
|
||||||
}
|
|
||||||
return newFuncDecl(c, C.Z3_mk_rec_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
return newFuncDecl(c, C.Z3_mk_rec_func_decl(c.ptr, name.ptr, C.uint(len(domain)), domainPtr, range_.ptr))
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddRecDef adds the definition (body) for a recursive function created with MkRecFuncDecl.
|
// AddRecDef adds the definition (body) for a recursive function created with MkRecFuncDecl.
|
||||||
func (c *Context) AddRecDef(f *FuncDecl, args []*Expr, body *Expr) {
|
func (c *Context) AddRecDef(f *FuncDecl, args []*Expr, body *Expr) {
|
||||||
cArgs := make([]C.Z3_ast, len(args))
|
_, argsPtr := exprsToASTs(args)
|
||||||
for i, a := range args {
|
|
||||||
cArgs[i] = a.ptr
|
|
||||||
}
|
|
||||||
var argsPtr *C.Z3_ast
|
|
||||||
if len(args) > 0 {
|
|
||||||
argsPtr = &cArgs[0]
|
|
||||||
}
|
|
||||||
C.Z3_add_rec_def(c.ptr, f.ptr, C.uint(len(args)), argsPtr, body.ptr)
|
C.Z3_add_rec_def(c.ptr, f.ptr, C.uint(len(args)), argsPtr, body.ptr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MkApp creates a function application.
|
// MkApp creates a function application.
|
||||||
func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr {
|
func (c *Context) MkApp(decl *FuncDecl, args ...*Expr) *Expr {
|
||||||
cArgs := make([]C.Z3_ast, len(args))
|
_, argsPtr := exprsToASTs(args)
|
||||||
for i, a := range args {
|
|
||||||
cArgs[i] = a.ptr
|
|
||||||
}
|
|
||||||
var argsPtr *C.Z3_ast
|
|
||||||
if len(args) > 0 {
|
|
||||||
argsPtr = &cArgs[0]
|
|
||||||
}
|
|
||||||
return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr))
|
return newExpr(c, C.Z3_mk_app(c.ptr, decl.ptr, C.uint(len(args)), argsPtr))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -691,16 +643,8 @@ func (e *Expr) Substitute(from, to []*Expr) *Expr {
|
||||||
// SubstituteVars replaces free variables in the expression with the expressions in to.
|
// SubstituteVars replaces free variables in the expression with the expressions in to.
|
||||||
// Variable with de-Bruijn index i is replaced with to[i].
|
// Variable with de-Bruijn index i is replaced with to[i].
|
||||||
func (e *Expr) SubstituteVars(to []*Expr) *Expr {
|
func (e *Expr) SubstituteVars(to []*Expr) *Expr {
|
||||||
n := len(to)
|
_, toPtr := exprsToASTs(to)
|
||||||
cTo := make([]C.Z3_ast, n)
|
return newExpr(e.ctx, C.Z3_substitute_vars(e.ctx.ptr, e.ptr, C.uint(len(to)), toPtr))
|
||||||
for i, t := range to {
|
|
||||||
cTo[i] = t.ptr
|
|
||||||
}
|
|
||||||
var toPtr *C.Z3_ast
|
|
||||||
if n > 0 {
|
|
||||||
toPtr = &cTo[0]
|
|
||||||
}
|
|
||||||
return newExpr(e.ctx, C.Z3_substitute_vars(e.ctx.ptr, e.ptr, C.uint(n), toPtr))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubstituteFuns replaces every occurrence of from[i] applied to arguments
|
// SubstituteFuns replaces every occurrence of from[i] applied to arguments
|
||||||
|
|
@ -816,12 +760,7 @@ func (q *Quantifier) String() string {
|
||||||
|
|
||||||
// MkQuantifier creates a quantifier with patterns
|
// MkQuantifier creates a quantifier with patterns
|
||||||
func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier {
|
func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names []*Symbol, body *Expr, patterns []*Pattern) *Quantifier {
|
||||||
var forallInt C.bool
|
forallInt := C.bool(isForall)
|
||||||
if isForall {
|
|
||||||
forallInt = true
|
|
||||||
} else {
|
|
||||||
forallInt = false
|
|
||||||
}
|
|
||||||
|
|
||||||
numBound := len(sorts)
|
numBound := len(sorts)
|
||||||
if numBound != len(names) {
|
if numBound != len(names) {
|
||||||
|
|
@ -864,12 +803,7 @@ func (c *Context) MkQuantifier(isForall bool, weight int, sorts []*Sort, names [
|
||||||
|
|
||||||
// MkQuantifierConst creates a quantifier using constant bound variables
|
// MkQuantifierConst creates a quantifier using constant bound variables
|
||||||
func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier {
|
func (c *Context) MkQuantifierConst(isForall bool, weight int, bound []*Expr, body *Expr, patterns []*Pattern) *Quantifier {
|
||||||
var forallInt C.bool
|
forallInt := C.bool(isForall)
|
||||||
if isForall {
|
|
||||||
forallInt = true
|
|
||||||
} else {
|
|
||||||
forallInt = false
|
|
||||||
}
|
|
||||||
|
|
||||||
numBound := len(bound)
|
numBound := len(bound)
|
||||||
var cBound []C.Z3_app
|
var cBound []C.Z3_app
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue