mirror of
https://github.com/Z3Prover/z3
synced 2026-03-01 11:16:54 +00:00
Merge pull request #8781 from Z3Prover/copilot/fix-ts-ocaml-issues
Add register_on_clause to OCaml and TypeScript bindings
This commit is contained in:
commit
fadf045df0
11 changed files with 159 additions and 14 deletions
8
src/api/js/package-lock.json
generated
8
src/api/js/package-lock.json
generated
|
|
@ -74,7 +74,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/core/-/core-7.19.3.tgz",
|
||||||
"integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==",
|
"integrity": "sha512-WneDJxdsjEvyKtXKsaBGbDeiyOjR5vYq4HcShxnIbG0qixpoHjI3MqeZM9NDvsojNCEBItQE4juOo/bU6e72gQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ampproject/remapping": "^2.1.0",
|
"@ampproject/remapping": "^2.1.0",
|
||||||
"@babel/code-frame": "^7.18.6",
|
"@babel/code-frame": "^7.18.6",
|
||||||
|
|
@ -1553,8 +1552,7 @@
|
||||||
"version": "17.0.45",
|
"version": "17.0.45",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.45.tgz",
|
||||||
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
|
"integrity": "sha512-w+tIMs3rq2afQdsPJlODhoUEKzFP1ayaoyl1CcnwtIlsVe7K7bA1NGm4s3PraqTLlXnbIN84zuBlxBWo1u9BLw==",
|
||||||
"dev": true,
|
"dev": true
|
||||||
"peer": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/prettier": {
|
"node_modules/@types/prettier": {
|
||||||
"version": "2.7.1",
|
"version": "2.7.1",
|
||||||
|
|
@ -1928,7 +1926,6 @@
|
||||||
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
"url": "https://tidelift.com/funding/github/npm/browserslist"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"caniuse-lite": "^1.0.30001400",
|
"caniuse-lite": "^1.0.30001400",
|
||||||
"electron-to-chromium": "^1.4.251",
|
"electron-to-chromium": "^1.4.251",
|
||||||
|
|
@ -3315,7 +3312,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/jest/-/jest-28.1.3.tgz",
|
||||||
"integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==",
|
"integrity": "sha512-N4GT5on8UkZgH0O5LUavMRV1EDEhNTL0KEfRmDIeZHSV7p2XgLoY9t9VDUgL6o+yfdgYHVxuz81G8oB9VG5uyA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jest/core": "^28.1.3",
|
"@jest/core": "^28.1.3",
|
||||||
"@jest/types": "^28.1.3",
|
"@jest/types": "^28.1.3",
|
||||||
|
|
@ -6544,7 +6540,6 @@
|
||||||
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz",
|
||||||
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
"integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cspotcode/source-map-support": "^0.8.0",
|
"@cspotcode/source-map-support": "^0.8.0",
|
||||||
"@tsconfig/node10": "^1.0.7",
|
"@tsconfig/node10": "^1.0.7",
|
||||||
|
|
@ -6664,7 +6659,6 @@
|
||||||
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
|
"integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
|
|
|
||||||
|
|
@ -72,10 +72,10 @@ fs.mkdirSync(path.dirname(ccWrapperPath), { recursive: true });
|
||||||
fs.writeFileSync(ccWrapperPath, makeCCWrapper());
|
fs.writeFileSync(ccWrapperPath, makeCCWrapper());
|
||||||
|
|
||||||
const fns = JSON.stringify(exportedFuncs());
|
const fns = JSON.stringify(exportedFuncs());
|
||||||
const methods = '["PThread","ccall","FS","UTF8ToString","intArrayFromString"]';
|
const methods = '["PThread","ccall","FS","UTF8ToString","intArrayFromString","addFunction","removeFunction"]';
|
||||||
const libz3a = path.normalize('../../../build/libz3.a');
|
const libz3a = path.normalize('../../../build/libz3.a');
|
||||||
spawnSync(
|
spawnSync(
|
||||||
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s TOTAL_MEMORY=2GB -s TOTAL_STACK=20MB -I z3/src/api/ -o build/z3-built.js`,
|
`emcc build/async-fns.cc ${libz3a} --std=c++20 --pre-js src/low-level/async-wrapper.js -g2 -pthread -fexceptions -s WASM_BIGINT -s USE_PTHREADS=1 -s PTHREAD_POOL_SIZE=0 -s PTHREAD_POOL_SIZE_STRICT=0 -s MODULARIZE=1 -s 'EXPORT_NAME="initZ3"' -s EXPORTED_RUNTIME_METHODS=${methods} -s EXPORTED_FUNCTIONS=${fns} -s DISABLE_EXCEPTION_CATCHING=0 -s SAFE_HEAP=0 -s TOTAL_MEMORY=2GB -s TOTAL_STACK=20MB -s ALLOW_TABLE_GROWTH=1 -I z3/src/api/ -o build/z3-built.js`,
|
||||||
);
|
);
|
||||||
|
|
||||||
fs.rmSync(ccWrapperPath);
|
fs.rmSync(ccWrapperPath);
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,6 @@ export async function init(): Promise<Z3LowLevel & Z3HighLevel> {
|
||||||
}
|
}
|
||||||
|
|
||||||
const lowLevel = await initWrapper(initZ3);
|
const lowLevel = await initWrapper(initZ3);
|
||||||
const highLevel = createApi(lowLevel.Z3);
|
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||||
return { ...lowLevel, ...highLevel };
|
return { ...lowLevel, ...highLevel };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ function isCoercibleRational(obj: any): obj is CoercibleRational {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createApi(Z3: Z3Core): Z3HighLevel {
|
export function createApi(Z3: Z3Core, em?: any): Z3HighLevel {
|
||||||
// TODO(ritave): Create a custom linting rule that checks if the provided callbacks to cleanup
|
// TODO(ritave): Create a custom linting rule that checks if the provided callbacks to cleanup
|
||||||
// Don't capture `this`
|
// Don't capture `this`
|
||||||
const cleanup = new FinalizationRegistry<() => void>(callback => callback());
|
const cleanup = new FinalizationRegistry<() => void>(callback => callback());
|
||||||
|
|
@ -1998,6 +1998,8 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
||||||
|
|
||||||
readonly ctx: Context<Name>;
|
readonly ctx: Context<Name>;
|
||||||
private _ptr: Z3_solver | null;
|
private _ptr: Z3_solver | null;
|
||||||
|
// Tracks a registered on_clause WASM callback index so it can be cleaned up
|
||||||
|
private _onClauseCallbackIdx!: { value: number | null };
|
||||||
get ptr(): Z3_solver {
|
get ptr(): Z3_solver {
|
||||||
_assertPtr(this._ptr);
|
_assertPtr(this._ptr);
|
||||||
return this._ptr;
|
return this._ptr;
|
||||||
|
|
@ -2013,7 +2015,20 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
||||||
}
|
}
|
||||||
this._ptr = myPtr;
|
this._ptr = myPtr;
|
||||||
Z3.solver_inc_ref(contextPtr, myPtr);
|
Z3.solver_inc_ref(contextPtr, myPtr);
|
||||||
cleanup.register(this, () => Z3.solver_dec_ref(contextPtr, myPtr), this);
|
// Shared mutable holder so registerOnClause and the cleanup closure see the same slot
|
||||||
|
const onClauseCallbackIdx: { value: number | null } = { value: null };
|
||||||
|
this._onClauseCallbackIdx = onClauseCallbackIdx;
|
||||||
|
cleanup.register(
|
||||||
|
this,
|
||||||
|
() => {
|
||||||
|
Z3.solver_dec_ref(contextPtr, myPtr);
|
||||||
|
if (onClauseCallbackIdx.value !== null && em) {
|
||||||
|
em.removeFunction(onClauseCallbackIdx.value);
|
||||||
|
onClauseCallbackIdx.value = null;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
this,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(key: string, value: any): void {
|
set(key: string, value: any): void {
|
||||||
|
|
@ -2260,11 +2275,46 @@ export function createApi(Z3: Z3Core): Z3HighLevel {
|
||||||
}
|
}
|
||||||
|
|
||||||
release() {
|
release() {
|
||||||
|
// Clean up any registered on_clause callback
|
||||||
|
if (this._onClauseCallbackIdx.value !== null && em) {
|
||||||
|
em.removeFunction(this._onClauseCallbackIdx.value);
|
||||||
|
this._onClauseCallbackIdx.value = null;
|
||||||
|
}
|
||||||
Z3.solver_dec_ref(contextPtr, this.ptr);
|
Z3.solver_dec_ref(contextPtr, this.ptr);
|
||||||
// Mark the ptr as null to prevent double free
|
// Mark the ptr as null to prevent double free
|
||||||
this._ptr = null;
|
this._ptr = null;
|
||||||
cleanup.unregister(this);
|
cleanup.unregister(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
registerOnClause(
|
||||||
|
callback: (proofHint: Expr<Name> | null, deps: number[], clause: AstVector<Name, Bool<Name>>) => void,
|
||||||
|
): void {
|
||||||
|
if (!em) {
|
||||||
|
throw new Error('registerOnClause requires the Emscripten module; pass it to createApi');
|
||||||
|
}
|
||||||
|
// Remove any previously registered callback before registering a new one
|
||||||
|
if (this._onClauseCallbackIdx.value !== null) {
|
||||||
|
em.removeFunction(this._onClauseCallbackIdx.value);
|
||||||
|
this._onClauseCallbackIdx.value = null;
|
||||||
|
}
|
||||||
|
// Signature: void(void* ctx, Z3_ast proof_hint, unsigned n, const unsigned* deps, Z3_ast_vector literals)
|
||||||
|
const cCallback = em.addFunction(
|
||||||
|
(_ctxPtr: number, proofHintPtr: number, n: number, depsPtr: number, literalsPtr: number) => {
|
||||||
|
const proofHint = proofHintPtr ? _toExpr(proofHintPtr as unknown as Z3_ast) : null;
|
||||||
|
const deps: number[] = [];
|
||||||
|
for (let i = 0; i < n; i++) {
|
||||||
|
deps.push(em.HEAPU32[(depsPtr >> 2) + i]);
|
||||||
|
}
|
||||||
|
const clause = new AstVectorImpl(literalsPtr as unknown as Z3_ast_vector) as AstVector<Name, Bool<Name>>;
|
||||||
|
callback(proofHint, deps, clause);
|
||||||
|
},
|
||||||
|
'viiiii',
|
||||||
|
);
|
||||||
|
this._onClauseCallbackIdx.value = cCallback;
|
||||||
|
// solver_register_on_clause is not auto-wrapped (has void* and fnptr params),
|
||||||
|
// so we call the raw Emscripten export directly.
|
||||||
|
em._Z3_solver_register_on_clause(contextPtr as unknown as number, this.ptr as unknown as number, 0, cCallback);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class OptimizeImpl implements Optimize<Name> {
|
class OptimizeImpl implements Optimize<Name> {
|
||||||
|
|
|
||||||
|
|
@ -1422,6 +1422,24 @@ export interface Solver<Name extends string = 'main'> {
|
||||||
* but calling this eagerly can help release memory sooner.
|
* but calling this eagerly can help release memory sooner.
|
||||||
*/
|
*/
|
||||||
release(): void;
|
release(): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a callback that is invoked when clauses are inferred during solving.
|
||||||
|
* The callback is called when a clause is:
|
||||||
|
* - asserted to the CDCL engine (input clause after pre-processing)
|
||||||
|
* - inferred by CDCL(T) using a SAT or theory conflict/propagation
|
||||||
|
* - deleted by the CDCL(T) engine
|
||||||
|
*
|
||||||
|
* Requires the Emscripten module to be passed to `createApi`.
|
||||||
|
*
|
||||||
|
* @param callback - Function called with:
|
||||||
|
* - proofHint: optional proof hint expression (may be null)
|
||||||
|
* - deps: array of clause dependency indices
|
||||||
|
* - clause: the clause as a vector of literals
|
||||||
|
*/
|
||||||
|
registerOnClause(
|
||||||
|
callback: (proofHint: Expr<Name> | null, deps: number[], clause: AstVector<Name, Bool<Name>>) => void,
|
||||||
|
): void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Optimize<Name extends string = 'main'> {
|
export interface Optimize<Name extends string = 'main'> {
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,7 @@ export * from './low-level/types.__GENERATED__';
|
||||||
|
|
||||||
export async function init(): Promise<Z3HighLevel & Z3LowLevel> {
|
export async function init(): Promise<Z3HighLevel & Z3LowLevel> {
|
||||||
const lowLevel = await initWrapper(initModule);
|
const lowLevel = await initWrapper(initModule);
|
||||||
const highLevel = createApi(lowLevel.Z3);
|
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||||
return { ...lowLevel, ...highLevel };
|
return { ...lowLevel, ...highLevel };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,6 @@ export * from './low-level/types.__GENERATED__';
|
||||||
* @category Global */
|
* @category Global */
|
||||||
export async function init(): Promise<Z3HighLevel & Z3LowLevel> {
|
export async function init(): Promise<Z3HighLevel & Z3LowLevel> {
|
||||||
const lowLevel = await initWrapper(initModule);
|
const lowLevel = await initWrapper(initModule);
|
||||||
const highLevel = createApi(lowLevel.Z3);
|
const highLevel = createApi(lowLevel.Z3, lowLevel.em);
|
||||||
return { ...lowLevel, ...highLevel };
|
return { ...lowLevel, ...highLevel };
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2020,6 +2020,11 @@ struct
|
||||||
List.iter (fun e -> Z3native.ast_vector_push (gc x) term_vec e) terms;
|
List.iter (fun e -> Z3native.ast_vector_push (gc x) term_vec e) terms;
|
||||||
List.iter (fun e -> Z3native.ast_vector_push (gc x) guard_vec e) guards;
|
List.iter (fun e -> Z3native.ast_vector_push (gc x) guard_vec e) guards;
|
||||||
Z3native.solver_solve_for (gc x) x var_vec term_vec guard_vec
|
Z3native.solver_solve_for (gc x) x var_vec term_vec guard_vec
|
||||||
|
|
||||||
|
let register_on_clause (s:solver) (callback: Expr.expr option -> int list -> Expr.expr list -> unit) =
|
||||||
|
Z3native.solver_register_on_clause (gc s) s (fun proof_hint deps lits ->
|
||||||
|
let lits_list = AST.ASTVector.to_expr_list lits in
|
||||||
|
callback proof_hint deps lits_list)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3499,6 +3499,13 @@ sig
|
||||||
variables are the variables to solve for, terms are the substitution terms,
|
variables are the variables to solve for, terms are the substitution terms,
|
||||||
and guards are Boolean guards for the substitutions. *)
|
and guards are Boolean guards for the substitutions. *)
|
||||||
val solve_for : solver -> Expr.expr list -> Expr.expr list -> Expr.expr list -> unit
|
val solve_for : solver -> Expr.expr list -> Expr.expr list -> Expr.expr list -> unit
|
||||||
|
|
||||||
|
(** Register a callback that is invoked when clauses are inferred during solving.
|
||||||
|
The callback is called when a clause is asserted to the CDCL engine, inferred
|
||||||
|
by CDCL(T), or deleted by the CDCL(T) engine.
|
||||||
|
The callback receives an optional proof hint expression, a list of dependency
|
||||||
|
indices, and the inferred clause as a list of literal expressions. *)
|
||||||
|
val register_on_clause : solver -> (Expr.expr option -> int list -> Expr.expr list -> unit) -> unit
|
||||||
end
|
end
|
||||||
|
|
||||||
(** Fixedpoint solving *)
|
(** Fixedpoint solving *)
|
||||||
|
|
|
||||||
|
|
@ -37,3 +37,6 @@ type rcf_num = ptr
|
||||||
|
|
||||||
external set_internal_error_handler : ptr -> unit
|
external set_internal_error_handler : ptr -> unit
|
||||||
= "n_set_internal_error_handler"
|
= "n_set_internal_error_handler"
|
||||||
|
|
||||||
|
external solver_register_on_clause : context -> solver -> (ast option -> int list -> ast_vector -> unit) -> unit
|
||||||
|
= "n_solver_register_on_clause"
|
||||||
|
|
|
||||||
|
|
@ -476,3 +476,71 @@ CAMLprim DLL_PUBLIC value n_mk_config() {
|
||||||
/* cleanup and return */
|
/* cleanup and return */
|
||||||
CAMLreturn(result);
|
CAMLreturn(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* on_clause callback infrastructure */
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
value callback; /* OCaml callback closure, registered as global root */
|
||||||
|
Z3_context_plus cp; /* solver's context, for wrapping AST values */
|
||||||
|
} ml_on_clause_ctx;
|
||||||
|
|
||||||
|
static void caml_ml_on_clause_eh(void* ctx, Z3_ast proof_hint, unsigned n, unsigned const* deps, Z3_ast_vector literals) {
|
||||||
|
CAMLparam0();
|
||||||
|
CAMLlocal5(cb, ph_opt, deps_cons, lv, cell);
|
||||||
|
CAMLlocal1(ast_v);
|
||||||
|
unsigned i;
|
||||||
|
ml_on_clause_ctx* oc;
|
||||||
|
Z3_context_plus cp;
|
||||||
|
|
||||||
|
oc = (ml_on_clause_ctx*)ctx;
|
||||||
|
cb = oc->callback;
|
||||||
|
cp = oc->cp;
|
||||||
|
|
||||||
|
/* Build proof_hint as OCaml ast option */
|
||||||
|
if (proof_hint == NULL) {
|
||||||
|
ph_opt = Val_int(0); /* None */
|
||||||
|
} else {
|
||||||
|
ast_v = caml_alloc_custom_mem(&Z3_ast_plus_custom_ops, sizeof(Z3_ast_plus), 8);
|
||||||
|
*(Z3_ast_plus*)Data_custom_val(ast_v) = Z3_ast_plus_mk(cp, proof_hint);
|
||||||
|
ph_opt = caml_alloc_small(1, 0); /* Some */
|
||||||
|
Field(ph_opt, 0) = ast_v;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Build deps as OCaml int list, constructed right-to-left */
|
||||||
|
deps_cons = Val_int(0); /* [] */
|
||||||
|
for (i = n; i-- > 0; ) {
|
||||||
|
cell = caml_alloc_small(2, 0);
|
||||||
|
Field(cell, 0) = Val_int((int)deps[i]);
|
||||||
|
Field(cell, 1) = deps_cons;
|
||||||
|
deps_cons = cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create literals as ast_vector OCaml value */
|
||||||
|
lv = caml_alloc_custom_mem(&Z3_ast_vector_plus_custom_ops, sizeof(Z3_ast_vector_plus), 32);
|
||||||
|
*(Z3_ast_vector_plus*)Data_custom_val(lv) = Z3_ast_vector_plus_mk(cp, literals);
|
||||||
|
|
||||||
|
caml_callback3(cb, ph_opt, deps_cons, lv);
|
||||||
|
|
||||||
|
CAMLreturn0;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAMLprim DLL_PUBLIC value n_solver_register_on_clause(value ctx_v, value solver_v, value cb_v) {
|
||||||
|
CAMLparam3(ctx_v, solver_v, cb_v);
|
||||||
|
Z3_context_plus cp;
|
||||||
|
Z3_solver_plus* sp;
|
||||||
|
ml_on_clause_ctx* oc;
|
||||||
|
|
||||||
|
cp = *(Z3_context_plus*)Data_custom_val(ctx_v);
|
||||||
|
sp = (Z3_solver_plus*)Data_custom_val(solver_v);
|
||||||
|
|
||||||
|
oc = (ml_on_clause_ctx*)malloc(sizeof(ml_on_clause_ctx));
|
||||||
|
if (!oc) caml_raise_out_of_memory();
|
||||||
|
|
||||||
|
oc->callback = cb_v;
|
||||||
|
oc->cp = cp;
|
||||||
|
caml_register_global_root(&oc->callback);
|
||||||
|
|
||||||
|
Z3_solver_register_on_clause(cp->ctx, sp->p, (void*)oc, caml_ml_on_clause_eh);
|
||||||
|
|
||||||
|
CAMLreturn(Val_unit);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue