mirror of
https://github.com/Z3Prover/z3
synced 2026-02-21 15:57:35 +00:00
git bindings v1.0
This commit is contained in:
parent
e2486eff77
commit
66d0fb5477
33 changed files with 5289 additions and 7 deletions
|
|
@ -9,6 +9,7 @@ set(MK_API_DOC_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/mk_api_doc.py")
|
|||
set(PYTHON_API_OPTIONS "")
|
||||
set(DOTNET_API_OPTIONS "")
|
||||
set(JAVA_API_OPTIONS "")
|
||||
set(GO_API_OPTIONS "")
|
||||
SET(DOC_EXTRA_DEPENDS "")
|
||||
|
||||
if (Z3_BUILD_PYTHON_BINDINGS)
|
||||
|
|
@ -41,6 +42,15 @@ else()
|
|||
list(APPEND JAVA_API_OPTIONS "--no-java")
|
||||
endif()
|
||||
|
||||
if (Z3_BUILD_GO_BINDINGS)
|
||||
list(APPEND GO_API_OPTIONS "--go")
|
||||
list(APPEND GO_API_OPTIONS "--go-search-paths"
|
||||
"${PROJECT_SOURCE_DIR}/src/api/go"
|
||||
)
|
||||
else()
|
||||
# Go bindings don't have a --no-go option, just omit --go
|
||||
endif()
|
||||
|
||||
option(Z3_ALWAYS_BUILD_DOCS "Always build documentation for API bindings" ON)
|
||||
if (Z3_ALWAYS_BUILD_DOCS)
|
||||
set(ALWAYS_BUILD_DOCS_ARG "ALL")
|
||||
|
|
@ -66,12 +76,26 @@ add_custom_target(api_docs ${ALWAYS_BUILD_DOCS_ARG}
|
|||
${PYTHON_API_OPTIONS}
|
||||
${DOTNET_API_OPTIONS}
|
||||
${JAVA_API_OPTIONS}
|
||||
${GO_API_OPTIONS}
|
||||
DEPENDS
|
||||
${DOC_EXTRA_DEPENDS}
|
||||
COMMENT "Generating documentation"
|
||||
USES_TERMINAL
|
||||
)
|
||||
|
||||
# Add separate target for Go documentation
|
||||
if (Z3_BUILD_GO_BINDINGS)
|
||||
set(MK_GO_DOC_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/mk_go_doc.py")
|
||||
add_custom_target(go_docs
|
||||
COMMAND
|
||||
"${Python3_EXECUTABLE}" "${MK_GO_DOC_SCRIPT}"
|
||||
--output-dir "${DOC_DEST_DIR}/html/go"
|
||||
--go-api-path "${PROJECT_SOURCE_DIR}/src/api/go"
|
||||
COMMENT "Generating Go API documentation"
|
||||
USES_TERMINAL
|
||||
)
|
||||
endif()
|
||||
|
||||
# Remove generated documentation when running `clean` target.
|
||||
set_property(DIRECTORY APPEND PROPERTY
|
||||
ADDITIONAL_MAKE_CLEAN_FILES
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
API documentation
|
||||
-----------------
|
||||
|
||||
To generate the API documentation for the C, C++, .NET, Java and Python APIs, we must execute
|
||||
To generate the API documentation for the C, C++, .NET, Java, Python, and Go APIs, we must execute
|
||||
|
||||
python mk_api_doc.py
|
||||
|
||||
|
|
@ -10,6 +10,12 @@ We must have doxygen installed in our system.
|
|||
The documentation will be stored in the subdirectory './api/html'.
|
||||
The main file is './api/html/index.html'
|
||||
|
||||
To include Go API documentation, use:
|
||||
|
||||
python mk_api_doc.py --go
|
||||
|
||||
Note: Go documentation requires Go to be installed (for godoc support).
|
||||
|
||||
Code documentation
|
||||
------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -15,24 +15,27 @@ import subprocess
|
|||
ML_ENABLED=False
|
||||
MLD_ENABLED=False
|
||||
JS_ENABLED=False
|
||||
GO_ENABLED=False
|
||||
BUILD_DIR='../build'
|
||||
DOXYGEN_EXE='doxygen'
|
||||
TEMP_DIR=os.path.join(os.getcwd(), 'tmp')
|
||||
OUTPUT_DIRECTORY=os.path.join(os.getcwd(), 'api')
|
||||
Z3PY_PACKAGE_PATH='../src/api/python/z3'
|
||||
JS_API_PATH='../src/api/js'
|
||||
GO_API_PATH='../src/api/go'
|
||||
Z3PY_ENABLED=True
|
||||
DOTNET_ENABLED=True
|
||||
JAVA_ENABLED=True
|
||||
Z3OPTIONS_ENABLED=True
|
||||
DOTNET_API_SEARCH_PATHS=['../src/api/dotnet']
|
||||
JAVA_API_SEARCH_PATHS=['../src/api/java']
|
||||
GO_API_SEARCH_PATHS=['../src/api/go']
|
||||
SCRIPT_DIR=os.path.abspath(os.path.dirname(__file__))
|
||||
|
||||
def parse_options():
|
||||
global ML_ENABLED, MLD_ENABLED, BUILD_DIR, DOXYGEN_EXE, TEMP_DIR, OUTPUT_DIRECTORY
|
||||
global Z3PY_PACKAGE_PATH, Z3PY_ENABLED, DOTNET_ENABLED, JAVA_ENABLED, JS_ENABLED
|
||||
global DOTNET_API_SEARCH_PATHS, JAVA_API_SEARCH_PATHS, JS_API_PATH
|
||||
global Z3PY_PACKAGE_PATH, Z3PY_ENABLED, DOTNET_ENABLED, JAVA_ENABLED, JS_ENABLED, GO_ENABLED
|
||||
global DOTNET_API_SEARCH_PATHS, JAVA_API_SEARCH_PATHS, GO_API_SEARCH_PATHS, JS_API_PATH, GO_API_PATH
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('-b',
|
||||
'--build',
|
||||
|
|
@ -54,6 +57,11 @@ def parse_options():
|
|||
default=False,
|
||||
help='Include JS/TS API documentation'
|
||||
)
|
||||
parser.add_argument('--go',
|
||||
action='store_true',
|
||||
default=False,
|
||||
help='Include Go API documentation'
|
||||
)
|
||||
parser.add_argument('--doxygen-executable',
|
||||
dest='doxygen_executable',
|
||||
default=DOXYGEN_EXE,
|
||||
|
|
@ -109,10 +117,17 @@ def parse_options():
|
|||
default=JAVA_API_SEARCH_PATHS,
|
||||
help='Specify one or more paths to look for Java files (default: %(default)s).',
|
||||
)
|
||||
parser.add_argument('--go-search-paths',
|
||||
dest='go_search_paths',
|
||||
nargs='+',
|
||||
default=GO_API_SEARCH_PATHS,
|
||||
help='Specify one or more paths to look for Go files (default: %(default)s).',
|
||||
)
|
||||
pargs = parser.parse_args()
|
||||
ML_ENABLED = pargs.ml
|
||||
MLD_ENABLED = pargs.mld
|
||||
JS_ENABLED = pargs.js
|
||||
GO_ENABLED = pargs.go
|
||||
BUILD_DIR = pargs.build
|
||||
DOXYGEN_EXE = pargs.doxygen_executable
|
||||
TEMP_DIR = pargs.temp_dir
|
||||
|
|
@ -123,6 +138,7 @@ def parse_options():
|
|||
JAVA_ENABLED = not pargs.no_java
|
||||
DOTNET_API_SEARCH_PATHS = pargs.dotnet_search_paths
|
||||
JAVA_API_SEARCH_PATHS = pargs.java_search_paths
|
||||
GO_API_SEARCH_PATHS = pargs.go_search_paths
|
||||
|
||||
if Z3PY_ENABLED:
|
||||
if not os.path.exists(Z3PY_PACKAGE_PATH):
|
||||
|
|
@ -288,6 +304,18 @@ try:
|
|||
print("Java documentation disabled")
|
||||
doxygen_config_substitutions['JAVA_API_FILES'] = ''
|
||||
doxygen_config_substitutions['JAVA_API_SEARCH_PATHS'] = ''
|
||||
if GO_ENABLED:
|
||||
print("Go documentation enabled")
|
||||
doxygen_config_substitutions['GO_API_FILES'] = '*.go'
|
||||
go_api_search_path_str = ""
|
||||
for p in GO_API_SEARCH_PATHS:
|
||||
# Quote path so that paths with spaces are handled correctly
|
||||
go_api_search_path_str += "\"{}\" ".format(p)
|
||||
doxygen_config_substitutions['GO_API_SEARCH_PATHS'] = go_api_search_path_str
|
||||
else:
|
||||
print("Go documentation disabled")
|
||||
doxygen_config_substitutions['GO_API_FILES'] = ''
|
||||
doxygen_config_substitutions['GO_API_SEARCH_PATHS'] = ''
|
||||
if JS_ENABLED:
|
||||
print('Javascript documentation enabled')
|
||||
else:
|
||||
|
|
@ -350,6 +378,13 @@ try:
|
|||
prefix=bullet_point_prefix)
|
||||
else:
|
||||
website_dox_substitutions['JS_API'] = ''
|
||||
if GO_ENABLED:
|
||||
website_dox_substitutions['GO_API'] = (
|
||||
'{prefix}<a class="el" href="go/index.html">Go API</a>'
|
||||
).format(
|
||||
prefix=bullet_point_prefix)
|
||||
else:
|
||||
website_dox_substitutions['GO_API'] = ''
|
||||
configure_file(
|
||||
doc_path('website.dox.in'),
|
||||
temp_path('website.dox'),
|
||||
|
|
@ -428,6 +463,97 @@ try:
|
|||
exit(1)
|
||||
print("Generated Javascript documentation.")
|
||||
|
||||
if GO_ENABLED:
|
||||
go_output_dir = os.path.join(OUTPUT_DIRECTORY, 'html', 'go')
|
||||
mk_dir(go_output_dir)
|
||||
go_api_abs_path = os.path.abspath(GO_API_PATH)
|
||||
|
||||
# Check if godoc is available
|
||||
godoc_available = False
|
||||
try:
|
||||
subprocess.check_output(['go', 'version'], stderr=subprocess.STDOUT)
|
||||
godoc_available = True
|
||||
except (subprocess.CalledProcessError, FileNotFoundError):
|
||||
print("WARNING: Go is not installed. Skipping godoc generation.")
|
||||
godoc_available = False
|
||||
|
||||
if godoc_available:
|
||||
# Generate godoc HTML for each Go file
|
||||
go_files = [
|
||||
'z3.go', 'solver.go', 'tactic.go', 'bitvec.go',
|
||||
'fp.go', 'seq.go', 'datatype.go', 'optimize.go'
|
||||
]
|
||||
|
||||
# Create a simple HTML index
|
||||
index_html = os.path.join(go_output_dir, 'index.html')
|
||||
with open(index_html, 'w') as f:
|
||||
f.write('<!DOCTYPE html>\n<html>\n<head>\n')
|
||||
f.write('<title>Z3 Go API Documentation</title>\n')
|
||||
f.write('<style>\n')
|
||||
f.write('body { font-family: Arial, sans-serif; margin: 40px; }\n')
|
||||
f.write('h1 { color: #333; }\n')
|
||||
f.write('ul { list-style-type: none; padding: 0; }\n')
|
||||
f.write('li { margin: 10px 0; }\n')
|
||||
f.write('a { color: #0066cc; text-decoration: none; font-size: 18px; }\n')
|
||||
f.write('a:hover { text-decoration: underline; }\n')
|
||||
f.write('.description { color: #666; margin-left: 20px; }\n')
|
||||
f.write('</style>\n')
|
||||
f.write('</head>\n<body>\n')
|
||||
f.write('<h1>Z3 Go API Documentation</h1>\n')
|
||||
f.write('<p>Go bindings for the Z3 Theorem Prover.</p>\n')
|
||||
f.write('<h2>Package: github.com/Z3Prover/z3/src/api/go</h2>\n')
|
||||
f.write('<ul>\n')
|
||||
|
||||
# Add links to the README
|
||||
readme_path = os.path.join(go_api_abs_path, 'README.md')
|
||||
if os.path.exists(readme_path):
|
||||
# Copy README as index documentation
|
||||
readme_html_path = os.path.join(go_output_dir, 'README.html')
|
||||
try:
|
||||
# Try to convert markdown to HTML if markdown module is available
|
||||
with open(readme_path, 'r') as rf:
|
||||
readme_content = rf.read()
|
||||
with open(readme_html_path, 'w') as wf:
|
||||
wf.write('<!DOCTYPE html>\n<html>\n<head>\n')
|
||||
wf.write('<title>Z3 Go API - README</title>\n')
|
||||
wf.write('<style>body { font-family: Arial, sans-serif; margin: 40px; max-width: 900px; }</style>\n')
|
||||
wf.write('</head>\n<body>\n<pre>\n')
|
||||
wf.write(readme_content)
|
||||
wf.write('</pre>\n</body>\n</html>\n')
|
||||
f.write('<li><a href="README.html">README - Getting Started</a></li>\n')
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not process README.md: {e}")
|
||||
|
||||
# Add module descriptions
|
||||
f.write('<li><a href="#core">z3.go</a> - Core types (Context, Config, Symbol, Sort, Expr, FuncDecl)</li>\n')
|
||||
f.write('<li><a href="#solver">solver.go</a> - Solver and Model API</li>\n')
|
||||
f.write('<li><a href="#tactic">tactic.go</a> - Tactics, Goals, Probes, and Parameters</li>\n')
|
||||
f.write('<li><a href="#bitvec">bitvec.go</a> - Bit-vector operations</li>\n')
|
||||
f.write('<li><a href="#fp">fp.go</a> - Floating-point operations</li>\n')
|
||||
f.write('<li><a href="#seq">seq.go</a> - Sequences, strings, and regular expressions</li>\n')
|
||||
f.write('<li><a href="#datatype">datatype.go</a> - Algebraic datatypes, tuples, enumerations</li>\n')
|
||||
f.write('<li><a href="#optimize">optimize.go</a> - Optimization with maximize/minimize objectives</li>\n')
|
||||
f.write('</ul>\n')
|
||||
|
||||
f.write('<h2>Usage</h2>\n')
|
||||
f.write('<pre>\n')
|
||||
f.write('import "github.com/Z3Prover/z3/src/api/go"\n\n')
|
||||
f.write('ctx := z3.NewContext()\n')
|
||||
f.write('solver := ctx.NewSolver()\n')
|
||||
f.write('x := ctx.MkIntConst("x")\n')
|
||||
f.write('solver.Assert(ctx.MkGt(x, ctx.MkInt(0, ctx.MkIntSort())))\n')
|
||||
f.write('if solver.Check() == z3.Satisfiable {\n')
|
||||
f.write(' fmt.Println("sat")\n')
|
||||
f.write('}\n')
|
||||
f.write('</pre>\n')
|
||||
|
||||
f.write('<h2>Installation</h2>\n')
|
||||
f.write('<p>See <a href="README.html">README</a> for build instructions.</p>\n')
|
||||
f.write('<p>Go back to <a href="../index.html">main API documentation</a>.</p>\n')
|
||||
f.write('</body>\n</html>\n')
|
||||
|
||||
print("Generated Go documentation.")
|
||||
|
||||
print("Documentation was successfully generated at subdirectory '{}'.".format(OUTPUT_DIRECTORY))
|
||||
except Exception:
|
||||
exctype, value = sys.exc_info()[:2]
|
||||
|
|
|
|||
654
doc/mk_go_doc.py
Normal file
654
doc/mk_go_doc.py
Normal file
|
|
@ -0,0 +1,654 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright (c) Microsoft Corporation 2025
|
||||
"""
|
||||
Z3 Go API documentation generator script
|
||||
|
||||
This script generates HTML documentation for the Z3 Go bindings.
|
||||
It creates a browsable HTML interface for the Go API documentation.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import argparse
|
||||
import re
|
||||
|
||||
SCRIPT_DIR = os.path.abspath(os.path.dirname(__file__))
|
||||
GO_API_PATH = os.path.join(SCRIPT_DIR, '..', 'src', 'api', 'go')
|
||||
OUTPUT_DIR = os.path.join(SCRIPT_DIR, 'api', 'html', 'go')
|
||||
|
||||
def extract_types_and_functions(filepath):
|
||||
"""Extract type and function names from a Go source file."""
|
||||
types = []
|
||||
functions = []
|
||||
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
content = f.read()
|
||||
|
||||
# Extract type declarations
|
||||
type_pattern = r'type\s+(\w+)\s+(?:struct|interface)'
|
||||
types = re.findall(type_pattern, content)
|
||||
|
||||
# Extract function/method declarations
|
||||
# Match both: func Name() and func (r *Type) Name()
|
||||
func_pattern = r'func\s+(?:\([^)]+\)\s+)?(\w+)\s*\('
|
||||
functions = re.findall(func_pattern, content)
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not parse {filepath}: {e}")
|
||||
|
||||
return types, functions
|
||||
|
||||
def extract_detailed_api(filepath):
|
||||
"""Extract detailed type and function information with signatures and comments."""
|
||||
types_info = {}
|
||||
functions_info = []
|
||||
context_methods = [] # Special handling for Context methods
|
||||
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
i = 0
|
||||
|
||||
while i < len(lines):
|
||||
line = lines[i].strip()
|
||||
|
||||
# Extract type with comment
|
||||
if line.startswith('type ') and ('struct' in line or 'interface' in line):
|
||||
# Look back for comment
|
||||
comment = ""
|
||||
j = i - 1
|
||||
while j >= 0 and (lines[j].strip().startswith('//') or lines[j].strip() == ''):
|
||||
if lines[j].strip().startswith('//'):
|
||||
comment = lines[j].strip()[2:].strip() + " " + comment
|
||||
j -= 1
|
||||
|
||||
match = re.match(r'type\s+(\w+)\s+', line)
|
||||
if match:
|
||||
type_name = match.group(1)
|
||||
types_info[type_name] = {
|
||||
'comment': comment.strip(),
|
||||
'methods': []
|
||||
}
|
||||
|
||||
# Extract function/method with signature and comment
|
||||
if line.startswith('func '):
|
||||
# Look back for comment
|
||||
comment = ""
|
||||
j = i - 1
|
||||
while j >= 0 and (lines[j].strip().startswith('//') or lines[j].strip() == ''):
|
||||
if lines[j].strip().startswith('//'):
|
||||
comment = lines[j].strip()[2:].strip() + " " + comment
|
||||
j -= 1
|
||||
|
||||
# Extract full signature (may span multiple lines)
|
||||
signature = line
|
||||
k = i + 1
|
||||
while k < len(lines) and '{' not in signature:
|
||||
signature += ' ' + lines[k].strip()
|
||||
k += 1
|
||||
|
||||
# Remove body
|
||||
if '{' in signature:
|
||||
signature = signature[:signature.index('{')].strip()
|
||||
|
||||
# Parse receiver if method
|
||||
method_match = re.match(r'func\s+\(([^)]+)\)\s+(\w+)', signature)
|
||||
func_match = re.match(r'func\s+(\w+)', signature)
|
||||
|
||||
if method_match:
|
||||
receiver = method_match.group(1).strip()
|
||||
func_name = method_match.group(2)
|
||||
# Extract receiver type
|
||||
receiver_type = receiver.split()[-1].strip('*')
|
||||
|
||||
# Only add if function name is public
|
||||
if func_name[0].isupper():
|
||||
if receiver_type == 'Context':
|
||||
# Special handling for Context methods - add to context_methods
|
||||
context_methods.append({
|
||||
'name': func_name,
|
||||
'signature': signature,
|
||||
'comment': comment.strip()
|
||||
})
|
||||
elif receiver_type in types_info:
|
||||
types_info[receiver_type]['methods'].append({
|
||||
'name': func_name,
|
||||
'signature': signature,
|
||||
'comment': comment.strip()
|
||||
})
|
||||
elif func_match:
|
||||
func_name = func_match.group(1)
|
||||
# Only add if it's public (starts with capital)
|
||||
if func_name[0].isupper():
|
||||
functions_info.append({
|
||||
'name': func_name,
|
||||
'signature': signature,
|
||||
'comment': comment.strip()
|
||||
})
|
||||
|
||||
i += 1
|
||||
|
||||
# If we have Context methods but no other content, return them as functions
|
||||
if context_methods and not types_info and not functions_info:
|
||||
functions_info = context_methods
|
||||
elif context_methods:
|
||||
# Add Context pseudo-type
|
||||
types_info['Context'] = {
|
||||
'comment': 'Context methods (receiver omitted for clarity)',
|
||||
'methods': context_methods
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not parse detailed API from {filepath}: {e}")
|
||||
|
||||
return types_info, functions_info
|
||||
|
||||
def extract_package_comment(filepath):
|
||||
"""Extract the package-level documentation comment from a Go file."""
|
||||
try:
|
||||
with open(filepath, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
comment_lines = []
|
||||
in_comment = False
|
||||
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('/*'):
|
||||
in_comment = True
|
||||
comment_lines.append(stripped[2:].strip())
|
||||
elif in_comment:
|
||||
if '*/' in stripped:
|
||||
comment_lines.append(stripped.replace('*/', '').strip())
|
||||
break
|
||||
comment_lines.append(stripped.lstrip('*').strip())
|
||||
elif stripped.startswith('//'):
|
||||
comment_lines.append(stripped[2:].strip())
|
||||
elif stripped.startswith('package'):
|
||||
break
|
||||
|
||||
return ' '.join(comment_lines).strip() if comment_lines else None
|
||||
except Exception as e:
|
||||
return None
|
||||
|
||||
def parse_args():
|
||||
parser = argparse.ArgumentParser(description=__doc__)
|
||||
parser.add_argument('-o', '--output-dir',
|
||||
dest='output_dir',
|
||||
default=OUTPUT_DIR,
|
||||
help='Output directory for documentation (default: %(default)s)',
|
||||
)
|
||||
parser.add_argument('--go-api-path',
|
||||
dest='go_api_path',
|
||||
default=GO_API_PATH,
|
||||
help='Path to Go API source files (default: %(default)s)',
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
def check_go_installed():
|
||||
"""Check if Go is installed and available."""
|
||||
try:
|
||||
# Try to find go in common locations
|
||||
go_paths = [
|
||||
'go',
|
||||
'C:\\Program Files\\Go\\bin\\go.exe',
|
||||
'C:\\Go\\bin\\go.exe',
|
||||
]
|
||||
|
||||
for go_cmd in go_paths:
|
||||
try:
|
||||
result = subprocess.run([go_cmd, 'version'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
check=True,
|
||||
timeout=5)
|
||||
print(f"Found Go: {result.stdout.strip()}")
|
||||
return go_cmd
|
||||
except (subprocess.CalledProcessError, FileNotFoundError, subprocess.TimeoutExpired):
|
||||
continue
|
||||
|
||||
print("WARNING: Go is not installed or not in PATH")
|
||||
print("Install Go from https://golang.org/dl/ for enhanced documentation")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"WARNING: Could not check Go installation: {e}")
|
||||
return None
|
||||
|
||||
def extract_package_comment(go_file_path):
|
||||
"""Extract package-level documentation comment from a Go file."""
|
||||
try:
|
||||
with open(go_file_path, 'r', encoding='utf-8') as f:
|
||||
lines = f.readlines()
|
||||
in_comment = False
|
||||
comment_lines = []
|
||||
|
||||
for line in lines:
|
||||
stripped = line.strip()
|
||||
if stripped.startswith('/*'):
|
||||
in_comment = True
|
||||
comment_lines.append(stripped[2:].strip())
|
||||
elif in_comment:
|
||||
if stripped.endswith('*/'):
|
||||
comment_lines.append(stripped[:-2].strip())
|
||||
break
|
||||
comment_lines.append(stripped.lstrip('*').strip())
|
||||
elif stripped.startswith('//'):
|
||||
comment_lines.append(stripped[2:].strip())
|
||||
elif stripped.startswith('package '):
|
||||
break
|
||||
|
||||
return ' '.join(comment_lines).strip()
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not extract comment from {go_file_path}: {e}")
|
||||
return ""
|
||||
|
||||
def generate_godoc_markdown(go_cmd, go_api_path, output_dir):
|
||||
"""Generate markdown documentation using godoc."""
|
||||
print("Generating documentation with godoc...")
|
||||
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
try:
|
||||
# Change to the Go API directory
|
||||
orig_dir = os.getcwd()
|
||||
os.chdir(go_api_path)
|
||||
|
||||
# Run go doc to get package documentation
|
||||
result = subprocess.run(
|
||||
[go_cmd, 'doc', '-all'],
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=30
|
||||
)
|
||||
|
||||
if result.returncode == 0:
|
||||
# Create markdown file
|
||||
doc_text = result.stdout
|
||||
godoc_md = os.path.join(output_dir, 'godoc.md')
|
||||
|
||||
with open(godoc_md, 'w', encoding='utf-8') as f:
|
||||
f.write('# Z3 Go API Documentation (godoc)\n\n')
|
||||
f.write(doc_text)
|
||||
|
||||
print(f"Generated godoc markdown at: {godoc_md}")
|
||||
os.chdir(orig_dir)
|
||||
return True
|
||||
else:
|
||||
print(f"godoc returned error: {result.stderr}")
|
||||
os.chdir(orig_dir)
|
||||
return False
|
||||
|
||||
except Exception as e:
|
||||
print(f"Error generating godoc markdown: {e}")
|
||||
try:
|
||||
os.chdir(orig_dir)
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def generate_module_page(module_filename, description, go_api_path, output_dir):
|
||||
"""Generate a detailed HTML page for a single Go module."""
|
||||
file_path = os.path.join(go_api_path, module_filename)
|
||||
if not os.path.exists(file_path):
|
||||
return
|
||||
|
||||
module_name = module_filename.replace('.go', '')
|
||||
output_path = os.path.join(output_dir, f'{module_name}.html')
|
||||
|
||||
# Extract detailed API information
|
||||
types_info, functions_info = extract_detailed_api(file_path)
|
||||
|
||||
with open(output_path, 'w', encoding='utf-8') as f:
|
||||
f.write('<!DOCTYPE html>\n<html lang="en">\n<head>\n')
|
||||
f.write(' <meta charset="UTF-8">\n')
|
||||
f.write(f' <title>{module_filename} - Z3 Go API</title>\n')
|
||||
f.write(' <style>\n')
|
||||
f.write(' body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; padding: 0; line-height: 1.6; }\n')
|
||||
f.write(' header { background: #2d3748; color: white; padding: 2rem; }\n')
|
||||
f.write(' header h1 { margin: 0; font-size: 2rem; }\n')
|
||||
f.write(' header p { margin: 0.5rem 0 0 0; opacity: 0.9; }\n')
|
||||
f.write(' .container { max-width: 1200px; margin: 0 auto; padding: 2rem; }\n')
|
||||
f.write(' .nav { background: #edf2f7; padding: 1rem; margin-bottom: 2rem; border-radius: 4px; }\n')
|
||||
f.write(' .nav a { color: #2b6cb0; text-decoration: none; margin-right: 1rem; }\n')
|
||||
f.write(' .nav a:hover { text-decoration: underline; }\n')
|
||||
f.write(' h2 { color: #2d3748; border-bottom: 2px solid #4299e1; padding-bottom: 0.5rem; margin-top: 2rem; }\n')
|
||||
f.write(' h3 { color: #2d3748; margin-top: 1.5rem; }\n')
|
||||
f.write(' .type-section, .function-section { margin: 1.5rem 0; }\n')
|
||||
f.write(' .api-item { background: #f7fafc; padding: 1rem; margin: 1rem 0; border-left: 4px solid #4299e1; border-radius: 4px; }\n')
|
||||
f.write(' .api-item h4 { margin: 0 0 0.5rem 0; color: #2b6cb0; font-family: monospace; }\n')
|
||||
f.write(' .signature { background: #2d3748; color: #e2e8f0; padding: 0.75rem; border-radius: 4px; font-family: monospace; overflow-x: auto; margin: 0.5rem 0; }\n')
|
||||
f.write(' .comment { color: #4a5568; margin: 0.5rem 0; }\n')
|
||||
f.write(' code { background: #e2e8f0; padding: 2px 6px; border-radius: 3px; font-family: monospace; }\n')
|
||||
f.write(' .method-list { margin-left: 1rem; }\n')
|
||||
f.write(' </style>\n')
|
||||
f.write('</head>\n<body>\n')
|
||||
|
||||
f.write(' <header>\n')
|
||||
f.write(f' <h1>{module_filename}</h1>\n')
|
||||
f.write(f' <p>{description}</p>\n')
|
||||
f.write(' </header>\n')
|
||||
|
||||
f.write(' <div class="container">\n')
|
||||
f.write(' <div class="nav">\n')
|
||||
f.write(' <a href="index.html">← Back to Index</a>\n')
|
||||
f.write(' <a href="godoc.md">Complete API Reference (markdown)</a>\n')
|
||||
f.write(' <a href="README.md">README</a>\n')
|
||||
f.write(' <a href="../index.html">All Languages</a>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
# Types section
|
||||
if types_info:
|
||||
f.write(' <h2>Types</h2>\n')
|
||||
for type_name in sorted(types_info.keys()):
|
||||
type_data = types_info[type_name]
|
||||
f.write(' <div class="type-section">\n')
|
||||
f.write(f' <h3>type {type_name}</h3>\n')
|
||||
if type_data['comment']:
|
||||
f.write(f' <p class="comment">{type_data["comment"]}</p>\n')
|
||||
|
||||
# Methods
|
||||
if type_data['methods']:
|
||||
f.write(' <div class="method-list">\n')
|
||||
f.write(' <h4>Methods:</h4>\n')
|
||||
for method in sorted(type_data['methods'], key=lambda m: m['name']):
|
||||
f.write(' <div class="api-item">\n')
|
||||
f.write(f' <h4>{method["name"]}</h4>\n')
|
||||
f.write(f' <div class="signature">{method["signature"]}</div>\n')
|
||||
if method['comment']:
|
||||
f.write(f' <p class="comment">{method["comment"]}</p>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
# Package functions section
|
||||
if functions_info:
|
||||
f.write(' <h2>Functions</h2>\n')
|
||||
f.write(' <div class="function-section">\n')
|
||||
for func in sorted(functions_info, key=lambda f: f['name']):
|
||||
f.write(' <div class="api-item">\n')
|
||||
f.write(f' <h4>{func["name"]}</h4>\n')
|
||||
f.write(f' <div class="signature">{func["signature"]}</div>\n')
|
||||
if func['comment']:
|
||||
f.write(f' <p class="comment">{func["comment"]}</p>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
if not types_info and not functions_info:
|
||||
f.write(' <p><em>No public API documentation extracted. See godoc for complete reference.</em></p>\n')
|
||||
|
||||
f.write(' <div class="nav" style="margin-top: 3rem;">\n')
|
||||
f.write(' <a href="index.html">← Back to Index</a>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write('</body>\n</html>\n')
|
||||
|
||||
print(f"Generated module page: {output_path}")
|
||||
|
||||
def generate_html_docs(go_api_path, output_dir):
|
||||
"""Generate HTML documentation for Go bindings."""
|
||||
|
||||
# Create output directory
|
||||
os.makedirs(output_dir, exist_ok=True)
|
||||
|
||||
# Go source files and their descriptions
|
||||
go_files = {
|
||||
'z3.go': 'Core types (Context, Config, Symbol, Sort, Expr, FuncDecl, Quantifier, Lambda) and basic operations',
|
||||
'solver.go': 'Solver and Model API for SMT solving',
|
||||
'tactic.go': 'Tactics, Goals, Probes, and Parameters for goal-based solving',
|
||||
'arith.go': 'Arithmetic operations (integers, reals) and comparisons',
|
||||
'array.go': 'Array operations (select, store, constant arrays)',
|
||||
'bitvec.go': 'Bit-vector operations and constraints',
|
||||
'fp.go': 'IEEE 754 floating-point operations',
|
||||
'seq.go': 'Sequences, strings, and regular expressions',
|
||||
'datatype.go': 'Algebraic datatypes, tuples, and enumerations',
|
||||
'optimize.go': 'Optimization with maximize/minimize objectives',
|
||||
'fixedpoint.go': 'Fixedpoint solver for Datalog and constrained Horn clauses (CHC)',
|
||||
'log.go': 'Interaction logging for debugging and analysis',
|
||||
}
|
||||
|
||||
# Generate main index.html
|
||||
index_path = os.path.join(output_dir, 'index.html')
|
||||
with open(index_path, 'w', encoding='utf-8') as f:
|
||||
f.write('<!DOCTYPE html>\n')
|
||||
f.write('<html lang="en">\n')
|
||||
f.write('<head>\n')
|
||||
f.write(' <meta charset="UTF-8">\n')
|
||||
f.write(' <meta name="viewport" content="width=device-width, initial-scale=1.0">\n')
|
||||
f.write(' <title>Z3 Go API Documentation</title>\n')
|
||||
f.write(' <style>\n')
|
||||
f.write(' body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; padding: 0; line-height: 1.6; }\n')
|
||||
f.write(' header { background: #2d3748; color: white; padding: 2rem; }\n')
|
||||
f.write(' header h1 { margin: 0; font-size: 2.5rem; }\n')
|
||||
f.write(' header p { margin: 0.5rem 0 0 0; font-size: 1.1rem; opacity: 0.9; }\n')
|
||||
f.write(' .container { max-width: 1200px; margin: 0 auto; padding: 2rem; }\n')
|
||||
f.write(' .section { margin: 2rem 0; }\n')
|
||||
f.write(' .section h2 { color: #2d3748; border-bottom: 2px solid #4299e1; padding-bottom: 0.5rem; }\n')
|
||||
f.write(' .file-list { list-style: none; padding: 0; }\n')
|
||||
f.write(' .file-item { background: #f7fafc; border-left: 4px solid #4299e1; margin: 1rem 0; padding: 1rem; border-radius: 4px; }\n')
|
||||
f.write(' .file-item h3 { margin: 0 0 0.5rem 0; color: #2d3748; }\n')
|
||||
f.write(' .file-item h3 a { color: #2b6cb0; text-decoration: none; }\n')
|
||||
f.write(' .file-item h3 a:hover { color: #4299e1; text-decoration: underline; }\n')
|
||||
f.write(' .file-item p { margin: 0; color: #4a5568; }\n')
|
||||
f.write(' .code-block { background: #2d3748; color: #e2e8f0; padding: 1.5rem; border-radius: 4px; overflow-x: auto; }\n')
|
||||
f.write(' .code-block pre { margin: 0; }\n')
|
||||
f.write(' .install-section { background: #edf2f7; padding: 1.5rem; border-radius: 4px; margin: 1rem 0; }\n')
|
||||
f.write(' .back-link { display: inline-block; margin-top: 2rem; color: #2b6cb0; text-decoration: none; }\n')
|
||||
f.write(' .back-link:hover { text-decoration: underline; }\n')
|
||||
f.write(' </style>\n')
|
||||
f.write('</head>\n')
|
||||
f.write('<body>\n')
|
||||
|
||||
f.write(' <header>\n')
|
||||
f.write(' <h1>Z3 Go API Documentation</h1>\n')
|
||||
f.write(' <p>Go bindings for the Z3 Theorem Prover</p>\n')
|
||||
f.write(' </header>\n')
|
||||
|
||||
f.write(' <div class="container">\n')
|
||||
|
||||
# Overview section
|
||||
f.write(' <div class="section">\n')
|
||||
f.write(' <h2>Overview</h2>\n')
|
||||
f.write(' <p>The Z3 Go bindings provide idiomatic Go access to the Z3 SMT solver. These bindings use CGO to wrap the Z3 C API and provide automatic memory management through Go finalizers.</p>\n')
|
||||
f.write(' <p><strong>Package:</strong> <code>github.com/Z3Prover/z3/src/api/go</code></p>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
# Quick start
|
||||
f.write(' <div class="section">\n')
|
||||
f.write(' <h2>Quick Start</h2>\n')
|
||||
f.write(' <div class="code-block">\n')
|
||||
f.write(' <pre>package main\n\n')
|
||||
f.write('import (\n')
|
||||
f.write(' "fmt"\n')
|
||||
f.write(' "github.com/Z3Prover/z3/src/api/go"\n')
|
||||
f.write(')\n\n')
|
||||
f.write('func main() {\n')
|
||||
f.write(' // Create a context\n')
|
||||
f.write(' ctx := z3.NewContext()\n\n')
|
||||
f.write(' // Create integer variable\n')
|
||||
f.write(' x := ctx.MkIntConst("x")\n\n')
|
||||
f.write(' // Create solver\n')
|
||||
f.write(' solver := ctx.NewSolver()\n\n')
|
||||
f.write(' // Add constraint: x > 0\n')
|
||||
f.write(' zero := ctx.MkInt(0, ctx.MkIntSort())\n')
|
||||
f.write(' solver.Assert(ctx.MkGt(x, zero))\n\n')
|
||||
f.write(' // Check satisfiability\n')
|
||||
f.write(' if solver.Check() == z3.Satisfiable {\n')
|
||||
f.write(' fmt.Println("sat")\n')
|
||||
f.write(' model := solver.Model()\n')
|
||||
f.write(' if val, ok := model.Eval(x, true); ok {\n')
|
||||
f.write(' fmt.Println("x =", val.String())\n')
|
||||
f.write(' }\n')
|
||||
f.write(' }\n')
|
||||
f.write('}</pre>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
# Installation
|
||||
f.write(' <div class="section">\n')
|
||||
f.write(' <h2>Installation</h2>\n')
|
||||
f.write(' <div class="install-section">\n')
|
||||
f.write(' <p><strong>Prerequisites:</strong></p>\n')
|
||||
f.write(' <ul>\n')
|
||||
f.write(' <li>Go 1.20 or later</li>\n')
|
||||
f.write(' <li>Z3 built as a shared library</li>\n')
|
||||
f.write(' <li>CGO enabled (default)</li>\n')
|
||||
f.write(' </ul>\n')
|
||||
f.write(' <p><strong>Build Z3 with Go bindings:</strong></p>\n')
|
||||
f.write(' <div class="code-block">\n')
|
||||
f.write(' <pre># Using CMake\n')
|
||||
f.write('mkdir build && cd build\n')
|
||||
f.write('cmake -DZ3_BUILD_GO_BINDINGS=ON -DZ3_BUILD_LIBZ3_SHARED=ON ..\n')
|
||||
f.write('make\n\n')
|
||||
f.write('# Using Python build script\n')
|
||||
f.write('python scripts/mk_make.py --go\n')
|
||||
f.write('cd build && make</pre>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' <p><strong>Set environment variables:</strong></p>\n')
|
||||
f.write(' <div class="code-block">\n')
|
||||
f.write(' <pre>export CGO_CFLAGS="-I${Z3_ROOT}/src/api"\n')
|
||||
f.write('export CGO_LDFLAGS="-L${Z3_ROOT}/build -lz3"\n')
|
||||
f.write('export LD_LIBRARY_PATH="${Z3_ROOT}/build:$LD_LIBRARY_PATH"</pre>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
# API modules with detailed documentation
|
||||
f.write(' <div class="section">\n')
|
||||
f.write(' <h2>API Modules</h2>\n')
|
||||
|
||||
for filename, description in go_files.items():
|
||||
file_path = os.path.join(go_api_path, filename)
|
||||
if os.path.exists(file_path):
|
||||
module_name = filename.replace('.go', '')
|
||||
|
||||
# Generate individual module page
|
||||
generate_module_page(filename, description, go_api_path, output_dir)
|
||||
|
||||
# Extract types and functions from the file
|
||||
types, functions = extract_types_and_functions(file_path)
|
||||
|
||||
f.write(f' <div class="file-item" id="{module_name}">\n')
|
||||
f.write(f' <h3><a href="{module_name}.html">{filename}</a></h3>\n')
|
||||
f.write(f' <p>{description}</p>\n')
|
||||
|
||||
if types:
|
||||
f.write(' <p><strong>Types:</strong> ')
|
||||
f.write(', '.join([f'<code>{t}</code>' for t in sorted(types)]))
|
||||
f.write('</p>\n')
|
||||
|
||||
if functions:
|
||||
# Filter public functions
|
||||
public_funcs = [f for f in functions if f and len(f) > 0 and f[0].isupper()]
|
||||
if public_funcs:
|
||||
f.write(' <p><strong>Key Functions:</strong> ')
|
||||
# Show first 15 functions to keep it manageable
|
||||
funcs_to_show = sorted(public_funcs)[:15]
|
||||
f.write(', '.join([f'<code>{func}()</code>' for func in funcs_to_show]))
|
||||
if len(public_funcs) > 15:
|
||||
f.write(f' <em>(+{len(public_funcs)-15} more)</em>')
|
||||
f.write('</p>\n')
|
||||
|
||||
f.write(f' <p><a href="{module_name}.html">→ View full API reference</a></p>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
f.write(' </div>\n')
|
||||
|
||||
# Features section
|
||||
f.write(' <div class="section">\n')
|
||||
f.write(' <h2>Features</h2>\n')
|
||||
f.write(' <ul>\n')
|
||||
f.write(' <li><strong>Core SMT:</strong> Boolean logic, arithmetic, arrays, quantifiers</li>\n')
|
||||
f.write(' <li><strong>Bit-vectors:</strong> Fixed-size bit-vector arithmetic and operations</li>\n')
|
||||
f.write(' <li><strong>Floating-point:</strong> IEEE 754 floating-point arithmetic</li>\n')
|
||||
f.write(' <li><strong>Strings & Sequences:</strong> String constraints and sequence operations</li>\n')
|
||||
f.write(' <li><strong>Regular Expressions:</strong> Pattern matching and regex constraints</li>\n')
|
||||
f.write(' <li><strong>Datatypes:</strong> Algebraic datatypes, tuples, enumerations</li>\n')
|
||||
f.write(' <li><strong>Tactics:</strong> Goal-based solving with tactic combinators</li>\n')
|
||||
f.write(' <li><strong>Optimization:</strong> MaxSMT with maximize/minimize objectives</li>\n')
|
||||
f.write(' <li><strong>Memory Management:</strong> Automatic via Go finalizers</li>\n')
|
||||
f.write(' </ul>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
# Resources
|
||||
f.write(' <div class="section">\n')
|
||||
f.write(' <h2>Resources</h2>\n')
|
||||
f.write(' <ul>\n')
|
||||
f.write(' <li><a href="https://github.com/Z3Prover/z3">Z3 GitHub Repository</a></li>\n')
|
||||
f.write(' <li><a href="../index.html">All API Documentation</a></li>\n')
|
||||
|
||||
# Check if README exists and copy it
|
||||
readme_path = os.path.join(go_api_path, 'README.md')
|
||||
if os.path.exists(readme_path):
|
||||
# Copy README.md to output directory
|
||||
readme_dest = os.path.join(output_dir, 'README.md')
|
||||
try:
|
||||
import shutil
|
||||
shutil.copy2(readme_path, readme_dest)
|
||||
f.write(' <li><a href="README.md">Go API README (markdown)</a></li>\n')
|
||||
print(f"Copied README.md to: {readme_dest}")
|
||||
except Exception as e:
|
||||
print(f"Warning: Could not copy README.md: {e}")
|
||||
|
||||
# Link to godoc.md if it will be generated
|
||||
f.write(' <li><a href="godoc.md">Complete API Reference (godoc markdown)</a></li>\n')
|
||||
|
||||
f.write(' </ul>\n')
|
||||
f.write(' </div>\n')
|
||||
|
||||
f.write(' <a href="../index.html" class="back-link">← Back to main API documentation</a>\n')
|
||||
f.write(' </div>\n')
|
||||
f.write('</body>\n')
|
||||
f.write('</html>\n')
|
||||
|
||||
print(f"Generated Go documentation index at: {index_path}")
|
||||
return True
|
||||
|
||||
def main():
|
||||
args = parse_args()
|
||||
|
||||
print("Z3 Go API Documentation Generator")
|
||||
print("=" * 50)
|
||||
|
||||
# Check if Go is installed
|
||||
go_cmd = check_go_installed()
|
||||
|
||||
# Verify Go API path exists
|
||||
if not os.path.exists(args.go_api_path):
|
||||
print(f"ERROR: Go API path does not exist: {args.go_api_path}")
|
||||
return 1
|
||||
|
||||
# Generate documentation
|
||||
print(f"\nGenerating documentation from: {args.go_api_path}")
|
||||
print(f"Output directory: {args.output_dir}")
|
||||
|
||||
# Try godoc first if Go is available
|
||||
godoc_success = False
|
||||
if go_cmd:
|
||||
godoc_success = generate_godoc_markdown(go_cmd, args.go_api_path, args.output_dir)
|
||||
|
||||
# Always generate our custom HTML documentation
|
||||
if not generate_html_docs(args.go_api_path, args.output_dir):
|
||||
print("ERROR: Failed to generate documentation")
|
||||
return 1
|
||||
|
||||
if godoc_success:
|
||||
print("\n✓ Generated both godoc markdown and custom HTML documentation")
|
||||
|
||||
print("\n" + "=" * 50)
|
||||
print("Documentation generated successfully!")
|
||||
print(f"Open {os.path.join(args.output_dir, 'index.html')} in your browser.")
|
||||
|
||||
return 0
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
sys.exit(main())
|
||||
except KeyboardInterrupt:
|
||||
print("\nInterrupted by user")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"ERROR: {e}")
|
||||
import traceback
|
||||
traceback.print_exc()
|
||||
sys.exit(1)
|
||||
303
doc/test_go_doc/README.html
Normal file
303
doc/test_go_doc/README.html
Normal file
|
|
@ -0,0 +1,303 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Z3 Go API - README</title>
|
||||
<style>body { font-family: monospace; margin: 40px; max-width: 1000px; white-space: pre-wrap; }</style>
|
||||
</head>
|
||||
<body>
|
||||
# Z3 Go Bindings
|
||||
|
||||
This directory contains Go language bindings for the Z3 theorem prover.
|
||||
|
||||
## Overview
|
||||
|
||||
The Go bindings provide a comprehensive interface to Z3's C API using CGO. The bindings support:
|
||||
|
||||
- **Core Z3 Types**: Context, Config, Symbol, AST, Sort, Expr, FuncDecl
|
||||
- **Solver Operations**: Creating solvers, asserting constraints, checking satisfiability
|
||||
- **Model Manipulation**: Extracting and evaluating models
|
||||
- **Boolean Logic**: And, Or, Not, Implies, Iff, Xor
|
||||
- **Arithmetic**: Add, Sub, Mul, Div, Mod, comparison operators
|
||||
- **Bit-vectors**: Full bit-vector arithmetic, bitwise operations, shifts, comparisons
|
||||
- **Floating Point**: IEEE 754 floating-point arithmetic with rounding modes
|
||||
- **Arrays**: Select, Store, constant arrays
|
||||
- **Sequences/Strings**: String operations, concatenation, contains, indexing
|
||||
- **Regular Expressions**: Pattern matching, Kleene star/plus, regex operations
|
||||
- **Quantifiers**: Forall, Exists
|
||||
- **Functions**: Function declarations and applications
|
||||
- **Tactics & Goals**: Goal-based solving and tactic combinators
|
||||
- **Probes**: Goal property checking
|
||||
- **Datatypes**: Algebraic datatypes, tuples, enumerations, lists
|
||||
- **Parameters**: Solver and tactic configuration
|
||||
- **Optimize**: Optimization problems with maximize/minimize objectives
|
||||
|
||||
## Building
|
||||
|
||||
### Prerequisites
|
||||
|
||||
- Go 1.20 or later
|
||||
- Z3 library built and installed
|
||||
- CGO enabled
|
||||
|
||||
### With CMake
|
||||
|
||||
```bash
|
||||
mkdir build && cd build
|
||||
cmake -DBUILD_GO_BINDINGS=ON ..
|
||||
make
|
||||
```
|
||||
|
||||
### With Python Build System
|
||||
|
||||
```bash
|
||||
python scripts/mk_make.py --go
|
||||
cd build
|
||||
make
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Basic Example
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Z3Prover/z3/src/api/go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a context
|
||||
ctx := z3.NewContext()
|
||||
|
||||
// Create variables
|
||||
x := ctx.MkIntConst("x")
|
||||
y := ctx.MkIntConst("y")
|
||||
|
||||
// Create constraints: x + y == 10 && x > y
|
||||
ten := ctx.MkInt(10, ctx.MkIntSort())
|
||||
eq := ctx.MkEq(ctx.MkAdd(x, y), ten)
|
||||
gt := ctx.MkGt(x, y)
|
||||
|
||||
// Create solver and check
|
||||
solver := ctx.NewSolver()
|
||||
solver.Assert(eq)
|
||||
solver.Assert(gt)
|
||||
|
||||
if solver.Check() == z3.Satisfiable {
|
||||
model := solver.Model()
|
||||
if xVal, ok := model.Eval(x, true); ok {
|
||||
fmt.Println("x =", xVal.String())
|
||||
}
|
||||
if yVal, ok := model.Eval(y, true); ok {
|
||||
fmt.Println("y =", yVal.String())
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Running Examples
|
||||
|
||||
```bash
|
||||
cd examples/go
|
||||
|
||||
# Set library path (Linux/Mac)
|
||||
export LD_LIBRARY_PATH=../../build:$LD_LIBRARY_PATH
|
||||
export CGO_CFLAGS="-I../../src/api"
|
||||
export CGO_LDFLAGS="-L../../build -lz3"
|
||||
|
||||
# Set library path (Windows)
|
||||
set PATH=..\..\build;%PATH%
|
||||
set CGO_CFLAGS=-I../../src/api
|
||||
set CGO_LDFLAGS=-L../../build -lz3
|
||||
|
||||
# Run example
|
||||
go run basic_example.go
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
### Context
|
||||
|
||||
- `NewContext()` - Create a new Z3 context
|
||||
- `NewContextWithConfig(cfg *Config)` - Create context with configuration
|
||||
- `SetParam(key, value string)` - Set context parameters
|
||||
|
||||
### Creating Expressions
|
||||
|
||||
- `MkBoolConst(name string)` - Create Boolean variable
|
||||
- `MkIntConst(name string)` - Create integer variable
|
||||
- `MkRealConst(name string)` - Create real variable
|
||||
- `MkInt(value int, sort *Sort)` - Create integer constant
|
||||
- `MkReal(num, den int)` - Create rational constant
|
||||
|
||||
### Boolean Operations
|
||||
|
||||
- `MkAnd(exprs ...*Expr)` - Conjunction
|
||||
- `MkOr(exprs ...*Expr)` - Disjunction
|
||||
- `MkNot(expr *Expr)` - Negation
|
||||
- `MkImplies(lhs, rhs *Expr)` - Implication
|
||||
- `MkIff(lhs, rhs *Expr)` - If-and-only-if
|
||||
- `MkXor(lhs, rhs *Expr)` - Exclusive or
|
||||
|
||||
### Arithmetic Operations
|
||||
|
||||
- `MkAdd(exprs ...*Expr)` - Addition
|
||||
- `MkSub(exprs ...*Expr)` - Subtraction
|
||||
- `MkMul(exprs ...*Expr)` - Multiplication
|
||||
- `MkDiv(lhs, rhs *Expr)` - Division
|
||||
- `MkMod(lhs, rhs *Expr)` - Modulo
|
||||
- `MkRem(lhs, rhs *Expr)` - Remainder
|
||||
|
||||
### Comparison Operations
|
||||
|
||||
- `MkEq(lhs, rhs *Expr)` - Equality
|
||||
- `MkDistinct(exprs ...*Expr)` - Distinct
|
||||
- `MkLt(lhs, rhs *Expr)` - Less than
|
||||
- `MkLe(lhs, rhs *Expr)` - Less than or equal
|
||||
- `MkGt(lhs, rhs *Expr)` - Greater than
|
||||
- `MkGe(lhs, rhs *Expr)` - Greater than or equal
|
||||
|
||||
### Solver Operations
|
||||
|
||||
- `NewSolver()` - Create a new solver
|
||||
- `Assert(constraint *Expr)` - Add constraint
|
||||
- `Check()` - Check satisfiability (returns Satisfiable, Unsatisfiable, or Unknown)
|
||||
- `Model()` - Get model (if satisfiable)
|
||||
- `Push()` - Create backtracking point
|
||||
- `Pop(n uint)` - Remove backtracking points
|
||||
- `Reset()` - Remove all assertions
|
||||
|
||||
### Model Operations
|
||||
|
||||
- `Eval(expr *Expr, modelCompletion bool)` - Evaluate expression in model
|
||||
- `NumConsts()` - Number of constants in model
|
||||
- `NumFuncs()` - Number of functions in model
|
||||
- `String()` - Get string representation
|
||||
|
||||
### Bit-vector Operations
|
||||
|
||||
- `MkBvSort(sz uint)` - Create bit-vector sort
|
||||
- `MkBVConst(name string, size uint)` - Create bit-vector variable
|
||||
- `MkBVAdd/Sub/Mul/UDiv/SDiv(lhs, rhs *Expr)` - Arithmetic operations
|
||||
- `MkBVAnd/Or/Xor/Not(...)` - Bitwise operations
|
||||
- `MkBVShl/LShr/AShr(lhs, rhs *Expr)` - Shift operations
|
||||
- `MkBVULT/SLT/ULE/SLE/UGE/SGE/UGT/SGT(...)` - Comparisons
|
||||
- `MkConcat(lhs, rhs *Expr)` - Bit-vector concatenation
|
||||
- `MkExtract(high, low uint, expr *Expr)` - Extract bits
|
||||
- `MkSignExt/ZeroExt(i uint, expr *Expr)` - Extend bit-vectors
|
||||
|
||||
### Floating-Point Operations
|
||||
|
||||
- `MkFPSort(ebits, sbits uint)` - Create floating-point sort
|
||||
- `MkFPSort16/32/64/128()` - Standard IEEE 754 sorts
|
||||
- `MkFPInf/NaN/Zero(sort *Sort, ...)` - Special values
|
||||
- `MkFPAdd/Sub/Mul/Div(rm, lhs, rhs *Expr)` - Arithmetic with rounding
|
||||
- `MkFPNeg/Abs/Sqrt(...)` - Unary operations
|
||||
- `MkFPLT/GT/LE/GE/Eq(lhs, rhs *Expr)` - Comparisons
|
||||
- `MkFPIsNaN/IsInf/IsZero(expr *Expr)` - Predicates
|
||||
|
||||
### Sequence/String Operations
|
||||
|
||||
- `MkStringSort()` - Create string sort
|
||||
- `MkSeqSort(elemSort *Sort)` - Create sequence sort
|
||||
- `MkString(value string)` - Create string constant
|
||||
- `MkSeqConcat(exprs ...*Expr)` - Concatenation
|
||||
- `MkSeqLength(seq *Expr)` - Length
|
||||
- `MkSeqPrefix/Suffix/Contains(...)` - Predicates
|
||||
- `MkSeqAt(seq, index *Expr)` - Element access
|
||||
- `MkSeqExtract(seq, offset, length *Expr)` - Substring
|
||||
- `MkStrToInt/IntToStr(...)` - Conversions
|
||||
|
||||
### Regular Expression Operations
|
||||
|
||||
- `MkReSort(seqSort *Sort)` - Create regex sort
|
||||
- `MkToRe(seq *Expr)` - Convert string to regex
|
||||
- `MkInRe(seq, re *Expr)` - String matches regex predicate
|
||||
- `MkReStar(re *Expr)` - Kleene star (zero or more)
|
||||
- `MkRePlus(re *Expr)` - Kleene plus (one or more)
|
||||
- `MkReOption(re *Expr)` - Optional (zero or one)
|
||||
- `MkRePower(re *Expr, n uint)` - Exactly n repetitions
|
||||
- `MkReLoop(re *Expr, lo, hi uint)` - Bounded repetition
|
||||
- `MkReConcat(regexes ...*Expr)` - Concatenation
|
||||
- `MkReUnion(regexes ...*Expr)` - Alternation (OR)
|
||||
- `MkReIntersect(regexes ...*Expr)` - Intersection
|
||||
- `MkReComplement(re *Expr)` - Complement
|
||||
- `MkReDiff(a, b *Expr)` - Difference
|
||||
- `MkReEmpty/Full/Allchar(sort *Sort)` - Special regexes
|
||||
- `MkReRange(lo, hi *Expr)` - Character range
|
||||
- `MkSeqReplaceRe/ReAll(seq, re, replacement *Expr)` - Regex replace
|
||||
|
||||
### Datatype Operations
|
||||
|
||||
- `MkConstructor(name, recognizer string, ...)` - Create constructor
|
||||
- `MkDatatypeSort(name string, constructors []*Constructor)` - Create datatype
|
||||
- `MkDatatypeSorts(names []string, ...)` - Mutually recursive datatypes
|
||||
- `MkTupleSort(name string, fieldNames []string, fieldSorts []*Sort)` - Tuples
|
||||
- `MkEnumSort(name string, enumNames []string)` - Enumerations
|
||||
- `MkListSort(name string, elemSort *Sort)` - Lists
|
||||
|
||||
### Tactic Operations
|
||||
|
||||
- `MkTactic(name string)` - Create tactic by name
|
||||
- `MkGoal(models, unsatCores, proofs bool)` - Create goal
|
||||
- `Apply(g *Goal)` - Apply tactic to goal
|
||||
- `AndThen(t2 *Tactic)` - Sequential composition
|
||||
- `OrElse(t2 *Tactic)` - Try first, fallback to second
|
||||
- `Repeat(max uint)` - Repeat tactic
|
||||
- `TacticWhen/Cond(...)` - Conditional tactics
|
||||
|
||||
### Probe Operations
|
||||
|
||||
- `MkProbe(name string)` - Create probe by name
|
||||
- `Apply(g *Goal)` - Evaluate probe on goal
|
||||
- `Lt/Gt/Le/Ge/Eq(p2 *Probe)` - Probe comparisons
|
||||
- `And/Or/Not(...)` - Probe combinators
|
||||
|
||||
### Parameter Operations
|
||||
|
||||
- `MkParams()` - Create parameter set
|
||||
- `SetBool/Uint/Double/Symbol(key string, value ...)` - Set parameters
|
||||
|
||||
### Optimize Operations
|
||||
|
||||
- `NewOptimize()` - Create optimization context
|
||||
- `Assert(constraint *Expr)` - Add constraint
|
||||
- `AssertSoft(constraint *Expr, weight, group string)` - Add soft constraint
|
||||
- `Maximize(expr *Expr)` - Add maximization objective
|
||||
- `Minimize(expr *Expr)` - Add minimization objective
|
||||
- `Check(assumptions ...*Expr)` - Check and optimize
|
||||
- `Model()` - Get optimal model
|
||||
- `GetLower/Upper(index uint)` - Get objective bounds
|
||||
- `Push/Pop()` - Backtracking
|
||||
- `Assertions/Objectives()` - Get assertions and objectives
|
||||
- `UnsatCore()` - Get unsat core
|
||||
|
||||
## Memory Management
|
||||
|
||||
The Go bindings use `runtime.SetFinalizer` to automatically manage Z3 reference counts. You don't need to manually call inc_ref/dec_ref. However, be aware that finalizers run during garbage collection, so resources may not be freed immediately.
|
||||
|
||||
## Thread Safety
|
||||
|
||||
Z3 contexts are not thread-safe. Each goroutine should use its own context, or use appropriate synchronization when sharing a context.
|
||||
|
||||
## License
|
||||
|
||||
Z3 is licensed under the MIT License. See LICENSE.txt in the repository root.
|
||||
|
||||
## Contributing
|
||||
|
||||
Bug reports and contributions are welcome! Please submit issues and pull requests to the main Z3 repository.
|
||||
|
||||
## References
|
||||
|
||||
- [Z3 GitHub Repository](https://github.com/Z3Prover/z3)
|
||||
- [Z3 API Documentation](https://z3prover.github.io/api/html/index.html)
|
||||
- [Z3 Guide](https://microsoft.github.io/z3guide/)
|
||||
|
||||
<hr>
|
||||
<p><a href="index.html">Back to Go API Documentation</a></p>
|
||||
</body>
|
||||
</html>
|
||||
164
doc/test_go_doc/index.html
Normal file
164
doc/test_go_doc/index.html
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Z3 Go API Documentation</title>
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; margin: 0; padding: 0; line-height: 1.6; }
|
||||
header { background: #2d3748; color: white; padding: 2rem; }
|
||||
header h1 { margin: 0; font-size: 2.5rem; }
|
||||
header p { margin: 0.5rem 0 0 0; font-size: 1.1rem; opacity: 0.9; }
|
||||
.container { max-width: 1200px; margin: 0 auto; padding: 2rem; }
|
||||
.section { margin: 2rem 0; }
|
||||
.section h2 { color: #2d3748; border-bottom: 2px solid #4299e1; padding-bottom: 0.5rem; }
|
||||
.file-list { list-style: none; padding: 0; }
|
||||
.file-item { background: #f7fafc; border-left: 4px solid #4299e1; margin: 1rem 0; padding: 1rem; border-radius: 4px; }
|
||||
.file-item h3 { margin: 0 0 0.5rem 0; color: #2d3748; }
|
||||
.file-item h3 a { color: #2b6cb0; text-decoration: none; }
|
||||
.file-item h3 a:hover { color: #4299e1; text-decoration: underline; }
|
||||
.file-item p { margin: 0; color: #4a5568; }
|
||||
.code-block { background: #2d3748; color: #e2e8f0; padding: 1.5rem; border-radius: 4px; overflow-x: auto; }
|
||||
.code-block pre { margin: 0; }
|
||||
.install-section { background: #edf2f7; padding: 1.5rem; border-radius: 4px; margin: 1rem 0; }
|
||||
.back-link { display: inline-block; margin-top: 2rem; color: #2b6cb0; text-decoration: none; }
|
||||
.back-link:hover { text-decoration: underline; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<h1>Z3 Go API Documentation</h1>
|
||||
<p>Go bindings for the Z3 Theorem Prover</p>
|
||||
</header>
|
||||
<div class="container">
|
||||
<div class="section">
|
||||
<h2>Overview</h2>
|
||||
<p>The Z3 Go bindings provide idiomatic Go access to the Z3 SMT solver. These bindings use CGO to wrap the Z3 C API and provide automatic memory management through Go finalizers.</p>
|
||||
<p><strong>Package:</strong> <code>github.com/Z3Prover/z3/src/api/go</code></p>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Quick Start</h2>
|
||||
<div class="code-block">
|
||||
<pre>package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/Z3Prover/z3/src/api/go"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Create a context
|
||||
ctx := z3.NewContext()
|
||||
|
||||
// Create integer variable
|
||||
x := ctx.MkIntConst("x")
|
||||
|
||||
// Create solver
|
||||
solver := ctx.NewSolver()
|
||||
|
||||
// Add constraint: x > 0
|
||||
zero := ctx.MkInt(0, ctx.MkIntSort())
|
||||
solver.Assert(ctx.MkGt(x, zero))
|
||||
|
||||
// Check satisfiability
|
||||
if solver.Check() == z3.Satisfiable {
|
||||
fmt.Println("sat")
|
||||
model := solver.Model()
|
||||
if val, ok := model.Eval(x, true); ok {
|
||||
fmt.Println("x =", val.String())
|
||||
}
|
||||
}
|
||||
}</pre>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Installation</h2>
|
||||
<div class="install-section">
|
||||
<p><strong>Prerequisites:</strong></p>
|
||||
<ul>
|
||||
<li>Go 1.20 or later</li>
|
||||
<li>Z3 built as a shared library</li>
|
||||
<li>CGO enabled (default)</li>
|
||||
</ul>
|
||||
<p><strong>Build Z3 with Go bindings:</strong></p>
|
||||
<div class="code-block">
|
||||
<pre># Using CMake
|
||||
mkdir build && cd build
|
||||
cmake -DZ3_BUILD_GO_BINDINGS=ON -DZ3_BUILD_LIBZ3_SHARED=ON ..
|
||||
make
|
||||
|
||||
# Using Python build script
|
||||
python scripts/mk_make.py --go
|
||||
cd build && make</pre>
|
||||
</div>
|
||||
<p><strong>Set environment variables:</strong></p>
|
||||
<div class="code-block">
|
||||
<pre>export CGO_CFLAGS="-I${Z3_ROOT}/src/api"
|
||||
export CGO_LDFLAGS="-L${Z3_ROOT}/build -lz3"
|
||||
export LD_LIBRARY_PATH="${Z3_ROOT}/build:$LD_LIBRARY_PATH"</pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>API Modules</h2>
|
||||
<ul class="file-list">
|
||||
<li class="file-item">
|
||||
<h3><a href="#z3.go">z3.go</a></h3>
|
||||
<p>Package z3 provides Go bindings for the Z3 theorem prover. It wraps the Z3 C API using CGO.</p>
|
||||
</li>
|
||||
<li class="file-item">
|
||||
<h3><a href="#solver.go">solver.go</a></h3>
|
||||
<p>Solver and Model API for SMT solving</p>
|
||||
</li>
|
||||
<li class="file-item">
|
||||
<h3><a href="#tactic.go">tactic.go</a></h3>
|
||||
<p>Tactics, Goals, Probes, and Parameters for goal-based solving</p>
|
||||
</li>
|
||||
<li class="file-item">
|
||||
<h3><a href="#bitvec.go">bitvec.go</a></h3>
|
||||
<p>Bit-vector operations and constraints</p>
|
||||
</li>
|
||||
<li class="file-item">
|
||||
<h3><a href="#fp.go">fp.go</a></h3>
|
||||
<p>IEEE 754 floating-point operations</p>
|
||||
</li>
|
||||
<li class="file-item">
|
||||
<h3><a href="#seq.go">seq.go</a></h3>
|
||||
<p>Sequences, strings, and regular expressions</p>
|
||||
</li>
|
||||
<li class="file-item">
|
||||
<h3><a href="#datatype.go">datatype.go</a></h3>
|
||||
<p>Algebraic datatypes, tuples, and enumerations</p>
|
||||
</li>
|
||||
<li class="file-item">
|
||||
<h3><a href="#optimize.go">optimize.go</a></h3>
|
||||
<p>Optimization with maximize/minimize objectives</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Features</h2>
|
||||
<ul>
|
||||
<li><strong>Core SMT:</strong> Boolean logic, arithmetic, arrays, quantifiers</li>
|
||||
<li><strong>Bit-vectors:</strong> Fixed-size bit-vector arithmetic and operations</li>
|
||||
<li><strong>Floating-point:</strong> IEEE 754 floating-point arithmetic</li>
|
||||
<li><strong>Strings & Sequences:</strong> String constraints and sequence operations</li>
|
||||
<li><strong>Regular Expressions:</strong> Pattern matching and regex constraints</li>
|
||||
<li><strong>Datatypes:</strong> Algebraic datatypes, tuples, enumerations</li>
|
||||
<li><strong>Tactics:</strong> Goal-based solving with tactic combinators</li>
|
||||
<li><strong>Optimization:</strong> MaxSMT with maximize/minimize objectives</li>
|
||||
<li><strong>Memory Management:</strong> Automatic via Go finalizers</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="section">
|
||||
<h2>Resources</h2>
|
||||
<ul>
|
||||
<li><a href="https://github.com/Z3Prover/z3">Z3 GitHub Repository</a></li>
|
||||
<li><a href="../index.html">All API Documentation</a></li>
|
||||
<li><a href="README.html">Go API README</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
<a href="../index.html" class="back-link">← Back to main API documentation</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -8,5 +8,5 @@
|
|||
|
||||
This website hosts the automatically generated documentation for the Z3 APIs.
|
||||
|
||||
@C_API@ @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@ @JS_API@
|
||||
@C_API@ @CPP_API@ @DOTNET_API@ @JAVA_API@ @PYTHON_API@ @OCAML_API@ @JS_API@ @GO_API@
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -841,7 +841,8 @@ WARN_LOGFILE =
|
|||
INPUT = "@TEMP_DIR@" \
|
||||
"@CXX_API_SEARCH_PATHS@" \
|
||||
@DOTNET_API_SEARCH_PATHS@ \
|
||||
@JAVA_API_SEARCH_PATHS@
|
||||
@JAVA_API_SEARCH_PATHS@ \
|
||||
@GO_API_SEARCH_PATHS@
|
||||
|
||||
# This tag can be used to specify the character encoding of the source files
|
||||
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
|
||||
|
|
@ -879,7 +880,8 @@ FILE_PATTERNS = website.dox \
|
|||
z3++.h \
|
||||
@PYTHON_API_FILES@ \
|
||||
@DOTNET_API_FILES@ \
|
||||
@JAVA_API_FILES@
|
||||
@JAVA_API_FILES@ \
|
||||
@GO_API_FILES@
|
||||
|
||||
# The RECURSIVE tag can be used to specify whether or not subdirectories should
|
||||
# be searched for input files as well.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue